Reputation: 133
I am writing a program uses a subroutine DIVU for unsigned integer division. The subroutine takes in R1 as the Dividend and R0 as the Divisor. The output should be R0 Remainder R1 with the carry flag 0 as long as the Divisor does not equal 0. My program is having issues, and I want to make sure there are no cases that this subroutine misbehaves to rule it out. Every input I have tried has given the correct output, but I was wondering if anybody sees any issues this code would have that I don't see.
DIVU PUSH {R2} ;store R2 Value
MOVS R2,#0 ;move 0 to R2 for quotient
CMP R0,#0 ;Compare divisor to 0
BEQ SETCARRY ;if divisor = 0 go to SETCARRY
WHILE CMP R1,R0 ;Compare R1 to R0
BLT ENDWHILE ;if dividend<Divisor End loop
ADDS R2,R2,#1 ;Add 1 to quotient
SUBS R1,R1,R0 ;Dividend - divisor
B WHILE ;branch to start of while
ENDWHILE
MOVS R0,R2 ;move quotient to R0, so R0 remainder R1
POP {R2} ;revert R2 to value before subroutine
PUSH {R0,R1} ;push R0 and R1
MRS R0,APSR ; Set C flag to 0
MOVS R1,#0x20 ; ""
BICS R0,R0,R1 ; ""
MSR APSR,R0 ; ""
POP {R0,R1} ;revert R0 and R1 to answer
QUITDIV BX LR ;Go back to program
SETCARRY
PUSH {R0,R1} ;Store R0 and R1
MRS R0,APSR ; Set C flag to 1
MOVS R1,#0x20 ;""
ORRS R0,R0,R1 ;""
MSR APSR,R0 ;""
POP {R0,R1} ; Revert R0 and R1 to answer
B QUITDIV ;Go back to program
Upvotes: 0
Views: 1339
Reputation: 20974
One issue is that, in the case where the divisor is zero, you never pop r2
, so you end up returning with a possibly unexpected value in r2
, and sp
pointing to the wrong place.
Another is that either way you're not touching the carry flag at all - that is bit 29 of the APSR, and your 0x20
mask is modifying bit 5 (the Thumb execution state bit), which depending on the processor mode you're in will either just be ignored or may give unpredictable behaviour if you try to write nonzero back to it.
That said, you can probably get rid of half the code at the same time as fixing it. On most architecture versions you're specifically allowed to write directly to the flag bits without a read-modify-write sequence, for which an immediate form of MSR
exists. Thus, clearing the flags is simply a case of MSR APSR_nzcvq, #0
, and setting the carry flag alone would be MSR APSR_nzcvq, #0x20000000
.
Upvotes: 1