TRS-80 in an FPGA - CPU, RAM and ROM

TRS-80 in an FPGA - CPU, RAM and ROM

"Big-80" is an implementation of a TRS-80 Model 1 in an FPGA.  This post describes the processor environment including the CPU itself, RAM, ROM and hooking it up to the video controller, keyboard and virtual cassette player to make a working TRS-80.

TRS-80 Memory and Port Map

The next step in building Big-80 was to setup the CPU and connect it to some RAM, ROM and all the previously created components.  This is what's needed:

  • CPU - Z80 running at 1.774MHz
  • 12Kb of ROM containing BASIC
  • 16Kb of RAM
  • 1Kb of Video RAM
  • Video Controller
  • Keyboard Controller
  • Virtual Cassette Player

The main part of all this is mapping things to the correct places in memory:

TRS-80 Memory Map

CPU and Address Space Mapping

For this project I'm using the OpenCores T-80 CPU core for the processor.  I've used this before for FPGABee and it's a great implementation of the Z-80 CPU.

As mentioned in a previous post for clocking I'm using an 80MHz master system clock and dividing by 45 to get a clock of 1.777 - which is close enough to the 1.774 of an original TRS-80.

Besides clocking and reset, the main signals of the T80 are the address, data-in, data-out and signals for whether the current operation is a read or write and whether it's targets to a memory address or I/O port and most of the interfacing of the CPU is simply mapping these read and write operations to the correct location. (source code)

ROM, RAM and Video RAM

The Basic ROM is implemented using an single-port FPGA block RAM component initialized in VHDL code. Obviously the write signals for this component have been removed since it's a ROM.  The VHDL code was generated using a simple NodeJS script that reads a binary ROM files and generates the appropriate code.

The 16Kb user RAM is also implemented using single-port FPGA block RAM however unlike the ROM it's writable and uninitialized.

Video RAM is implemented as a 1Kb dual-port FPGA block RAM.  It's dual-port since this memory needs to be accessible from the CPU and the video controller.  Unlike the original TRS-80 that had contention between the video circuitry and the CPU when accessing this memory there's no such issues with this FPGA implementation.

Video and Keyboard Controllers

The video and keyboard controllers had already been implemented and tested (see prior posts) and just needed to be hooked up and mapped to the correct memory addresses.

Check out the source code to see how all these components are wired up - it's really just a matter of connecting signals and a bit of address space mapping.

First Boot

Normally for a project like this I'd like to start with just the CPU, test it with a little routine to blink some LEDs or something else trivial and then build on that until I had a working machine.

This time because of all the testing I'd done on each of the main components I decided to just take a punt and hook it all up (except for the cassette player) and see what happens.

It booted and ran first go...

Virtual Cassette Player

Once the machine was up and running I figured the best way to put it through its paces would be by loading some games... so the next step was to hook up the cassette player.

All cassette I/O is handled through port 0xFF:

TRS-80 Port 0xFF Bit Map

When reading the cassette port, the high-bit is a latch that gets set to 1 when a rising edge on the cassette signal is detected.  To detect the next edge it needs to be cleared by writing to the port and setting it back to zero.  You'll see there's a little bit of logic here and here to provide this functionality.

Note there's no explicit support for sound on a TRS-80 but it didn't take long for people to figure out you could connect a speaker to the cassette output and write programs that produce sound.  To support this, the cassette output pin was wired directly to the Mimas V2's audio output pins.

Again, thanks to all the earlier testing, it worked first go and for the first test I load the classic Big Five game Galaxy Invasion.

A Couple of Bugs

Running Galaxy Invasion showed up a few small bugs.  

The first was a glitch in the graphics characters.  Here's a still capture from the above video:

Obviously there's some kind of weird pixel wrapping issue on the graphics characters.  The reason it doesn't show up in text mode is because the right most column of pixels in all characters is black so nothing shows up.

So I went back to the video controller test project but couldn't reproduce it - everything looked fine there.  Finally, after a bit of a code walk I spotted the problem - the video RAM wasn't using the clock enable signal so it was loading the next character before the current character had finished drawing.   A couple of lines of code and it was fixed.

The second problem showed up when I tried playing Galaxy Invasion - the keyboard wouldn't work.  It was fine outside the game, not in the game.  Luckily I'd seen this problem before in a TRS-80 emulator I wrote once.  

The Big Five games had support for the TRSSTICK - a joystick they developed.   To detect its presence they queried an I/O port (I can't remember which one off hand) and if it returns anything other than 0xFF it assumes a joystick is connected and ignores the keyboard while playing the game.

The TRS-80 is supposed to return 0xFF for disconnected ports, but I had it returning 0x00.  Once small  change later and it was all working!

Finishing Touches

I now had an almost fully functional TRS-80 Model 1 - certainly it met my original goal of a TRS-80 I could load and play a game on.

However it was a bit rough around the edges.  Stay tuned, in the next post I'll talk about a some tweaks and improvements...

Banner image from NightFallCrew, used with permission.


Have thoughts on this? Leave a comment on Twitter.