As you all know, Bmack36 is working with CollectorVision to realize an FPGA-based ColecoVision clone console
. I was looking at the specs and how they were planning to add MSX, Sega Master System and even Atari 2600 cores to their system, and this got me thinking about what could be done with this Spartan-6 FPGA.
It's always good to have FPGA cores for real consoles, since many games become automatically playable as soon as the cores are operational. But how cool would it be to build an FPGA core for a gaming system that never existed, and which would be supported exclusively by bedroom coders?
Back in 2014, I took a mandatory course in assembly programming at my local university. For the entire semester, our teacher based all his lectures and assignments on an academic assembly language called Pep/8. By "academic", I mean that there's no physical machine that actually implements this assembly language; it works exclusively through a barebones simulator application that anyone can download and use for free. Pep/8 is a very simplified assembly language (simpler than "real" languages like for the Z80 processor) and I actually found it quite enjoyable as a learning tool. There's apparently a newer version called Pep/9 that came out, but I haven't checked it out.
Fast-forward to today, and I'm actually wondering if it could be possible to implement an "imaginary" game console based on a Pep/8 processor, as an FPGA core on the Spartan-6. Pep/8 may be too simplistic to be used for a full-featured real computer, but with a few minor alterations, I think it would suit a retro game console perfectly.
So I started imagining what features could be devised to make this imaginary game console interesting for homebrewers. I'm no expert in electronics, and even less in FPGA core programming, so I could only push my analysis as far as my limited knowledge could allow me. There could very well be some technical hurdles to my design which I'm not aware of (and that I would probably have trouble understanding if someone took the time to explain these issues to me) so please see what follows merely as an exercise in technical creativity, especially given that no one will probably ever program such a Pep/8 core for real. That's why I named this imaginary console "Pep/Dream", because it's indeed a pipe-dream of an FPGA core. But it's still fun to dream about "what might be".
I perceive the Pep-Dream as an academic machine for game homebrewers who want to learn assembly language, just like the original Pep/8 is an academic language that was devised for the same purpose. Once they understand the concepts behind programming in assembly, they can move up to the next level, namely the Z80 (ColecoVision, MSX, SMS) or the 6502 (NES).HARDWARE
The Pep/Dream is designed to work with a miniature color screen of 128 x 128 pixels. Each pixel would have to be magnified for display on a regular TV screen, especially on modern TVs via HDMI output.
The machine also has some standard speakers built into it for music and sound effect output.
Cartridges are limited to 32K in ROM size.
Finally, the system features a single controller. I suppose a second controller could be added to the hardware's design, but really, who would want to play a two-player game on such a small screen? Anyhow, the controller would feature one joystick, two fire buttons, one "pause" button and one "select" button. If this controller were to be supported via a Coleco controller on CollectorVision's FPGA console, the "pause" button would probably be mapped to the (*) key and the "select" button would be mapped to the (#) key.CPU
The CPU of the Pep/Dream implements the Pep/8 instruction set, with some minor language modifications to accomodate such things as controller input and sound output. Memory adressing is done with two bytes, which means the main addressing range is 64K (just like the ColecoVision and many other machines from that era).BIOS
The BIOS would take up the first 2K of the 64K addressing range. It would contain a boot strap routine that checks for the presence of a cartridge. If no cartridge is found, a simple "NO CARTRIDGE" message is displayed on the screen. Otherwise, execution jumps to the first instruction of the cartridge ROM (located at 8000h).
The BIOS would also contain a few basic service routines, such as sound output routines similar to the ones found in the ColecoVision BIOS.RAM
Anything that is not part of the BIOS or the cartridge ROM within the 64K addressing range would be RAM. This represents 30K of RAM, which should be good for beginner programmers who are often wasteful with their RAM usage.
With that much RAM available, I am faced with a technical dilemma: I would like to use 10K of that 30K RAM space as video RAM, but the problem is that two components (namely the main CPU and the video display processor) cannot normally access the machine's RAM simultaneously. I was told that with an FPGA equipped with fast RAM, it should be possible to devise some kind of system that would make it possible for those two components to share the same RAM "almost" simultaneously without impacting performance.
Including VRAM inside the main RAM space is important to me because it makes graphic output management much easier and straightforward (which, again, is a good thing for beginners) but if it's really not possible, then the hardware would need to accomodate auxiliary VRAM, like the ColecoVision.
Assuming it's indeed technically possible to use a portion of the RAM as VRAM, here are some specs:
- 20K of pure RAM (0800h to 57FFh)
- Main stack starts at 57FFh
- Top 10K used as VRAM by custom graphic processor:
--- 5800h to 58FFh = Character table #1 (256 bytes)
--- 5900h to 60FFh = Tile pattern table #1 (2048 bytes)
--- 6100h to 68FFh = Tile pattern table #2 (2048 bytes)
--- 6900h to 69FFh = Character table #2 (256 bytes)
--- 6A00h to 71FFh = Tile pattern table #3 (2048 bytes)
--- 7200h to 79FFh = Tile pattern table #4 (2048 bytes)
--- 7A00h to 7AFFh = Sprite attribute table (256 bytes)
--- 7B00h to 7FFFh = Sprite pattern table (1280 bytes)
The cartridge ROM would be located at 8000h to FFFFh, by the way.CUSTOM GRAPHIC PROCESSOR
This is the fun part of this analysis, at least for me!
The VDP would be custom-designed for the 128x128 pixels display. Graphics are defined as either 8x8 pixel tiles or 16x16 pixel sprites. Each pixel in a tile uses two bits to specify its color, so each pixel in a tile can be one of four colors. Sprites use only 1 bit per pixel, so a sprite can only be of a single color (the other color is transparent).
The VDP offers 4 configurable color palettes, with 4 colors per palette. This means 16 displayable colors, selectable from a total of 64 available colors (same as the Sega Master System). Tiles can only use the first two palettes (the first color of each palette can be set as transparent or opaque via a register bit) while sprites can pick any color from any of the four palettes.
Tiles are defined in pattern tables. Each pattern table requires 2048 bytes (2 bits per pixel x 8 pixels per line x 8 lines per tile x 128 tiles). A 128 x 128 pixel display implies a character table of 16x16 tiles (8x8 pixel per tile) so the character table takes up 256 bytes.
- Tile pattern table #1 is associated to palette #0, and is used by character table #1
- Tile pattern table #2 is associated to palette #1, and is used by character table #1
- Tile pattern table #3 is associated to palette #0, and is used by character table #2
- Tile pattern table #4 is associated to palette #1, and is used by character table #2
The game software can switch between character table #1 or #2 at any time.
About sprites, as mentioned before, all sprites are 16x16 pixels, with one color per sprite (so you must super-impose multiple sprites to create one multi-color sprite).
All sprite patterns are defined in a single pattern table, which is big enough to define 40 different patterns.
Sprites are displayed on the screen via a sprite attribute table similar to the ColecoVision's, but it can manage up to 64 sprites, and the VDP can display all 64 sprites on the same scanline without flicker or missing sprites (no annoying 4-sprites-per-scanline limit here!).
Each sprite attribute takes up 4 bytes in the sprite attribute table. Here's a description of the contents of those 4 bytes:
- mode = 2 bits
--- 00 = End of sprite list (like y=208 on ColecoVision)
--- 01 = Sprite is not displayed
--- 10 = Sprite is placed behind tiles
--- 11 = Sprite is placed over tiles
- palette number = 2 bits
--- 00 = palette #0
--- 01 = palette #1
--- 10 = palette #2
--- 11 = palette #3
- color = 2 bits
--- 00 = First color of selected palette
--- 01 = Second color of selected palette
--- 10 = Third color of selected palette
--- 11 = Fourth color of selected palette
- flip sprite horizontally = 1 bit (1=flip, 0=no flip)
- flip sprite vertically = 1 bit (1=flip, 0=no flip)
- x position = 8 bits (0 to 256, offset at -24 which allows sprite to go off-screen)
- y position = 8 bits (0 to 256, offset at -24 which allows sprite to go off-screen)
- pattern number = 8 bits (0 to 39)
The graphic processor also offers another fun feature, which is sprite masking: Set a certain VDP register to a number between 0 and 127, and sprites will not be displayed between the first scanline and the scanline indicated by the register. Likewise, if you set that same VDP register to a number between 128 and 255, then sprite support will be disabled between scanline (number-128) and the last scanline of the screen. This is useful when you want to display a status bar or a message window (at the top or bottom of the screen) and you don't want sprites to cover such screen areas.
You may notice that the graphic processor has only one display mode (I suppose I could add another one for variety) and it does not offer any advanced features like hardware-based scrolling. I prefer it this way because this would be a gaming console with an academic scope, aimed at beginner homebrew programmers. If someone wants to program games with hardware scrolling and other eye-candy, they should just learn to program NES or GameBoy games. SOUND OUTPUT
I'm no expert regarding sound chips, so let's keep things familiar for the sake of this analysis: Three sound channels and one noise channel, same as ColecoVision. As mentioned before, the programmer can use some BIOS routines to facilitate sound output. 'Nuff said.CONCLUSION
I attached a little image below, which shows how tiles are managed and what kind of result can be achieved with some color usage planning (and artistic talent).
Again, I'm not expecting anyone will ever implement the machine described above as an FPGA core. I wrote this analysis mostly because I like the idea of an easy-to-learn assembly language, and just to get it out of my system.
Thanks for reading. Comments are welcome, of course.