andrewem wrote:
The code segment goes something like this:
Code:
Result = Accumulator + 1's Complement of Memory Byte + (Carry Flag * 16)
If the Result is greater than 127 or less than -128 Then
Set the Overflow Flag
Otherwise
Clear the Overflow Flag
The multiplying by 16 is what's throwing me off.
That's not quite enough context to know for sure, but to do a BCD calculation, you have to work one hex digit at a time. You can work a byte a time with a binary calculation, but the emulator may be doing a digit at time just in case decimal mode is in effect. When you work one digit at a time, you have to account for a carry between the two digits in a byte, i.e. between bit 3 and bit 4 of the byte. When working on the upper digits, that "carry between the digits" would go into bit 4, rather than bit 0. Also see below.
andrewem wrote:
Again, here's some pseudocode:
Code:
If the Decimal Flag is set Then
Subtract 66h from the Accumulator
Clear the Carry Flag
If the lower 4-bits of the Accumulator is > 9 Then
Add 6h onto the Accumulator
If the upper 4-bits of the Accumulator is > 90 Then
Add 60h onto the Accumulator
Set the Carry Flag
To convert the binary (hex) result of LDA N1 SBC N2, you're checking for two conditions:
#1: If the lower digit of N2 < the lower digit of N1, then subtract $06 from the binary result
#2: If N2 < N1, then subtract $60 from the binary result
(Actually, those are for SEC SBC. For CLC SBC, use <= instead of < in both condtions.) Since these two conditions are independent of one another, there are four possiblities: neither conditions is true, #1 only is true, #2 only is true, or both are true. For each case:
Neither: $00 is subtracted from the binary to produce the decimal result subtracted
#1 only: $06 is subtracted from the binary to produce the decimal result subtracted
#2 only: $60 is subtracted from the binary to produce the decimal result subtracted
Both: $66 is subtracted from the binary to produce the decimal result
Ordinarily you would start from the "neither" case and check each condition one at time to cover the other three cases. The pseudocode is starting from the "both" case, then checking each condition to cover the other three cases, since:
-$66 + $00 = - $66
-$66 + $06 = - $60
-$66 + $60 = - $06
-$66 + $06 + $60 = - $00
You may also find that "General Discussions -> Flag setting on the 65C02 in decimal mode" in the forum is helpful.
Most other microprocessors that directly support BCD don't have a decimal mode. They use an instruction usually called DAA which stands for some combination of Decimal, Adjust, Accumulator, and Addition, which would follow the ADC instruction. On some of these processors, there is a corresponding DAS instruction for subtraction. These processors have two carry flags: the normal between byte carry, and a between digit carry. Using these carry flags and the binary result, they adjust the binary result accordingly. It may be easier to understand how BCD works (and how 6502 emulators implement BCD) by looking at DAA and DAS documentation. Intel (8086 family) and Motorola (68HC08 and later families) both have manuals on their web pages that contain this sort of detail. Naturally, this sort of thing is usually in a multi-megabyte .pdf manual, which is pain to download if you only want to look up one instruction. I can look up the exact manual titles if you can't figure out which ones to download.
By having a decimal mode on the 6502, the BCD result gets directly generated, rather than having to derive it from the binary result. So the specifics of how BCD works aren't often covered, certainly not to that they are on microprocessor with a DAA instruction.