2
\$\begingroup\$

I'm trying to build a game console from scratch (as an exercise, not necessarily for practicality).

What I want to do is to have multiple "CPUs", in this case one being the Main CPU and the other one controlling the controller ports. My idea is to use shared RAM, where the "Interface Controller" CPU is polling the controller ports and then writing the results to RAM, where the "Main" CPU can read it.

What I'm trying to figure out is how I would connect the RAM to the system - I doubt I can just connect the address/data pins of both CPUs to the same pin on the RAM chip directly, but I'm not familiar with what arbitration methods exist.

What is commonly done here? Is there some kind of "intermediary" chip that serves as a "switch" to select which CPU is connected to the RAM at any given time? Or maybe some kind of "buffer" that the Interface CPU writes into, and which is then somehow flushed into the RAM? Or is there a simple "Bus" that allows multiple components to access it? (I'm thinking of SPI here, with it's chip select/SS pin)

Assume a system that's using simple CPUs (e.g., Z80, 6502) and SRAM (e.g., Cypress CY62256), so nothing that supports sophisticated protocols out of the box. And if it helps, one CPU would only ever write and one only ever read.

| improve this question | | | | |
\$\endgroup\$
6
\$\begingroup\$

In general: There are many ways and it's not trivial. You will need to design something yourself.

If the amount of data is very small (like controller inputs) you could use a register which stores the latest data. The input side of the register connects (somehow - you'll need to design some logic) to the interface CPU's memory bus, and the output side connects (somehow) to the main CPU's memory bus. Apart from this register, the two CPUs have entirely separate memory. Done. (It seems like a waste of a CPU though)

Most CPUs don't access the memory every single cycle, so you can make them take turns. When the main CPU wants to access memory, let it access the memory bus. When the interface CPU wants to access memory and the main CPU doesn't, let it access the memory bus. When the interface CPU wants to access memory and the main CPU does, pause the interface CPU. You'll still need to design some logic.

You could give each CPU its own memory bus, but design some logic (see the pattern?) to allow the main CPU to access some of the interface CPU's memory (or vice versa). You could pause the interface CPU whenever the main CPU accesses its memory (easier) or only when the main CPU tries to access the shared memory at the same time as the interface CPU (harder, but still doable).

In any case, the specific logic circuit can't be designed without knowing all the details of how the RAM and CPUs need to connect. "Assume we have a Z80 or 6502" is not enough information to actually design the circuit. We can only make approximations and draw block diagrams.

Here are some general tips:

  • You can pause a "retro" CPU by stopping its clock signal. (This is not always true for modern CPUs)
  • In order to connect/disconnect part of a bus, you want to search for a "bidirectional bus transceiver" chip, such as a 74xx245.
  • Feel free to do the above things as often as you want. If you had shared memory, you could disconnect it and reconnect it every single cycle, and the RAM won't care. (connecting it at the correct time is where the complexity is)
  • CPUs only access a specific address at a time. They don't care what other addresses are doing. Don't feel bad about disconnecting RAM from a CPU - as long as the RAM is there when the CPU actually accesses it, it won't care.
  • Dual port RAM, which has two busses, exists. I don't know how common dual port RAM chips are. It's pretty standard for FPGAs to have some dual port RAM inside them, so if you're building your console on an FPGA, this is a non-problem.
  • (thanks to Richard the Spacecat) Many CPUs are designed to share their bus already. With a Z80 you can use the /BUSREQ signal to ask the CPU to pause itself and electrically disconnect itself from the bus (so you don't need a bus transceiver). It runs for a few cycles first, and it tells you when it's disconnected by using the /BUSACK signal.
| improve this answer | | | | |
\$\endgroup\$
  • 2
    \$\begingroup\$ Many CPUs (like the Z80) also have signals originally meant for DMA/bus sharing, where the CPU would 3-state all its bus IO when requested and signal handover. It should also be possible to share the bus (in perhaps a round-robin fashion) using these signals. \$\endgroup\$ – Richard the Spacecat Jan 27 at 10:48
  • \$\begingroup\$ @RichardtheSpacecat Good point, I will add that. \$\endgroup\$ – user253751 Jan 27 at 10:52
  • 4
    \$\begingroup\$ A hint on dual-port-RAM: in the PC world dual port RAM is also known as video RAM or VRAM and they are used by graphics cards. The use case is obvious - the CPU needs to draw objects to the graphics card and the graphics card need to draw rasters to the screen and dual port RAM turned out to be the most obvious way to do it \$\endgroup\$ – slebetman Jan 27 at 18:03
  • \$\begingroup\$ Thanks! I revisit this once I know what I'm actually using, but I wanted to know common options to figure out some of my design constraints. This list is very helpful! \$\endgroup\$ – Michael Stum Jan 29 at 16:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.