Go Down

Topic: µC as a Super Famicom (SNES) cartridge (Read 705 times) previous topic - next topic

hirschmensch

I'll try to keep the question simple...

Let's say I take an STM32F4 processor running at 168MHz, I connect all the adress and data lines of the 65C816 to GPIOs of the STM32F4, and everytime the 65C816 asks for an instruction at a specific adress, the STM32F4 answers with the data present on the GPIOs... Any ideas why this should NOT work? :)

I'd like to emulate a ROM for the Super Famicom aka. SNES (with the lowest means possible).

Lucario448

Any ideas why this should NOT work? :)
I have three:

  • Storage capacity: while some games (as raw data) can fit into the built-in storage of some microcontrollers, others are too much.
  • Timing: this is the most crucial part, because ROM chips usually output the data bits as soon as the address lines are set; and depending of the CPU's efficiency per cycle, it latches the data bits either in a second clock pulse or one of the edges of the first one (after setting the address bus). So what this means is that the microcontroller would have to react to the change in the address lines 2 or 4 times faster than the SNES CPU itself. To make matters worse, the buses of the motherboard are built in a parallel fashion; which takes us to the third idea.
  • Insufficient GPIOs: they call it "16-bit console" for some reason, indeed the CPU latches or outputs 16 bits of data at a time; thus you'll need 16 pins just for the data part. Unless SNES cartridges used some kind of bank switching, the address lines are even worse, because to handle the largest ROM possible, I guess close to 24 bits are requiered. More or less you may need some microcontroller with 40 GPIOs, that can react quick enough against that many inputs and outputs.

If the microcontroller can't match or surpass the ROM chip's "reaction time", you'll end up with an unreliable cartridge emulation if the game ever manages to boot up.

Games that require hardware enhancements (e.g. StarFox with the SuperFX) are basically impossible with just a single microcontroller.

hirschmensch

Alright! Good points, thank you!

Storage capacity: while some games (as raw data) can fit into the built-in storage of some microcontrollers, others are too much.
Yes that's true... But I guess if I just wanted to forward some opcodes and values that are computed by the Microcontroller I would not run into this problem. Also external (fast) memory seems like a simple solution, right?


Timing: this is the most crucial part, because ROM chips usually output the data bits as soon as the address lines are set; and depending of the CPU's efficiency per cycle, it latches the data bits either in a second clock pulse or one of the edges of the first one (after setting the address bus). So what this means is that the microcontroller would have to react to the change in the address lines 2 or 4 times faster than the SNES CPU itself. To make matters worse, the buses of the motherboard are built in a parallel fashion; which takes us to the third idea.
This might really be a problem... But isn't a 168MHz processor many times faster than a 1MHz processor anyway?
Another possible solution would be to analyse the program code and prepare the data in advance so the SNES CPU doesn't need to wait at all, right?
Also the STM32F4 has a flexible memory controller that can handle parallel data up to 32 bits. I have no experience with this but it might work in this case too don't you think?


Insufficient GPIOs: they call it "16-bit console" for some reason, indeed the CPU latches or outputs 16 bits of data at a time; thus you'll need 16 pins just for the data part. Unless SNES cartridges used some kind of bank switching, the address lines are even worse, because to handle the largest ROM possible, I guess close to 24 bits are requiered. More or less you may need some microcontroller with 40 GPIOs, that can react quick enough against that many inputs and outputs.
The STM32F4 has 70 GPIOs. That's not a problem at all.

Lucario448

But I guess if I just wanted to forward some opcodes and values that are computed by the Microcontroller I would not run into this problem. Also external (fast) memory seems like a simple solution, right?
In fact, ROM chips store actual machine code along with the game's data; so I don't see why an uncompressed ROM image shouldn't.

External fast memory? Yes, as long as it doesn't delay the reaction time too much. ROM chips are very quick in random access, and so the external memory should be too.

But isn't a 168MHz processor many times faster than a 1MHz processor anyway?
Well then... it's an overkill; but not for too much considering the amout of overhead some functions and interrupts may have.


Another possible solution would be to analyse the program code and prepare the data in advance so the SNES CPU doesn't need to wait at all, right?
Maybe programming the "boot code" (sort of speak) and a block of data/instructions you know the game will always frequently request, into the micro's program memory; and then the rest to an external memory if necessary.


Also the STM32F4 has a flexible memory controller that can handle parallel data up to 32 bits. I have no experience with this but it might work in this case too don't you think?
Probably.
But the CPU can handle only 16 bits of data at once, so half of the width is wasted. Also, it doesn't need any fancy features; it's just to output data in binary form, no control signaling or whatever it may have.
In the next reply you will know what I'm talking about.


The STM32F4 has 70 GPIOs. That's not a problem at all.
Good, because you can read/write groups of GPIOs directly by the corresponding port registers. Since the registers are 32-bit long, you can perfectly use one port for the data and another one for the address.
By using port registers, you can read or change the state of up to 32 pins in one microcontroller's clock cycle; leaving a lot of time to do other stuff.

If the STM has a "pin change interrupt", that would be fantastic. That way you don't have to waste time actively polling the port register to react as soon as possible to a change in the address bus (again, as a real ROM chip will do).



There's still some things you have not considered yet:

  • Voltage level: I know STM32s works with 3.3V, but what about the buses?
  • Anti-piracy and region locks: remember that you need to also somehow provide the required signals to pass (or bypass) any piracy and region test; otherwise the CPU will refuse to do anything and the game won't even boot.
  • Write attempts: not everything is about reading a cartridge, some games pretend having built-in non-volatile memory (either battery-backed RAM or some sort of EEPROM) for save files. In these cases, not all the address space is dedicated to ROM only; part of it is mapped to the secondary memory. Fortunately, it isn't matter of guessing; the CPU should have an extra line to signal the data bus direction, aka it wants to read from or write to. It's required even to access its on-board RAM, so this technique is carried up to the cartridge port because it's connected to the same buses anyway. The big trouble isn't just emulate the non-volatile memory, but the pin modes. If two devices sharing the same lines have their pins in a low impedance mode (aka output mode), there would be a nice short circuit and something would end up fried and toasty. In conclusion: watch the R/W line, because you'll have to immediately change the data pins to inputs only while it's pulled to the "write" state; doesn't matter if it's addressing any of the on-board chips.



PD: you really have RAM and processing time to spare, you may implement cache algorithms. The idea is to automatically learn which parts (blocks) of the ROM are the most frequently requested, in order to maintain them in RAM (cached) for an immediate deliver without risking a delay from the external memory (unless it's quick as the RAM itself, the risk is always present).

hirschmensch

That way you don't have to waste time actively polling the port register to react as soon as possible to a change in the address bus (again, as a real ROM chip will do).
Do you know if the SNES processor, which is an upgrade of the 6502, expects data instantly after applying the adress on the adress lines? Or will it wait for some sort of handshake?

Voltage level: I know STM32s works with 3.3V, but what about the buses?
A bus transceiver or level shifter will prevent problems here I guess.

Anti-piracy and region locks: remember that you need to also somehow provide the required signals to pass (or bypass) any piracy and region test; otherwise the CPU will refuse to do anything and the game won't even boot.
I can just use a manufactured cartridge and its CIC chip.

watch the R/W line, because you'll have to immediately change the data pins to inputs only while it's pulled to the "write" state; doesn't matter if it's addressing any of the on-board chips.
Ha! True! Didn't think about this...

I actually don't really need to implement whole ROMs of SNES games. My main goal is just to interface with the 65816 processor to do something else with the SNES than play games. The sound chip on this console is actually really interesting and I'd like to use its wavetable synthesizer.

Lucario448

Do you know if the SNES processor, which is an upgrade of the 6502, expects data instantly after applying the adress on the adress lines? Or will it wait for some sort of handshake?
Ehh we have to do some research just to be sure.

Nevertheless, I suspect that the ROM chips are literally what they are (and not just for definition): circuits that immediately give you an output (data lines) depending on the inputs (address lines); like a bunch of logic gates. If the ROM chips were actually flash memories, then problably there would be some kind of protocol, and not as straightfoward as setting some pins.


A bus transceiver or level shifter will prevent problems here I guess.
There should be bus transceivers before the cartridge port; otherwise ROM chips and hardware enhancements will mess up the data lines while addressing on-board components.

However, bus transceivers either block signals or pass them unchanged; they don't level shift. So still pay attention to the voltage levels of the cartridge port.
Measuring switiching voltage with a multimeter is not a good idea; so your only choices are an oscilloscope or to somehow halt the CPU.


I can just use a manufactured cartridge and its CIC chip.
So I guess you have covered that aspect, all right.



I actually don't really need to implement whole ROMs of SNES games. My main goal is just to interface with the 65816 processor to do something else with the SNES than play games.
Like testing homebrew programs? Then you still have to emulate a ROM chip, because I've told you there is where the whole machine code resides (instructions and data).




The sound chip on this console is actually really interesting and I'd like to use its wavetable synthesizer.
Once again, you still need the ROM even to initiate the sound chip.

I'm sorry, but I think the SNES doesn't have any wavetable built-in; the sound chip is more like the one in the Commodore Amiga (aka a MOD player). The wavetable ("instruments") is also loaded from ROM, as well as the "musical partitures".

I think the "musical partitures" are just a stream of commands for the sound chip. I don't know if only the CPU can command it, or if some other CPU from the cartridge can too.
If only the CPU can, then it's just matter of having those instructions on the emulated ROM, or generating them on the fly when used as a MIDI synthesizer for example. But for that, you'll have to investigate what are those commands; interacting with the sound chip I guess is just some kind of OUT (write) instruction to the chip's addresses.


PD 1: you can give the microcontroller a break if needed, by making the CPU to copy part of the ROM's code to its RAM, and then execute from there by "jumping" (setting the program counter) to an address that belongs to the on-board RAM. But be careful, if the PC never goes back to ROM; the CPU will be stuck in whatever it's on RAM.

PD 2: by reading this article on Wikipedia, I've realized I was partially correct and partially wrong. The CPU still has 8 data lines, but has 24+8 address lines.

Go Up