Computing > Vintage Computing

Yet another TRS-80 Model 1 Clone

(1/3) > >>

Hi All,
I've decided to go ahead a share a project I've been working on for the last year or so... 
This is really just a personal project to get myself back up to speed on where the current "state of the art" is for hobby electronics.  I've been doing enterprise programming for the last couple decades, and the last hardware I designed (professionally) was an AMD29000 based graphics processor.  I've been pretty out of the loop on what's available to the hobbiest, but of course I've been seeing cheap PCBs, all the Arduino uController stuff, etc - just wanted to get a feel for what's available now...

So I decided to clone the first computer I owned the Radio Shack TRS-80 Model 1.

I know, I know, it's been done - there are plenty of software emulators available that run faster than the original did, etc, etc...  For me, this wasn't about the end goal, but more about the journey.  I figured this should be an achievable goal, it has a defined 'growth path' (expansion interfaces, disks, etc) and should let me start exploring several different technologies (KiCad, SMD, FPGA) right from the start.

I started by playing with a Cyclone-IV development board like this one:

It has VGA output, and a PS/2 input so that pretty-much covers the original Model-1 user interface: Monitor and Keyboard.  So step one began as figure out how use FPGAs.  I found a Z80 CPU implemented in VHDL and have used that, but everything else in the FPGA has been written from scratch using VHDL in Quartus-II.  Obviously I've looked at example designs for the various features I've eventually added, but other than the base CPU, pretty much everything else was a learning experience with VHDL.

One of my (self imposed) design constraints is that I wanted all original software to run without any modifications.  My goal is to end up with a hardware re-implementation of the original TRS-80 design.  The lines get really blurry when I start dealing with the disk controller, but even there I've tried to stick with my original goal as much as possible.  So, for example, the keyboard implementation needed to take the PS/2 keyboard events and translate them into the memory-mapped switch array of the original keyboard.  Also, since the original video was 384x192 pixels as composite video I've transmuted that to 800x600 VGA signal.

Looking through my phone it appears I didn't take any pics of the early iterations, so let's just say - the first iteration of my TRS80 lived almost entirely on that demo board, had 48K of RAM, 12K of ROM (both implemented inside the FPGA) and ran Level II BASIC.  I did cobble up the original cassette interface on a breadboard connected to that dev board and was able to CSAVE and CLOAD from a little hand-held audio recorder.  Since I had simply copied the orignal design, it was plagued by sensitivity to the audio level, just like the original!

The next evolutionary step was to begin development of the "expansion interface" and to introduce floppy drives to the mix.  Little did I know at the time how long that was going to take me, but (spoiler alert) I eventually got there.  My approach was to use an Arduino Mega board to emulate the original floppy disk controller (WD FD1771) hardware, but instead of read/writing 5-1/4 floppy drives, it would support virtual floppies on an SD card in any of the common diskette formats supported by the SW emulators (DMK, JV1 and JV3 formats).  I started with a custom serial interface between the Arduino and the FPGA board, controlled by the Arduino.  The FPGA would provide the register set supported by the original FD1771 and the arduino could read and write them via the serial interface under software control from it's end.  Pretty quickly I had to learn how to access SD cards on the Arduino, how to talk to displays (an LCD display in this revision), etc.  I  also quickly learned that the Arduino development environment *just sucks*!  I looked at alternatives and have settled on using the Eclipse Arduino plugin for CDT - it has a couple wrinkles, but overall it's certainly head-and-shoulders above the native arduino gui.  I also quickly learned that having all these bits cobbled together with jumper wires wasn't a very stable dev platform.  I don't have any pics of the actual setup at the time, but let's just say this is a fairly accurate representation:

Once I was fairly confident that I had basic communication between the FPGA and the Arduino, plus I knew I could talk to both the SD card and the LCD display I decided it was time to take the plunge and commit my prototype to a PCB.  This was another new learning curve for me (which is good, as that was the whole point of this exercise).  I did a little research and pretty quickly settled on using KiCad for the schema capture and PCB layout.  When I was last doing hardware design we were using Apollo workstations and we sent all our boards out for layout...  I've found KiCad to be reasonably good for the schema capture and so far I've been pretty impressed with it's PCB layout capabilities.  Of course the fact they're available for free to hobbiests is just mind-boggling to me...

Anyway, here's the board I ended up laying out:

Here's a pic of it populated (with some areas reworked for lack of pullup resistors, bungled PS/2 Keyboard connector footprint, etc):

You may notice a distinct lack of actual chips on that board?  To reduce my initial costs for the putting this together I decided to go with a Cyclone-II instead of a Cyclone-IV (verified the design would fit, except for RAM, before making that change), and also to stick with an actual Arduino Mega board as a subassembly that plugs into this board (so I suppose technically my board can be thought of as an arduino shield).  I also decided to use one of these:

to host the Cyclone-II instead of trying to deal with hand-soldering a 200-some pin smd package...  So my lash-up now looks like this:

With the Cyclone-II board plugged in below my board, the Arduino Mega on extension headers below that (but plugged into my board), then the LCD panel (with SD slot) plugged into the top of my board.  It's quite a random stackup - but it worked, so I was actually pretty happy with how it turned out.  Actually since this was my very first PCB layout (in a non-professional setting) and my first attempt at using SMD components and hand soldering them (I did get and do a few of those SMD soldering practice boards), I was actually pretty tickled with it...

This seems like a reasonable place to take a break...  I've done one more evolution of this design that I plan to document in the next post, and I'm getting ready to begin the third version which I'll start documenting in real-time after that...

If you've read this far and are bored to tears - I appologize.  I know I enjoy reading and following along with the journey others go through with their development.  Two great examples are GK's posts:
Cloning a Commodore PET-2001 -
Cloning a Tandy TRS-80 Model 1 -

So I'm just trying to contribute back in a little way, and hope someone finds this stuff interesting. 


--- Quote from: kizmit99 on June 12, 2019, 01:24:20 am ---This seems like a reasonable place to take a break...  I've done one more evolution of this design that I plan to document in the next post, and I'm getting ready to begin the third version which I'll start documenting in real-time after that...
--- End quote ---

That will be worth reading through  :) Particularly interested in the floppy disk controller/emulator.

That is a very neat setup. Congrats!

The four board setup I described in the last post is what I did the majority of the floppy emulator development with. 

The basic approach I've took was to implement holding registers on the FPGA to mimic the 4 registers on the FD1771 controller chip (CMD/Status, Track, Sector and Data).  These registers can also be accessed by the Arduino code over a custom serial bus used to connect the FPGA to the Arduino.  The serial bus implements a simple r/w protocol with the Arduino as the bus master, allowing it to read/write up to 16 registers from the FPGA.  In addition to the 4 registers mentioned, I ended up needing 1 additional register (sourced from the Z80/FPGA) to mimic the original drive select register on the expansion interface, and 2 more registers (sourced from the Arduino) to inform the FPGA of the virtual drives' status (DiskPresent, WriteProtect and Track0 status). 

The idea was that when the Z80 wrote to the CMD register I would generate an interrupt to the Arduino and it would start responding to that command, updating the status register back on the FPGA as it went about its work. 

It turns out that the TRS80 disk code places some pretty tight restrictions on how long it will wait for the FD1771 to reflect Status register updates (such as the BUSY bit) and the amount of time it was taking for the Arduino to respond to the interrupt just wasn't even close to fast enough.  I ended up having to implement a fair amount of dynamic behavior on the status register as it was being read by the Z80 - for example the BUSY bit is dynamically generated in the FPGA, when the Z80 writes the CMD register the BUSY bit goes active, it will stay active until the Arduino gets around to writing the Status register, once that occurs the BUSY bit returns to reflecting the state set by the Arduino (so it can remain BUSY for a while as the Arduino completes the CMD request.  Similar dynamic behavior ended up being necessary for the DRQ and LostData bits as well as the DiskReady, TrackZero and IndexPulse bits.

Another tricky bit with this approach is that the Z80 needs to be able to send a ForceInterrupt command to the FD1771 while it's in the middle of processing another command (so before BUSY is released) - this has the effect of terminating any currently running command on the FD1771.  With my implementation the Arduino is off executing the original command, and I didn't want to sprinkle a bunch of tests for whether the current command was terminated, so I just let the Arduino finish up what it was doing.  But the Z80 then needs to be held from sending another new command before the Arduino finishes, which I handled by forcing wait-states on CMD register writes while waiting for the Arduino to finish up.

In the end I was shocked by the amount of time I spent working on the Arduino emulation of the FD1771 chip.  I've tried to emulate the original hardware's behavior as closely as I could, while remembering that it's not actually talking to real floppy drives with write-gates, etc.  To replace those physical drives it uses virtual floppy files (DMK, JV1 and JV3 format) on an SD card.  I started with the DMK format (and I'm glad I did) because it most closely resembles the physical data format laid out on the floppy media - so most closely resembles what the original FD1771 thought it was talking to.  Where I ended up I can start with an almost blank DMK file (with just the 16 disk header) and use the various 'format' programs on the various DOSes to create formatted disks.  The key to this is supporting the FD1771 WriteTrack command (and of course the DMK Format's ability to support that).  Once DMK virtual disks were working, adding JV1 support was trivial, and JV3 support wasn't very difficult.

One of the biggest challenges dealing with the disk images was the 8K RAM limit of the Arduino Mega board.  A double-density track on a 5-1/4" floppy is about 6K in length, and some of these formats have significant size overhead just to locate a sector in the virtual image (I'm looking at you JV3!).  In the end I went with a paging scheme where I would swap the SDFile contents in/out through a single 2K buffer shared by all the virtual disk implementations, and all 4 virtual drives.  It's not efficient (lot's of having to reread the same bits of the vdisk files) but it let's me live in the memory footprint available on the Mega.

In order to test the disk interface while I was developing it, I had to learn and figure out the SignalTap IP module that Altera provides with Quartus - it is basically a built-in logic analyzer you can include in your design then setup triggers and capture various signals from inside you FPGA design.  It's surprisingly good, although you do have to jump through some hoops to make sure you can actually (efficiently) reference the signals you want it to monitor.  I ended up setting it up to (basically) monitor the whole Z80 bus (address, data and control lines), then would try to boot from an LDOS diskette image and then (spend way too much time) hand decompiling the instructions the processor was running to figure out what it was trying to do and see what it was getting back that it didn't like (assuming it wasn't actually booting at the time). 

I must say, that really put me back in-the-day - tallying addresses and bytes, then converting the bytes to Z80 instructions, then reverse engineering the assembly code -- fun way to waste spare time!
Sorry for the lack of any intersting pics - not much to show for all of the above.  But I do have a shot of the Arduino UI I ended up creating:

Each line represents a virtual floppy drive.  You can scroll between them with a rotary encoder.  Pressing the encoder button is like opening the door of the drive.  You're then presented a list of the files on the SD card, you can scroll through the files and traverse down directories.  When you select a file (pressing the encoder button with the file hilighted) you're "inserting" that file into the drive.  The arduino code will detect whether the file is DMK, JV1 or JV3 formatted file and 'mount' it if it is.  The indicator to the left of the filename is the drive activity light ("on" when the motor for that drive is active).

Once the basic single-density controller was implemented and working, I dug around the internet trying to find some schematics for the various double-density controllers available back in the day.  I eventually was able to locate schematics for both the official Radio Shack Doubler, and some hand-drawn reverse engineered schematics of the Percom Doubler.  Both were effectively identical, using the FD1791 to supplement the FD1771, with only the way the 1771/1791 were switched being different.  I ended up implementing the Percom Doubler for my emulator, so now it also supports double-sided, double-density vdisks (whoo-hoo, 360K on a single diskette!)...

I spent far too much time on the emulator, but eventually got it to the point it can boot LDOS and NewDOS/80 (and should work for the other various DOSes out there) and it's been able to run any program I've thrown at it so far...

I think this brings me up to about Jan/Feb of this year.  One more post and I'll probably be up to real-time and what I'm looking at doing with it next...

With the basic functionality of the floppy controller complete I decided it was time to redo the PCB. 

The overall height of the original board stack was pretty wacky, so I spent a some time trying to clean up the overall physical form.  I ended up keeping the Cyclone-II daughter board, but decided to take a shot at replacing the pre-fab Arduino Mega board with my own layout.  The basic design was lifted from the arduino design, but I decided to go with an Atmega1281 uC instead of the Atmega2561.  I didn't require all the extra pins and I figured the package would be a little easier to hand solder.

In the end this meant I had to use a 3rd party device lib for the Arduino stack (MegaCore) and had to make some modifications to a couple of libraries I was using to support the new chip (DirectIO and EnableInterrupt), but that's good because it gave me a much better appreciation for exactly what is (and isn't) going on in the Arduino space.  I also ended up with a much deeper understanding (or lack of) of the "Pin" definitions that are occuring under-the-hood of the Arduino stack - Not sure that's a good thing, but it is what it is...

Another change I made during the redesign was to replace the large LCD display with a smaller OLED display that I could mount directly to the Expansion PCB. 
Also by this point I had grown very tired of having to enter Date and Time each time I rebooted LDOS, so I scrounged around for details on how the original NewClock/80 worked (which provided a battery backed up Real Time Clock for the original TS80).  I learned it would be really easy to add a modern I2C based RTC chip and have the Arduino code translate from the original NewClock/80 register read/writes into messages the new RTC chip could understand.  So I went ahead and added a provision for an MCP7940N with a battery to the new design.

At this point I was still sticking with a two board design, one for the TRS80 base unit (except it supported the full 48K RAM), and a second "Expansion Interface" board to provide the Floppy emulation, RTC, and emulation of the original RS232 board (piped to/from the usb-serial interface).  I believe the only thing missing is the parallel printer port - and if I want to add that it would just be couple more registers on the FPGA and then figuring out what the Arduino should do with the data...

This is what I ended up with:

The main processor board still has the Cyclone-II as daughter board plugged into the back.  I also moved all the I/O connectors to the bottom of the board to acheive a tighter overall package envelope.  Oh, I also added a separate audio amp to take the cassette out signals and drive a speaker -- this provides the extremely primitive audio that some original games supported:

This is the expansion board:

UI components live on the top of the board, while most of the active components were placed on the bottom side.  A 26 pin header connects the two boards together; supporting the serial interface between FPGA and Atmega, plus some interrupts from the FPGA, an ability for the FPGA to detect whether the expansion board is present or not, and a way for the FPGA to wait until the Atmega is ready (up and running -- which takes a surprising long time), plus several spare pins going in each direction reserved for future use...

This is the current stack-up of boards:

At this point I consider this project pretty-much feature complete.  I've got this acting like the original TRS-80 with Cassette, Floppy controller with 4 drives (single and double density)-complete with simulated stepping clicks!, NewClock/80, Serial port, and even overclocking support (original @1.77Mhz, 2x @3.54Mhz and 4x @7.08Mhz).

Here's a short video of it running (I'm changing the clock speed when I'm mucking with the slide-switches):


[0] Message Index

[#] Next page

There was an error while thanking
Go to full version