2015-02-21 2 views
0

Я пишу программу использует подпрограмму DIVU для целых делений без знака. Подпрограмма берет R1 в качестве дивиденда и R0 в качестве делителя. Вывод должен быть R0 Remainder R1 с флагом переноса 0, если Divisor не равен 0. У моей программы есть проблемы, и я хочу убедиться, что нет случаев, когда эта подпрограмма неверно работает, чтобы исключить ее. Каждый вход, который я попробовал, дал правильный вывод, но мне было интересно, не обнаружит ли кто-нибудь какие-либо проблемы, которые этот код будет иметь, которых я не вижу.ARM Unsigned Integer Division подпрограмма

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 
+0

Библиотека ARM включает в себя оптимизированную функцию разделения, которая генерирует обратный делитель, используя некоторые таблицы и сходящийся алгоритм, который проходит через фиксированное количество команд (единственным условием является проверка, чтобы проверить, 1). Это можно проверить, проверив инверсию всех чисел 2^32-1 и используя умножить, чтобы проверить, что продукт равен 1. – rcgldr

ответ

1

Одна проблема в том, что в случае, когда делитель равен нулю, то вы никогда не pop r2, так что вы в конечном итоге возвращаются с возможно неожиданное значение в r2 и sp указывая на неправильное место.

Другим является то, что в любом случае вы не касаетесь флага переноса вообще - это бит 29 APSR, а ваша маска 0x20 модифицирует бит 5 (бит состояния выполнения Thumb), который в зависимости от режима процессора вы будете либо просто проигнорированы, либо можете дать непредсказуемое поведение, если вы попытаетесь написать ненулевое обратно к нему.

При этом вы, вероятно, можете избавиться от половины кода одновременно с его фиксацией. В большинстве архитектурных версий вам разрешено напрямую записывать бит флага без последовательности чтения-изменения-записи, для которой существует an immediate form of MSR. Таким образом, очистка флагов - это просто случай MSR APSR_nzcvq, #0, а установка флага переноса только MSR APSR_nzcvq, #0x20000000.