Well... THAT has been an odyssey into the unknown.
"What?", you might ask (if you care... ;-) ).
Simple. An accurate emulation of the SBC instruction.
For the non-microcode bunch-of-transistors that is the 6502, the
behaviour of the flags in SBC is actually fairly complicated.
I have finally (hopefully correctly!) arrived at:
Case &HE1, &HE5, &HE9, &HED, &HF1, &HF2, &HF5, &HF9, &HFD:
' SBC SuBtract memory with acc with Carry
' A,fC = A - mem - (!fC)
' Affects CZVN
If (CPU.PS.D = False) Then
' Calculate to a temporary place
CPU.Addr = CPU.A - CPU.Temp - _
(IIf((CPU.PS.C = True), 0&, 1&))
' NOTE that carry set = no subtract, else -1
If ((CPU.Addr) < 0) Then
' less than zero? flag a carry has occurred, then
' correct the result to fit into a byte
SBCCarry = True
CPU.Addr = 256 + CPU.Addr ' casting is 'painful' in VB
SBCCarry = False
' Carry is CLEAR if a borrow occurred, love the 6502! :-)
CPU.PS.C = SBCCarry Xor True
If ((CPU.A And &H80) <> (CPU.Addr And &H80)) Then
' bit 7 is different between orig/final so sign has changed...
CPU.PS.V = True
' ...except when the result is less than zero (a borrow)...
If (SBCCarry = True) Then CPU.PS.V = False
CPU.PS.V = False
' Assign the result
CPU.A = CByte(CPU.Addr And 255&)
' And the last two...
CPU.PS.N = (CPU.A > 127)
CPU.PS.Z = (CPU.A = 0)
' ...no support for BCD maths mode...
BTW, you can, no doubt, optimise this a *lot*, but I am coding for
(extreme) clarity, not to be clever. [*]
To give an example, the above in B-Em is:
p.v=((a^(temp+(p.c?0:1)))&(a^(unsigned char)tempv)&0x80); \
Which is small, tight, and implemented as a macro (!). It is also a PITA
to take apart and relate to other things to figure out what exactly is
going on, so I ignored it and wrote my own.
But... hey... It's pretty complex, this SBC instruction. For instance:
10DIM CODE% 256
15P% = CODE%
25 OPT 0
30 LDA #0
40 SBC #1
55R = USR(CODE%)
All well and proper, until you look at the flags:
C = Unset (a borrow occurred)
N = Set as 255 is a signed negative
V = Unset - the sign of the result is not wrong?
0 (b7 clear) -> 255 (b7 set) is not a sign change!?
Z = Unset, ain't zero!
Oh, and 'B' is returned as set. Is this a bug in BeebEm, or does BASIC
do something pretty weird when returning? I was under the impression
that the BRK flag only really existed in the value pushed to the stack.
Well... In various tests, my emulator appears to match BeebEm and 6502
* - I am thinking of adding support for Rob's TCP/IP<>Econet extensions
into the ADLC module, so theoretically my emulator will, eventually, be
able to function as a working server emulator. However it was never
intended to work in that way, per se (there are enough competent Beeb
emulators around already); it was specifically written to permit
revisions to the firmware (cf. mass storage on SD cards, etc) to be
prototyped virtually without the grief of
erasing/blowing/fitting/testing EPROMs and a real FileStore. And, let's
face it, also because I felt like writing an emulator in VisualBasic
because it was a pretty insane thing to do. ;-) But, hey, when it is all
working, at least it will *feel* like using a real FileStore (ie, quick
as treacle). Dah-duh, authenticity guaranteed! :-) :-) :-)
Rick Murray, eeePC901 & ADSL WiFI'd into it, all ETLAs!
BBC B: DNFS, 2 x 5.25" floppies, EPROM prog, Acorn TTX
E01S FileStore, A3000/A5000/RiscPC/various PCs/blahblah...
Posted on the Bbc-micro mailing list. Go to http://lists.cloud9.co.uk/mailman/listinfo/bbc-micro to subscribe.