I’ve started getting the display emulation working first, as this, along with the sound emulation are the biggest unknowns to me. I’m using C and SDL, which seems to be pretty straightforward to use.
The Standard Microtan 65 Display
The basic Microtan 65 board had a 32×16 character display which could show the standard ASCII character set, but capital letters only. There were two optional extras available, which I am going to include in the emulation:
- Lower case letters. This was an additional character set ROM to support lower case letters.
- “Chunky” graphics. Which was a RAM and some logic to give basic graphic support of 64×64 black and white pixels.
The display memory is between addresses 0x0200 and 0x03FF, with 0x0200 being the top left character on the screen and 0x03FF being the bottom right character. Writing a value to one of the display addresses caused the associated ASCII character to appear at the corresponding location on the screen.
The chuny graphics system was a bit odd to use. The RAM effectively added an extra 9th bit to each display character. If this bit is “1”, the character was shown as a “chunky” graphic. If “0”, it was shown as an ASCII character.
Unfortunately, it wasn’t possible to read or write to the RAM directly. Instead, the program would read from address 0xBFF0 and all subsequent writes to the display would set the corresponding “chunky” bit for that character. A write to address 0xBFF3 caused all subsequent writes to the display to clear the corresponding “chunky” bit.
This meant that the display could show both ASCII and chunky graphics, which was nice. However, because the chunky bit could not be read, if the screen was scrolled, the entire display would turn ASCII or chunky.
Another optional extra was a high resolution (remember that it’s 1979, when I give you the numbers!) graphics board. This board provided 256×256 black/white pixels, but it was possible to have more than one in a system, so with 3, you could have 8 colours and 4 would give 16 colours! This was impressive. Trust me. Although it would cost about the same as a small house 🙂
One problem is that the 8 bit 6502 microprocessor could only access a total of 64kB and each hi-res board needed 8kB RAM, so having four would take up half of the total accessible address space. As the address space included the system ROMs as well as I/O, which is also memory mapped and program RAM, this is an issue.
To get around this, there was some logic on the backplane which would enable the memory on a single card. This allowed multiple hi-res graphics cards to occupy the same addresses. All you had to do was select the required card before reading or writing it.
The downside, of course, is that to write a single pixel then becomes a long operation:
- Select the “red” card
- Read the byte containing the pixel that you want to change
- AND/OR the corresponding bit to get the new value
- Write the new value to the “red” card
- Repeat 1 through 4 for green, blue and intensity
This takes quite a bit of time, so was nice for drawing graphs and things, but it’s never going to play “doom”.
The Emulator supports all of the above.
I’ve written the code to support 16 colour hi-res graphics and the standard display. The ASCII characters are taken from a “charset.rom” file, which is a binary dump of the original full upper/lower character case ROM. The chunky graphic character equivalents are calculated at run time.
A “display_render” function populates a 256×256 array of RGB values. A “white” colour array is created from the standard display, using the RAM between addresses 0x0200 and 0x03FF to provide an index into either the ASCII character set or the chunky characters. The memory of the four hi-res boards is combined to produce a pixel colour, which is ORed with the white array.
I then use SDL_UpdateTexture to create the image texture for the window.
The image below will be somewhat familiar to anyone who used the original system…
This is a high level description of the emulator archchitecture:
- mmu.c – memory management. This will keep a copy of the 64k system memory, which will largely be RAM. It will provide functions to read and write the memory and a function to register a device on the memory bus (this registers callbacks associated with an address range). If a memory access occurs within a registered address space, then it will call the appropriate callback funcition to handle it. For example, the display will register a callback associated with 0x0200 to 0x03FF. When a write to this address range occurs, it will set a flag which the main loop can read to determine of the window needs to be rendered. It will also register devices at 0xBFF0 and 0xBFF3 which will set/clear a flag to set or clear the chunky graphics bit when display writes occur.
- display.c – display handler. Keeps its own copies of the RAM for the hi-res boards, renders the display.
- ay8910.c – sound chip. This will handle everything to do with sound emulation. Again, I’m going to use SDL for the actual audio output.
- rom.c – all ROMs. Loads all rom addresses from rom files (BASIC, XBUG and TANBUG).
- 6522.c – emulates the the 6522 I/O chips on the Tanex expansion board. One of these will be used to have an emaulated joystick.
- 6502.c – the CPU emulator.
- microtan65.c – any bits of hardware not covered by other source files.
- main.c will have the usual initialisation and then go into a loop, calling the 6502 emulator and rendering the display until the program is closed. It will also handle the program menu for loading/saving/preferences, etc.