Available for pre-order
View Purchasing OptionsHiya, it’s Clyde again!
The Crowd Supply campaign for GameTank Devkits has passed 100% funded! Huge thanks to everyone who has backed the project, you’ve made it possible to bring 100+ new GameTanks into the world!
There’s a few days left so if you want to get in on the campaign price and July shipping target you still have time. :)
I’m back from VCF SoCal where I met many wonderful and interesting people, learned cool stuff about old computers, and (of course) demonstrated the GameTank to a lovely audience of like-minded computer nerds.
In this update I’d like to elaborate on two of the GameTank’s special hardware features that set it apart from other 8-bit systems: the Blitter and the Audio Coprocessor.
In motion, the graphics on the GameTank look almost too smooth for an 8-bit machine. If I had a nickel for each time someone accused it of secretly being 16-bit, well I’d have two nickels but it’s still an oddly specific comment to hear twice!
The GameTank’s Blitter circuit is what allows for such smoothness. Compared to tile and sprite hardware, there are a few advantages:
The graphics system controls two areas of memory, a 32 kilobyte chip I call "Video RAM" that is used for two framebuffers, and a 512 kilobyte chip "Graphics RAM" that stores graphics for the blitter to read. In its inactive mode, the blitter can connect either the Video or Graphics RAM to the CPU so they can be accessed with normal reads and writes.
The CPU only gets a 16 kilobyte window into either of these areas. Depending on the register settings one of the two framebuffers can be selected for CPU access, or a "quadrant" in Graphics RAM can be selected.
Why are they called quadrants? The CPU can only access a 128x128 area without changing banking settings, but the blitter can access 256x256 on its input side. This means it’s possible to load a sprite sheet into Graphics RAM that is twice as wide and tall as the screen, without having to break drawing operations into multiple pieces.
As per their name, the quadrants are in groups of four which form a Graphics RAM bank. There are eight Graphics RAM banks, for a total sprite sheet area 32 times the size of the screen.
To draw these images to the screen, the programmer need only put the Blitter into its active mode, set the width, height, destination X/Y coordinates, source X/Y coordinates, and write to a designated "Start!" register that begins the drawing operation.
During the draw, the CPU is free to continue running code. If the CPU puts the blitter into the inactive state or changes parameters during the drawing, it might be interrupted or modified in ways that could either be detrimental or interesting depending on programmer intention.
The Blitter triggers an IRQ signal when it is done, which makes it easy to know when it is safe to perform the next drawing operations.
Overall this Blitter is a fairly simple one, but it does have some handy features:
The C SDK provides library functions perform common drawing operations such as clearing the screen or drawing a frame from a sprite sheet. It also offers a queue system to help layer simultaneous Blitter operations and CPU computation, by keeping a list of requested draw operations and starting them automatically as previous draws complete.
The Audio Coprocessor (or "ACP") of the GameTank is its other special party trick. It can be considered as a software defined soundcard, implemented in an additional 6502 processor.
The ACP is linked to the rest of the system by a dual-ported RAM chip. The dual-port RAM interfaces to both the main CPU and the ACP as if it were a normal RAM chip in each, but with a shared memory pool between the two sides.
The CPU can also pause the ACP or trigger its reset interrupt. The ACP has a programmable hardware timer that triggers an IRQ interrupt at a consistent rate, signaling it to generate the next value for the output DAC.
A typical way to use this is to pause the ACP at the start of a program, load a firmware binary into it, trigger the reset, and then unpause the ACP. While it runs, the CPU can write to designated memory locations to update paramaters such as pitch or volume.
By adjusting these values each frame, a game can play back music or sound effects.
Early software for the GameTank used a simple audio firmware that produced NES-like audio with two square waves, a sine wave, and a noise channel. It’s relatively simple to produce a square wave, as you need only count for a number of cycles between flipping an output. Sine waves are also easy if you have a table to look them up in.
Noise can be produced with a technique called a Linear Feedback Shift Register, where a two-byte value is bit-shifted and creates the new lowest value by XORing certain other bits producing a pseudorandom signal.
More recently, as mentioned in an earlier update, I figured out how to fit Frequency Modulation synthesis into the constraints of the ACP. FM synthesis is actually equivalent to Phase Modulation when the waveforms are all sines.
It’s a computationally cheap way to produce rich audio with multiple overtones, since it only requires addition. The gist of it is that you look up an entry in your sine table for the current wave time, then you add that to the wave time again and look up the resulting number in your sine table.
In other words, you just offset your sine lookup by an amount that varies sinusoidally across time. When the offset amount modulates your sine lookup at a rate that’s an integer multiple of your base pitch, the resulting output wave has lots of harmonics and a more natural sound.
The FM synth firmware in the GameTank C SDK (and in Ganymede) stacks this transformation to three modulation layers and an output layer. It does this four times with different parameters, providing four channels.
Each of the layers in the transformation is an "operator" in audio synth parlance, so the FM firmware for the GameTank can be described as a 4-channel 4-operator synth. It also has a feedback stage on each channel, bringing the total number of oscillators to 20.
A wide variety of sounds can be produced with this technique, and I’m still working on ways to take full advantage of it.
I also want to highlight that kaosctrl’s BASIC SDK that I mentioned in the previous update is now available to play with, including several examples and VSCode integration.
You can clone the repository at https://github.com/fetchingcat/gametank_basic_sdk.
After following the installation steps in the readme and configuring the emulator, and having opened the repo as the root of a VSCode workspace, you can open an example *.bas file and hit Ctrl+Shift+B to compile the program and run it in the emulator!
GameTank is part of Soldered Electronics Inkubator