TRS-80 Model 1 on a PIC32

TRS-80 Model I emulated on a PIC32MX processor; VGA, PS/2, and SD for tape and disk images. Oh, and glourious cassette sound.

Similar projects worth following
TRS-80 Model I emulated on a PIC32MX processor. It provides VGA video and PS/2 keyboard so as to be usable with commonly available hardware to-date (well, PS/2 keyboards are becoming rare, but it works with a USB-to-PS/2 adapter as well).

I did this project to keep myself occupied while recovering from some surgery in 2015, for which I would have limited mobility for about a month. I didn't think I'd be up to doing bench work, so I used some existing PCBs to allow me to focus on the firmware, which I could do lying down (both literally and figuratively). I used a UBW32 (from Schmalzhaus) as a CPU 'breakout board' and also a UBW32-MCC (from Dontronics) to provide the VGA, PS/2 keyboard, SD card, and power connectors.


"If I have seen farther than others, it is because I have stood on the shoulders of giants." -- Newt.

Props to Geoff Graham, who allowed me to pilfer his Maximite code for the video and keyboard 'drivers'. And also indirectly to Lucio Di Jasio, for describing the clever 'SPI and DMA as a video generator' technique, which was used in Geoff's project (and by extension, mine). I am very jealous that I can't claim to have invented that myself! Brilliant!

Props also to Tim Mann, a developer of software for the TRS-80 (actual) back in the day, and also creator of the 'xtrs' emulator for unixian systems. I used the Z80 CPU emulation code (which I modified a bit for my purposes). (It, in turn, is derived from another source which I cannot name, or else I'd cite it as well. Clarendon Hill? Either way, the license seems functionally public domain.)

Props also to Matthew Reed, author of TRS32, an excellent (albeit non-open-source) emulator for Win32 systems. I use it sometimes for comparison, and also the TRSTools are quite useful for extracting files from floppy images.

Props also to all those others who helped kept the memory of the TRS-80 alive; otherwise I would have had scratch to work with when starting this out.

SD card filesystem contents; unzip into the root of a microSD (I hav used up to 32 Gb cards), to have requisite files in place for the emulator to be useful. I also put the firmware image and the boot loader exe in 'doc'. These are not required for the emulator of course (the image has to be burned onto the chip!), but I put them in here for convenience to causally interested parties, to avoid downloading the source, setting up the toolchain, and building. Operation of the bootloader exe (Windows) is intuitively obvious. It's HID-based, so no drivers are needed. It does not appear to be usable on XP alas, so you'll need win 7 and up. There is also a 'README.txt' in the 'doc' folder which explains things in more detail.

x-zip-compressed - 15.68 MB - 09/22/2016 at 19:34


View file

  • 1 × Olimex Duinomite-MINI Alternative board; no soldering. If you go this route, you only need the SD card, and optionally the audio amplifier.
  • 1 × 2 GB microSD card this project is barely useable without cassette and floppy disk images. I think 2 GB is the max that the MicroChip firmware can support. EDIT: no, I have used it successfully with 8 and 32GB cards.
  • 1 × Audio amplifier; e.g. LM386 and speaker for convenience, if you want sound. Commodity board via eBay.
  • 1 × UBW32 If you're gong to do it my original way, you'll need this and all subseqently listed parts. CPU breakout board; Schmalzhaus, various retailers
  • 1 × UBW32-MCC connectors board; dontronics UBW32-MCC-PCB-Letter
  • 1 × SD card socket Molex 47309; Mouser number 538-47309-3751
  • 1 × PS/2 DIN connector Element14 number 42K7524
  • 1 × VGA connector Element14 number 16M3874
  • 1 × sundry passives various commodity passives, etc. see the UBW32-MCC 'manual' for deets

  • USB to PS/2 keyboard adapter improvement

    ziggurat2909/22/2016 at 19:57 0 comments

    PS/2 keyboards are getting rarer, and I knew I had successfully used one of the USB to PS/2 adapters before, but for some reason it no longer worked. So, out came the oscilloscope again.

    What I found was that the keyboard (or probably it was the adapter) was continually sending the 0xaa value every 600 ms. That value, 0xaa, is the 'Basic Assurance Test' (BAT), meaning that the keyboard passed the power-on self-test. But why was it sending it repeatedly, and not sending any key codes?

    I hazarded a guess that it want some interaction from the host, so I sent the 'set LEDs' code upon reception of the BAT. Doing so seemed to take the adapter out of whatever state it was in, and restored relaying of keycodes from the USB keyboard.

    While I had my probe wires soldered to the board, I tried a USB wireless keyboard through the adapter. This did not work. Unlike as with the wired USB keyboard, in this case the adapter simply remained silent.

    So, I've checked all that in, and you should now be OK to use one of those adapters with the emulator, with a more modern USB (wired) keyboard if you don't have a native PS/2 one on-hand.

  • 2nd Platform Support -- Olimex board

    ziggurat2909/20/2016 at 20:42 0 comments

    "...O frabjous day! Callooh! Callay!' He chortled in his joy."

    Today I finished porting the code to the Olimex Duinomite Mini board, so now you can have your emulator for about $25 USD (for what we paid upwards of a couple grand in the day), and soooo much more reliable. (and no soldering for the Olimex board).

    I have tested video, keyboard, SD card (cassette/floppy), and sound. I believe the porting task to be complete.

    I have updated the project-related file to now contain both firmware images, one for the UBW32 (based) board, and also the aforementioned Olimex board.

    The Olimex board does imply some limitations:

    • it is a monochrome only VGA board. Since the original TRS-80 was monochrome, this isn't the end of the world, but you won't be able to simulate the green screen filter. Also, pay a little closer attention to the controls states in the 'hypervisor' since you won't have color cues to guide you. But I think the reverse video does an adequate job of letting you know what control has the focus.
    • this board does not have a battery-backed RTC, alas. I haven't really been using that feature yet, anyway, since OSs needed to be patched to use the aftermarket RTC's of those days. I guess it would affect the file modification date on the SD card, but who cares?
    • this board only has one PWM channel, so you won't get Orchestra-85 stereo. I arbitrarily selected 'right' as the available channel. The cassette-based sound is directed there, so you can play all the games just fine. Do note that the PWM channel on this board is not capacitively coupled.
    • this board can be run from USB power, or from adapter by selecting a jumper near the jack. YOU MUST USE ONLY 5V REGULATED ADAPTER with the Olimex board. Not even 7v. Get a cheap 5V switcher wall wart off ebay or something. There is a zener on the board to help a little with booboos, but mr zener gets pretty hot and cranky when he's made to work.

    I guess what I have left is serial emulation, maybe hard disk, maybe some sort of printer, and maybe a 3D printed case might be nifty.

  • VGA Timing Improvements

    ziggurat2909/16/2016 at 17:55 0 comments

    Having grown weary of swapping my main monitor back-and-forth between the dev computer and the project board, I decided to invest in an inexpensive ($35) 7" vga monitor off ebay from china. After about a month, it arrived, and I eagerly plugged it in. And... nothing... (sigh). I was able to get it to display a little bit by fiddling with the controls but it was still way off screen to the left and unuseable. Hmm.

    Up to this point I have been using a video driver which I had borrowed hacked upon to make signals that would also be compatible with VGA multisync, but also some integral multiple of the archaic 384x192 resolution of the TRS-80 model I (which is too low for modern things). Truthfully, and I am chagrined to admit that I did less calculating and measuring than fiddling with constants until it worked. Since this project started as a lark, and since it had worked on the few monitors I had tested, I didn't really think that much about it. But, now, OK, maybe we need to check our assumptions with the oscilloscope and some standards.

    OK, so the current video is not exactly any standard mode, but it is most close to SVGA 800x600/60 Hz. I generate it by tripling the vertical lines and doubling the horizontal pixels to 768x576. So, I decided to close the gap to 800x600 with some blanked lines (handled in the frame gen state machine) and the horizontal doesn't strictly matter: there's some blank to the right that you don't really notice unless you want to, and all the more so because monitors these days are usually widescreen anyway, so there's already plenty of blankness. (Strictly, there is an old VESA mode of 768x576 which would be perfect, but I have a doubt that would be supported on cheap monitors like the one I got. Anyway, the dot clock in that mode is 34.96 MHz, as opposed to 40 MHz for 800x600 which is an integral divisor of the PIC32 system clock (80MHz)).

    So, having meansured, the vertical look good at about 59 Hz, and the horizontal looks good at about 37 KHz. The vertical sync was wildly out-of compliance at 54.8 us (instead of 105.6). That's easy, there's a constant which defines the number of horizontal lines which was 2 and now is 4 so it's good now at about 108.8 usec.

    The horizontal sync looked good at 3.8 usec (spec calls for 3.2), but the horizontal back porch is wildly out of spec at 1.6 us (spec says 2.2 usec). This almost certainly explains why the video is hopelessly off the screen to the left; that 1 us is 40 pixels! How to fix?

    OK, the video generation is done mostly using hardware peripherals: 3 SPI for pixel data, 3 DMA to feed the SPIs with no CPU overhead, a Timer set to count up and recycle once per raster line, and an Output Compare unit to generate horizontal sync pulses based on the counter value in the Timer. Also, the rising edge of the Output Compare (end of horz sync) is what triggers the SPI to start, because the 3 SPI are configured into 'frame slave mode' with the horz sync fed back into the frame start inputs. The SPI is in 32-bit mode, and is preloaded with a value of '0', and is clocked at sysclock/4 = 20MHz (since I'm doubling the physical horizontal resolution from 384 to 768, I halve the dot clock rate to make each pix twice as long). The DMA starts clocking out the actual frame buffer once that initial '0' has been sent.

    There is a short ISR entered at the rollover of the timer (i.e. at the beginning of the horizontal sync pulse) which drives a state machine that bit-bangs the vertical sync, and sets up the DMA to point to the current fame buffer line. All this preparatory happens while the sync is low, with negligible CPU overhead. The time-critical magic happens under hardware control for all three color planes, in sync, when the Output Compare goes high (i.e. the end of the horizontal sync pulse). Meanwhile the CPU is off tending to other stuff, not to be bothered again for about 27 usec.

    All this is great,...

    Read more »

  • Finally finished with FDC....

    ziggurat2909/06/2016 at 21:13 0 comments

    OK, I think I am truly done with the FDC emulation now. My problem in TRSDOS 2.7 formatting turned out to be due to the (emulated) disk interrupt coming in way sooner than (actual code of) TRSDOS expected during the 'writing system information' phase, and because the TRSDOS 2.7 ISR does not ack the fdc IRQ any more (unknown why they dropped this). The net result is that during that phase, a 'restore' is done to seek to track 0, and the IRQ is issued immediately (because we're virtual hardware), but the TRSDOS is not in a position to ever acknowledge that interrupt, so it infinite loops re-interrupting itself.

    This implementation defect is probably masked in the real world, because the 'restore' would take a finite amount of time, which would allow the code to move forward a few instructions to reach the point where it is polling the status bit, which does clear the irq. So, I introduced a 'deferred' interrupt request on Type I commands (seeks, etc) to simulate the non-zero amount of time that the FDC would take to execute the commands.

    So now that can be considered 'done' I hope. Now it's time for some serial port emulation. My intent is to use the USB CDC as my serial port, rather than the physical UARTS. I'm a little bit concerned, though. The USB involves code execution, which might slow down the emulator too much. If so, then I have at least two choices: 1) invoke the code only periodically, instead of every pass through the cyclic executive loop, and 2) punt on USB and use the hardware ports. I really hope I can get the USB option working, though. The hardware UART would probably mean needing some more parts -- probably a FTDI interface board -- and really I don't want to add any more parts since I've got a perfectly serviceable USB connector on-board already.

  • "It's the little things" -- FDC formatting (write track) now working

    ziggurat2909/02/2016 at 17:50 0 comments

    OK, after spending some quality time with the disassembler, disassembling TRSDOS 2.3 FORMAT/CMD, and stepping through the emulator, I found a bug: I failed to invert a bit being used in an AND mask. Obviously this caused all the other bits to be reset, one of which was 'Track 0 detect'. So.... a one-character ('~') fix, but hours of debugging. It's the little things, no?

    So, I'm formatting in TRSDOS 2.3 and LDOS 5.3.1 in single, double, mixed, 1 and 2 sides, and semi-arbitrary number of tracks. And I can reformat (oh that failed too, for coincidentally a different AND mask reason - there I forgot to mask off some flags from an offset value).

    So, I am nearly done with this FDC journey. TRSDOS 2.7 is not formatting properly for some reason. Well, it's formatting, per se, but hangs at 'writing system information'. I can verify that the disk image is properly formatted at that point, but the directory track is not written and the track 0 'mixed density' track has not been reformatted. Hmm. Well, I guess I should probably download and test other OSs as well -- NewDOS, UltraDOS, MultiDOS come to mind. Hopefully they work as is.

    One additional challenge with 2.7 is that it does not reference the 'system' files (the OS) in the directory, like previous versions, and all other OSs do. I am guessing that this is either to free those directory slots for the user, or perhaps less charitably, to make reverse-engineering more difficult. So, disassembling that OS will be an extra challenge just in setting up to disassemble it. Fortunately, I had written a tool to dump the floppy image in a low-level form (basically, a sorted extraction of the sector images with hexdump and some drive metadata about them). So I will first 'disassemble' the floppy to find the 'hidden' OS 'files', and then go back and forth between that and the code disassembly following from boot until I can glean how 2.7 is put together. Sounds like slow going, alas. Fortunately, I am Number 5's nemesis, and I love to disassemble!

    LDOS has definitely become my go-to OS, so I could possibly punt, but I really want to get these last cases put to bed (so that I can be put to bed) and move on to other things. Namely:

    * along the way I implemented Newclock-80 emulation. It seemed trivial to do -- and it was -- but what is not trivial is that a hardware RTC was a fancy thing in 1980. None of the OS recognize it out-of-box, and require patches to actually make use of it. I did find a patch for LDOS 5.1.3, but not 5.3.1. Most of that patch is reuseable with simple ORG changes, but the last thing is an internal routine named 'PACKIT', which I cannot find in the 5.3.1 code. So I need to spend some more time with the disassembly to see what I can do about it, which means also understanding the surrounding code better, as well.

    * serial port emulation. The USB serial is in-place, but I need to implement the emulator parts and wire it to it.

    * depending on mood, I may do hard drive and printer. I can easily punt on those for a while.

    * more important is porting it all to the new hardware platform. As mentioned before, this is going to be a little more work than I initially had expected, but c'est la vie, it's required. I'll miss the color, though.

  • FDC Read/Write working

    ziggurat2909/02/2016 at 06:55 0 comments

    OK, short update. The FDC emulation seems to be working correctly for sector reads and writes, in single and double density, both Percom and RadioShack doublers. Tested wtih TRSDOS 2.3, 2.7, LDOS 5.3.1 (and less aggressively with NewDOS/80).

    Testing/debugging incurred a bit more work than expected, since the various DOSes use different techniques for different things; e.g. some use a loop counter to time index hole passings, and others use the interrupt-driven 'heartbeat' counter. (In the latter case I wasted a couple days debugging in the desktop development app only to eventually discover I had not implemented the heartbeat interrupt in that environment. sigh. Most of that time was spent disassembling the OS to figure out why it specifically was unhappy, so at least I got some pleasant disassembly time in....) Another one was detection of the disk density -- LDOS was reporting double density disks as single density because it tries to figure it out by reading the dir track first as single-density, then if it fails, retries as double density. But my virtual floppy implementation was reporting 'success' on reading sectors without considering that a single density FDC cannot read double density magnetics. So I needed to add some logic to make those reads fail; and then LDOS behaved as expected.

    I did implement also ReadTrack and WriteTrack. I had been dreading these, but they wound up being fairly easy. I also think they work correctly -- at least in the virtual floppy implementation. However, I can't break out the champagne yet (well, maybe some of the cheap stuff), because I still have some issue whereby FORMAT is not working (which is what uses those commands). In LDOS I get a formatted disk, however, every other track (odd) is single density. LDOS is indeed explicitly requesting to change FDC's, but obviously it should not be, so "why?". I disassembled the double density driver, and that looks sane (or rather my understanding seems sane relative to what the disassembly showed). Anyway, the driver issues controller select changes based upon a bit in a byte in a structure. There are 10 of these, and I think collectively they are called the 'Device Control Table' ('DCT'). All the operations I have seen use the IY register to be the 'this' pointer referencing the target device's structure instance, and in this case +3 is the bitfield I mentioned. It uses bitmask 0x40 to indicate single(0)/double(1) density.

    Stepping in the debugger, I can see this value flapping wildly between, say 0x4c, and 0x04. WTF? this should be stable since it represents the characteristics of the drive. I also note that IY is wildly off in the weeds at 0x656f, and I know that normally the DCT is at 0x4700 + nDevice*10. Hmm. Corruption of CPU state? Jeez, I would think I would have seen the effects of a bug of that nature long before I got down to the execution of an entered command for formatting a disk. But maybe -- read/write track do alloc new, special, structures (the track image and state data), and write does alter memory.

    Anyway, I did a cursory disassembly of FORMAT/CMD and it seems it makes a copy of the DCT entry for some reason, so the IY value is not completely insane, but I need to understand why it's flapping in the wind.

    Also, TRSDOS 2.3 is not formatting, either. This is significant because it is a single-density-only OS, and is blythely unaware of 'selecting disk controllers' -- that's so 1980! -- so it's not a density thing. Also TRSDOS 2.7 hangs at 'analyzing disk' before getting into formatting at all.

    All this smells like 'status register infidelity', so I guess there's going to be more disassembly and single stepping in my future. Single-stepping; hmm. If there is a 'Texas two-step', is there a 'Wisconsin one-step'?

    Anyway, on the plus side, sector reads and writes to already-formatted floppy images...

    Read more »

  • Cursory Look at 2nd Platform

    ziggurat2908/20/2016 at 19:10 0 comments

    Today I took a cursory look at the candidate second hardware platform (since as I mentioned it appears that the one I originally used, the UBW32-MCC is not generally available in-market anymore). The candidate I am currently looking at is the Olimex Duinomite Mini.

    Well, studying the schematic, it turns out the pin assignment is wildly different, so it definitely will not be able to take the firmware images I have built for the UBW32 version as-is. This isn't the end-of-the-world, but I will have to do some mundane project reconfiguration to build the two different images. A little more disappointing, though, is that the Duinomite is monochrome only. No color VGA (I was wondering how the color planes were so well-aligned -- they're hardwired together). This will incur some work for me since I had gutted the video and previously threw out the monochrome support. Again, not the end-of-the-world, and anyway the firmware for that board is on github, so I should be able to do that fairly quickly.

    Anyway, my source has become a bit of a mess, so it will give me an opportunity to tidy it up. On the other hand, code tidying is not quite as fun as feature implementation.... :(

  • FDC somewhat working; w00t!

    ziggurat2908/20/2016 at 03:32 0 comments

    OK, I can boot TRSDOS 2.3 and 2.7 via single density and double density DMK images, also with Percom and Radio Shack doublers. That code is checked in.

    It's quite far from 'done' though; I have not implemented the read address (do I really need to?), read track, and write track commands. Those are necessary for formatting disks. I intend to, but I can punt on that a little while, I guess, by formatting disk images in another emulator (e.g. trs32). But the other stuff seems to work correctly. (Well, 'write sector' probably needs more thorough testing).

    DMK only at this point. Maybe I'll do JV1/3 later, but it's not a priority for me relative to getting the other stuff working fer shur.

    So, it's a start!

  • Getting back to FDC emulation

    ziggurat2908/14/2016 at 20:59 0 comments

    I'm now getting back to floppy emulation after being busy with other things for some time. Now I am in the thick of ancient Western Digital datasheets from the 70s, disassembled TRSDOS (I know of course this has been done myriad times in the past 40 years, but I actually really like disassembling), and of course, looking at other folks existing code.

    For starters I'm just going to support the 'DMK' disk format, because it's the richest. Maybe later I'll support the others.

    One thing I noticed in passing is that it seem Dontronics is no longer carrying the UBW32-MCC board (well, as best as I can infer based on it being out-of-stock for sometime), which I used to conveniently mount the various peripheral connectors onto the UBW32 for this project. One could fabricate their own, of course, since the design is open source, but I am thinking about instead porting the whole thing to the Olimex DuinoMite-Mini board. Aside from those being still in-production, it's also much cheaper (about USD$ 20, versus ~ $60+ if you did it my original way), and you wouldn't have to solder anything at all. I imagine this would be convenient for the casually interested. One thing I notice is that there is no DS1307 RTC - rather the on-chip clock is supported, but on that particular board there is no provision for battery. :( So it will be more authentic like the old-days where you have to enter the date and time upon power on haha.

    I wish there was something like that board with the PIC32MZ on it. I could use the extra speed and memory. I don't know if they fixed the huge list of bugs on that chip, but those bugs don't really affect my this project's requirements. If there was, then I might be able to pull off a Model 4 or maybe even a Model II (but where to get floppy images?), and with a higher resolution video.

  • Faster video emu

    ziggurat2901/08/2016 at 02:06 0 comments

    As mentioned, the code for the 'drivers' was used, with permission, from various sources. In particular, I used video code from the Maximite project (I tweaked it for my TRS-80 native resolution (which further required a line-tripling hack for modern monitors) and discarded a bunch that were for features I didn't need). It worked great and was a huge help. One nagging problem was with video performance.

    For the most part, it worked good enough. I could tell with my developer's eye that it was a little sluggish, but that sluggishness was quickly compensated for in subsequent non-video activities (the speed throttling tries to keep the emulated cpu's clock's error function at zero, so if an emulated operation takes a longer than expected time, subsequent instructions execute faster than expected until it catches up). So, for all practical uses, it was perfectly fine. But there was a pathological case: that of switching between normal and wide character mode.

    The TRS-80 had a 'wide character' mode, which was rarely used. I mean, who would want to reduce an already constrained 64x16 text display to 32x16? Well, one program did, one of my faves: SpaceWarp. SpaceWarp used the wide character mode as a visual effect by rapidly switching between normal and wide to simulate a 'starquake' when you drove into a star (OK, a period. It was ASCII art.) This worked on the original hardware because the wide character feature was implemented in hardware -- it had no software burden -- but here we had to do a full screen repaint pixel-by-pixel when switching modes.

    Anyway, long story short (too late, I know): the new code is fast enough to make this unusual effect work.

    OK. Maybe I should get back to work on either emulating the WD1771/91 or making BogoDOS....

View all 11 project logs

  • 1

    get a UBW32 for the CPU. plenty of online retailers for this

  • 2

    get a UBW32-MCC for the jacks. assemble it. It's a fairly simple board. I do highly recommend buying a CR1616 solder tab (search 'gameboy' on ebay) battery that you can wrap in electrical tape and stuff underneath the mounted UBW32. Anyway, you'll need the connectors. The parts list enumerates the peculiar ones; the rest are commodity parts, so I didn't list them. Alternatively, you can make your own PCB, of course. Mostly, it just provides mounting for the connectors.

  • 3

    get a monitor. I am running just fine on a modern LCD flat panel

View all 8 instructions

Enjoy this project?



ziggurat29 wrote 09/09/2016 at 14:58 point

@Hacker404:  re descenders, yes, for the most part you should be able to simply move them up a pix and have them look correct.  'p' is the exception because it has two lines of descender in the image I have sent, so you need also clear the last line (making it look like a reversed 'q')

I have sent you the data (too long to post here), but as an example, here is image of the the lowercase 'p' with 'descender':

{ 0x0000, 0x0000, 0x002c, 0x0032, 0x0032, 0x002c, 0x0020, 0x0020, 0x0020, 0x0000, 0x0000, 0x0000 }, //p

to convert it to 'no descender' you would remove the top row (the first 0x0000) and stick a blank row at the bottom (the last entry); i.e.

{ 0x0000, 0x002c, 0x0032, 0x0032, 0x002c, 0x0020, 0x0020, 0x0020, 0x0000, 0x0000, 0x0000, 0x0000 }, //p

and in the special case of 'p' clear row 7 to zero.  (the others don't require this, they only have one descender row)

{ 0x0000, 0x002c, 0x0032, 0x0032, 0x002c, 0x0020, 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, //p

The characters affected are:

'g', 'j', 'p', 'q', 'y'


1) I explained separately why these are 16-bit quantities -- a technical need for my emulator.  Only the lower 6 bits are significant, so disregard the 10 leading bits.

2) Similarly, this bit image is for the full 6x12 character cell (I do graphics through the char gen as well).  If you are generating the signals via hardware, and only need the character images with no descenders, you probably want to drop the last 5 entries (raster lines) since they are always blank in that case.

3) Lastly, these image include the inter-character spacing in bit 0 (hence why all the even numbers).  If you generate that part of timing electronically, then shift all values down one, and there will only be 5 significant digits, so less logic (maybe; I guess the compiler will figure out that bit 0 is always 0 and there's not a lot of logic needed to generate for that case!)

4) Oh yes, 'lastly' lastly, as mentioned separately, if you are generating your video signals in hardware, you probably don't need the images for the graphics characters (0x80-0xff) and the first 32 which alias the uppercase characters (0x00-0x1f -> 0x40-0x5f).  Maybe that saves some logic for you.

Doing the things above will yield a 5x7 char gen array that should be accurate for the TRS-80 Model I second versions chargen (no-descenders, corrected bug for 'flying 'a'').


  Are you sure? yes | no

Hacker404 wrote 09/07/2016 at 23:40 point

Hi, I love the project. 

I would like to ask a favor. I am making a hardware clone, It's here -

I had a system crash and i lost the pixel data used by the character ROM (generator).

Can you send a link to where you found it or a copy of your data? I would save me so much time. I am especially wanting the very simplified model I character set that hasn't been modified because I want to fit into the computational logic of a CPLD if possible so I don't have to include an expensive fast FLASH chip just for this function. 

Thank, Rob.

  Are you sure? yes | no

ziggurat29 wrote 09/08/2016 at 14:56 point

Absolutely.  Send me a PM with where I can send it (email or whatever).

System crash sucks!  I myself have a little stack of harddrives with long lost projects.  One day I may become bold enough to take the soldering iron to them....

Where I got it:  I found a TrueType font for the characters.  I then wrote a Windows program to emit text with the font, followed by code to pluck the pixels from the resulting screen image and assemble the binary image for the character generator.  This was straightforward, if boring code.  Also, the TrueType font was not absolutely correct, so there was an intermediate correction step (minor; characters 00-1f alias 40-5f, and c0-ff alias 80-bf).

The output I generate is (now) a simplified format; an array

const unsigned short g_abyFontData_00[256][12]

of binary pixel data.  Each of the second subscript 0-11 is successive rows, and each of the first is obviously characters.  The values are row data, msb = first pixel, with the value right justified, i.e. there are leading zeros for unused pixels; the trs80 character cell is 6x12 pix.  So why did I use unsigned short instead of unsigned char?  For my software generator, I generated two fonts, one for normal and one for the wide characters, hence I needed more bits for the latter.  I'm sure you wont need that for your hardware-based system, but I wanted to explain why the extra bits are there.

As simple as that array definition is, I suspect you can use it as-is, perhaps with some textual massaging for getting it into the form you need for your CPLD.  If it's more handy for you to have it in a different form, let me know; I could tweak the fontmaker program output for you to save you some time in the text editor.

Final note:  this image represents the last character generator rom -- i.e. the one with the glourious one-pix descenders.  There were two prior:  the second had no descenders, which made some chars look goofy, and the first had a bug where the @ was raised one row.  If you wanted to have those for historical accuracy, you could tweak the font generator (or really just hand edit the binary since the change is trivial) to create them.

Anyway, let me know where you what me to send whatever and I'll do so.

Cheers and good luck!  I think your hardware replica is very cool, too!


  Are you sure? yes | no

Hacker404 wrote 09/09/2016 at 05:30 point


I tried a version with descender and that was too complex to fit into the small CPLD that I am using so I am really after a version with no descender. Can I just lift the descender characters up a couple of pix or are they different in other ways?


  Are you sure? yes | no

mauroxavierneto wrote 01/18/2016 at 22:02 point

I tried to write your hex in my  Colour Maximite from Altronics (K9555), but it doesn´t work (black screen). Can you give me any tip to compile from the source to run in my board?

PS.: Sorry about my bad english.

  Are you sure? yes | no

ziggurat29 wrote 01/18/2016 at 22:33 point

Hmm, I would /think/ that it would work as-is with the colour maximite, but I did toss out a lot of maximite model-specific stuff, so maybe I rendered it more bound to the UBW32 version.  (e.g. I'm pretty sure the original monochrome model is not supported).

On second thought, I believe the major difference between the 'classic' colour maximite and the UBW32 version has to do with the linker script, to accomodate a different boot loader.  If that's true, then the prebuilt hex file for the UBW32 version could easily be expected to not work for different hardware (well, different memory layout).

As an initial sanity check, I would flash back your original firmware to prove the board is good, and not bricked, then we can look at what needs to be done here.

So, are you able to compile at all now?  The project should be self contained, (I think).  It is created for the older Microchip stuff (i.e. pre-MPLABX).  Coincidentally I had just set up a new build VM, so I can see I installed:
*  MPLAB IDE v8.22
*  MPLAB C32 v2.02a

I'm pretty sure that  is all you need insofaras toolchain.  You may want to do this in a virtual machine (as I do) because you really want to compile with -Os, which you only get for 60 days.  It will work at -O1 (supported by the 'Lite' version), but the extra optimization really helps having more free CPU overhead for the emulation.

OK, also let me know if you can get the code from the repository (linked on the project page).  That's a Fossil-SCM repository; if you log in as 'anonymous', then you will be able to download a zip file of the current source snapshot.  On the other hand, if you have trouble or just don't want to bother, then PM me with, say, and email, and I'll zip up my project workspace and send it to you.  At least then you'll have a chance at futzing with it to see what's up.  Actually, I'd like to know, too, since it really should run on the 'classic' colour maximite just fine, but I don't have one in my possession to test with.  I'll do a little googling on the model you mention to see if there is anything obvious about it's implementation.

Your English is surely better than my Portuguese.

  Are you sure? yes | no

mauroxavierneto wrote 01/18/2016 at 22:46 point

My board are working ok, I reversed to original firmware and it´s fine. I´m curious about the fact that in the Geoff´s Projects site are saying that the UBW32 and Colour Maximite share exactly the same firmware...

When I saw your site in 2015, I tried to compile the firmware without success (has generated a .elf and have the same black screen). In any case, I´m glad that you answered me so fast.

I will gonna try to compile it again...

  Are you sure? yes | no

ziggurat29 wrote 01/18/2016 at 23:25 point

(I don't know why I can't reply to your last post, so I am replying to your first; this may make messages out of order).

Yes, hasty words about the bootloader.  I concur that is not it.  I did notice one thing looking at the code, in Main.c::18-21, I have commented-out an include that originally have a bunch of #pragma config items for doing all manner of things like setting up clocks, etc.  I took that out, because the UBW32 bootloader does that beforehand, but maybe it is still necessary for 'classic' colour maximite.  I don't think I have that file in the repo ("Configuration Bits.h"), but I can send it to you if you want to try that.

Some other things:
*  black screen.  Hmm.  Is CPU halted, or is it just unable to generate video?  As a quicky, you can plug your [black screen] maximite into USB, and you should still get CDC enumeration (I have that in the firmware, though I'm not using it yet.  But it will enumerate as a COM port).
*  When I was bringing the board up, I relied upon twinkling the various LEDs to know how far it got in the code.  (I don't know why, I cannot use JTAG to debug this board and firmware).  Things like

    LATECLR = 1<<0; //led 3 (yellow) on

    LATECLR = 1<<1;  //put on the red light

    LATECLR = 1<<2; //led 1 (white) on

    LATECLR = 1<<3; //led 4 (green) on

will turn on the various LEDs, and you can move that code incrementally down to see where things start to croak.  I would start an Main.c:1978 (after setting vectored interrupts)  with the yellow LED, and do a kind of manual binary search up until about 2001, at which point all the hardware should have been initialized successfully, and the video machine cranked up.  If you need to go further, at line 2019, you should definitely have something on the screen, because that's a decorative simulation of the random screen data on boot up that the original machine had.

I do appreciate your trying out the project, and I'm sure we can make it work.

  Are you sure? yes | no

mauroxavierneto wrote 01/18/2016 at 23:42 point

When I flashed with your actual hex, I think the CPU was freezed because when I turn on the Colour Maximite, the keyboard led flashed one time in the boot, and then turn off one second after. I tried some keyboard commands to control de TRS80emu but nothing has happened, no sound, no image, no lights.

Can you send me a new .hex file compiled with the original "Configuration Bits.h"? 

  Are you sure? yes | no

greenaum wrote 01/06/2016 at 19:35 point

If a disk program doesn't load in extra data once running, then a snapshot would be fine anyway. Indeed many of the games for the Spectrum (an example I'm most familiar with) are snapshotted after the copy-protection check has been done. 

The Multiface, btw, was an add-on for 8-bit computers, those that exposed the CPU bus to a connector on the back, at least. Usually paged in it's own ROM, and contained 8K RAM (or early versions used the screen RAM for workspace, messing the screen up til the game re-drew it). Pressing a button tripped the NMI line and paged in it's ROM, from there you could snapshot to any medium it supported.

There was also some nice support software that you could load into the 8K RAM. Stuff that would search for values in the machine's main RAM, for things like life counters, spaceship shield levels, etc. It could alter the code from there, letting you make  up your own cheats. Magazines were full of POKEs back then, Multiface or otherwise, you could always type your own in, after the machine code has loaded but before it runs.

Ah, the good old days! I can see why you're doing this!

On the issue of disk drives, the common controller chips have been emulated somewhere or other, there might be code you can plug in, perhaps if you contacted a friendly emulator author. Sure you know, programmers are usually keen to share code with someone who appreciates it and can put it to use, even if the source isn't publicly released.

  Are you sure? yes | no

ziggurat29 wrote 01/08/2016 at 02:20 point

I can see the Multiface via wikipedia.  I don't think we had one for the TRS-80, but probably could have, at least for the Model I, which had the whole bus pants-down on the card edge (a lot of it's electrical undoing, and part of the reason for the unibody Model III and IV.  Well that and FCC part 15...).

Yes, the existing desktop emulators have plenty of  existing code to use; I would probably use xtrs's at least for reference, if not as-is.  Still, the idea of making a BogoDOS interests me because I'm making new Z80 code for an old machine (and because it might give a better user experience, sort of like with the cassette emulation, which now makes 'cassettes' a delight to work with).  But you never know what I'll do -- I certainly don't -- and I'm eager to get back to my cryptographic calculator project, so I want to close this one up for a while....

  Are you sure? yes | no

greenaum wrote 01/06/2016 at 02:08 point

As far as disk loading goes, you could do what the early ZX Spectrum emulators did, with (originally) .SNA and then .Z80 files. Just take a snapshot (from a PC emulator, perhaps) of the machine's RAM and registers (including hardware ones) while a program is running. Then have a simple menu system, outside the TRS-80 emulation, that loads the snapshot into RAM.

Another way might be to add some pseudo-instructions of your own to the Z80, that load in snapshots. Then patch the DOS / BASIC etc to use them, at which time the hardware takes over and loads a snapshot in.

Or if not pseudo-instructions, have your hardware keep an eye on a certain I/O address, and again, load in a snapshot when it's called. Patch your routines accordingly.

Yes, it's cheating, but easier than emulating a disk drive, and it gets the job done!

Actually snapshotting was done back in the day, the Multiface interface would dump a memory / register snapshot to disk / microdrive / etc, as a way of supporting hardware that the Spectrum's own ROM didn't.

For bigger games that rely on disk access, this won't work, but are there any?

  Are you sure? yes | no

ziggurat29 wrote 01/06/2016 at 03:40 point

You make valid points; I do currently use some unimplemented instructions to facilitate a 'trap' mechanism, and I currently use that to patch the ROM cassette routines to directly read from SD rather than bit-bang in at realtime speed.  Now cassette is some 160x faster -- it's more pleasant than floppy disk, haha.  But I'm hosed if I want to run a program that has it's own low-level cassette loader.  And yes there many that do their own disk IO -- it was commonly done as a copy protection scheme (e.g. non-standard formatted track that BACKUP can't copy).  But, also as you point out, 'who cares'? because this is more of a toy than a saleable product.

As for snapshotting running state, that should be child's play, especially because the entire address space is only 64K, and I've got a 2GB SD card, haha, so room for some 32000 snapshots, haha.  Maybe I'll add that....

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

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