Shop OBEX P1 Docs P2 Docs Learn Events
16bit SX-28 BIN2BCD routine — Parallax Forums

16bit SX-28 BIN2BCD routine

FrasseFrasse Posts: 11
edited 2006-03-31 11:30 in General Discussion
Hi,

Does anybody out there have a working 16bit Binary to BCD routine in SX assembler?
Any help would be much appreciated.

Best regards
Frasse

Comments

  • Michael ChadwickMichael Chadwick Posts: 80
    edited 2006-03-02 06:21
    ;Number to be converted goes into NumH (high byte) and NumL (low byte)
    

    ; Then call bin2bcd, result will be 5 ASCII characters in
    

    ; TenK, Thou, Hund, Tens and Ones suitable for output to an LCD etc.
    

    ; snagged off [url=http://www.sxlist.com]www.sxlist.com[/url]
    

    ;  org SCRATCH
    ;input
    ;=A3*163 + A2*162 + A1*161 + A0*160
    ;=A3*4096 + A2*256 + A1*16 + A0
    NumL     DS      1       ;A1*16+A0
    NumH     DS      1       ;A3*16+A2
    ;output
    ;=B4*104 + B3*103 + B2*102 + B1*101 + B0*100
    ;=B4*10000 + B3*1000 + B2*100 + B1*10 + B0
    TenK     DS      1       ;B4
    Thou     DS      1       ;B3
    Hund     DS      1       ;B2
    Tens     DS      1       ;B1
    Ones     DS      1       ;B0
    

    ;==============================================================================
    ;  bin2bcd
    ; Converts binary number in NumH, NumL to decimal in
    ; TenK, Thou, Hund, Tens, Ones
    ;
    ;==============================================================================
    ;Takes hex number in NumH:NumL  Returns decimal in ;TenK:Thou:Hund:Tens:Ones
    ;written by John Payson, who must be a very clever fellow.
    

    bin2bcd
            bank SCRATCH
            mov     W, <>NumH       ;w  = A2*16+A3
            or      W, #$F0         ;w  = A3-16
            mov     Thou, W         ;B3 = A3-16
            add     Thou, W         ;B3 = 2*(A3-16) = 2A3 - 32
            mov     Hund, W
            mov     W, #$E2
            add     Hund, W         ;B2 = A3-16 - 30 = A3-46
            mov     W, #$32
            add     W, Hund
            mov     Ones, W         ;B0 = A3-46 + 50 = A3+4
    

            mov     W, NumH         ;w  = A3*16+A2
            and     W, #$0F         ;w  = A2
            add     Hund, W         ;B2 = A3-46 + A2 = A3+A2-46
            add     Hund, W         ;B2 = A3+A2-46  + A2 = A3+2A2-46
            add     Ones, W         ;B0 = A3+4 + A2 = A3+A2+4
    

            mov     Tens, W
            mov     W, #$E9
            add     Tens, W         ;B1 = A2-23
            mov     W, Tens
            add     Tens, W         ;B1 = 2*(A2-23)
            add     Tens, W         ;B1 = 3*(A2-23) = 3A2-69 (Doh! thanks NG)
    

            mov     W, <>NumL       ;w  = A0*16+A1
            and     W, #$0F         ;w  = A1
            add     Tens, W         ;B1 = 3A2-69 + A1 = 3A2+A1-69 range -69...-9
            add     Ones, W         ;B0 = A3+A2+4 + A1 = A3+A2+A1+4 and Carry = 0 (thanks NG)
    

            rl      Tens            ;B1 = 2*(3A2+A1-69) + C = 6A2+2A1-138 and Carry is now 1 as tens register had to be negitive
            rl      Ones            ;B0 = 2*(A3+A2+A1+4) + C = 2A3+2A2+2A1+9 (+9 not +8 due to the carry from prev line, Thanks NG)
            not     Ones            ;B0 = ~(2A3+2A2+2A1+9) = -2A3-2A2-2A1-10 (ones complement plus 1 is twos complement. Thanks SD)
    ;;Nikolai Golovchenko [noparse][[/noparse]golovchenko at MAIL.RU] says: complement [noparse][[/noparse]not Ones] can be regarded like:
    ;;      not     Ones
    ;;      inc     Ones
    ;;      dec     Ones
    ;;First two instructions make up negation. So,
    ;;Ones  = -Ones - 1
    ;;      = - 2 * (A3 + A2 + A1) - 9 - 1
    ;;      = - 2 * (A3 + A2 + A1) - 10
            rl      Ones            ;B0 = 2*(-2A3-2A2-2A1-10) = -4A3-4A2-4A1-20
    

            mov     W, NumL         ;w  = A1*16+A0
            and     W, #$0F         ;w  = A0
            add     Ones, W         ;B0 = -4A3-4A2-4A1-20 + A0 = A0-4(A3+A2+A1)-20 range -215...-5 Carry=0
            rl      Thou            ;B3 = 2*(2A3 - 32) = 4A3 - 64
    

            mov     W, #$07         ;w  = 7
            mov     TenK, W         ;B4 = 7
    

    ;B0 = A0-4(A3+A2+A1)-20,  -5...-200
    ;B1 = 6A2+2A1-138,       -18...-138
    ;B2 = A3+2A2-46,         -1...-46
    ;B3 = 4A3-64,            -4...-64
    ;B4 = 7,                 7
    

    ; At this point, the original number is
    ; equal to TenK*10000+Thou*1000+Hund*100+Tens*10+Ones
    ; if those entities are regarded as two's compliment
    ; binary.  To be precise, all of them are negative
    ; except TenK.  Now the number needs to be normal-
    ; ized, but this can all be done with simple byte
    ; arithmetic.
    

            mov     W, #$0A         ;w  = 10
    Lb1:                            ;do
            add     Ones, W         ; B0 += 10
            dec     Tens            ; B1 -= 1
            sb      3.0
            ;skip no carry
            jmp     Lb1             ; while B0 < 0
            ;jmp carry
    Lb2:                            ;do
            add     Tens, W         ; B1 += 10
            dec     Hund            ; B2 -= 1
            sb      3.0
            jmp     Lb2             ; while B1 < 0
    Lb3:                            ;do
            add     Hund, W         ; B2 += 10
            dec     Thou            ; B3 -= 1
            sb      3.0
            jmp     Lb3             ; while B2 < 0
    Lb4:                            ;do
            add     Thou, W         ; B3 += 10
            dec     TenK            ; B4 -= 1
            sb      3.0
            jmp     Lb4             ; while B3 < 0
    

     mov w,#$30  ; convert to ASCII
     add TenK,w
     add Thou,w
     add Hund,w
     add Tens,w
     add Ones,w
            retp
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    MRC
  • FrasseFrasse Posts: 11
    edited 2006-03-02 22:03
    Michael,

    Thanks ever so much for your posted routine for conversion - works like a dream!

    That is when I'm singlestepping it in the debugger. However I am planning to use it as a subroutine within a SXB program and have not been able to get it working in that environment.

    I think I know how to pass the parameters to the subroutine, however I think I'm messing things up when putting the routine in another memory bank.

    I equated the start of the subroutine way out of the way of the "basic code" according to the device listing, but trying to singlestep a SXB program I·get totally·lost among all the embedded bank statements.

    Do you happen to have any example of how to call the (a) subroutine from within an SXB program? I would be very greatful.

    Best regards and many thanks

    Hans alias Frasse
  • Michael ChadwickMichael Chadwick Posts: 80
    edited 2006-03-03 05:37
    Hi Hans,

    I have only used bin2bcd with assembly language. I have not used it with SXB as I only·use SXB to do quick test programs.

    I will look into how to make the bin2bcd work as an SXB subroutine using the parameter variables to pass in the 16 bit value. It would be a valuable exercise for me.

    It will take me a day or two before I can get to it.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    MRC
  • FrasseFrasse Posts: 11
    edited 2006-03-05 09:39
    Thanks Michael,

    Very kind of you, it will be very much appreciated.
    I am eagerly waiting.

    Regards

    Hans
  • Michael ChadwickMichael Chadwick Posts: 80
    edited 2006-03-07 18:39
    Hi Hans,

    It is going to be a bit longer than I anticipated, we have had a death in the family. [noparse]:([/noparse]
    My father in law, who I loved very much, has passed on.

    Later this week, when things settle out some I'll get back to work.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    MRC
  • FrasseFrasse Posts: 11
    edited 2006-03-12 11:11
    Michael,

    Sorry to hear about your great loss.
    Take all the time you need! After all it's only a hobby ours. Some things are more important than others and your family is by far the most important.

    Regards
    Hans
  • Michael ChadwickMichael Chadwick Posts: 80
    edited 2006-03-31 11:30
    Hi Hans,
    Things have finally settled down enough that I could get back to this.· I found a better 16 bit to BCD conversion routine, it is much faster and works very well as an SXB subroutine.· The word to be converted is a two byte array, the output is a 5 byte array.· The input is least significant byte first, the output is most significant digit first.· The output is ASCII and is not zero terminated by the subroutine, but that would be trivial to add.· I have tested it with SXSIM to verify it works with the SX28 and the SX52.· It works very nicely and requires no temporary space other than the __PARAM variables used in SXB.
    ' =========================================================================
    '
    '   File...... BCD_QUICK.SXB
    '   Purpose... Test a Binary to BCD conversion routine in SXB
    '   Author.... Mike Chadwick 
    '   E-mail....  
    '   Started... 2006/03/30
    '   Updated...
    '
    ' =========================================================================
    
    ' -------------------------------------------------------------------------
    ' Program Description
    ' -------------------------------------------------------------------------
    ' Test code for an SXB compatible 16 bit Binary to BCD conversion subroutine
    ' -------------------------------------------------------------------------
    ' Device Settings
    ' -------------------------------------------------------------------------
    ' uncomment one DEVICE line to test with SX29 v 52/48
    DEVICE          SX28, OSC4MHZ, TURBO, STACKX, OPTIONX
    'DEVICE          SX52, OSC4MHZ
    FREQ            4_000_000
    
    ' -------------------------------------------------------------------------
    ' IO Pins
    ' -------------------------------------------------------------------------
    
    ' -------------------------------------------------------------------------
    ' Constants
    ' -------------------------------------------------------------------------
    ' Test values, uncomment one pair only
    TESTVALUEL CON 12345//256
    TESTVALUEH CON 12345/256
    'TESTVALUEL CON 65535//256
    'TESTVALUEH CON 65535/256
    'TESTVALUEL CON 0//256
    'TESTVALUEH CON 0/256
    ' -------------------------------------------------------------------------
    ' Variables
    ' -------------------------------------------------------------------------
    'variables to use while we test the routines
    TestInput VAR Byte(2)  'Our test word to be output low byte then high byte
                           'Subroutine wrapper may be changed for high then low
    TestOutput VAR Byte(5) 'Our test output string, will be most significant
                           'digit first so we can output the string to a serial
                           'device in the correct order
    ' -------------------------------------------------------------------------
      INTERRUPT
    ' -------------------------------------------------------------------------
    ISR_Start:
      ' ISR code here
    ISR_Exit:
      RETURNINT ' {cycles}                                 
    
    ' =========================================================================
      PROGRAM Start
    ' =========================================================================
    Pgm_ID:
      DATA  "Binary to BCD Test", 0
    
    ' -------------------------------------------------------------------------
    ' Subroutines / Jump Table
    ' -------------------------------------------------------------------------
    '
    'Use: BIN2BCD input, output
    ' where input is the starting address of a two byte array to be converted to ASCII bcd
    ' into output which is the address of a 5 byte array, the output is just the 5 ASCII digits
    ' the routine does not zero terminate them.
    ' input is least significant byte then most significant byte
    ' output is most significant digit first.
    BIN2BCD SUB 1,2
    ' -------------------------------------------------------------------------
    ' Program Code
    ' -------------------------------------------------------------------------
    Start:
      ' initialization code here
    Main:
      ' main code here
    TestInput(0) = TESTVALUEL
    TestInput(1) = TESTVALUEH
    '-- Try each number in turn
    TestAnother:
    BIN2BCD TestInput, TestOutput 'this works because the base address of the array is passed
    TestInput(0) = TestInput(0)+1
    TestInput(1) = TestInput(1) + C
    GOTO TestAnother
    
    ' -------------------------------------------------------------------------
    ' Page 1 Code
    ' -------------------------------------------------------------------------
    Page_1:
      ADDRESS $200
    P1_Start:
      GOTO P1_Start                                 ' error if Pg0 overruns Pg1
    
    ' -------------------------------------------------------------------------
    ' Page 2 Code
    ' -------------------------------------------------------------------------
    Page_2:
      ADDRESS $400
    P2_Start:
      GOTO P2_Start                                 ' error if Pg1 overruns Pg2
    
    ' -------------------------------------------------------------------------
    ' Page 3 Code
    ' -------------------------------------------------------------------------
    Page_3:
      ADDRESS $600
    ' -------------------------------------------------------------------------
    'Use: BIN2BCD input, output
    ' where input is the starting address of a two byte array to be converted to ASCII bcd
    ' into output which is the address of a 5 byte array, the output is just the 5 ASCII digits
    ' the routine does not zero terminate them.
    ' input is least significant byte then most significant byte
    ' output is most significant digit first.
    BIN2BCD:
    ASM
    ' Original code by Nikolai Golovchenko found on SXLIST.COM
    ' Original Total execution time:
    ' worst case: 59 + 80 + 66 + 46 = 251 cycles
    ' Modified for SXB by Michael Chadwick
    ' Time from call through return using SXSIM
    ' Brief testing shows 300 cycles worst case at input 63990d $F9F6
    ' Best time 133 Cycles at 12220d $2FBC
    ' Works properly for SX28 and SX 48/52
    ' And doesn't care where the variables are located
    
     
           mov     FSR,__PARAM1 'source address
           mov     __PARAM3,IND 'least significant byte
           inc     FSR
           mov     __PARAM4,IND 'most significant byte
           mov     FSR,__PARAM2 ' pointer to most significant digit of output
           clr     IND  ' clear result
    :sub30k
           mov     W, #3
           add     IND, W
           mov     W, #30000 & $FF
           sub     __PARAM3, W
           mov     W, #30000 >> 8
           sb      C
           mov     W, #(30000 >> 8) + 1
           sub     __PARAM4, W
           snb     C
           jmp     :sub30k
    :add10k
           dec     IND
           mov     W, #10000 & $FF
           add     __PARAM3, W
           mov     W, #(10000 >> 8)
           snb     C
           mov     W, #(10000 >> 8) + 1
           add     __PARAM4, W
           sb      C
           jmp     :add10k
           add     IND,#$30  ; convert to ASCII
     
    ;worst case: 12 * 3 + 11 * 3 - 1 = 59
                                    
           inc     FSR  ' point to next most significant digit out
           clr     IND
    :sub3k                         
           mov     W, #3           
           add     IND, W          
           mov     W, #3000 & $FF 
           sub     __PARAM3, W     
                                   
           mov     W, #3000 >> 8  
           sb      C               
           mov     W, #(3000 >> 8) + 1
           sub     __PARAM4, W     
           snb     C               
           jmp     :sub3k         
                                    
    :add1k                         
           dec     IND             
           mov     W, #1000 & $FF 
           add     __PARAM3, W     
                                    
           mov     W, #(1000 >> 8)
           snb     C               
           mov     W, #(1000 >> 8) + 1
           add     __PARAM4, W     
           sb      C               
           jmp     :add1k         
           add     IND,#$30  ; convert to ASCII
     
    ;worst case: 12 * 4 + 11 * 3 - 1 = 80
                                    
           inc     FSR  ' point to next most significant digit out
           clr     IND
    :sub300                         
           mov     W, #3           
           add     IND, W          
           mov     W, #300 & $FF 
           sub     __PARAM3, W     
                                    
           mov     W, #300 >> 8  
           sb      C               
           mov     W, #(300 >> 8) + 1
           sub     __PARAM4, W     
           snb     C               
           jmp     :sub300         
                                    
    :add100                         
           dec     IND             
           mov     W, #100 & $FF 
           add     __PARAM3, W     
                                    
           mov     W, #(100 >> 8)
           snb     C               
           mov     W, #(100 >> 8) + 1
           add     __PARAM4, W     
           sb      C               
           jmp     :add100         
           add     IND,#$30  ; convert to ASCII
     
    ;worst case: 11 * 4 + 6 * 3 + 3 = 66
                                    
           inc     FSR  ' point to next most significant digit out
           clr     IND
           mov     w,#30
    :sub30 inc     IND
           sub     __PARAM3, W           
           snb     C               
           jmp     :sub30           
           mov     W, IND         
           rl      IND            
           add     IND, W         
           mov     W, #10          
    :add10                           
           dec     IND            
           add     __PARAM3, W           
           sb      C               
           jmp     :add10
           add     IND,#$30
           inc     FSR
           add     __PARAM3,#$30
           mov     IND,__PARAM3   'least significant digit
     
    ;worst case: 6 * 4 + 6 * 3 + 4 = 46
                                    
    ENDASM
           RETURN
     
    P3_Start:
      GOTO P3_Start                                 ' error if Pg3 overruns Pg4
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    MRC
Sign In or Register to comment.