Revisiting My Modern Retro Console Idea
A while back on my blog, I wrote a few articles brainstorming ideas
for a modern 8-bit retro console - something sharing the same processor as
stuff like the NES, the Atari VCS, the Apple II, and the Commodore 64,
but including fun modern amenities such as multiprocessing and a triangle
rasterizer!
I still think a lot of these ideas are fun to read about on their own,
but looking at everything all together, it's definitely a bit unrealistic
and has some holes in the implementation. So I thought it might be good
to go through this and identify some ways the ideas could be made more
realistic for an actual implementation.
CPU Selection and Design
As its central processing unit, the console was powered by a cluster of
four WDC65C02 processors, each of which is connected to central memory
and which execute instructions one cycle at a time in a round robin mechanism.
Each processor was also connected to a 16 KiB range of private memory
(giving each processor its own zero page, stack, workspace, and ROM/hardware
locations so they can identify themselves), and can switch into and out
of a "private full-speed" mode that cuts off access to the central memory
in exchange for accelerating to their full speed of 14 MHz.
As it turns out, this private full-speed mode is likely more important
than I thought it would be. In the central mode, I had intended for the
total cycle rate for the round robin scheduler to be whatever the central
RAM could handle, while each individual processor runs at less than 14 MHz,
but I had failed to account for the fact that the processors likely need
1/14,000,000th of a second to complete a cycle. This means that the total
cycle rate for the round robin scheduler can really only be 14 MHz total,
with each processor running at 2-3 MHz - in order to get the benefits of
multiprocessing, processors would likely need to spend most of their time
in private full-speed mode.
I had originally selected the WDC65C02 processor, due to its similarity with
the iconic 6502 that powered so many 8-bit devices, but another realistic
choice that would still be considered plenty retro is its 16-bit successor,
the WDC65816, which powered the SNES and the Apple IIGS. The 65816 has some
features that are better for multithreading, such as the ability to address
16 megabytes of address space and to set the fast-access "zero" page and
stack to whatever page you want. And it's only marginally more expensive
than the 65C02! Of course, for the cycle length reasons stated above, the
private full-speed mode is still important.
Another interesting design idea would be to embrace the "actor model", where
the multiple processors do not actually share any memory at all other
than a set of mailboxes - essentially, they are in the
private full-speed mode at all times and can only communicate through a
set of serial connections. This could probably be as simple as something
like UART connections, though having some hardware that can keep a buffer
would help keep multiprocessing more efficient.
It's also worth considering other kinds of processors available for such
a console - other systems of these eras used processors such as the
Zilog Z80 used in the Game Boy and the Motorola 68000 used in the Commodore Amiga,
Apple Macintosh, and SEGA Genesis. Also, depending on what you call "retro",
you could even go as far forward as early 3D consoles such as the MIPS
processors used in the PlayStation 1 and Nintendo 64, or even the ARM
microcontroller used in the Game Boy Advance.
GPU Design
This was probably the craziest idea I had - using 16-bit posits, an alterative
to IEEE 754 floats, I would present a triangle rasterizer that could
render in 16 colors and do things like texture mapping. I knew this idea
was monstrous, and the more I learn about hardware design and implementation,
the more certain of this I become - this GPU is probably only something I
could implement in software as a sort of fantasy system like the PICO-8.
However, any number of more traditional designs would likely work great
on a system like this, especially since having multiple cores would make
any fancier techniques easier to parallelize. For instance:
- The simplest option would be to simply have a linear framebuffer, like an EGA card.
This would give a graphical experience similar to an IBM PC or maybe
an Apple II.
- A tile- and sprite-based renderer like the NES or MSX line would be
a more than appropriate choice for a home video game console or arcade
machine.
- If you still wanted to lean a bit more ambitious and do stuff with posits,
you could offer an emulated (or real!) XY vector display, similar to the
ones used by games like Asteroids and Star Wars.
- Heck, you could probably even do a simpler version of that triangle
rasterizer to assist with the wireframe look, creating an aesthetic similar
to games like Vib-Ribbon. The main limitations would be that rather than
allow multiple colors and texture mapping, all shape outlines must be
solid colors and the only allowed color for triangle faces is black - that
is, all graphics are still wireframe, but you are allowed to draw solid
geometry in order to occlude lines at the back of the model.
Honestly, my biggest inspiration for writing about the posit GPU was to have
an excuse to write about posits in depth. Maybe I should just write a standalone
article about posits in depth. :P
Cartridge Verification Design
In Part 3, I proposed using a cartridge design controlled by DMA, and using
a cryptographic signature system similar to Secure Boot in order to verify
the integrity of the cartridge, with various options presented as to how users
can easily add their own signing keys. I've come to realize that modern
cryptographic algorithms are still really difficult for 8-bit processors to
handle, and it's probably still a bit too ambitious an idea for this console.
Since we would expect our processors to spend most of their time in private
exclusive mode, it's probably safe for the cartridge itself to be mapped
to memory in a more traditional way - either in a banked format for a 65C02 design,
or mapped flat to the address space in a 65816-based design. I still think
that the checksum is a good idea as a quality of life feature, though,
so I would keep a small BIOS in the very top of memory that verifies the
header of the cartridge and displays some sort of boot logo, stopping boot
and giving some sort of indication if the cartridge could not be verified.
Of course, someone has gotten Gemini to run on an Amiga, so some sort of
cryptographics signature verification is probably not out of the question
in a 65816-based design. Though again, I would never want this feature
to be used to prevent homebrew software from running - if there's anything
at all I would want to do, I would want to show a different logo and message
than what I would show for a first-party game. I do think that the replaceable
ROM chip idea for loading unofficial signatures shows some promise.
Controller Design
As I mention in the original post, USB is likely too much for a 65C02 to handle
directly, meaning that our controllers would need to use a simpler protocol
such as I2C, UART, or something bespoke. If we're not primarily using a 3D display,
then a controller based entirely on digital switches and a D-pad would be more
than sufficient, and easily readable as memory-mapped registers by the console.
If we were willing to cheat a little bit on the console's design, though, it may
be worth adding a 32-bit microcontroller specifically to drive a USB controller
and a set of USB 2.0 ports on the front of the console. This would allow players
to plug in whatever USB-HID-compatible controller they liked. You could also
perhaps drive a USB controller directly with one or more of the system processors
if you went with a newer processor design, such as the MIPS or ARM chips.