# Quiz2 of Computer Architecture (2020 Fall)
:::info
:information_source: General Information
* You are allowed to read [lecture materials](http://wiki.csie.ncku.edu.tw/arch/schedule).
* That is, an open book exam.
* You shall not disclose your answer during the quiz.
* Each answer has 5 points.
* :timer_clock: 09:10 ~ 10:00AM on Oct 6, 2020
:::
## Question `A`
For each RISC-V instruction sequence below, provide the ==hex== values of the specified registers after each sequence has been executed. Assume that all registers are initialized to 0 prior to each instruction sequence. Each instruction sequence begins with the line (`. = 0x0`) which indicates that the first instruction of each sequence is at address 0. Assume that each sequence execution ends when it reaches the `UNIMPL` instruction.
```cpp
. = 0x0
jal x5, L1 # Value left in x5? __A01__
jal x6, end # Value left in x6? __A02__
L1: j L2
jal x6, end
L2: jr x5 # Address of label L2? __A03__
end:
UNIMPL
```
> * A01 = ?
> * A02 = ?
> * A03 = ?
---
## Question `B`
:::info
Pseudo-instructions
– shorthand syntax for common assembly idioms
– `mv rd, rs` = `addi rd, rs, 0`
– `li rd, 13` = `addi rd, x0, 13`
:::
RISC-V sequence B refers to certain locations in memory. Provide the ==hex== values of the specified registers after each sequence has been executed. Assume that the first 5 memory locations starting from address 0x600 have been initialized with the following 5 words. Assume that each sequence execution ends when it reaches the `UNIMPL` instruction.
```cpp
. = 0x600
# First 5 words at address 0x600
.word 0x60046004
.word 0x87654321
.word 0x12345678
.word 0x00000001
```
Sequence `B`
```cpp
. = 0x0
li x7, 0x600
mv x8, x7 # Value left in x7? __B01__
loop: addi x8, x8, 4 # Value left in x8? __B02__
lw x9, 0(x8)
sw x9, -4(x8)
blez x9, loop # Value left in x9? __B03__
lw x7, 0(x7)
end:
UNIMPL
```
> * B01 = ?
> * B02 = ?
> * B03 = ?
---
:::info
Function Calls
The following pseudo instructions are available to call subroutines far from the current position:
* `call <symbol>`: call away subroutine
- ra is implicitly used to save the return address.
* `call <rd>, <symbol>` : call away subroutine
- similar to `call <symbol>`, but `<rd>` is used to save the return address instead.
* `tail <symbol>` : tail call away subroutine
- `t1` is implicitly used as a scratch register.
* `jump <symbol>, <rt>` : jump to away routine
- similar to `tail <symbol>`, but `<rt>` is used as the scratch register instead.
:::
## Question `C`
Below is the C code for a recursive implementation of binary search, which finds the index at which an element should be inserted into a sorted array to ensure that the array is still sorted after the insertion. The roughly translated RISC-V assembly follows the C code.
```cpp
/* A recursive binary search function.
* It returns location of x in given array arr[l..r] is present,
* otherwise -1
*/
int binary_search(int arr[], int l, int r, int x)
{
if (r >= l) {
int mid = l + (r - l) / 2;
/* If the element is present at the middle itself */
if (arr[mid] == x)
return mid;
/* If element is smaller than mid, then it can only be present
* in left subarray
*/
if (arr[mid] > x)
return binary_search(arr, l, mid - 1, x);
/* Else the element can only be present in right subarray */
return binarySearch(arr, mid + 1, r, x);
}
/* We reach here when element is not present in array */
return -1;
}
```
- [ ] Translated RISC-V Assembly (`C01` is unknown)
```cpp
binary_search:
addi sp, sp, -8
sw ra, 4(sp)
sw s0, 0(sp)
mv s0, a2
beq a1, a2, done
add t0, a1, a2
srli t0, t0, 1
slli t1, t0, 2
add t1, a0, t1
lw t1, 0(t1)
if_: bge __C01__
mv a2, t0
j recurse
else_:
addi t0, t0, 1
mv a1, t0
recurse:
call binary_search
mv s0, a0
done:
mv a0, s0
lw s0, 0(sp)
lw ra, 4(sp)
L1:
addi sp, sp, 8
ret
```
1. What should be in the blank on the line labeled if to make the assembly implementation match the C code?
> C01 = ?
2. How many words will be written to the stack before the program makes each recursive call to the function binary_search? That is, number of words pushed onto stack before each recursive call?
> C02 = ?
3. The program’s initial call to function binary_search occurs outside of the function definition via the instruction `call binary_search`. The program is interrupted during a recursive call to `binary_search`, just prior to the execution of `addi sp, sp, 8` at label L1. The diagram on the right shows the contents of a region of memory. All addresses and data values are shown in hex. The current value in the SP register is `0xEB0` and points to the location shown in the diagram CONTENT. What are the ==hex== values in the following registers right when the execution of binary_search is interrupted?
Current value of `s0`?
> C03 = ?
Current value of `ra`?
> C04 = ?
| Memory address | Data content |
| -------------- | ------------ |
| 0xEA4 | 0x0 |
| 0xEA8 | 0x5 |
| 0xEAC | 0xC4 |
| SP→ 0xEB0 | 0x6 |
| 0xEB4 | 0xC4 |
| 0xEB8 | 0x6 |
| 0xEBC | 0xC4 |
| 0xEC0 | 0xA |
| 0xEC4 | 0xC4 |
| 0xEC8 | 0x3E |
| 0xECC | 0xCA4 |
| 0xED0 | 0xCED |
> diagram: CONTENT. `sp` points to address `0xEB0`
4. What is the hex address of the `ret` instruction?
> C05 = ?
---
## Question `D`
The following functions are missing code to save/restore registers to/from the stack. Identify the registers that need to be saved to the stack at any point in the function. You do not need to provide the missing code. If the RISC-V calling convention does not require any registers to be saved to / restored from the stack, write `none`.
- [ ] Case `1`
```cpp
# register save/restore code missing
func:
beqz a0, done
mv s0, a0
addi a0, a0, -1
jal func
# use return value of func:
add a0, s0, a0
done:
ret
```
registers needing saving (or "none")?
> D01 = ?
- [ ] Case `2`
```cpp
# register save/restore code missing
func:
li t0, 0x5F3759DF
xor t0, a0, t0
loop:
beqz t0, end
srli t0, t0, 1
andi t0, t0, 0x1
beqz t0, lsb_zero
addi s0, s0, 1
j loop
lsb_zero:
addi s1, s1, 1
j loop
end:
ret
```
registers needing saving (or "none")?
> D02 = ?
---
## Question `E`
Below is the C code and translated RISC-V assembly.
```cpp
int func(int m, int n)
{
if (m == 0)
return n + 1;
if (n == 0) /* m_nonzero */
return func(m - 1, 1);
/* both_nonzero */
return func(m - 1, func(m, n - 1));
}
```
- [ ] Translated RISC-V Assembly (`X` is unknown.)
```cpp
func:
bnez a0, m_nonzero
addi a0, a1, 1
ret
m_nonzero:
addi sp, sp, -X
sw ra, 0(sp)
bnez a1, both_nonzero
addi a0, a0, -1
li a1, 1
call func
lw ra, 0(sp)
addi sp, sp, X
ret
both_nonzero:
sw a0, 4(sp)
# inner call
addi a1, a1, -1
call func
mv a1, a0
lw a0, 4(sp)
# outer call
addi a0, a0, -1
call func
lw ra, 0(sp)
addi sp, sp, X
ret
```
What is the minimum value of `X`, the number of bytes needed on the stack?
> E01 = ?
---
## Question `F`
You are given the following C code along with an incomplete translation of this code into RISC-V assembly. Assume that execution ends when it reaches the `UNIMPL` instruction.
```cpp
int a[4] = {0x1, 0x2, 0x4, 0x8};
int b = 0x5;
int c = 0;
for (int i = 3; i >= 0; i--) {
c = a[i] & b;
if (c) break;
}
```
- [ ] Translation into RISC-V assembly (`F01` is unknown)
```cpp
. = 0x0
li a0, 0x800 // starting address of array
li a1, 0x5
li a2, 0x3
loop:
mv t0, a2
__F01__
add t0, a0, t0 # Value left in t0? __F02__
lw t1, 0(t0)
and t1, t1, a1
bnez t1, end; # Value left in t1? __F03__
addi a2, a2, -1
bgez a2, loop # Value left in a2? __F04__
end:
UNIMPL
. = 0x800 # contents of array a, where a[0] is at 0x800
.word 0x1
.word 0x2
.word 0x4
.word 0x8
```
> F01 = ?
Provide the ==hex== values left in the registers below following the execution of the corrected code.
* Value left in t0?
> F02 = ?
* Value left in t1?
> F03 = ?
* Value left in a2?
> F04 = ?
---
## Question `G`
Consider the C code below and its translation to RISC-V assembly code, shown in the later.
```cpp
int f(int a, int b)
{
int c = b – a;
if (c & G01 == 0) /* c is a multiple of 4 */
return 1;
int d = f(a – 1, b + 2);
return 3 * (d + a);
}
```
- [ ] RISC-V Assembly (`G01` is unknown.)
```cpp
f: sub a2, a1, a0
andi a2, a2, __G01__
bnez a2, ELSE
li a0, 1
jr ra
ELSE:
addi sp, sp, -8
sw a0, 0(sp)
sw ra, 4(sp)
addi a0, a0, -1
addi a1, a1, 2
jal ra, f
A4: lw a1, 0(sp)
lw ra, 4(sp)
L1: add a0, a0, a1
slli a1, a0, 1
add a0, a0, a1
addi sp, sp, 8
jr ra
```
1. What value should the `G01` term in the C code and the assembly be replaced with to make the if statement correctly check if the variable `c` is a multiple of 4?
> G01 = ?
2. How many words will be written to the stack before the program makes each recursive call to the function f? That is, number of words pushed onto stack before each recursive call?
> G02 = ?