Exercise 1

原代码:

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
39
40
41
42
43
map:
addi sp, sp, -12
sw ra, 0(sp)
sw s1, 4(sp)
sw s0, 8(sp)

beq a0, x0, done # if we were given a null pointer, we're done.

add s0, a0, x0 # save address of this node in s0
add s1, a1, x0 # save address of function in s1
add t0, x0, x0 # t0 is a counter

# remember that each node is 12 bytes long:
# - 4 for the array pointer
# - 4 for the size of the array
# - 4 more for the pointer to the next node

# also keep in mind that we should not make ANY assumption on which registers
# are modified by the callees, even when we know the content inside the functions
# we call. this is to enforce the abstraction barrier of calling convention.
mapLoop:
add t1, s0, x0 # load the address of the array of current node into t1
lw t2, 4(s0) # load the size of the node's array into t2

add t1, t1, t0 # offset the array address by the count
lw a0, 0(t1) # load the value at that address into a0

jalr s1 # call the function on that value.

sw a0, 0(t1) # store the returned value back into the array
addi t0, t0, 1 # increment the count
bne t0, t2, mapLoop # repeat if we haven't reached the array size yet

la a0, 8(s0) # load the address of the next node into a0
lw a1, 0(s1) # put the address of the function back into a1 to prepare for the recursion

jal map # recurse
done:
lw s0, 8(sp)
lw s1, 4(sp)
lw ra, 0(sp)
addi sp, sp, 12
jr ra

纠错

  • 数组偏移量不对

    1
    2
    3
    4
    5
    6
    7
    8
    9
    before:
    add t1, t1, t0 # offset the array address by the count
    lw a0, 0(t1) # load the value at that address into a0

    after:
    li t3, 4
    mul t4, t0, t3
    add t1, t1, t4 # offset the array address by the count
    lw a0, 0(t1) # load the value at that address into a0
  • 调用函数时没有及时存储

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    before:
    jalr s1 # call the function on that value.

    after:
    addi sp, sp, -24
    sw ra, 0(sp)
    sw s1, 4(sp)
    sw s0, 8(sp)
    sw t1, 12(sp)
    sw t2, 16(sp)
    sw t0, 20(sp)

    jalr s1 # call the function on that value.

    lw t0, 20(sp)
    lw t2, 16(sp)
    lw t1, 12(sp)
    lw s0, 8(sp)
    lw s1, 4(sp)
    lw ra, 0(sp)
    addi sp, sp, 24
  • 加载下一node地址进入a0错误

    1
    2
    3
    4
    before:
    la a0, 8(s0) # load the address of the next node into a0
    after:
    lw a0, 8(s0)

    修改前8(s0) 的写法并不适用于 la 指令,因为 la 指令的参数是一个符号(例如标签或变量名),而不是偏移地址。正确的用法应该是像 la a0, symbol 这样的形式。

  • 加载返回函数地址错误

    1
    2
    3
    4
    5
    before:
    lw a1, 0(s1) # put the address of the function back into a1 to prepare for the recursion

    after:
    add a1, s1, x0

    add t0, s0, x0 的结果是 t0 = s0 + x0,实际上等价于 t0 = s0,因为 x0 永远是0。

    lw t0, 0(s0) 的结果是将内存地址 s0 中的数据加载到 t0

  • 加载当前node地址错误

    1
    2
    3
    4
    5
    before:
    add t1, s0, x0 # load the address of the array of current node into t1

    after:
    lw t1, s0, 0(x0)

    add t0, s0, x0 的结果是 t0 = s0 + x0,实际上等价于 t0 = s0,因为 x0 永远是0。

    lw t0, 0(s0) 的结果是将内存地址 s0 中的数据加载到 t0

Exercise 2

1
2
3
4
5
6
7
8
9
10
11
12
f:
# YOUR CODE GOES HERE!
add t0, a0, 3 # The index of array
add t1, a1, x0 # The address of array

li t2, 4
mul t3, t2, t0 # The offset of array

add t4, t1, t3

lw a0, 0(t4) # The result of the index of array
jr ra # Always remember to jr ra after your function!