Bbc-micro Archive

List Statistics

  • Total Threads: 360
  • Total Posts: 2182
  #1  
22-07-2010 05:27 PM
Bbc-micro member admin is online now
User
 

OMG.

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:
--8<--------
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
Else
SBCCarry = False
End If

' Carry is CLEAR if a borrow occurred, love the 6502! :-)
CPU.PS.C = SBCCarry Xor True

' Overflow?
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
Else
CPU.PS.V = False
End If

' 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)

' Else
' ...no support for BCD maths mode...
End If
--8<--------

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:
--8<--------
tempw=a-(temp+(p.c?0:1)); \
tempv=(short)a-(short)(temp+(p.c?0:1)); \
p.v=((a^(temp+(p.c?0:1)))&(a^(unsigned char)tempv)&0x80); \
p.c=tempv>=0;\
a=tempw&0xFF; \
setzn(a); \
--8<--------
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:
--8<--------
10DIM CODE% 256
15P% = CODE%
20[
25 OPT 0
30 LDA #0
35 SEC
40 SBC #1
45 RTS
50]
55R = USR(CODE%)
60PRINT ~R
>RUN
197F
B00000FF
>
--8<--------

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
Simulator. *Finally*.


Best wishes,

Rick.


* - 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.

  #2  
22-07-2010 05:37 PM
Bbc-micro member admin is online now
User
 

On 22/07/10 17:27, Rick Murray wrote:

> 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.

It does - the value pushed to the stack on an interrupt is the only time
when the BRK flag is meaningful. On all other occasions, the BRK flag
will appear to be set.

--
Andrew Benham
Southgate, London N14, United Kingdom

The gates in my computer are AND OR and NOT, not "Bill"

_______________________________________________
___________________________________________________

Posted on the Bbc-micro mailing list. Go to http://lists.cloud9.co.uk/mailman/listinfo/bbc-micro to subscribe.

  #3  
22-07-2010 05:54 PM
Bbc-micro member admin is online now
User
 

> To give an example, the above in B-Em is:
> --8<--------
> tempw=a-(temp+(p.c?0:1));    \
> tempv=(short)a-(short)(temp+(p.c?0:1));     \
> p.v=((a^(temp+(p.c?0:1)))&(a^(unsigned char)tempv)&0x80); \
> p.c=tempv>=0;\
> a=tempw&0xFF;           \
> setzn(a);             \
> --8<--------

I'm amazed I haven't simplified that yet. Carry can be worked out as p.c=(a>=temp), and overflow can be simplified a bit.

Did notice you haven't attacked the BCD version, presumably that's for sanity reasons.

> 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.

B is always set, except when pushed to the stack on an interrupt.

Tom




_______________________________________________
___________________________________________________

Posted on the Bbc-micro mailing list. Go to http://lists.cloud9.co.uk/mailman/listinfo/bbc-micro to subscribe.

  #4  
23-07-2010 05:40 AM
Bbc-micro member admin is online now
User
 

On 22/07/2010 18:54, Tom Walker wrote:

> Carry can be worked out as p.c=(a>=temp),

How does this work? A borrow occurs (carry clear) if the temp workspace
value is less than Acc?
Surely it is if the calculated value is less than zero? Or am I missing
something?


> Did notice you haven't attacked the BCD version, presumably that's
> for sanity reasons.

Yes... and also because AFAIK the FileStore firmware does not make use
of BCD, so there didn't seem to be much point including it.


> B is always set, except when pushed to the stack on an interrupt.

Mmmm... I don't think my code does that entirely correctly then.


--8<--------
The B flag
----------
No actual "B" flag exists inside the 6502's processor status register.
The B flag only exists in the status flag byte pushed to the stack.
Naturally, when the flags are restored (via PLP or RTI), the B bit is
discarded.

Depending on the means, the B status flag will be pushed to the stack as
either 0 or 1.

software instructions BRK & PHP will push the B flag as being 1.
hardware interrupts IRQ & NMI will push the B flag as being 0.
--8<--------

BRK sets B, PHP sets B (it does now). IRQ/NMI do not set B, and when the
status is popped off the stack, B is hardwired to false.

The snippet above is from:

http://nesdev.parodius.com/the%20%27B%27%20flag%20&%20BRK%20instruction.txt


B is ALWAYS set? I know PHP sets it, so:
PHP
PLA
will see the B flag set... but what about in normal code execution?
Surely it is considered 'unset' except when flags are pushed to the
stack in which case it is set except for an actual IRQ?


Best wishes,

Rick.

--
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.

  #5  
23-07-2010 07:55 AM
Bbc-micro member admin is online now
User
 

On 23/07/2010 05:40, Rick Murray wrote:
> On 22/07/2010 18:54, Tom Walker wrote:
>
>> Carry can be worked out as p.c=(a>=temp),
> How does this work? A borrow occurs (carry clear) if the temp workspace
> value is less than Acc?
> Surely it is if the calculated value is less than zero? Or am I missing
> something?
>
As the SBC operation is effectively A = A - operand, a borrow occurs if
the operand is larger than A.

As C comparisons give a '1' for true and a '0' for false, the code Tom
sent will set C to 1 (borrow doesn't occur) if A is larger than or
equal to the operand, which is the same as "not(operand>A)", which is
the logic that's needed.

>> Did notice you haven't attacked the BCD version, presumably that's
> > for sanity reasons.
>
> Yes... and also because AFAIK the FileStore firmware does not make use
> of BCD, so there didn't seem to be much point including it.
>
>
>> B is always set, except when pushed to the stack on an interrupt.
> Mmmm... I don't think my code does that entirely correctly then.
>
>
> --8<--------
> The B flag
> ----------
> No actual "B" flag exists inside the 6502's processor status register.
> The B flag only exists in the status flag byte pushed to the stack.
> Naturally, when the flags are restored (via PLP or RTI), the B bit is
> discarded.
>
> Depending on the means, the B status flag will be pushed to the stack as
> either 0 or 1.
>
> software instructions BRK& PHP will push the B flag as being 1.
> hardware interrupts IRQ& NMI will push the B flag as being 0.
> --8<--------
>
> BRK sets B, PHP sets B (it does now). IRQ/NMI do not set B, and when the
> status is popped off the stack, B is hardwired to false.
>
I'm not an expert on the B flag, by any means, but this is surely wrong.
If the B flag was always false when popped off the stack, how would you
(simply) be able to tell whether the value that had been pushed to the
stack by the IRQ, BRK or PHP had B set to true or false?

Or is the theory that you pull the value into A and then do a CMP to
find out whether the B position would have been set? That would seem
rather messy to me though - to restore the flags, and check B you
effectively have to do PLA : PHA : PLP : CMP #x, which seems a lot of
instructions.

I'm guessing the idea of the B flag is that when you do a PLP, you can
tell by testing B whether the status flags were pushed by an IRQ/NMI (B
clear), or by software means (B set).

It also seems from the other descriptions that I've seen that B is
effectively an "active low" signal to indicate an IRQ/NMI has happened,
which potentially makes "true" and "false" slightly confusing terms to
use for it.
> The snippet above is from:
>
> http://nesdev.parodius.com/the%20%27B%27%20flag%20&%20BRK%20instruction.txt
>
>
> B is ALWAYS set? I know PHP sets it, so:
> PHP
> PLA
> will see the B flag set... but what about in normal code execution?
> Surely it is considered 'unset' except when flags are pushed to the
> stack in which case it is set except for an actual IRQ?
>
>
> Best wishes,
>
> Rick.
>
Regards

Michael

_______________________________________________
___________________________________________________

Posted on the Bbc-micro mailing list. Go to http://lists.cloud9.co.uk/mailman/listinfo/bbc-micro to subscribe.

  #6  
23-07-2010 10:14 AM
Bbc-micro member admin is online now
User
 

Michael Firth wrote:
> If the B flag was always false when popped off the stack, how would you
> (simply) be able to tell whether the value that had been pushed to the
> stack by the IRQ, BRK or PHP had B set to true or false?
> Or is the theory that you pull the value into A and then do a CMP to
> find out whether the B position would have been set?

Correct. Standard 6502 IRQ code starts off:

.irqhandler
STA irqtmp ; Save A
PLA ; Get stacked flags
PHA ; Put back again
AND #16 ; Check BRK flag
BNE brkhandler ; BRK occured
; continue with IRQ handler
LDA irqtmp ; Restore A
RTI ; Restore P and return

.brkhandler
; continue with BRK handler

IRQ also disables IRQs (ie, sets I) so irqtmp won't get trampled by
another IRQ interupting the IRQ handler.

--
J.G.Harston -


_______________________________________________
___________________________________________________

Posted on the Bbc-micro mailing list. Go to http://lists.cloud9.co.uk/mailman/listinfo/bbc-micro to subscribe.

  #7  
24-07-2010 04:01 PM
Bbc-micro member admin is online now
User
 

[SNIP discussion in 6502 emulation]

Anybody if free to look at 65TubeEm at
http://mdfs.net/Apps/Emulators/Tube/65TubeEm which is explicitly
written in BBC BASIC (BASIC V) to show how the 6502 is emulated
(and also as a demonstration of writing code in seperate modules).

The module 6502 implements the 6502 CPU engine.

--
J.G.Harston - - mdfs.net/jgh
BBC IDE Hard Drive Interface - http://mdfs.net/Info/Comp/BBC/IDE

_______________________________________________
___________________________________________________

Posted on the Bbc-micro mailing list. Go to http://lists.cloud9.co.uk/mailman/listinfo/bbc-micro to subscribe.

  #8  
25-07-2010 12:40 AM
Bbc-micro member admin is online now
User
 

On 24/07/2010 17:01, J.G.Harston wrote:

> Anybody if free to look at 65TubeEm at
> http://mdfs.net/Apps/Emulators/Tube/65TubeEm which is explicitly

Eeek! Multiple FN entry points and *no* spaces in the actual code!


> written in BBC BASIC (BASIC V)

For those using Windows, my ROView software contains a BASIC-to-text
filter; it shouldn't be too hard to get Windows to auto-run it once you
typed JGH's files as .basic
http://www.heyrick.co.uk/software/roview/


Best wishes,

Rick.

--
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.

  #9  
25-07-2010 01:47 AM
Bbc-micro member admin is online now
User
 

Rick Murray wrote:
> On 24/07/2010 17:01, J.G.Harston wrote:
>
>> Anybody if free to look at 65TubeEm at
>> http://mdfs.net/Apps/Emulators/Tube/65TubeEm which is explicitly
>
> Eeek! Multiple FN entry points and *no* spaces in the actual code!

Are you reading the source? It's full of spaces, eg:

140 DEFFNm0 :A%=(mem%!((mem%?rpc%+rx%)AND&FF))AND&FFFF:=0 :REM (zp,X)
150 DEFFNm4 :A%=mem%?rpc%:=0 :REM zp
160 DEFFNm8 :A%=rpc%:=0 :REM #n
170 DEFFNmC :A%=(mem%!rpc%)AND&FFFF:rpc%=rpc%+1:=0 :REM abs
180 DEFFNm10:A%=(mem%!(mem%?rpc%)+ry%)AND&FFFF:=0 :REM (zp),Y
190 DEFFNm12:A%=(mem%!(mem%?rpc%))AND&FFFF:=0 :REM (zp)
200 DEFFNm14:A%=(mem%?rpc%+rx%)AND&FF:=0 :REM zp,X
210 DEFFNm18:A%=(mem%!rpc%+ry%)AND&FFFF:rpc%=rpc%+(B%AND1):=0 :REM abs,Y
220 DEFFNm1C:A%=(mem%!rpc%+rx%)AND&FFFF:rpc%=rpc%+1:=0 :REM abs,X

JGH


_______________________________________________
___________________________________________________

Posted on the Bbc-micro mailing list. Go to http://lists.cloud9.co.uk/mailman/listinfo/bbc-micro to subscribe.

  #10  
25-07-2010 03:08 AM
Bbc-micro member admin is online now
User
 

On 25/07/2010 02:47, J.G.Harston wrote:

>> Eeek! Multiple FN entry points and *no* spaces in the actual code!
> Are you reading the source? It's full of spaces, eg:
>
> 140 DEFFNm0 :A%=(mem%!((mem%?rpc%+rx%)AND&FF))AND&FFFF:=0 :REM (zp,X)

That's why I qualified it with "in the actual code".

Try:

140 DEFFNm0 :A% = ( mem%!( ( mem%?rpc% + rx% ) AND &FF ) ) AND &FFFF :
=0 :REM (zp,X)

:-)

[doesn't fit on one line in an email...]


Best wishes,

Rick.

--
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.





NewsArc Lists  |  Culture Pages   |  Computing Archive  |  Media-Pages
Link to this page on your blog or website by copying the HTML code below and pasting it into your site: