Simulating a Machine from the 80s

1 hour ago 2

2025-08-10

The book

I recently read a book on the history of computing in Ukraine: Innovation in Isolation. It has the story of Fahivets-85 - my first computer I got as a birthday gift when I was 6. The urge to try this machine again was so big I decided to simulate it and run some programs (and games) I remember from the childhood. Even though there are several existing emulators of this and similar machines, I wanted to take the implementation path myself.

The code

At the moment of writing I have an emulator that compiles into Web Assembly and is good enough to run the game called "Rain". The game is quite simple: press any key to go past the main screen, then use the arrow keys (left and right) to control a up and catch the rain drops. Is you miss a drop once, a cactus starts growing. If you miss twice on the same place, the cactus get bigger and you will die if you touch it. If you miss for the 3rd time, the cactus will transform into a demon that will move randomly.

There are some issues with how the keyboard is handled, and I don't yet have the sound. But the game is quite playable.

It took me 43 commits to get to this state. Here are the main ones.

  • Add first implementation Reviewing the specs for Intel 8085, I'm building the ops.txt file with a short spec of different CPU commands. It looks like this: each line has info about how the command is encoded in the binary code, its duration; semantics can be interpreted as micro-assembler code, and an example can be used as an illustration and a test.
cmd encoding flags size cycles time semantics example ACI 11001110 ZSCPA 2 2 7 A = A + data + fC |A=2, data=1, fC=1 => A=4 ADC 10001r/m ZSCPA 1 1/2 4/7 A = A + r/m + fC |A=2, B=1, r/m=b000, fC=1 => A=4

My original idea was that I can write a generator of Go code from this table. Instead of implementing my own generator, I take the path of asking AI assistant to generate implementation and tests for me looking at those specs. It took some time to get implementation and tests in the style I liked, but once I prepared first examples myself, AI was quite good in following the existing pattern and adding other implementations.

  • arch: Add first decoding logic I wanted to get to trying real binary codes I could find for Фахівець as fast as possible, so even though I haven't yet had full commands implementation, I started adding their decoding logic too.

  • Add go.mod Not much to say. Feels like it's time.

  • arch: Support decoding of more instructions Continue with adding the decoding logic for the instructions I already have.

  • Add more instructions support including load Extend the coverage of the CPU commands, keep using AI help. Instructions that load data from memory are now supported.

  • Add move codes Support coping data between registers and memory. Why did people call it MOV, and not COPY?

  • Complete instruction set

  • arch: Debug first ROM code Now we have the full coverage of instructions, and we can try running the bootloader code, see what happens. I'm adding the code of the bootloader and monitor (BIOS-like programs that were in the ROM of the computer) and add tests that load them. This leads to adjusting some code and fixing some obvious bugs. Dumping the registers state and some
    regions of memory helps with debugging. It's possible to see that something is written into the display buffer: nice the program tries to visualize something. But we need to interact with the program: we need a keyboard.

  • arch: Implement simple 8255 simulator Integration between the CPU is the keyboard is done via a dedicated device: an IO controller. So we need to emulate it too.

  • .github: Add first workflow The code is ont GitHub by this moment. Why not to benefit from the test reports there.

  • devices: Draft keyboard implementation Continue the work on the keyboard. Now we need an emulator for the keyboard behaviour that will integrate with the keyboard controller.

  • Test first keyboard scan program Compose my own program that scans what key is pressed to test is the emulator works according to my expectations. Hope that real programs for Fahivets are similar...

  • Fix IO controller mapping and expectations Debugging the bootloader and looking at my own program I realize that I used the wrong memory range to address the IO controller.

  • devices: Add monochrome display After getting tired of the keyboard story, I wanted some satisfaction. What is better than getting some graphics? So now we can render what is the display buffer into PNG to understand if anything really works. Capture the image and add it to the test to avoid regressions when we run the bootloader code after changing the emulator.

  • cmd/sim: Add web interface We can render and inject keyboard events. Let's try exposing it on a web page via Web Assembly.

  • Start analyzing bootloader code I have problems making the bootloader do something after I inject keyboard events. So digging deeper into its logic. Committing the disassembled code and add some annotations on how I understand it.

  • fahivets: Add RKS reader logic

  • fahivets: Add some test rks files But why to be stuck with the bootloader/monitor? Why not to try loading other programs? Most of the programs for Fahivets that can found on the Internet are in some .rks format. I found how to interpret it om some forums.

  • cmd/sim: Load rain game for a test Now we can get the game running and it kinda works.

  • cmd/sim: Scale the rendered frame The display buffer is just 384x256, so the output image is quite small on a modern monitor. Let's scale it up before rendering.

  • cmd/sim: Use JS animation frames Experiment a bit how to organize routines to run the simulation, capture user input, display the frames.

  • arch: Fix parity bit The rain game had an obvious bug: the drops were falling at the same location. It was pointing to the fact I had some issue with the CPU commands implementation. It turned out to be a problem with how I was calculating the parity bit: somehow I decided to check if the number is even instead of checking how many bits are set in the register.

Now the game is playable. Most likely, I have more problems with the CPU emulation. I'm not confident in my decimal addition implementation and handing the decimal carry flag (A). Other games are not working yet.

But it's such a joy to see the first result and share it with friends... Let's see when I get energy to continue.

Read Entire Article