[posted] Teensy 3.6 based 8086 PC emulator with CGA graphics, PS2 keyboard

Mike Chambers

Well-known member
Hi all! This is something I did last year, but thought I'd finally share. I wrote a PC-based PC emulator some years ago, and later wanted to see how it worked on a microcontroller. So, I ripped the CPU core and a few other bits out, and got to work. I originally tried this with an Arduino Mega2560. It worked. Very, very slowly. Turns out AVRs don't make the best CPU emulators! :D Thanks to Paul for putting out these great little boards!

Like the title says, it's an 8086 (actually 80186) PC emulator based around a Teensy 3.6. It uses as much fast native RAM as it can, but then digs into SPI RAM to complete the 640 KB range you'd find in an old PC. It supports CGA graphics on an LCD screen and lets you plug in a PS2 keyboard. It uses raw access to an SD card as a hard disk.

It's no speed demon, but it runs well enough for MOST old programs you'd have come across in the 80's when overclocked to 240 MHz. Some other software is pretty painful, like Ultima 6. That was really aimed at 286+ anyway though. The main thing slowing it down is waiting for SPI communications with the RAM and LCD.

If anybody is interested in the code to create your own or hack it up a bit, I'll be sharing it probably tomorrow. I'll come back and edit the post. It's been a while since I wrote this, and want to make sure I remember all the different libraries used so I can link to them. I need to glance over the code again.

Here's a pic and some video. My soldering is terrible, and sorry for the shaky video.

teensy-sm.jpg


 
Nice work. Did you try the edit in boards.txt to allow 256MHz?

remove '#' to uncomment:
Code:
#teensy36.menu.speed.256=256 MHz (overclock)
#teensy36.menu.speed.256.build.fcpu=256000000
That will bump bus speed if that might break anything - though it might help depending.

Bus speed can also be doubled if desired finding these lines in ...\hardware\teensy\avr\cores\teensy3\kinetis.h
Code:
 #define F_BUS 64000000
 //#define F_BUS 128000000  // all the usual overclocking caveats apply...
 #endif
 #define F_MEM 32000000
#elif (F_CPU == 240000000)
 #define F_PLL 240000000
 #ifndef F_BUS
 #define F_BUS 60000000
 //#define F_BUS 80000000   // uncomment these to try peripheral overclocking
 //#define F_BUS 120000000  // all the usual overclocking caveats apply...

Not sure if RAM could run faster with that?
 
Thanks for the info, I wasn't aware of those options. I'll give them a try tonight and see how it goes. The emulator actually runs a bit faster than it shows in these videos, as tonight I realized I had it compiled with the "ADVANCED_CLIENT" define, which causes it to send all video memory updates through the UART.

The "advanced client" is a PC program I wrote that could be used as a display and keyboard instead of using an LCD and PS2 keyboard. It also allows the Teensy emulator to have a makeshift emulated Ethernet adapter, which I wrote a DOS packet driver for. The PC program uses pcap and forwards packet data between the Teensy and your real network. I was using it to run a web browser and an IRC client on this. If there's any interest in that, I can release it too.

It also looks like I can't edit the original post, so I'll put the code here.

The only libraries I used are the optimized ILI9341 lib by Paul, and the SPIRAM24 library by FemtoCow.

I used the LCD screen available from pjrc.com.

I've attached a ZIP with the code. It's pretty messy after lots of experimenting. I haven't taken the time to clean it up, but if I don't release it now, I probably never will get around to it. If you're wondering why it's called "zero86" it's because I was starting to develop it for the Arduino Zero and never changed the name.

You can actually use this without SPI RAM if you don't have any, but you'll be limited to 231,424 bytes of RAM in the emulator.

SPI RAM pins:
- 256 KB SPI RAM chips CS lines should be on pins 25, 26.
- MOSI = 21
- MISO = 5
- SCK = 20

LCD/TFT screen pins:
- DC = 9
- CS = 10
- MOSI = 11
- MISO = 12
- SCK = 13

PS/2 keyboard pins:
- Data = 18
- Clock = 19

I believe that covers all the pins.

Here's a sample hard drive image with DOS 6.22, Windows 3.0, and a few 80's games. Just write it directly to an SD card with something like HDD Raw Copy.

http://s000.tinyupload.com/index.php?file_id=01325083938351129329

You can make your own image if you want using another emulator. It expects disk geometry of 16 heads, 63 sectors. It can be up to 500 MB.

I hope somebody gets some use out of this! It was a fun project to work on.
 

Attachments

  • zero86.zip
    86.6 KB · Views: 930
Last edited:
Oh my.. that SPIRAM24 lib looks very unoptimized and slow..
For Teensy, it really should use the FIFOs and the max allowed SPI speed. Then, it supports single Bytes transfers only? Pretty high overhead..
 
I wondered how Teensy efficient that SPIRAM24 might be! Those PSRAM chips can run as fast at 84 MHz when crossing page boundaries - so T_3.6 could clock at 60/64 with faster OC F_BUS?

Hi FrankB - was wondering if you saw this thread. I ordered 8 of the 8MB PSRAM chips, nice you got yours so fast!
 
Yes, they were surprisingly fast with shipping.
If anyone wants to use these RAMs: They use the usual commands (0x02/0x03), but they need a reset command to initialize, like a flash. And they don't like CS too long active without data transfer, best is to deassert it immediately.
But I don't want to be off-topic here.
 
That 8 MB RAM chip looks great! I'll need to see if I can get one of those.

I also didn't know about the FIFO capability, I'm going to have to see what kind of improvements can be had with that. It should be pretty substantial! :)

When running entirely on the 3.6's native RAM, the emulator is quite fast.

I haven't dug into the details too much with the Teensy hardware yet, I'm coming from an AVR background. (And a little bit of PIC)

I'm glad you like the project, Frank!
 
Am I correct in assuming that the FIFO can only be used on SPI0? I'll need to rewire the board slightly if that's the case. The RAM is on SPI1 right now, I'll need to share the LCD's bus with it.
 
Article posted on the website:

I am just now seeing this. Thanks for the post, Paul!

I happen to currently be working on the "next generation" version of this with a Teensy 4.1. This one emulates a 486 PC. You need to install 16 MB of PSRAM on the board for this project and I highly recommend a heatsink and full 1 GHz overclock!

I wonder if the speed would benefit from a TCM cache, or if the caching mechanism overhead will cancel it out. I'll have to experiment.

I'm going to be adding an LCD and PS/2 keyboard support to it ASAP, but for now it can be used over serial. Here's a sneak preview. Debian 2.2 Potato running on the Teensy 4.1. :D

1748466194054.png
 
Last edited:
This looks interesting:)

Thanks! I'm not sure how useful it will be to play 486-era games, but it's a fun experiment to see how far I can push the Teensy. An old Linux distro seems relatively usable on it if you are just doing console mode text stuff. Commands and basic applications work fast enough.

1.64 bogomips. :)

1748533813442.png


That's with the Teensy overclocked to 816 MHz.

DOS games should work faster though. When I get an LCD attached, I'll see how that goes. When you're running Linux, every memory access has to go through page table translation which adds quite a lot of overhead. I believe DOS4GW just sets up a flat memory map with no paging.

But even with no paging overhead, I doubt you're going to get very playable speeds for games that wanted a fast 486 back in the day.
 
Wow, this is really great! Do you have any approximate estimate of speed equivalence?

I've been thinking about emulation of processors on which one might actually use to do work; I was thinking of exploring Desqview/QEMM and Desqview/X, in emulation on a desktop just to poke around, but your x86 emulator opens up far more. I'm not interested in gaming so modest display performance would be fine.

I know the hardware and code well enough to get in trouble, but I am completely deficient in knowledge around memory management... But you're running an ancient debian!!! Damn cool stuff. AWESOME.
 
Wow, this is really great! Do you have any approximate estimate of speed equivalence?

I've been thinking about emulation of processors on which one might actually use to do work; I was thinking of exploring Desqview/QEMM and Desqview/X, in emulation on a desktop just to poke around, but your x86 emulator opens up far more. I'm not interested in gaming so modest display performance would be fine.

I know the hardware and code well enough to get in trouble, but I am completely deficient in knowledge around memory management... But you're running an ancient debian!!! Damn cool stuff. AWESOME.

Thanks! I'd say Linux runs like a slow 386 and DOS games run like a mid-tier or fast 386.

The display performance has to be pretty slow, think 5 to 10 FPS. Otherwise the rendering will start eating away at the CPU performance too much since the Teensy's micro isn't a dual core. I wish it were so I could do rendering in another thread. I was thinking about hooking up a second Teensy to do all of the video rendering. Like it could handle all of the VGA functions and the first Teensy can forward register and memory IO requests to it.

There are still some bugs in my CPU and ATA controller emulation that I need to find. All that really works right now is Debian 2.2 (with some bugs), DOS4GW games, and real-mode DOS games.

No Windows version will boot. I think NT4 is getting the closest, but it blue screens with INACCESSIBLE_BOOT_DEVICE so it doesn't like something about my ATA controller. Sometimes even Debian will hang for 20-30 seconds, then spit out "hda: interrupt lost" and then it continues on.
 
Still impressive. Have you looked at wwatson's VGA_4BIT? It does VGA display via DMA. It's been absolutely rock-solid for me. A few bugs (reverse scrolling), and scroll is via movmem not fiddling start registers but it's otherwise great and very fast.
 
Back
Top