6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Fri Nov 22, 2024 11:07 pm

All times are UTC




Post new topic Reply to topic  [ 19 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Fri Jun 30, 2023 12:38 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
I'm quite excited about this: I had the idea to probe a possible side-effect of perhaps the most interesting 6502 instruction, JSR.

And I got a result! My program runs one way on a real 6502, and another way on, I think, most emulators. And those emulators do the obvious thing, which is to say, they do what most people expect them to do. And so the result should be modestly surprising to most people here - which makes it interesting. (I expect most hardware re-implementations might also do the obvious thing, but haven't yet tested any. Not the MOnSter 6502 obviously.)

The program is in BBC Basic, but the motivated experimenter won't find that an obstacle.

On a BBC Master, which has a 65C102 in it:
Code:
>L.
   10 DIM code 99:P%=code
   20 [ SEI:TSX:STX&70:LDX#0:TXS:JMP&00FE:]
   30 P%=&FE: REM here's the vital code to test
   40 [ JSR &4321:]
   50 P%=&121: REM real 6502 will land here
   60 [ LDX&70: TXS: LDA #ASC("P"):CLI:RTS: ]
   70 P%=&4321:REM incorrect emulator will land here
   80 [ LDX&70: TXS: LDA #ASC("F"):CLI:RTS: ]
   90 PRINT CHR$(USR code)
>SA."jsrtest"
>RUN
0F48 78                 SEI
0F49 BA                 TSX
0F4A 86 70              STX&70
0F4C A2 00              LDX#0
0F4E 9A                 TXS
0F4F 4C FE 00           JMP&00FE
00FE 20 21 43           JSR &4321
0121 A6 70              LDX&70
0123 9A                 TXS
0124 A9 50              LDA #ASC("P")
0126 58                 CLI
0127 60                 RTS
4321 A6 70              LDX&70
4323 9A                 TXS
4324 A9 46              LDA #ASC("F")
4326 58                 CLI
4327 60                 RTS
P
>


Edit: see below for an improved version

At the time of writing, in owlet, which uses jsbeeb, an unusually high-fidelity emulation, the program prints F. Likewise in two of the three 6502 models in PiTubeDirect.

(To my slight surprise, the lib6502 model in PiTubeDirect prints a P, which doesn't match what I think lib6502 is doing, but this is probably my failure of understanding.)

What is that I'm testing, you ask? It's that JSR has two operand bytes, and it has to do two stack pushes, and in a real 6502 the sequence is that the first operand byte is read, then the two stack pushes happen, and then the second operand byte is read. So the test is to arrange that the second operand byte is overwritten by the stack. Truly self-modifying code.

There might be more to explore, both in the test program and in the emulators and re-implementations which we might be interested in.

Edit: oops, Mike (barrym95838) reminds us that he sketched exactly this kind of test only last year. I was there. And I'd forgotten.


Last edited by BigEd on Sat Jul 01, 2023 4:36 pm, edited 2 times in total.

Top
 Profile  
Reply with quote  
PostPosted: Fri Jun 30, 2023 12:42 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
(former placeholder - edited!)

Dave/hoglet has kindly run tests on various emulations and implementations, using the updated version of the test, which spots the kind of behaviour we see from lib6502 and in that case returns "X":

Quote:
Here's a few results.

Beeb with 6502: P

Beeb with ICE-T6502 (T65 Core): P
Beeb with ICE-T65C02 (AlanD Core): P
Matchbox Co Pro 0 (Arlet 65C02 Core): P

Beeb FPGA Model B (T65 Core): P
Beeb FPGA Master (AlanD Core): P
PiTubeDirect Co Pro 0: F
PiTubeDirect Co Pro 16: X
PiTubeDirect Co Pro 24: F
PicoTube: X
B-Em Model B: F
B-Em Master: F

BeebJit Model B: F
BeebJit Master: F


Also
Quote:
Beeb816 with a genuine WD65C816 returns F

(Which tells us that the '816 doesn't behave as a cycle-accurate 6502, as already noted in documentation and in this thread. By which I mean, the F does not mean that the '816 is failing as a CPU!)


Last edited by BigEd on Sat Jul 01, 2023 4:44 pm, edited 3 times in total.

Top
 Profile  
Reply with quote  
PostPosted: Fri Jun 30, 2023 12:52 pm 
Offline
User avatar

Joined: Wed Feb 14, 2018 2:33 pm
Posts: 1488
Location: Scotland
That is very, very subtle. Well found!

-Gordon

_________________
--
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/


Top
 Profile  
Reply with quote  
PostPosted: Fri Jun 30, 2023 6:31 pm 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1949
Location: Sacramento, CA, USA
That looks like a more mature version of my little brain-tickler from a while ago. :)

_________________
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!

Mike B. (about me) (learning how to github)


Top
 Profile  
Reply with quote  
PostPosted: Fri Jun 30, 2023 6:32 pm 
Offline
User avatar

Joined: Mon Aug 30, 2021 11:52 am
Posts: 287
Location: South Africa
Interestingly the 65C816 doesn't seem to have this same behaviour (if I've read the datasheet correctly).
Attachment:
JSR816.png
JSR816.png [ 41.4 KiB | Viewed 11504 times ]

It reads both the new program counter low and high bytes before it pushes them onto the stack. Even in emulation mode.

At least I really hope that's what it does because that's how I've implemented it in my emulator. I damaged my '816 board so I can't quickly test this but I'd be interested to know if anyone else does.

Cheers!
Andrew


Top
 Profile  
Reply with quote  
PostPosted: Fri Jun 30, 2023 6:36 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
Oh goodness me, you're quite right Mike! Only last year, and I was engaged in the thread too, so I have no excuse for not remembering. I'll add a credit to the head post.

Meanwhile, I've got an improved version which distinguishes lib6502's different fail. I haven't yet tested on an NMOS 6502 or an '816 or any FPGA core yet. (Edit: but Dave now has, see the updated second post. Thanks Dave!)

Here's an improved version which sees lib6502's different kind of fail (it fails with "X"):

Code:
>L.
   10 DIM code 99:P%=code
   20 [ SEI:TSX:STX&70:LDX#&21:TXS:JMP&011F:]
   30 P%=&011F: REM here's the vital code to test
   40 [ JSR &4340: NOP: ]
   50 P%=&0123:REM incorrect emulator may land here
   60 [ LDX&70: TXS: LDA #ASC("X"):CLI:RTS: ]
   70 P%=&140: REM real 6502 will land here
   80 [ LDX&70: TXS: LDA #ASC("P"):CLI:RTS: ]
   90 P%=&4340:REM incorrect emulator may land here
  100 [ LDX&70: TXS: LDA #ASC("F"):CLI:RTS: ]
  110 PRINT CHR$ USR code
>SA."jsttst2"
>RUN
0FAA 78                 SEI
0FAB BA                 TSX
0FAC 86 70              STX&70
0FAE A2 21              LDX#&21
0FB0 9A                 TXS
0FB1 4C 1F 01           JMP&011F
011F 20 40 43           JSR &4340
0122 EA                 NOP
0123 A6 70              LDX&70
0125 9A                 TXS
0126 A9 58              LDA #ASC("X")
0128 58                 CLI
0129 60                 RTS
0140 A6 70              LDX&70
0142 9A                 TXS
0143 A9 50              LDA #ASC("P")
0145 58                 CLI
0146 60                 RTS
4340 A6 70              LDX&70
4342 9A                 TXS
4343 A9 46              LDA #ASC("F")
4345 58                 CLI
4346 60                 RTS
P
>


Last edited by BigEd on Sat Jul 01, 2023 4:48 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Fri Jun 30, 2023 6:38 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
(well spotted Andrew, I'll see if we can test an '816)


Top
 Profile  
Reply with quote  
PostPosted: Fri Jun 30, 2023 7:52 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8507
Location: Midwestern USA
AndrewP wrote:
Interestingly the 65C816 doesn't seem to have this same behaviour (if I've read the datasheet correctly).
Attachment:
JSR816.png

It reads both the new program counter low and high bytes before it pushes them onto the stack. Even in emulation mode.

Unsurprising, given that the 816 is a 16-bit processor. :D

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Fri Jun 30, 2023 7:58 pm 
Offline

Joined: Sun Jun 29, 2014 5:42 am
Posts: 352
I believe on the 65816 there are a couple of forms of JSR that might exhibit this behaviour:

JSL (opcode 0x22)
Code:
     // JSL: <opcode> <op1> <op2> <write pbr> <read dummy> <op3> <write pch> <write pcl>


JSR (IND16, X) (opcode 0xFC)
Code:
      // <opcode> <op1> <write pch> <write pcl> <op2> <internal> <read new pcl> <read new pch>


These both needed "special casing" in the 6502 Decoder.

Dave


Top
 Profile  
Reply with quote  
PostPosted: Fri Jun 30, 2023 8:55 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
Ah, that's a good point Dave, any core which works as a 6502 with the decoder must be doing the right thing.


Top
 Profile  
Reply with quote  
PostPosted: Sat Jul 01, 2023 4:42 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
Dave (hoglet) has kindly run tests - see the second post which has been updated.

Dave also has traced the execution of the "X" case which we see in lib6502 and in the '816:

Quote:
Your new "X" test case is interesting. Am I right in thinking this catches the case where the emulator pushed both bytes to stack before reading any of the target address bytes?

Code:
0FAA 78                 SEI
0FAB BA                 TSX
0FAC 86 70              STX&70
0FAE A2 21              LDX#&21
0FB0 9A                 TXS
0FB1 4C 1F 01           JMP&011F
011F 20 40 43           JSR &4340
0122 EA                 NOP
0123 A6 70              LDX&70
0125 9A                 TXS
0126 A9 58              LDA #ASC("X")
0128 58                 CLI
0129 60                 RTS
I think the target of the JSR then becomes &0121
Here's a trace from the PiTubeDirect debugger running on Co Pro 16:

Code:
Exec breakpoint hit at 09aa
09aa 78       sei
09ab ba       tsx
09ac 86 70    stx 70
09ae a2 21    ldx #21
09b0 9a       txs
09b1 4c 1f 01 jmp 011F
011f 20 40 43 jsr 4340
0121 01 ea    ora (EA,X)
0123 a6 70    ldx 70
0125 9a       txs
0126 a9 58    lda #58
0128 58       cli
0129 60       rts
Is this what you were expecting? (i.e. was the ora instruction carefully crafted to be benign?)


And the answer is, yes indeed, the ORA comes for free from the stack pushes, and I couldn't think how to avoid it, but realised it's harmless and just needs an operand byte - which is a NOP. (I thought at first that 01 was an undefined opcode, but visual6502 reminded me that it's an ORA.)


Top
 Profile  
Reply with quote  
PostPosted: Sun Jul 02, 2023 7:49 am 
Offline

Joined: Sun Jul 02, 2023 7:08 am
Posts: 2
FWIW, this was apparently fixed in VICE (the C64, C128, VIC20, PET and CBM-II emulator) some time in 2002. The memory access order for JSR is incorrect in VICE version 1.9, but correct in 1.10.

Very cool test case mind, I might have to do some code that relies on that at some point.

(Also, on my first reading I was distracted by the JSR instruction straddling the border between zero page and page 1 - took me a few minutes to realise that it was the pushes to stack that were vandalising the destination, not some kind of zero page memory access related thing!)

-ChristopherJam


Top
 Profile  
Reply with quote  
PostPosted: Sun Jul 02, 2023 7:55 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
Interesting info on VICE, thanks!


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 03, 2023 2:25 pm 
Offline

Joined: Sun Jul 02, 2023 7:08 am
Posts: 2
No worries.

If anyone's interested, here's the variant groepaz (once of the VICE maintainers) used to test with VICE's c64 emulator (I just went back and looked at old source tgzs after that to see when the pertinent emu code turned up). Formatted for ACME.

Code:
;   10 DIM code 99:P%=code
;   20 [ SEI:TSX:STX&70:LDX#0:TXS:JMP&00FE:]
;   30 P%=&FE: REM here's the vital code to test
;   40 [ JSR &4321:]
;   50 P%=&121: REM real 6502 will land here
;   60 [ LDX&70: TXS: LDA #ASC("P"):CLI:RTS: ]
;   70 P%=&4321:REM incorrect emulator will land here
;   80 [ LDX&70: TXS: LDA #ASC("F"):CLI:RTS: ]
;   90 PRINT CHR$(USR code)


    * = $0900

    sei

    ldx #2
-
    lda code1,x
    sta $00fe,x
    dex
    bpl -

    ldx #7
-
    lda code2,x
    sta $0121,x
    dex
    bpl -

    ldx #7
-
    lda code3,x
    sta $4321,x
    dex
    bpl -

    ldx #0
    txs
    jmp $00fe

; here's the vital code to test
code1:
!pseudopc $00fe {
    jsr $4321
}

; real 6502 will land here
code2:
!pseudopc $0121 {
    lda #5  ; green
    sta $d020
    jmp *
}

; incorrect emulator will land here
code3:
!pseudopc $4321 {
    lda #2  ; red
    sta $d020
    jmp *
}


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 03, 2023 3:52 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
Thanks! There are many emulators out there and it might be interesting to see how many took care of this.


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

All times are UTC


Who is online

Users browsing this forum: No registered users and 16 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: