---
# System prepended metadata

title: Lab1 RV32I
tags: [RISCV]

---

---
title: Lab1 RV32I
tags: RISCV
---
# [268. Missing Number](https://leetcode.com/problems/missing-number/description/)
## Description
Given an array nums containing n distinct numbers in the range [0, n], return the only number in the range that is missing from the array.
## Code
```c=
/**
 * 268. Missing Number
 * Given an array nums containing n distinct numbers in the range [0, n], 
 * return the only number in the range that is missing from the array.
 * Return the minimum number of patches required.
 * 
 * Thought:
 * 1. Because we know that nums array contains n numbers and that it is missing exactly one number on the range [0..n−1].
 * 2. we know that n definitely replaces the missing number in nums. 
 * 3. Therefore, if we initialize an integer to n and XOR it with every index and value, we will be left with the missing number.
 */

#include<stdio.h>

int missingNumber(const int*, const int);

int main()
{
    const int nums[] = {3, 0, 1};
    const int numsSize = 3;
    printf("%d\n", missingNumber(nums, numsSize));
    return 0;
}

int missingNumber(const int* nums, const int numsSize)
{
    int ans = numsSize;
    for (int i = 0; i < numsSize; ++i) {
        ans ^= i ^ nums[i];
    }
    return ans;
}
```
## Assembly Code
```c=
.data
nums:    .word 3, 0, 1
numsSize:    .word 3

.text
#include<stdio.h>
#
#int missingNumber(const int*, const int);
#
#int main()
#{
#    const int nums[] = {3, 0, 1};
#    const int numsSize = 3;
#    printf("%d\n", missingNumber(nums, numsSize));
#    return 0;
#}
#
#int missingNumber(const int* nums, const int numsSize)
#{
#    int ans = numsSize;
#    for (int i = 0; i < numsSize; ++i) {
#        ans ^= i ^ nums[i];
#    }
#    return ans;
#}

main:
    la     a0, nums         # a0 = nums[];  // array
    lw     a1, numsSize     # a1 = numsSize;     // length of the array
    jal    ra, missingNumber   # Function call

    # a0 is the return value and also the value we want to print
    li     a7, 1            # print a0
    ecall
    li     a0, 0            # return 0
    li     a7, 10           # Exit code
    ecall                   
    
missingNumber:
    addi   s0, a1, 0        # s0 = ans
    addi   s1, x0, 0        # s1 = i
    bgeu   s1, a1, exit     # i < numsSize
    loop:
        slli   t0, s1, 2    # t0 = i*4
        add    t0, a0, t0   # t0 = nums + i*4
        lw     t0, (0)t0    # t0 = nums[i]
        #nop
        xor    t0, t0, s1   # t0 = i XOR num[i]
        xor    s0, s0, t0   # ans = ans XOR t0
        addi   s1, s1, 1    # ++i
        bgeu   s1, a1, exit # i < numsSize
        j      loop
exit:
    mv     a0, s0           # return value = ans
    ret
```
## Analysis
### IF
* PC 從 0x0 開始
![](https://i.imgur.com/rvHSJ69.png)
* 其對應的值為
![](https://i.imgur.com/4ITKgNi.png)
* machine code 為
![](https://i.imgur.com/f54fMIj.png)
### ID
* 在 ID 階段，cpu 會 decoded 從 IF 階段過來的指令(0x00058413)，以 ```addi x8 x10 0``` 為例，addi 會把 x10 暫存器的值與 0 相加後再放回 x8 暫存器
* ID 階段最後可以看到 reg1 輸出 x11 暫存器的值 0x3
![](https://i.imgur.com/ZgVwaQ4.png)

### EXE
* 在 EXE 階段，指令會被執行，這邊可以看到在存取 x10 暫存器的值時會有 ==Read-after-write hazard== 的問題，所以要從 MEM/EB 暫存器取值(黃色線)
![](https://i.imgur.com/Qvj7hJw.png)
### MEM
* 這邊會負責處理需要 data memory 的部分像是 LW、SW 等指令，但由於現在指令是 addi 不需要 memory，所以會跳過
![](https://i.imgur.com/1mHiQD2.png)
### WB
* 最後 WB 階段再把結果存回指定的暫存器
![](https://i.imgur.com/374RF8w.png)
### Control hazard
* branch 的結果尚未產生時，後續的指令就已經進入 pipeline，如果決定要 branch 到別的位置便會發生錯誤
* 這邊透過把指令 flush 掉來避免
![](https://i.imgur.com/a5ByJ0B.png)












