Close
0%
0%

GameTank 8-Bit Retroconsole

6502-powered game console with hardware-accelerated drawing

Similar projects worth following
The GameTank is an 8-bit console that's been implemented in hardware with through-hole components that can still be sourced new from electronics distributors. The system is designed after key aspects of early home game consoles, such as storing programs in cartridges, output via composite video, and having its own custom "first party" controllers. Dedicated blitter hardware allows it to easily render at 60 frames per second, while still having computational overhead for game logic and other potential software features. The project also includes an emulator being developed alongside the console hardware. Documentation and a user-friendly toolchain are also planned.

Earlier writeups are posted at https://clydeshaffer.com/gametank/

Specs:

  • 128x128 framebuffer, 128x100 visible onscreen
  • NTSC Composite video output
  • Fast 1 cycle per byte hardware blitter
  • 8KB of RAM
  • CPU clock at 3.5MHz
  • 4-channel soundcard with two square wave generators, LFSR noise, and a wavetable (may be revised soon)
  • Cartridge/expansion port that exposes the system bus, as well as a SPI port
  • 32KB of address space allocated to the cartridge port
  • Controller ports compatible with Genesis controller

Much of the GameTank is fairly typical of a W65C02-based retrocomputer project, but it does have a special trick up its sleeve. The composite video signal generator uses a dual-ported RAM as a framebuffer, and between the CPU and framebuffer sits a dedicated memory copy controller that can copy bytes into VRAM without the overhead of a software-defined copy loop. 

Sound on the v1 prototype is produced by dedicated square wave generators based around the 74HC40103, along with an LFSR noise generator and a wavetable controlling a DAC. However, the digital potentiometers used for controlling channel volume were discontinued. To get around this I'm testing the idea of replacing the soundcard with a second 6502 as audio coprocessor which will control an 8-bit DAC.

Once I work out the bugs remaining in the design, I plan to write up a detailed programming manual along with tutorials and a comprehensive software development toolchain. The third prototype will be designed to fit a case with a proper game console form factor.

The EAGLE design files, the emulator, and the first game developed for the system are on my Github:
https://github.com/clydeshaffer/gametank

https://github.com/clydeshaffer/GameTankEmulator

https://github.com/clydeshaffer/cubicleknight

Some other updates can be viewed on my 6502.org forum posts:

  • 2MB Flash Cartridges Finally Fully Functional!

    Clyde Shaffer01/31/2021 at 20:23 0 comments

    Up until recently the only program storage media I had physically prototyped was the 8KB EEPROM cartridges. These were pretty easy to design and assemble, since all the had to do was adapt the pins of a 28C64 to the cartridge slot. The data was say to address and access since fit well within the memory map of the system.

    However, while developing more content-heavy demos such as Cubicle Knight I found myself bumping hard into this memory limit. Already I had compressed the sprite sheet, tilemaps, and music with zlib but could basically only fit one level in the game. I also now had to deal with the ROM space requirements of the new soundcard, which would need a program loaded into it before it could be of use. 

    I had already reserved the upper half of the memory map for hardware residing in the cartridge port, and there are certainly EEPROM chips that can fit into this address space. An AT28C256 for instance would fill the 32KB and have plenty of room for game content. They're a bit more expensive though, and a mere 4x memory growth would be somewhat underwhelming.

    So when I found a flash memory chip on Mouser with a parallel interface and 2 megabytes of space I figured I'd give it a try!

    Having already saved the cartridge form factor in my Eagle library, I was able to quickly sketch up a design for a 2MB flash cartridge. The flash chip is a M29F160 (or it's Alliance counterpart AS29CF160), which is a NOR flash that defaults to a simple read mode for an 8 or 16 bit bus, selected by a "byte/word" pin level. In the byte mode the chip has 21 address pins, of which I directly control 14 with the 6502 bus. The rest get their values either from a shift register, or a buffer chip depending on whether A14 is high or low. If A14 is high, the system is possibly accessing the interrupt vectors and so addresses the very top of flash memory.

    The shift register is accessed by a "SPI interface" that's actually just four of the 6522 VIA's pins on port A. At any time the CPU can shift out an address, and move the 16KB window mapped from $8000 to $BFFF. I'm still thinking of different techniques to take advantage of this in software, but one convenient way to use it is to put game engine code in the fixed window and put content data into the other pages such that the same 16-bit pointer can be used to access a certain type of info on each page. (Such as keeping the music, tilemaps, graphics for a level under 16KB and then giving each level its own page.)

    To support this new flash cartridge, I also built a new cartridge programmer tool. Unlike the previous two where a shift register or a counter was used to expand the IO pins of an Arduino Nano (clone), this time I implemented it as a shield for an Arduino Mega to reduce complexity and increase flexibility. To allow for even faster programming, I aligned the address and data pin connections of the cartridge connector to the port registers of the ATmega2560. Having done this, my programmer firmware would be able to put a byte on the data bus simply by storing it in the port register variable. Ditto for each half of the 16 bit address. 

    Quite handily, this new programmer can write data 15 times faster than the old one. The old cartridges used to take almost two minutes to flash, but now only take about eight seconds. Of course, on the new boards this 15x speedup is countered by the 256x increase in data to send and filling the whole chip with data takes half an hour. Fortunately this flash chip also has a command to erase only a single sector at a time, which makes it quick to update individual segments of code or content.

  • Audio Coprocessor highlights need for larger program storage

    Clyde Shaffer01/10/2021 at 14:27 0 comments

    Until now, the GameTank generated sound using discrete logic ICs to generate two square waves and a noise signal, as well as loop through short clips of PCM sample data that would be fed to a DAC to produce arbitrary waveforms. These four channels would be generated separately and then mixed together using digital potentiometers to control the volume of each channel.

    This potentiometer was the DS1866+, and unfortunately it was abruptly discontinued in 2019. Most options for replacing its role in the soundcard design would have required not only an overhaul of the mixing scheme, but also an overhaul of the CPU's interface to the audio hardware.

    So, I started by considering an approach where each channel is summed in the digital domain rather than analog. This would use a few adder ICs to combine all the channels and then feed them through a shared DAC. Given that most available adder ICs are 4-bit, I'd need six of them to combine the four channels.

    This seemed like a bit much, so I then considered an approach where a single pair of 4-bit adders was used, the four channels would share an output bus with the adder's input, and each channel's output buffer would be activated in turn to add these values into an accumulation register which would then be loaded into the DAC.

    Finally I realized this was becoming its own little discrete logic CPU design, which isn't actually my goal and would have made the soundcard huge. The only reason I haven't used any microcontrollers for subsystems on this project is that it "feels like cheating" to include little computers into my computer design that are individually more powerful than the whole.

    But what if the little computer-within-the-computer was equally as powerful? This seemed fine according to my completely arbitrary rubric, so I spun up a daughterboard design that simply used another 6502 to control a DAC. 

    The interface carried over from the old soundcard provides 7 memory-mapped selection signals, 4 kilobytes of memory access, and all four of the clock divisions used in the system. So it was relatively trivial to control the new Audio Coprocessor by loading programs into the dual-ported RAM and manipulating the RESET, READY, and NMI lines with the memory selection signals.

    The design for this audio computer is actually pretty simple. The dual-ported RAM is wrapped around the whole 64k address space, while the DAC register is written on any write cycle while A15 is high. To prevent jitter on the audio sample rate, a 40103 8-bit down-counter is used to generate an interrupt that generates each audio sample. The samples sent to the DAC are double-buffered, meaning that every time the IRQ line strobes it copies the sample generated by the previous run of the interrupt handler. As long as the handler can complete in the time between samples, it doesn't matter precisely how long it takes to generate the final DAC value.

    The jumper in the picture is for switching the coprocessor's clock between 3.5MHz and 7MHz. The system's main CPU runs at 3.5MHz due to the rather loose timing of the address decoding and the devices hanging off of the bus. I figured that the Audio Coprocessor could run a bit faster due to its simplicity, but I hadn't realized that it would even run fine at 14MHz. Not pictured is the bodge wire I added to let the audio system run at 14MHz, giving ample headroom for more complex audio synthesis routines.

    Once I had determined that this new soundcard design was working, I wrote up a program for it that had similar capabilities to the original soundcard design. I'm not sure this technically qualifies as irony, but that code ended up being remarkably similar to what I had already written in C++ to generate audio in the GameTank Emulator. I'm not sure how many times in human history someone will replace a swath of C++ code with a call to a 6502 emulator performing the same computation.

    To test out this device, I converted the music playing code from Cubicle Knight...

    Read more »

  • Gameplay footage

    Clyde Shaffer12/12/2020 at 18:57 0 comments

    This is a few months ago, running a game on the v1 prototype. Note the color artifacts on high-contrast edges, and how faint the player character's hair is against the black background. These have subsequently been fixed by redesigning the video signal combiner circuit.

    The game runs at a consistent 60 frames per second thanks to the blitter, which is capable of writing every pixel on the screen over 800 times per second if needed. It also runs independently of the CPU, which is free to perform other tasks during a draw operation. Thus it is very cheap to clear the screen and redraw a tilemap every frame, as well as draw movable objects on top. The blitter has a transparency mode which can skip zero-valued pixels, making it simple to draw animated characters to the framebuffer.

  • Initial post to Hackaday.IO

    Clyde Shaffer12/12/2020 at 18:39 0 comments

    I've already been working on this for about two years, but figured I might as well also give the project a profile on here.

    The first physical prototype was assembled at the beginning of January 2020. It consisted of a backplane-style motherboard with cards for graphics, audio, and input. It used jumper wires to connect the selection outputs of the address decoder to each addon card, to maximize modularity. Overall the first prototype was good for proving initial design ideas and discovering the problems with my design. However, it was also quite fragile and unreliable.

    Currently I am working with the second physical prototype, which trades much of the modularity for reliability and ease of inspection. The selection signals have been moved to PCB traces, while the graphics and audio board now use dedicated connectors. The boards are also arranged flat instead of at a right angle to the motherboard, for easier access with oscilloscope probes.

    The primary remaining hardware issues are as folllows:

    • The blitter has a glitch when the draw rectangle starts at an X coordinate ending in ****1111
    • The digital potentiometers used for audio volume controls have been discontinued during the development of the project

View all 4 project logs

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates