It is currently Mon May 22, 2017 10:33 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 9 posts ] 
Author Message
PostPosted: Thu May 18, 2017 9:21 am 
Offline
User avatar

Joined: Sat Jul 12, 2014 3:04 pm
Posts: 788
I've been trying to work out in my head how to debug and tracelog solely from cart-edge signals. Obviously, one could simply fully-replicate the 6502 state. That would take too many FPGA resources, I believe, so I'm trying to pare it down first. This will also save me having to implement an entire 6502.
What seems key is maintaining a working knowledge of T₁, that is, when an instruction fetch happens: this allows you to know it's an opcode fetch, and what, if you must; it certainly seems helpful to know BRAnch, JMP, JSR, BRK for tracing.

My first inclination was "count argument bytes, next fetch is opcode, too". It didn't take long to come up with some problem cases: BRA [-1,0,+1], or
Code:
   LDA next,y  ;where y = 1
next:
as the dummy fetch will seem to be at the right address, but won't be an opcode fetch. Then, of course, the knowledge of "is-opcode-fetch" is lost. (The page-boundary fixup cycles are moderately-easily-detectable, on loads nor branches: loads, they're less-than; branches, out-of-range, though care will need be taken to spot a -128 branch)

NMIs may be another problem, at least, if one isn't allowing an assumption that $FFFA-FFFF is never executed. For a debugger, you don't want assumptions like that. However, if one is logging stack accesses, a [surprise] triple-push of PCH, PCL, P (which is a triple-write, if I'm understanding things, something that the processor never does, else) would seem to be a good tripwire for "now interrupting" and is followed by reading the destination vector. (BRK and IRQ are less problematic; IRQ will be asserted by mapper hardware and is thus interceptable; if we maintain opcode fetch parity knowledge, BRK is just another known.)

[hr]
So perhaps I should attack it from a different angle than keeping track. Log the last four reads, keeping track of where, particularly when they're sequential.
Hypothesis: Three sequential reads must include at least one opcode/operand fetch.
(I'm trying to think of("fuzz") how to set up a degenerate["pathological" was the word that timed my post out trying to remember] case for executing through the stack page…hmm…I think a JMP (label) label: would confuse, but there's a simpler triple-read: RTI (an RTS precisely into stack will also trip this.)
ldy #1 .org $4A ldy ($4C),y .db $4E, $00, $any, $any provides 6 nonopcode-fetches. An RTI in-stack will hit 5.

(These are all problems for "keep memory of what's the opcode" too.)

One needs really only trap branches-taken(hard), interrupts/BRK (easy), JSR (easy-ish), JMP (harder, no stack-write evidence)…argh.

I'm pretty sure there's a pathological case for every simple comparison I've come up with so far…
catching a JMP seems easy prima facie (read #$4C, read #$lo, read#$hi, read $hilo) , but the above case would trip it incorrectly.

JSR should be catchable by any double-descending-write that is not followed by the P push an interrupt does…should. Does an indexed y/x=FF pagebreak trigger? No, that's an extra descending read, not a write.

---
ed2:
Pathological cases for a Branch-detector:
Code:
.org $100
ldx #$06
txs
clc
bcc 0
pha ;gets read twice or three times, instead of 1-2 for a branch to +1


Last edited by Myask on Thu May 18, 2017 10:28 am, edited 2 times in total.

Top
 Profile  
 
PostPosted: Thu May 18, 2017 9:43 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 18332
Location: NE Indiana, USA (NTSC)
I know the Missile Command hardware special cases the (d,X) addressing mode for frame buffer access and turns it into a read-modify-write sequence on the underlying memory. How does it do that?


Top
 Profile  
 
PostPosted: Thu May 18, 2017 10:29 am 
Offline
User avatar

Joined: Sat Jul 12, 2014 3:04 pm
Posts: 788
I, uh, haven't implemented one yet.

and if I implemented one on PowerPak it would not help understand any mapper hardware, technically, as I'd have to implement the mapper myself! Only on a game-genielike thing (which, I suspect, Memblers already has managed) would one be able to do it with arbitrary mapper…though that would also deny you simple access to mapper regs.


Top
 Profile  
 
PostPosted: Thu May 18, 2017 10:36 am 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 5665
Location: Seattle
The plain-jane 6502 includes a SYNC output that lets an external device know when it's fetching an opcode vs data.

From the Missile Command Service Manual:
SYNC - Signal generated directly from the microprocessor that occurs at the beginning of an instruction read cycle and lasts one cycle of micrprocessor φ2 clock. Five φ0 cycles later, MADSEL goes high.


Top
 Profile  
 
PostPosted: Thu May 18, 2017 11:54 pm 
Offline
Site Admin
User avatar

Joined: Mon Sep 20, 2004 6:04 am
Posts: 3416
Location: Indianapolis
Not too long ago I also wanted to make a similar code/data discriminator fit in a CPLD, but I also hit that same brick wall of branches requiring that it know the status flags, which pretty much leads to emulating the whole 6502. Might as well! Most recently I've been experimenting with the iCE40HX4K. I tried Arlet Otten's 6502, only synthesizing it by itself though, and it used about 1400 of 3500 logic cells. This post shows that core should be under 500 LUTs + some block RAM on a Spartan 2. Seems pretty small, maybe it could fit in the PowerPak?

Your suspicion was correct, I am working on a game-genie-like device. :) As usual, I've redesigned the thing 5 different ways before starting it, but what I have managed so far is to settle on a design, and making progress on a board layout.


Top
 Profile  
 
PostPosted: Mon May 22, 2017 12:14 am 
Offline

Joined: Tue Feb 07, 2017 2:03 am
Posts: 109
Question, why does the cart need to know so much detail? Surly it is connected to a PC of some sort to display said info, to which said PC could also have its own copy of the ROM, probably with a labels file for better display?

at which point the PC,R/W and data bus are all you need, were the PC could be encoded so that it only send the full 16bits if it is not a +1

Then you can count out access cycles to find the OpCodes.
You can use the I switched from Write to Read, which says you are on an OpCode fetch
Check the VECTOR pulls for the IRQ/NMI and Pushes in the middle of an opcode Read cycle - knowing that the IRQ flag has gone high is not enough, it will let you know it is coming, but not when the CPU actually reacts to it
For branches, the next opcode might be loaded a couple of times, so if you have a PC, PC + 1 not taken PC,PC,PC +/- then branch was not taken so basically you need to keep the last 2 PCs, and see if they change. Either way when the PC changes again you are on your opcode.

However can you trap AEC on the cart, to know when a DMA process kicks in to steal cycles?


Top
 Profile  
 
PostPosted: Mon May 22, 2017 2:10 am 
Offline
Site Admin
User avatar

Joined: Mon Sep 20, 2004 6:04 am
Posts: 3416
Location: Indianapolis
If the cartridge was able to know which fetch is an opcode, assuming it's not running from internal RAM, then you could instead feed it a JMP or something into your own single-stepping code.

If you tracelog one frame that would be about 117kB (if simply logging 4 bytes per frame) and that's reasonable, but can't be done on anything that exists (yet..!). I tend to think of this in terms of frames, because the NMI seems like an obvious entry/exit point. Seems fairly workable if you can tell the FPGA to begin logging once it hits a certain condition or breakpoint, and only upload data to the PC for the interesting part.

2A03 does not have an AEC signal, but it doesn't seem like it would be too hard to detect a DMA access. When it writes $4014, then you can count the next 513/514 cycles as DMA. Memory locations for the DPCM samples could be determined by the most recent address and length register writes. There is virtually no reason that anyone would read DPCM data manually with the CPU, so that seems safe enough.


Top
 Profile  
 
PostPosted: Mon May 22, 2017 5:00 am 
Offline

Joined: Tue Feb 07, 2017 2:03 am
Posts: 109
Ah the DMA logic is all internal on the NES.

If you have a break point though, you can assume that point is a valid opcode. To which you can then take it that you step code exits when the opcode is complete and hence the next byte will be a valid opcode?


Top
 Profile  
 
PostPosted: Mon May 22, 2017 6:44 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 18332
Location: NE Indiana, USA (NTSC)
Oziphantom wrote:
If you have a break point though, you can assume that point is a valid opcode.

Not necessarily. Setting a breakpoint against a previous build, adding 1 byte of code before the breakpoint, rebuilding the ROM, and then running the code again will likely cause the breakpoint to become on an operand instead of an opcode.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 9 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 3 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:  
Powered by phpBB® Forum Software © phpBB Group