--- tags: Computer Architecture 2022 --- # Lab1 RV32I ## Move Zeroes This problem is based on leetcode problem 283. Given an integer array nums, move all 0's to the end of it while maintaining the relative order of the non-zero elements. ## Assembly Code ```clike= main: li s0 0 #array base addr addi s1 x0 5 #array_size = 5 #start filling up array [1,0,0,2,5] li t0 1 sw t0 0(s0) li t0 0 sw t0 4(s0) sw t0 8(s0) li t0 2 sw t0 12(s0) li t0 5 sw t0 16(s0) #call function moveZeroes jal t6 moveZeroes #Print Result Array #li a0, 0 # return 0 lw a0 0(s0) # print s[0] jal printInt lw a0 4(s0) # print s[1] jal printInt lw a0 8(s0) # print s[2] jal printInt lw a0 12(s0) # print s[3] jal printInt lw a0 16(s0) # print s[4] jal printInt li a7, 10 # Exit code ecall moveZeroes: li s2 0 #next non zero index addi s3 x0 -1 # i = -1 addi t1 x0 0 loop: addi s3 s3 1 #i++ bge s3 s1 exit #i >= array_size exit slli t1 s3 2 #i*4 add t1 s0 t1 #array + i*4 lw t3 0(t1) #t3 = array[i] beq t3 x0 loop slli t2 s2 2 #next_nonzero_index * 4 add t2 t2 s0 #array + next_nonzero_index * 4 sw t3 0(t2) #array[next_nonzero_index] = array[i] beq s2 s3 do #if(next_nonzero_index != i) sw x0 0(t1) #store 0 to array[i] do: addi s2 s2 1 #next_nonzero_index++ j loop exit: jr t6 printInt: li a7, 1 ecall jr ra ``` :::warning :warning: Can you use fewer instructions? :notes: jserv ::: ## Edit ```clike= .data nums1: .word 1 .word 0 .word 0 .word 2 .word 5 nums2: .word 1 .word 9 .word 0 .word 6 .word 7 nums3: .word 0 .word 0 .word 0 .word 0 .word 4 .text main: la s0 nums1 # load nums base address to s0 addi s1 x0 5 #nums_size = 5 #call function moveZeroes add a0 s0 x0 # a0 which stands for address of nums array is the first argument add a1 s1 x0 # a1 which stands for array size of nums is the second argument jal ra moveZeroes #jump to moveZeroes function #PrintArray jal ra printArray li a7 10 ecall moveZeroes: addi sp sp -12 sw ra 0(sp) sw s0 4(sp) sw s1 8(sp) li s1 0 #next non zero index = 0 addi s2 x0 0 # i = 0 loop: bge s2 a1 exit #i >= array_size exit slli t0 s2 2 #i * 4 add t0 a0 t0 #array + i*4 lw t1 0(t0) #t1 = array[i] beq t1 x0 next_iter slli t2 s1 2 #next_nonzero_index * 4 add t2 t2 a0 #array + next_nonzero_index * 4 sw t1 0(t2) #array[next_nonzero_index] = array[i] beq s1 s2 next_iter_addIndex #if(next_nonzero_index != i) sw x0 0(t0) #store 0 to array[i] next_iter_addIndex: addi s1 s1 1 #next_nonzero_index++ next_iter: addi s2 s2 1 #i++ j loop exit: lw ra 0(sp) lw s0 4(sp) lw s1 8(sp) addi sp sp 12 jr ra printArray: li a7 1 addi sp sp -8 sw ra 0(sp) sw s0 4(sp) add s0 a0 x0 # s1 = pointer to array add t0 x0 x0 # t0 = i in for loop printloop: bge t0 a1 finish_print_loop slli t1 t0 2 # t1 = i * 4 add t1 t1 s0 # t1 = t1 + array address lw a0 0(t1) # a0 = element in nums[i] li a7 1 ecall addi t0 t0 1 j printloop finish_print_loop: lw ra 0(sp) lw s0 4(sp) addi sp sp 8 jr ra ``` ## Analysis ### Jump and Link ![](https://i.imgur.com/LoT0ffg.png) (image from : https://inst.eecs.berkeley.edu/~cs61c/resources/su18_lec/Lecture7.pdf) jal is an UJ-format instruction. It saves PC+4 in register rd (the return address), then set PC to PC+offset. Target somewhere within +-$2^{19}$ locations. ![](https://i.imgur.com/MbEFXMo.png) In my code, "jal ra moveZeroes" instruction store PC+4 to ra register, and jump to label "moveZeroes". The point is jal instruction won't know where to jump until it moves on to EX stage. Control Hazard occurs, so the next two instructions will be flush. ![](https://i.imgur.com/n4qh8TR.png) ### Data Hazard ![](https://i.imgur.com/xuaQXLu.png) Here is a read after write(RAW) situation happened. In pipeline, we only get data from memory at MEM stage. The two instructions after lw will stall for a cycle(do same thing again) to ensure that it gets the right data from register.