I wanted to implement the restoring division algorithm (without using the div operation) in RISCV assembly language.
The algorithm I have to implement is the following
.
I implemented this, but it is not working (consider the a0 register the dividend and the a1 register the divisor).
.data
a: .word 3
b: .word 7
stringa_overflow: .string "Overflow nella divisone"
stringa_div_0: .string "Divisione per 0"
.text
lw a1 a #loading the divisor
lw a0 b #loading the dividend
jal div
end:
li a7 10
ecall
div:
addi sp sp -4 #stack for return address
sw ra 0(sp) #saving the return addrest
add a2 zero a0 #remainder initially set as the dividend
addi a3 zero 0 #Quotient initially set as the remainder
addi t6 t6 32
jal controllo_segno_div
loop:
sub a2 a2 a1
bge a2 zero resto_mag0
add a2 a2 a1
slli a3 a3 1
andi t4 a3 1
beq t4 zero fine_div
addi t5 a3 -1
and a3 a3 t5
j fine_div
resto_mag0:
slli a3 a3 1
andi t4 a3 1 #LSB quotient
bne t4 zero fine_div
addi t5 a3 1
or a3 a3 t5
fine_div:
srli a1 a1 1
addi t6 t6 -1
bne t6 zero loop
lw ra 0(sp)
jr ra
#This procedure changes the sign of the operands so that they are both #positive
controllo_segno_div:
beq a1 zero divide_0 #this gives an error if we are dividing by 0
bge a0 zero secondo_controllo
sub a0 zero a0
addi t2 t2 1
secondo_controllo:
bge a1 zero fine_controllo
sub a1 zero a1
addi t3 t3 1
fine_controllo:
jr ra
divide_0:
la a0 stringa_div_0
li a7 4
ecall
j end
I understand that the divisor should be put (in the first step) in the left part of a 64 bit chunk (we consider 32 bit unsingend integers) but I dont know how to do that.
If possible write a bit of assembly code as english is not my first language.
Other informations that the professor gave (regarding how to initialize variables) is this
Thank you
The biggest obstacle here seems to be that the flow-chart at the top of the question is either incomplete or plain incorrect. I was at first confused about the right-shifting of the divisor shown in the flow-chart, as most bit-by-bit division algorithms keep the divisor unchanged and instead apply a left shift to the concatenation of partial remainder and quotient. I then recalled that Niklaus Wirth presented just such a shift-divisor method in his book Systematic Programming.
Wirth's method is the binary analogue to the decimal long-hand division we learned in elementary school, which requires that we align the most significant digit of the divisor with the most significant digit of the dividend before starting with subtractive iterations to determine the quotient digits. In the same way Wirth's algorithm requires that we "normalize" the divisor so the most significant 1-bits of divisor and dividend are in the same bit position. It is this preparatory step that is missing from the flow chart. By simply right-shifting the divisor, the low-order bits of the divisor are lost one-by-one. The hardware diagram at the bottom of the question is likewise suspect, because a 32-bit division does not require a 64-bit ALU nor a 64-bit divisor and remainder registers. At most it requires 64-bit shift-by-one capability.
The method of normalization given by Wirth is incorrect in finite-precision unsigned integer arithmetic due to overflow in intermediate computation. A correct canonical method of divisor normalization is to count the leading zeros of the two operands, with the difference indicating how many bits the divisor needs to be shifted left. Various processor architectures have a specialized instruction for this, often called
CLZ, but base RISC-V does not have such an instruction. The operation can be emulated, which is a bit cumbersome. In a 2008 research report Rodeheffer gave a modified construction which avoids the overflow problem and does not require a count-leading-zeros primitive.As I am unfamiliar with RISC-V assembly language I am showing ISO-C99 code below that should translate 1:1 into assembly code for 32-bit RISC-V. I am showing the variant based directly on Wirth's algorithm as well as the one based on Rodeheffer's modification.
I noticed belatedly that flowchart and hardware diagram in the question are from Patterson and Hennessy, Computer Organization & Design: The Hardware / Software Interface, 1994, section 4.7. As such, it seems to represent a didactic rather than a real-life example. The only way I can make work what is being described is by emulating a subtraction with carry-out to indicate whether the partial remainder is negative after subtraction:
On a 32-bit RISC-V platform, all of the 64-bit operations would have to be emulated:
I conclude that the example chosen by Patterson and Hennessy is an exceedingly poor choice for an initial introduction to binary division algorithms.