# Lab1: R32I Simulator <contributed by:`xl86305955`> ###### tags:`Computer Architecture`, `RISC-V` ## Requirements 1. Following the instructions of [Lab1: R32I Simulator](/@sysprog/H1TpVYMdB), you shall write RISC-V assembly programs (R32I ISA) such as calculating Fibonacci numbers and output to the console with system calls. * Don't implement the same subject as others do. Your program shall be different. * You have to ensure the program functioned with [Ripes](https://github.com/mortbopet/Ripes) simulator. 2. You have to explain how each instruction works along with [Ripes](https://github.com/mortbopet/Ripes) simulator. * Explain your program with the visualization for multiplexer input selection, register write/enable signals and more. You have to illustrate each stage such as IF, ID, IE, MEM, and WB. In addition, you should discuss the steps of memory updates accordingly. 3. Write down your thoughts and progress in [HackMD notes](https://hackmd.io/s/features). * [Example page](https://hackmd.io/@kksweet8845/2019q3homworkquiz2): Do not modify this note. * Insert your HackMD notes and RISC-V assembly programs in the following table. ## Development Environment * Tools * Using [Ripes](https://github.com/mortbopet/Ripes) as a RISC-V simulator ## Implementing 9*9 multiplication table using RISC-V ### 9*9 multiplication table implementing in psuedo code My thought is very simple, just translated the high-level language into RISC-V assembly language. ```clike for i from 1 to 9 for j from 1 to 9 print i * j = product print '\n' ``` ### Instruction and Pipeline explanation The RISC-V source code: ```l= .data mul: .string "*" spa: .string " " row: .string "\n" equ: .string "=" .text main: addi s0, zero, 1 # i = 1 loop1: #for i loop slti t0, s0, 10 #if(i<10) beq t0, zero, exit #if(i>=10) go exit addi s1, zero, 1 #else set j=1 loop2: #for j loop slti t0, s1, 10 #if(j<10) beq t0, zero, label #if(j>=10) go label mv t0, s0 # i mv t1, s1 # j mul t2, t0, t1 # i*j mv a1, t0 #else printf i li a0, 1 ecall la a1, mul #printf * li a0, 4 ecall mv a1, t1 #printf j li a0, 1 ecall la a1, equ #printf = li a0, 4 ecall mv a1, t2 #printf i*j li a0, 1 ecall la a1, spa #printf " " li a0, 4 ecall addi s1, s1, 1 #j++ j loop2 label: la a1, row #printf \n li a0, 4 ecall addi s0, s0, 1 #i++ j loop1 exit: #exit li a0, 10 ecall ``` As you can see, the output is showed in `Application Output` like `1*1 = 1 1*2 = 2` ..., and so on ![](https://i.imgur.com/B7rrxas.png) :::danger The changing line operation `\n` don't operate as expected.I can't find the syntax corresponding to this operation in RISC-V ::: The five stage pipeline diagram will represent the circumstance of `i = 1`.The similar instruction will be repeat ten times until `j = 9`,and the tenth times will jump out the loop and do the another block which is the same as the block below. ![](https://i.imgur.com/bHtz6c1.png) ![](https://i.imgur.com/9XuN7wf.png) After seeing the source code and five stage pipeline diagram, we can strat to discuss about the dataflow in this source code now Briefly descibe about which `five stage` represented: * IF (Instuction Fetch): Get the next instruction address which is going to execute in CPU from `PC` (programming counter) * ID (Instruction Decode): Decode the instruction, determine what format is it and what registers to read * MEM (Memory): Some instruction may need memory access, like load world, store world * WB (Write Back): Write back to registers The assembled code: ```= addi x8 x0 1 slti x5 x8 10 beq x5 x0 144 addi x9 x0 1 slti x5 x9 10 beq x5 x0 108 addi x5 x8 0 addi x6 x9 0 mul x7 x5 x6 addi x11 x5 0 addi x10 x0 1 ecall auipc x11 65536 addi x11 x11 -48 addi x10 x0 4 ecall addi x11 x6 0 addi x10 x0 1 ecall auipc x11 65536 addi x11 x11 -64 addi x10 x0 4 ecall addi x11 x7 0 addi x10 x0 1 ecall auipc x11 65536 addi x11 x11 -100 addi x10 x0 4 ecall addi x9 x9 1 jal x0 16 auipc x11 65536 addi x11 x11 -120 addi x10 x0 4 ecall addi x8 x8 1 jal x0 4 addi x10 x0 10 ecall ``` The first instuction set the value of `i` to 1 ```= addi x8 x0 1 ``` These two instructions determined the branch should or should not taken by the value of `i` ```= slti x5 x8 10 beq x5 x0 144 ``` The branch taken or not is based on the value in`x5` and determined in `ID` stage.The value in `x5` register was calculated in EXE stage. This would cause the `control hazard`. The solution of the control hazard is flushed the instuctions, setting the control signal to `NOP` instruction, waiting the `slti` instruction arrive in `WB` stage, so the `beq` instruction can get the right value. ![](https://i.imgur.com/M8pYLkF.png) Then goto loop2, setting up the value of `j` and determine the branch taken or not.Because of the `slti` and `beq` instruction,the control hazard would arise again. ```= addi x9 x0 1 slti x5 x9 10 beq x5 x0 108 ``` Now we enter the loop of `j`. Fisrt of all, we move the value of `i`, `j` to `x5`, `x6` registers respectively, calculate the value of `i*j` and save the result to `x7` register ```= addi x5 x8 0 addi x6 x9 0 mul x7 x5 x6 ``` We want to print out the result. The `ecall` instruction can do so. The `ecall` instuction represented `system call` in RISC-V. For example: ```= la a1, mul // load the * symbol address which defined in .data li a0, 4 // 4 is represented the system call service code to print the string ecall // system call, set the mode bit to kernel mode ``` ![](https://i.imgur.com/LVWlL3m.png) We can print the result `i*j = product` by the following instructions. ```= addi x11 x5 0 addi x10 x0 1 ecall auipc x11 65536 addi x11 x11 -48 addi x10 x0 4 ecall addi x11 x6 0 addi x10 x0 1 ecall auipc x11 65536 addi x11 x11 -64 addi x10 x0 4 ecall addi x11 x7 0 addi x10 x0 1 ecall auipc x11 65536 addi x11 x11 -100 addi x10 x0 4 ecall ``` The `ecall` will cause the pipeline stall for two clocks, until it get the system call information from the forward instructions. ![](https://i.imgur.com/X4MiQK7.png) Finished the first iteration of `j`, the value of `j` add one, and jump to loop2 ```= addi x9 x9 1 jal x0 16 ``` After serveral loops, we can get the result.