Who needs an OS?


The QR Code jam popped up in my feed, and its size restrictions reminded me of boot sector games. Making one seemed like a fun challenge and an excuse to do 8086 assembly! I’m developing from an M1 (aka arm64) mac, but thankfully nasm and QEMU are both available here. As are DOSBox and 86Box, which came in handy for later more thorough testing.

The Mini Jam this time around had as its limitation “only three buttons”. I wanted to do something simple, a puzzle game of sorts, both for ease of implementation and to fit into the 510 usable bytes of a boot sector. At the same time, I didn’t want to do something that had already been done. First thinking of card games, then other sorts of puzzles, I eventually settled on the 5x5 puzzle known as Lights Out — also available as 5x5 in Emacs. Next up: the control scheme. In a recent Mini Jam, somebody did a simultaneous Snake/Pong mash-up: Snong. This inspired me to meet the limitation by replacing the typical cursor in the puzzle game with a Snake. Growth at each toggling ensures that the game grows more difficult as you progress.

With an idea in mind, it was time to get programming. I had recently developed a different absurd Snake clone — Free Range Snake — and its implementation was still fresh in my mind. A couple ring-buffers of coordinates, a start, a length… The ring-buffers are sized to be precisely indexed by a byte, so no instructions are wasted on modular arithmetic. This implementation has one ring buffer for X-coordinates and a second for Ys, and it might be worthwhile to explore the consequences of doing a single buffer for X/Y pairs (as words). In any case, it was quick to code up basic Snake movement and growth.

But then I poked hexdump to see how much space I had left and … oh. Now to be fair, I wasn’t out of space. Just, more than half of it had been used for this movement. So the business and display logic for the actual puzzle had to be even smaller than I had expected. After a first attempt, only six bytes needed to disappear to make everything fit. And fit it did. Ran on QEMU, DOSBox, and even booted on an old laptop I had lying around, but it was behaving oddly there.

Somebody recommended 86Box for testing, and by going through many options, I found that a 386 or better was required to properly run the game. Knowing that somewhere there was an incompatibility lurking, I went to sleep, hoping it would expose its cause in my dreams. It did not. It could not. I settled for uploading the 386+ version.

But the Wikipedia page on x86 instruction encodings was a great help! Looking at the disassembly, I saw that nasm had “helpfully” translated some of my conditional jumps into “near jumps”, which require a 386+. Aha! That’s the culprit for sure! So I swapped the logic and made a little bypass for an unconditional jump, staving off these errors. Well now it works on a 286. Why not the plain 8086?

That comes down to shift instructions. Apparently, you can’t use an immediate count on the 8086. Not bad, just a couple instructions to change. Needed to shave a couple bytes, but thankfully there was some low-hanging fruit on that front. A couple 16-bit loads when 8-bit or from-register loads would work just as well. And finally! It works on the 8086 machines in 86Box. But wait — why so fast? Ah, it appears the WAIT call doesn’t work? No matter, I can use the RTC instead. Done.

Just as I was about to upload the finished version, I happened to notice that the site I was using as BIOS-call documentation — https://www.pcjs.org — actually has emulators. In-browser emulators. I can have a web build! And indeed, loading up the padded-out floppy image and saving the resulting machine, I have a web build.

In all, I’d say this was definitely a good first foray into the joys and pitfalls of 8086.

Get Snakelight!

Download NowName your own price

Leave a comment

Log in with itch.io to leave a comment.