It has been 519 days since the last update, the content of the article may be outdated.

📢
本系列文章只提供课上测试的解读
所有课下作业的源代码请按下面指示前往我的Github仓库~

BUAA-2023-CO

通过阅读本文,您可以大致了解 2023 年秋季北航计算机组成原理课程 P2 课上测试的题目内容、难度和解题思路
P2 课上测试 3题做出2题 通过。主要内容是对 MIPS汇编语言 的使用综合考察
题目每年都会发生变化,题意描述大致清晰,但是可能与原题有一定差异

T0·合并两个有序数组

题目描述

给你两个按非递减顺序排列的整数数组nums1nums2,请你将两个数组合并为 nums,并使合并后的 nums 同样按非递减顺序排列。

边界条件

  • 数组中可能包含重复元素,两个数组中的重复元素需要全部保留;同时,对于边界条件,数组中可能存在负数,请注意自己的实现方式。
  • 输入的数组长度大于0不大于64
  • 输出的数组各元素在-128~128范围内,包含边界

    具体要求

    输入要求

    首先读入 nums1 数组的元素个数 n1
    接下来,每行读取一个元素 nums1[i],共读取 n1 行
    然后读入 nums2 数组的元素个数 n2
    接下来,每行读取一个元素 nums2[i],共读取 n2 行

    输出要求

    逐一输出合并后的 nums 数组元素 nums[i],每个 nums[i] 之间以空格分隔
    最后一个 nums[i] 后面有无空格都可以

    样例输入1

    text
    1
    2
    3
    4
    5
    6
    7
    8
    3
    1
    2
    2
    3
    2
    7
    8

    样例输出1

    text
    1
    1 2 2 2 7 8

    样例输入2

    text
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    8
    -9
    0
    2
    4
    4
    4
    4
    9
    7
    -3
    2
    4
    6
    6
    6
    9

    样例输出2

    text
    1
    -9 -3 0 2 2 4 4 4 4 4 6 6 6 9 9

    求解思路

    我用C语言代码来解释最核心的处理逻辑,你可以自行将其翻译成MIPS
    c
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    //前面已经读入了所有给定的输入
    int i = 0, j = 0;
    while (i + j < n1 + n2)
    {
    if (j >= n2 || (nums1[i] <= nums2[j] && i < n1))
    {
    //如果nums2已经读完,或者nums1[i]小于等于nums2[j]且nums1还没读完
    printf("%d ", nums1[i]);
    i++;
    }
    else
    {
    printf("%d ", nums2[j]);
    j++;
    }
    }

T1&T2

说明

由于T1和T2在考试时提供了相应的C语言代码。
不熟练的同学建议直接翻译,保证测试拿分才是最主要的
由于自身实力有限,我也采用了这种方法,因此这里就不介绍题意,分享一些MIPS的常用模板。

MIPS常用模板

宏模版

mips
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 结束程序
.macro end
li $v0, 10
syscall
.end_macro
# 从键盘读入一个整数存储到%des
.macro getInt(%des)
li $v0, 5
syscall
move %des, $v0
.end_macro
# 将%src存储的整数打印到屏幕
.macro printInt(%src)
move $a0, %src
li $v0, 1
syscall
.end_macro
# 将%src存储的一个字入栈
.macro push(%src)
sw %src, 0($sp)
subi $sp, $sp, 4
.end_macro
# 将栈顶的一个字出栈到%des
.macro pop(%des)
addi $sp, $sp, 4
lw %des, 0($sp)
.end_macro
# 计算二维数组的地址偏移量(字节)
.macro calc_addr(%dst, %row, %column, %rank)
# dts: the register to save the calculated address
# row: the row that element is in
# column: the column that element is in
# rank: the number of lines(rows) in the matrix
multu %row, %rank
mflo %dst
addu %dst, %dst, %column
sll %dst, %dst, 2
.end_macro

主程序模版

mips
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# for (int i = 0; i < n; i++){...},下面$t0为i,$s0为n
for_begin1:
slt $t1,$t0,$s0
beq $t1,0,for_end1

#...

addiu $t0,$t0,1
j for_begin1
for_end1:

# 函数调用的模板
move $a0,$t3
move $a1,$t4
jal dfs #调用函数,需要将实参存入$a0,$a1(这里以两个实参为例)中

dfs:
# arg: x->a0,t0 y->a1,t1
push($ra)
push($t0)
push($t1) #返回地址和需要入栈的中间变量或者参数都要入栈,$t0,$t1只是举例

# 加载实参
move $t0,$a0
move $t1,$a1
#...函数主体

# 返回语句,特别注意某些隐式的返回(C语言中不明写return)
pop($t1)
pop($t0)
pop($ra)
jr $ra

助教问答环节

这部分只提供问题。

  1. 1号寄存器和$sp寄存器的作用是什么?
  2. 哪两个寄存器是保留给操作系统的?
  3. 如何将MIPS汇编导出为二进制代码?
  4. .word伪指令和.space的区别是什么?
  5. 请你简述T0题的求解思路。