BCD division by 2

Here you can ask questions or provide insights about how to use efficiently 6502 assembly code on the Oric.
User avatar
Twilighte
Game master
Posts: 819
Joined: Sat Jan 07, 2006 12:07 am
Location: Luton, UK
Contact:

BCD division by 2

Post by Twilighte »

Whats the simplest way to divide a single BCD number by 2 or 4 ?

BCD is a special mode in the 6502 that holds decimal numbers in Bytes as two 4 bit digits. So that maximum value is 99 and minimum is 00.
In BCD mode only ADC and SBC behave appropriately like setting carry if the result of the ADC takes the number over 99.

I can't use LSR since it doesn't operate in the right way. For example 99/2 in BCD mode using LSR would give me 4C which is clearly wrong, and should be 49.

I tried using a simple loop like this preloading A with the BCD number..

Code: Select all

      LDX #00
      SED
      SEC
loop1 INX
      SBC #02
      BCS loop1
      CLD
But it fails because whilst the accumulated number in X is correct, it is not BCD encoded.
The only way i can see is this..

Code: Select all

      STA BCDNumber
      SED
      LDA #00
      STA Result
      CLC
loop1 LDA Result
      ADC #00
      STA Result
      LDA BCDNumber
      SEC
      SBC #02
      STA BCDNumber
      BCS loop1
      CLD
But this seems extremely long winded just to divide the BCD number by 2 even in its optimised form, any thoughts? :P
User avatar
Chema
Game master
Posts: 3013
Joined: Tue Jan 17, 2006 10:55 am
Location: Gijón, SPAIN
Contact:

Post by Chema »

Tricky one...

I don't see an easy (I mean compact and fast) way of doing this, but searching a bit with Google I found this:

http://www.atarimagazines.com/compute/i ... OUTINE.php

It is a routine to convert BCD to binary, but he is using the trick of dividing by two, so we can borrow this part, I assume. The explanation that might be useful is this one:
"The eight bit "weights" in a byte of memory that represent a binary number are 1, 2, 4, 8, 16, 32, 64, and 128, proceeding from the right-most bit to the left-most bit. Clearly, shifting the number to the right divides each bit weight by two. That is why an LSR or an ROR instruction may be used to divide a binary number by two. However, if the same memory location represents a BCD number, then the bit weights are 1, 2, 4, 8, 10, 20, 40, 80. consequently, a shift-right or a rotate-right instruction results in division-by-two only for bits zero, one, two, three, five, six, and seven. Shifting bit four (with a weight of ten) to the right changes its weight to eight. Eight is three more than five, the number you usually get when you divide ten by two. So, the trick to dividing a BCD number by two is to shift right or rotate right as usual, but if a one is shifted from bit four to bit three, then you must subtract three from the shifted-right result to get the correct answer. That's it folks. I wish I could say it was my idea, but I found it in Peatman's5 book."
It includes some code, so it could be worth having a look.

Cheers
User avatar
Twilighte
Game master
Posts: 819
Joined: Sat Jan 07, 2006 12:07 am
Location: Luton, UK
Contact:

Post by Twilighte »

Thats logical until the end. Done the maths and he is right, subtracting 3 if a carry from Bit4 to 3 occurs is correct but looks like a kludge or bodge, even if it does work.

In code this is difficult because we cannot examine bits (apart from B6 and 7 with BIT) without affecting the Accumulator on the 6502..

Code: Select all

      LSR
      STA temp01
      AND #08
      CMP #8
      LDA temp01
      BCC skip1
      SBC #03
skip1 
And that final SBC must be in binary, not BCD.
Definately less readable than previous code but definately faster and shorter, thanks Chema :P
User avatar
Dbug
Site Admin
Posts: 4438
Joined: Fri Jan 06, 2006 10:00 pm
Location: Oslo, Norway
Contact:

Post by Dbug »

If you are going to use BCD, make sure you don't do anything wrong in your interrupt handlers, or that you stop interrupts before :)

Was bitten by that when I worked on my minigames :D
Post Reply