Go Down

Topic: 8086 PC emulator w/ CGA graphics and a VNC server on Arduino Due (and Mega2560?) (Read 248 times) previous topic - next topic


Hi, all. I've been writing an 8086 (actually 80186) PC emulator for the Arduino Due. You can interface with it via VNC using a Wiznet 5x00 Ethernet module/shield. I'm working on making it function on a Mega2560 as well, but that's not working quite right yet. Will update if I get that going.

Here's an overview of how it works. It emulates an old 1980's PC's 640 KB of memory space with a mix of a byte array of 80 KB in native SRAM, and uses SPI RAM for the rest. I have an 8 KB generic XT BIOS embedded in the program.

There is a CPU emulation engine which steps through the memory the same way a real 8086 does, interpreting and executing x86 machine instructions how the original CPU does, but with equivalent C code and variables simulating the hardware logic and registers.

This way, it can execute original PC software in a way that the original code does not need to be modified, or even know it's not working on a real PC. So you can run anything an original PC could. MS-DOS, Windows 3.0 or earlier, old games, or whatever else you want.

It also required emulating a couple of the other chips found on a PC/XT like the 8253 timer and 8259 interrupt controller. I did not really emulate the 8255 PPI properly. I got around that with a couple of simple hacks. It hasn't seemed to cause any problems.

It uses an SD card in raw mode as a hard disk. You can either just start with my included disk image, or make your own and install DOS with another emulator like PCem/86Box/Fake86. The emulator expects 16 heads, 63 sector disk geometry. It can be up to a 500 MB image.

There's also the VNC server part of the code that lets a client connect to it over Ethernet, renders the video memory contents the same way an old CGA card would have, and sends the bitmap data to the client to display. It also reads keyboard input from the client.

You could also ditch that and use an LCD display if you wanted, and even make it talk to a real PS2 or AT keyboard! Then you could get rid of the Ethernet module and be able to use it stand-alone with no PC needed. :)

Note: You NEED to use TurboVNC for proper color reproduction! As far as I can tell, I've followed the VNC/RFB spec, but only TurboVNC seems to properly unpack the 8-bit color values. I don't want to use 32-bit color data, as that quadruples the Ethernet data writes. It's slow enough as it is!

It emulates the following:
- 80186 CPU
- CGA video card
- Intel 8253 PIT
- Intel 8259 interrupt controller
- Disk access via SD card (with raw image written to card)

Libraries used:
- Paul Stoffregen's optimized Ethernet library
- DueTimer

Hardware requirements:
- Arduino Due
- Wiznet 5x00 Ethernet module/shield (I've tested a Seeed Studio 5500 shield and an unknown brand 5100 shield)
- SD card for disk
- Five 128 KB SPI RAM modules (I used two FemtoCow NVRAM shields)

You don't strictly need all five SPI RAM modules, but you will need to modify the RAM_SIZE define in emu.h if you have less. Remember that the first 80 KB is emulated with the Due's native SRAM, and also that the last 16 KB of SPI RAM is reserved for the 16 KB of CGA video memory.

For example, if you have one 128 KB SPI RAM module, then available emulator memory is 128 KB + 80 KB - 16 KB = 192 KB. (196,608 bytes should be your #define)

CS pins for SPI RAM modules are, in this order: 5, 6, 7, 8, 9, 3. If you have less than five, start with the first pin in the list.

So, the speed. It's pretty slow. Quite a few times slower than a real 8086/8088. With a VNC client connected, it's much worse while video memory is being written to! Sending out all the screen updates in real time slows it way down. It's really bad. Don't expect to be be playing any games at usable speeds. I'm not sure how much this can be mitigated, but if anybody wants to have a go at optimization, have at it! Share your improvements if you want. :)

I expected it to be slow, but I just had fun making this as a proof-of-concept.

You should definitely change the compiler's optimization to -O3!!!!! Replace all "-Os" with "-O3" in C:\Users\username\AppData\Local\Arduino15\packages\arduino\hardware\sam\1.6.12\platform.txt

That makes a huge difference in performance.

Other things to note:
- Default IP address is (Can change this in rfb.ino)
- The SD card CS pin is 4. (Typical for Ethernet shields)
- The Ethernet CS pin is 10. (Also typical)
- If you're using FemtoCow NVRAM shield(s), put them on top of the Ethernet shield. You need to bend out pins 11, 12, 13 so that they're not contacting the Arduino. You also need to install headers for the SPI pins on the right, and jump them to 11, 12, 13. (See pics below)

Here's a ZIP with my code, the libraries I used, and a disk image to write to your SD card. The image has DOS 6.22, and a few very old programs to play with.


Here are some pics of my project, and some screenshots!

Let me know if you have any questions. Have fun!


Great project. Thanks for sharing!
Thank you! I just went through and added more information about how it works to my post. I just kind of threw this on here last night in a rush since I was a bit tired.

It will hopefully clear up what this is in case anybody doesn't understand it completely.

Go Up