Intercepting the data lines from the 2A03

Discuss hardware-related topics, such as development cartridges, CopyNES, PowerPak, EPROMs, or whatever.

Moderator: Moderators

Post Reply
kxnz
Posts: 2
Joined: Sun Jan 11, 2015 8:52 pm

Intercepting the data lines from the 2A03

Post by kxnz »

Hi All,

This is my first post, so please let me know if this is the wrong place for this type of question.

What I am trying to do is listen in on the data lines while a game is being played on the NES and catch the APU commands ($4000-$4017) with a microcontroller which will then convert them to a MIDI output in real time. I was wondering if anyone could point me towards anyone who has done this sort of thing before?

Right now I am running an atmega1280 uC at 20MHz and attempting to read the data lines from the 2A03 via a buffer circuit. What I'm currently unsure of is what will be the best place to tap an interrupt from.

Any thoughts, ideas, references etc. would be very welcome!
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: Intercepting the data lines from the 2A03

Post by lidnariq »

Here's the timing you're working with:

2A03 drives A0-A15 and R/W at beginning of cycle.
To decode whether the APU is being addressed, you have to check whether the address bus is 0b'0100 0000 000x xxxx' and R/W is 0.
You can probably ignore M2 here.

You have 559ns, minus something due to real-world transition times, to capture the right value. You can only be assured that the address and data bus are valid while M2 is high, but in practice you have a little bit more time.

At 20MHz, an atmega will do something every 50ns. Unfortunately, it has to do a WHOLE LOT of somethings to handle an interrupt:
embedded related forum wrote:The processor first synchronizes the external input to its own clock, that takes 2 clocks. The processor also has to finish the currently executing instruction. It takes 3 cycles to go the interrupt vector, from where it executes a jump to your ISR, another 3 cycles. This is 8 cycles to 11 cycles total time, depending on the executing instruction; or 0.6875 us. Then it has entered your ISR; you at least need to save the statusregister and a few registers before useful work can be done.
8-11 cycles is 400-550ns, almost your entire budget. Atmega interrupts are really lousy in comparison to (e.g.) PIC interrupts.

Ok, so maybe you could instead overclock your Atmega a smidge more and run it directly off the 21.5MHz master clock that the NES uses. At this point, the atmega will execute exactly 12 instructions for every one of the NES's. You could write a careful assembly loop that would take EXACTLY 12 cycles, and would check the address bus, the data bus, the R/W line, and M2, and then, if it's the write you want it to be, you could then send it to the Atmega's UART ... except that games usually write to a significant number of the 24 registers in rapid succession, and a MIDI byte takes a comparative eternity of 32µs (57 2A03 cycles) to send a single byte. So you'll have to make a transmit buffer that can play well with this. No interrupts are allowed, though: the 8-11 cycles mentioned above become 6-9 cycles (because we don't need to synchronize to an external source), but handling the interrupt will still eat up your entire budget for a cycle.

Ok, so what if we add extra hardware? We could instead decode all writes to $4000-$401F, and latch the 13 bits of address and data bus. We know the 2A03 can't write to them any faster than once every four 2A03 cycles, so that's at least 44 cycles instruction cycles on a 20MHz atmega. That sounds possible.
User avatar
mikejmoffitt
Posts: 1353
Joined: Sun May 27, 2012 8:43 pm

Re: Intercepting the data lines from the 2A03

Post by mikejmoffitt »

Even still, things like instruction cache and branch prediction in the hardware might make writing a timed loop difficult on something like that.

For this, a CPLD or FPGA might be more willing to help. You could build a queue of captured APU writes and raise an interrupt to the MCU, but have the MCU clock out the data a speed it can handle. It will introduce a small latency and you will have to be sure you are reading out the data quickly in big enough "chunks" that you won't overrun your little buffer of APU commands.
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: Intercepting the data lines from the 2A03

Post by lidnariq »

Anyway, now that I've told you why you're going to find it difficult, to directly answer your question, try using a 74'138 hooked up as follows:

A15 - /G2a
A14 - G1
A13 - /G2b
A12 - A
A11 - B
R/W - C
microcontroller /Interrupt input - /Y0

This will let you know any time the 2A03 is writing to $4000-$47FF.

Then again, given that someone managed to implement UNROM using an attiny, maybe that's all you need.
kxnz
Posts: 2
Joined: Sun Jan 11, 2015 8:52 pm

Re: Intercepting the data lines from the 2A03

Post by kxnz »

Thank you very much lidnariq for your detailed reply.

So continuing on your line of thought, the best way to isolate the 5 LSBs will be to cascade three 74'238s to generate an interrupt when the address is 0b'0100 0000 000x xxxx'. The interrupt would then just read the lower byte of the address port, and the 8bit data port and dump them to a FIFO buffer for the uC to deal with when it has time.

The non-interrupt part of the program would then interpret the pairs of values so that for example, if the address was $4002, (lower byte 0b'0000 0010) and the value in the data lines at the time of that interrupt was 0b'0000 0011' then that represents that a decimal value of 3 was written to the low byte of the pulse 1 channel timer.

Is there anything there that doesn't seem correct or plausible?

Thanks again for your help.
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: Intercepting the data lines from the 2A03

Post by lidnariq »

kxnz wrote:cascade three 74'238s to generate an interrupt when the address is 0b'0100 0000 000x xxxx'.
Or 74'138s. Or a '138 and a 74'4078. You don't really need to decode all of the address lines; no game released in the US would care about addresses below $4100. And if you stick to just licensed US games, the strictest requirement is the MMC5, which pays attention to writes to $5100 and up, so just a single '238, '138, '139, or '239 is sufficient.

Otherwise, that seems like a reasonable starting point.
Post Reply