Page 1 of 1

Problem with the logic besides the SBC instruction emulation

Posted: Tue Aug 17, 2010 3:03 am
by ehguacho
i came across this code to emulate the SBC instruction:

Code: Select all

uint temp = (uint)(ACC - src - C_FLAG);
Z_FLAG = !(temp & 0xff);
N_FLAG = (temp & 0x80);
V_FLAG = ((ACC ^ temp) & (Memoria[PC] ^ temp) & 0x80)
C_FLAG = (temp < 0x100);
ACC = (byte)(temp & 0xff);
i tested the code it do work perfectly, but what about this line?

Code: Select all

V_FLAG = ((ACC ^ temp) & (Memoria[PC] ^ temp) & 0x80)
already read the doc in 6502.org that covers the V flag, but i still can't understand the logic besides how the V flag is set in that code line.

anyone smarter than me to help me out? :(

Posted: Tue Aug 17, 2010 4:15 am
by GARTHWILSON
I'm not sure I understand the question, but have you looked at http://6502.org/tutorials/vflag.html ?
Quote:
sorry about my english, i'm from Argentina :S
¡Eh, gaucho! You estaba en Jujuy, Salta, y Tucumán unos ocho años cuando fui niño, y aprendí a leer y escribir primero en castellano y luego en inglés. Desafortunadamente, tengo casi nada de vocabulario técnico en castellano.

Posted: Tue Aug 17, 2010 5:25 am
by ehguacho
yes i did Garth, actually that's the doc if was reffering to.

looks like that expression was whipped up from a Karnaugh map or something like that, who knows... :shock:

Posted: Tue Aug 17, 2010 6:03 am
by GARTHWILSON
You can also get the explanation on pages 135-136 of the excellent programming manual at http://www.westerndesigncenter.com/wdc/ ... manual.pdf , something everyone here should have. It's a 1.7MB file. (Hmmm... that doesn't seem possible since it's 469 pages! Oh well, 1.7MB is what the computer says.)

Posted: Wed Aug 18, 2010 4:33 am
by BigDumbDinosaur
GARTHWILSON wrote:
It's a 1.7MB file. (Hmmm... that doesn't seem possible since it's 469 pages! Oh well, 1.7MB is what the computer says.)
That the size my system reports.

Posted: Wed Aug 18, 2010 2:12 pm
by ElEctric_EyE
oh, nice. I wasn't aware of this manual. Thanks Garth! This is how I really learn about a processor, maybe set me on a path to the '816...

Posted: Wed Aug 18, 2010 3:05 pm
by kc5tja
That must be some freakin' insane compression. Even if you round up to 2MB, that weighs in at less than 5KB per page, average!

Posted: Wed Aug 18, 2010 4:44 pm
by GordonZaft
there's a lot of whitespace in the doc.

Posted: Wed Aug 18, 2010 5:01 pm
by kc5tja
I hope that's intended to be humorous, for PDFs don't record whitespace. :) PDFs are scene graphs.

Posted: Wed Aug 18, 2010 5:15 pm
by GordonZaft
(okay, the forum lost this post once before, hopefully this one will stick)

It's not intended to be humorous. I am certainly not "up" on PDF tech but reading Wikipedia (http://en.wikipedia.org/wiki/Pdf#Technical_overview) seems to suggest that strings in the doc are stored as... strings. The large amount of whitespace in the document as it appears shouldn't take up storage space, since it's due to the font specifications used for the text in the doc.

Re: Problem with the logic besides the SBC instruction emula

Posted: Thu Aug 19, 2010 1:27 am
by dclxvi
ehguacho wrote:

Code: Select all

uint temp = (uint)(ACC - src - C_FLAG);
Z_FLAG = !(temp & 0xff);
N_FLAG = (temp & 0x80);
V_FLAG = ((ACC ^ temp) & (Memoria[PC] ^ temp) & 0x80)
C_FLAG = (temp < 0x100);
ACC = (byte)(temp & 0xff);
That code doesn't look correct.

First, the formula is A = A - M - 1 + C, where M (memory) is the operand of the SBC instruction. So the C flag should be inverted prior to the temp calculation (to be fair, since this is only an excerpt of code, maybe it was).

Second, for a calculation such as $10-$20, temp would be $F0 (-16), so there should be no overflow, but the V_FLAG calculation would be non-zero. Yet $20-$10 also has no overflow, but V_FLAG would be zero (which is correct).

Third, -- this is not necessarily an error, just an observation -- it's strange that src is used in the temp calculation but the Memoria array is used in the V_FLAG calculation.

Anyway, one way to determine the formula for the V flag is from the truth table for 1-bit subtraction. (In this table, N is the N flag, i.e. the A output.) A 1-bit twos complement number ranges from -1 to 0.

Code: Select all

A M c | N C V
------+------
0 0 0 | 1 0 0   0 -  0 - 1 + 0 = -1
0 0 1 | 0 1 0   0 -  0 - 1 + 1 =  0
0 1 0 | 0 0 0   0 - -1 - 1 + 0 =  0
0 1 1 | 1 0 1   0 - -1 - 1 + 1 =  1
1 0 0 | 0 1 1  -1 -  0 - 1 + 0 = -2
1 0 1 | 1 1 0  -1 -  0 - 1 + 1 = -1
1 1 0 | 1 0 0  -1 - -1 - 1 + 0 = -1
1 1 1 | 0 1 0  -1 - -1 - 1 + 1 =  0
Just as you can extend 8-bit to subtraction to 16 bits with a sequence like:

Code: Select all

LDA NUM1
SBC NUM2
STA NUM3
LDA NUM1
SBC NUM2
STA NUM3
a 1-bit subtraction can be extended to 2 bits, 3 bits, etc. in the same sort of way. So the 1-bit subtraction truth table above is actually sufficient to describe 8-bit addition. c represents the carry from the addition of the first 7 bits, A and M are the hi bits of the A and the operand, and then N, C, and V represent the N, C, and V flag results. (If you're having trouble seeing this, you could work out the 32 cases for a 2-bit addition by hand -- the input bits will be A1, A0, M1, M0, and c -- and you'll find that the formulas below still hold true.)

From the truth table, you can derive common formulas for the V flag:

V = C XOR c
V = ((NOT A) AND M AND N) OR (A AND (NOT M) AND (NOT N))

The latter formula is the same as:

V = (A XOR M) AND (A XOR N)

so replacing the second temp with ACC should do the trick.

Re: Problem with the logic besides the SBC instruction emula

Posted: Thu Aug 19, 2010 7:18 am
by ehguacho
dclxvi wrote:
First, the formula is A = A - M - 1 + C
that's not way the i've found the formula. that "-1" doesn't appears in any doc i've checked.
dclxvi wrote:
it's strange that src is used in the temp calculation but the Memoria array is used in the V_FLAG calculation
my mistake. forgot to chanage that "Memoria[PC]" for "src" while copying the text from my source code to the post.

thanks for your reply! even if the formula isn't the correct one, now i know from where it came up :)

Posted: Thu Aug 19, 2010 9:25 am
by BitWise
Quote:
First, the formula is A = A - M - 1 + C
The 6502 ALU doesn't have subtraction circuitry, it calculates

Code: Select all

A = A + ~M + C
The ones complement ~M is (roughly) equivalent to -1 - M, giving

Code: Select all

A = A + (-1 - M) + C = A - M + C - 1
Which kind of explains why you have to clear the carry when you have a borrow (e.g C = 0 so that last bit become + 0 - 1 = -1)

Posted: Sat Aug 21, 2010 6:20 pm
by dclxvi
A quick note on the various formulas here: the A + ~M + C formula that BitWise mentioned is indeed how the 6502 actually operates. In most documentation that I've seen, the formula is usually written as A - M - (NOT C) -- in other words, A - M when the carry is set, and A - M - 1 when the carry is clear. Since C can only be 0 or 1, NOT C is the same as 1 - C. So all of these formulas are equivalent, even though that may not be easy to see unless you work out the algebra.

I usually use the A - M - 1 + C form, even though it is somewhat unconventional, because you can plug in a value from -128 to 127 for A and M, and a value from 0 to 1 for C, and then the overflow is set when result outside the range -128 to 127. Likewise, if use plug in a value in the range 0 to 255 for A and M, the carry will be clear when the value is less than 0. Other people may find different forms more convenient for their purposes.

Posted: Sat Aug 21, 2010 9:38 pm
by ehguacho
and again thanks dclxvi. probably there's some typos in some docs.

usually the operation is written some docs (the correct ones) as "A = A - M - (IF_CARRY() ? 0 : 1)".
then, if C is set the formula goes "A = A - M" and "A = A - M - 1" if it's not set, wich is the correct behavior.