6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Sep 29, 2024 11:24 am

All times are UTC




Post new topic Reply to topic  [ 32 posts ]  Go to page Previous  1, 2, 3  Next
Author Message
 Post subject:
PostPosted: Sat Feb 25, 2006 10:10 pm 
Offline
User avatar

Joined: Thu Mar 11, 2004 7:42 am
Posts: 362
I don't know of any processor that would convert an invalid BCD number (i.e. a number that contains at least one digit in the range A-F) to a valid BCD number before performing BCD arithmetic. Basically, what the 6502 and other processors do is use an algorithm that gives the correct results for valid BCD numbers, and the results from invalid BCD numbers are "don't care". For example, to add two BCD digits to one another, the following steps could be used:

1. Add the two digits using binary arithmetic
2. If the result is greater than 9, add 6 to the result using binary arithemetic

So, when the algorithm above is used to add 5 and 8, the result from the first step is 5+8 = $0D (in hex). This is greater than 9, so the second step adds 6, and the result from the second step is $0D+$06 = $13.

Notice that this BCD arithmetic algorithm is defined in terms of binary arithmetic. BCD arithmetic is not defined for digits in the range A-F, but binary arithmetic is defined for all digits 0-F, so digits in the range A-F can be plugged into the algorithm above, and the result will be consistent and predictable. For example, when $E is added to $F, the result of the first step is $E+$F = $1D. This is greater than 9, so the second step adds 6, and the result from the second step is $1D+6 = $23. There is no correct answer when at least one of the numbers is an invalid BCD number, so it doesn't matter if the result was $23, $FF, zero, or random (just to list a few examples). In fact, a third step could be added stating: "If either digit is in the range A-F, return a random number", and the algorithm would still be correct, because it still gives the correct result when both numbers are valid BCD numbers.

There are not many uses for performing BCD arithmetic on invalid BCD numbers, so it makes sense for a processor to cater to the common case and use an algorithm as simple as possible while still giving correct results for valid BCD numbers, and just let the chips fall where they may for invalid BCD numbers. Keeping the algorithm simple help keeps the circuitry simple. Generally speaking, simpler circuitry keeps cost lower and allows higher clock speeds, so there is a strong incentive for simplicity. Checking for digits in the range A-F so that they can be handled specially would only add a lot more unnecessary work for processor.

Incidentally, when zero is added to an invalid BCD digit using the (two step) algorithm above, the result will be $10-$15. For example, $A+0 = $0A, which is greater than 9, so adding 6 gives the result $0A+6 = $10. Thus, the algorithm can be used to convert an invalid BCD digit to a valid BCD number by adding zero. The algorithm was not designed with this special case in mind, it just happens to be an unintended benefit.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Feb 27, 2006 9:45 pm 
Offline

Joined: Tue Feb 14, 2006 2:36 pm
Posts: 11
Ok, when do you set the N, V and Z flags when working in 65C02 mode? Obviously, the Z flag is set on a 0 but when do you set the N and V flags? I can't imagine it being the same as binary mode (i.e. > 0x79 == N).


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Tue Feb 28, 2006 1:14 am 
Offline
User avatar

Joined: Thu Mar 11, 2004 7:42 am
Posts: 362
In decimal mode on the 65C02, N means "the most significant bit" (i.e. bit 7 for an 8-bit number), just as it does in binary mode. Thus N is zero when the (8-bit) accumulator result is $00-$7F, and N is one when the accumulator result is $80-$FF in decimal mode. For the most part, in decimal mode it is more convenient for $80 to $99 represent 80 to 99 than -20 to -1.

The V flag in decimal mode is exactly the same on the 65C02 as the 6502. The seven step method in the other thread can be used to predict/calculate its value using only binary arithmetic, even for invalid BCD numbers. In other words, the V flag after

Code:
SED
ADC NUMBER


will be the same on both the 6502 and the 65C02 assuming the accumulator and carry flag upon entry were the same for both processors. Likewise, the V flag after

Code:
SED
SBC NUMBER


will be the same on both the 6502 and the 65C02, again assuming the accumulator and carry flag upon entry were the same for both processors. So despite the statements that the V flag is now "valid" on the 65C02 (and 65816) in decimal mode, its behavior hasn't actually changed at all!


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri Mar 17, 2006 12:39 pm 
Offline

Joined: Tue Feb 14, 2006 2:36 pm
Posts: 11
I have recently purchased an Atari 2600 and a Supercharger and have been testing the 6507 inside for my 6502 emulator. I have answered all of my own questions but have raised one. In decimal mode if the Accumulator or Operand is not a BCD number then this has a big affect on ADC/SBC. Does anybody know the formula? I have performed test after test and sometimes the Accumulator is BCD converted before the ADC/SBC and other times it seems to be converted afterwards (the same goes for the Operand). All I get are strange results. Please Help!!!


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri Mar 17, 2006 3:00 pm 
Offline

Joined: Sun Feb 05, 2006 1:20 am
Posts: 21
Location: The Netherlands
Alucard,
There is no such thing as an 'undocumented feature'. You are really asking about the side effects of improper use.
These so called features are inheritly circumstantial, and no one is familiar with the exact circumstances. So you'll never get reliable answers.

_________________
I trust my somewhat flawed English is comprehensible to all.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Mar 27, 2006 4:38 am 
Offline
User avatar

Joined: Thu Mar 11, 2004 7:42 am
Posts: 362
Sigh. Once again, the 6502 (or 65C02 or 65816) NEVER converts to BCD before performing an addition or subtraction.

Do you understand how, for example, the V flag is determined in decimal mode? The accumulator follows a similar process. But it differs on the 6502 and 65C02, e.g. $20-$0F is $0B on the 65C02, but $1B on the 6502 (and 65816). I've got a program that can compute the decimal mode results (flags and accumulator) using only binary arithmetic, but my program is not documented. If you basically understand the 7 step method for determining the V flag and the accompanying program in the other thread, you'll probably be able to follow my program. Otherwise, you can always wait until I finish my decimal mode write-up. I can't say when that will be, as I am doing it in my free time. But it is near the top of my list of 6502-related projects to do.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Mar 27, 2006 7:54 pm 
Offline

Joined: Tue Feb 14, 2006 2:36 pm
Posts: 11
dclxvi wrote:
Sigh. Once again, the 6502 (or 65C02 or 65816) NEVER converts to BCD before performing an addition or subtraction.


Actually my Atari 2600's 6507 does.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Mar 27, 2006 8:22 pm 
Offline

Joined: Sat Jan 04, 2003 10:03 pm
Posts: 1706
Alucard wrote:
dclxvi wrote:
Sigh. Once again, the 6502 (or 65C02 or 65816) NEVER converts to BCD before performing an addition or subtraction.


Actually my Atari 2600's 6507 does.


Can you post code that demonstrates this? E.g.,

Code:
LDA #$0F
CLC
SED
STA ShouldBe15


If ShouldBe15 does not contain 0x15, then your theory is disproven. Remember: you're saying it converts it before an addition, not after -- hence, if this is true, then you shouldn't need an addition operation before the conversion takes place.

However:

Code:
LDA #$0F
CLC
SED
ADC #$00
STA ShouldBe15


is likely converting it after the addition.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Tue Mar 28, 2006 4:51 am 
Offline
User avatar

Joined: Thu Mar 11, 2004 7:42 am
Posts: 362
There are examples where the result produced by the 6502 in decimal mode will be the same as the result you would get if you converted to BCD beforehand. Such as $00+$0A=$10. That does not mean that this is what the 6502 actually does. The fact that you've found that the "convert to BCD beforehand" theory doesn't always hold true suggests that this is not what the 6502 is really doing.

The cases the 6502 has to cover are for valid BCD numbers. It does not need to convert these to BCD beforehand, of course. The cases with invalid BCD numbers are "don't care". There is no reason why the 6502 would add an EXTRA step which would not affect the cases it has to cover when it is free to do whatever it likes in the "don't care" cases.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Tue Mar 28, 2006 3:46 pm 
Offline

Joined: Tue Feb 14, 2006 2:36 pm
Posts: 11
Here is proof; (performed on an Atari 2600 Jr. with a Starpath SuperCharger)

Code:
SED
CLC
LDA #$FF
ADC #$01

or

F8 18 A9 FF 69 01


I then execute code that displays the accumulator as 1's and 0's on the screen. The result is $66 (01100110).


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Mar 29, 2006 6:37 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8521
Location: Southern California
Alucard, can you try some more combinations of numbers to try to figure out what's going on; because the answer you're getting, as far as anything I can think of so far, is wrong any way you look at it. I don't have any hardware I can try an NMOS 6502 (or derivative) on, and I don't have documentation on what it does in this kind of situation.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Mar 29, 2006 8:46 pm 
Offline

Joined: Tue Mar 09, 2004 3:43 pm
Posts: 44
Location: Bristol, UK
Surely $FF is an invalid BCD number to begin with? Which means that adding one to it is undefined, and can vary from one 6502 (or 6502-like) chip to another.

What happens if you load the accumulator with, say, $42 and add one?


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Mar 30, 2006 9:57 am 
Offline

Joined: Tue Feb 14, 2006 2:36 pm
Posts: 11
If the accumulator is $FF and you add, say $01 then the result is $66. $42 + $01 = $43. Here is what I am sure of;

Code:
SED
CLC
LDA #$FF

// ADC

if( (A & 0xF0) > 0x90 )
A += 0x60;
if( (A & 0x0F) > 0x09 )
A += 0x06;

// A = $65

A += Immediate; ($01)

// A = $66


The immediate data is NOT converted.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Mar 30, 2006 2:25 pm 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
Thats doesn't make sense. The ALU would have to decimal correct twice under your scheme, once before addition and again after.

Consider what would happen if you added $F9 and $01. In your scheme the $F9 would become $69 before the $01 was added leaving $6A. Another round of decimal correction would be needed to correct the least nybble.

I've always understood BCD correction to be a phase applied after a binary addition/subtraction has been performed.

Can you rerun your tests using different memory locations just incase the ones you chose are trashed by an interrupt or operating system routine to double check your results.

_________________
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Mar 30, 2006 6:47 pm 
Offline

Joined: Sat Jan 04, 2003 10:03 pm
Posts: 1706
Alucard wrote:
If the accumulator is $FF and you add, say $01 then the result is $66.


Correct; however, $FF is 255 in decimal, so pre-conversion would result in A=$55, not $66. Adding 1 then would result in $56.

You just proved that the 6507 does not, in fact, do BCD pre-conversion, but rather instead, responds by adding $FF + $60 + $06 + $01 + carry, all at once. I think this is a significant difference, because it proves that merely enabling and disabling the D bit doesn't "pre-convert" the contents of A, but rather, you need an ADC to trigger it.

It also proves that the ALU has 5 inputs to its adder, which is pretty amazing. That's a big-ass adder. :)

I verified this on the Commodore +4 emulator and the Commodore 128 emulators as well -- so its behavior exists on the MOS Technology CPUs as well. Also, as a quick test, I typed the following quick program into the Commodore Plus/4 emulator:

Code:
MONITOR
A 033C  F8       SED
A 033D  18       CLC
A 033E  A9 FD    LDA #$FD
A 0340  69 01    ADC #$01
A 0342  D8       CLD
A 0343  00       BRK
A 0344
G 033C
BREAK
   PC  SR AC XR YR SP
; 0345 31 64 FF FF F9


Note that AC is $64 in this case. Changing the addend to $07 yields $6A as the result, as expected above. However,

Code:
MONITOR
A 033C  F8       SED
A 033D  18       CLC
A 033E  A9 F0    LDA #$F0
A 0340  69 0F    ADC #$0F
A 0342  D8       CLD
A 0343  00       BRK
A 0344
G 033C
BREAK
   PC  SR AC XR YR SP
; 0345 31 65 FF FF F9


Notice that the result is $65 here, not $6F as one would expect. Therefore, the proper emulation code (in this case) is this:

Code:
// SED
// CLC
// LDA #$F0
// ADC #$0F

A += 0x0F;

if( (A & 0xF0) > 0x90 )  A += 0x60;
if( (A & 0x0F) > 0x09 )  A += 0x06;


Thus, the behavior of BCD mode when given incorrect inputs cannot really be predicted. At least, not without a careful, exhaustive search of all 131072 input combinations (2x8 operand bits, plus carry bit).

I'm sure that this artifact can be exploited in some beneficial manner, though, especially when doing binary manipulation of bits 6, 5, 2, or 1.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 32 posts ]  Go to page Previous  1, 2, 3  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 31 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: