Full Version : Nixon's Packed BCD Subtraction (PIC ASM)
avr >>PIC 8051 ZILOG ARM TI H8 ETC >>Nixon's Packed BCD Subtraction (PIC ASM)


Admin3- 04-18-2006
BCD (packed) subtraction
From: Tony Nixon


CODE
;       ------------------------------------------
; SUBROUTINE - 24 BIT DIVISION
; numerator:        nratorH  nratorM  nratorL
; denominator:      denomH   denomM   denomL
;
; result:           nratorH  nratorM  nratorL
; remainder:        remainH  remainM  remainL
;
divizn  movlw .24
       movwf BCount
       movf nratorH,w
       movwf shiftH
       movf nratorM,w
       movwf shiftM
       movf nratorL,w
       movwf shiftL
       clrf nratorH
       clrf nratorM
       clrf nratorL
      ;
       clrf remainH
       clrf remainM
       clrf remainL
dloop   bcf status,carry
       rlf shiftL
       rlf shiftM
       rlf shiftH
       rlf remainL
       rlf remainM
       rlf remainH
       movf denomH,w
       subwf remainH,w
       btfss status,z
       goto nochk
      ;
       movf denomM,w
       subwf remainM,w
       btfss status,z
       goto nochk
      ;
       movf denomL,w
       subwf remainL,w
nochk   btfss status,carry
       goto nogo
      ;
       movf denomL,w
       subwf remainL
       btfss status,carry
       decf remainM
       movf remainM,w
       xorlw 0xff
       btfsc status,z
       decf remainH
       movf denomM,w
       subwf remainM
       btfss status,carry
       decf remainH
       movf denomH,w
       subwf remainH
       bsf status,carry
nogo    rlf nratorL
       rlf nratorM
       rlf nratorH
       decfsz BCount
       goto dloop
      ;
       return





Dear webmaster,

Looking for a routine that works.....

In the PIC list , the only one I could get working and that produced a
useable result was Tony Nixons....

QUOTE
Even so it needed tweaking

First compile with MPLAB gave  more than 30 errors plus warnings.

1 Things  not defined initially
2  default warnings
3 Errors like status should be STATUS

These are the things that leave us newbies on  the floor.

Having said all this this code is quite quick and the ONLY ONE that is easy
to get working.

The  tweaked code follows:



CODE
;---------------------------------------------------------------------

;-------                 HEADER                ----------
;---------------------------------------------------------------------
;   FredMaher    Madrid  30 Sept 02  fredfmah@terra.es
;   Tony Newton's 24÷24  routine with worked example
;                      LCD MESSAGES
; position at beginning of 1st line col 0  movlw H'80
; position at beginning of second line     movlw H'C0'


      LIST P=16F628          ;  16F628 Runs at 20 MHz
      INCLUDE "p16F628.inc"

      __CONFIG    _CP_OFF & _WDT_OFF & _HS_OSC & _PWRTE_ON & _LVP_OFF &
_BODEN_OFF

      ERRORLEVEL -224       ;  suppress annoying message because of tris
      ERRORLEVEL -302       ;  suppress message because of page change

;__FUSES _PWRTE_ON & _CP_OFF & _WDT_ON & _HS_OSC & _LVP_OFF & _MCLRE_OFF
& _BODEN_OFF




; Define Information
     #DEFINE RS PORTA, 2
     #DEFINE E  PORTA, 3
   ;#DEFINE TOGGLESW PORTB, 6 ; not used at the moment
   ;#DEFINE LED PORTB, 5

;  Macro
Bank0 macro
bcf STATUS, RP0  ;Select memory bank 0
bcf STATUS, RP1
endm

Bank1 macro
bsf STATUS, RP0  ;Select memory bank 1
bcf STATUS, RP1
endm


;---------------------------------------------------------------
            CBLOCK 20H  ; from 20C to 7F = 67 ;Note. Careful with memory
pages
;                                                      until you get some
practice.
;---------------------------------------------------------------

;                   MATH ROUTINES
;                   24 / 24 Div --> 24

  ; TONY NIXON's Algorithm starts here + my retouching

; SUBROUTINE - 24 BIT DIVISION
; numerator:        nratorH  nratorM  nratorL
; denominator:      denomH   denomM   denomL
;
; result:           nratorH  nratorM  nratorL
; remainder:        remainH  remainM  remainL
nratorH
nratorM
nratorL
denomH
denomM
denomL
remainH
remainM
remainL
shiftH
shiftM
shiftL
BCount


;-------------------------------------------------------------------
       ENDC    ; end of definition block
;-------------------------------------------------------------------




   ORG 0       ; start at location 0
   goto Main   ; jump over to main routine

Main:
   call      Div24
Homesweethome:
   nop
   goto Homesweethome


Div24:

; Example  1000000/16960 = F4240 / 4240  =58.962 ( remainder...
remain/denom gives the decimal correctly... = Dec 0.962)



  movlw 0x0F; using Tony's notation
movwf nratorH
  movlw 0x42
movwf nratorM
  movlw 0x40
movwf nratorL
  movlw 0x00
movwf denomH
  movlw 0x42
movwf denomM
  movlw 0x40
movwf denomL


divizn  movlw .24
        movwf BCount
        movf nratorH,w
        movwf shiftH
        movf nratorM,w
        movwf shiftM
        movf nratorL,w
        movwf shiftL
        clrf nratorH
        clrf nratorM
        clrf nratorL
       ;
        clrf remainH
        clrf remainM
        clrf remainL
dloop   bcf STATUS,C
        rlf shiftL,f
        rlf shiftM,f
        rlf shiftH,f
        rlf remainL,f
        rlf remainM,f
        rlf remainH,f
        movf denomH,w
        subwf remainH,w
        btfss STATUS,Z
        goto nochk
       ;
        movf denomM,w
        subwf remainM,w
        btfss STATUS,Z
        goto nochk
       ;
        movf denomL,w
        subwf remainL,w
nochk   btfss STATUS,C
        goto nogo
       ;
        movf denomL,w
        subwf remainL,f
        btfss STATUS,C
        decf remainM,f
        movf remainM,w
        xorlw 0xff
        btfsc STATUS,Z
        decf remainH,f
        movf denomM,w
        subwf remainM,f
        btfss STATUS,C
        decf remainH,f
        movf denomH,w
        subwf remainH,f
        bsf STATUS,C
nogo:
        rlf nratorL,f
        rlf nratorM,f
        rlf nratorH,f
        decfsz BCount,f
        goto dloop
       ;




              Return

     end
;---------------------------------------------------------------------------------------------------------------------------------
;                                  End of 24/24 division routine by Tony Nixon
;----------------------------------------------------------------------------------------------------------------------------------




QUOTE
Correcting High byte remainder error and added comments to Tony Nixon Code and Fred Mahers update to the 24bit by 24bit divide routine.  Thank you all for the USEFUL Code references and comments here. note Nikolai Golovchenko and Zet P.
Fred Finster 3/15/2005


CODE

;   Here is the changed code, that corrects the HIGH byte remainder error
;     btfsc    STATUS, C      ; Carry Set? Then execute fixup code for when a borrow is generated
;      goto   nodec_remainM  ; when no borrow bit is needed from the higher byte positions.
;
;
;--------------------------------------------------------------------
; SUBROUTINE - 24 BIT DIVISION  from  TONY NIXON
; numerator:        nratorH  nratorM  nratorL
; denominator:      denomH   denomM   denomL
;
; result:           nratorH  nratorM  nratorL
; remainder:        remainH  remainM  remainL
;
Divide_24x24:
     movlw    .24 ; set decimal 24 loop count
     movwf    BCount
     movf     nratorH,w; copy Numerator into Shift Holding ram registers
     movwf    shiftH
     movf     nratorM,w
     movwf    shiftM
     movf     nratorL,w
     movwf    shiftL
     clrf     nratorH;  clear final Answer Numerator Ram locations
     clrf     nratorM
     clrf     nratorL
    ;
     clrf     remainH ;  clear final Answer Remainder Ram locations
     clrf     remainM
     clrf     remainL
dloop:
     bcf  STATUS, C ; bit clear Carry Flag in STATUS register
     rlf  shiftL, f ; Shift numerator(dividend) Left to move
     rlf  shiftM, f ; next bit to remainder
     rlf  shiftH, f ; and shift in next bit of result

     rlf  remainL, f; shift carry (next Dividend bit) into remainder
     rlf  remainM, f
     rlf  remainH, f
     movf     denomH,w
     subwf    remainH,w ; subtract divsor(denomH) from(newly shifted left) Remainder HIGH byte.
     btfss    STATUS, Z
     goto     nochk   ; skip if result was ZERO from good subtraction result
    ;
     movf     denomM,w
     subwf    remainM,w ; subtract divsor(denomM) from(newly shifted left) Remainder MIDDLE byte.
     btfss    STATUS, Z
     goto     nochk   ; skip if result was ZERO from good subtraction result
    ;
     movf     denomL,w
     subwf    remainL,w ; subtract divsor(denomL) from(newly shifted left) Remainder LOW byte.
nochk:
     btfss    STATUS, C  ;  Carry SET? then denom is larger than reemainder
     goto     nogo
    ;
     movf     denomL,w    
     subwf    remainL, f    ; Subtract denominator from remainder value in Low Byte
     btfsc    STATUS, C      ; Carry Set? Then execute fixup code for when a borrow is generated
     goto   nodec_remainM  ; when no borrow bit is needed from the higher byte positions.
     decf     remainM, f     ; Decrement to Borrow from Middle Byte, because carry was SET.
     movf     remainM,w
     xorlw    0xff    ; Check if rollover from Borrow occurred. remainM value went from 0 to 0xFF
     btfsc    STATUS, Z
     decf     remainH, f  ; ZERO bit set, yes rollover, so Decrement to Borrow from High Byte, too!
nodec_remainM:
     movf     denomM,w
     subwf    remainM, f  ; Subtract denominator from remainder value in Middle Byte
     btfss    STATUS, C
     decf     remainH ,f     ; Decrement High Byte, to borrow 1 bit
     movf     denomH,w      
     subwf    remainH, f     ; Subtract denominator from remainder value in High Byte
     bsf  STATUS, C      ; set CARRY bit to rotate in Numerator Result next.
nogo:
     rlf  nratorL, f ; rotate Numerator result left 1 bit
     rlf  nratorM, f
     rlf  nratorH, f
     decfsz   BCount, f  ; decrement the Loop Bit Counter
     goto     dloop
    ;
     return      ; all done



Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.