简体   繁体   中英

ARM Unsigned Integer Division subroutine

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

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM