blog dot information dash superhighway dot net

retrocomputing

or, discovering and recovering a lost programming language over the course of a weekend

I go down rabbit holes. One of the great pleasures of this dumb future we live in is that you can dig through the milk crates of our culture forever, following whatever interests you, and there is no bottom. My latest rabbit hole looked something like this:

Wait, hold on a minute. This kind of sounds exactly like the weird idealized programming environment I keep in my head. Obviously with serious restrictions and caveats, but, as a learning tool? They implemented this on an Apple II in 1984? How far exactly did they go?

Read more...

Honeylisp is a programming environment for the Apple II which attempts to leverage the absurd computational horsepower of a modern laptop to make programming a 1mhz 8-bit processor more magical.

Step 1: Write a 6502 assembler

The Honeylisp assembler is written in Fennel, which is a Lisp dialect that compiles to Lua. My goal in writing it was that the input to the assembler would be simple lists, making Fennel into a super-powerful macro assembler basically for free. 6502 assembly is treated as simple data, a kind of embedded DSL that can trivially be generated by simple Fennel functions.

Step 2: Integrate into a text editor

The Honeylisp environment runs on top of lite, a very small and extensible programmer's text editor written in Lua. It's trivial to add new commands that trigger whatever kind of interactive build process I want. It's also straightforward to extend to create custom UI; I put together the bones of a simple tile editor in an evening. I ended up porting lite to the love2d runtime to allow me more flexibility in how I could build these custom editors.

It is also a fairly straightforward matter to add hot code reloading, though it requires a bit of forethought to take full advantage of it. When I put together the tile editor, I could make changes to it, hit Alt-R, and those changes were immediately live. It's cool to be able to use your editor to live-edit your editor.

Step 3: Integrate into an emulator

Back in July, I came across this video of Dagen Brock talking about an Apple IIgs emulator project he was working on that had an interesting property. Instead of integrating a debugger into the emulator, he decided he would implement a socket-based debugging interface that anyone could write a front-end for. Any external program could use this to gain full control of the emulated computer – read and write memory, set registers, set breakpoints, anything.

It turns out this idea kind of languished, and he never quite got to polishing up and releasing his debugger. But this emulator, GSPlus, exists, and it gave me the core idea at the heart of Honeylisp – if I can arbitrarily read and write memory, and I have the ability to augment my assembler, then I can do anything. I can take snapshots and jump back and forth between them, recovering from hard crashes. I can push code updates while the game is running; I just need to be able to specify an appropriate “merge point”. I can map variables from one version of the program to another, so even if data moves around in memory, I can compensate. I can put breakpoints on memory I know should be read-only, to catch wild pointer accesses. I can implement a REPL entirely on the PC side; assemble tiny snippets of code and trigger them. I can integrate with my tools, so making changes to a graphical tile in my editor instantly updates the screen of my emulated Apple II. The possibilities are truly vast.

Step 4: Integrate with hardware

One of the pretty unique features of the Apple II is that it comes with a built-in machine language monitor, complete with a mini assembler and disassembler. It turns out that this can trivially be controlled over a serial port to do things like... write arbitrary memory. So I can plug my laptop directly into a stock Apple II, type IN #1, and then run a single command to bootstrap my environment. In fact writing arbitrary memory in response to serial port commands is not very complicated, and many of the magical abilities I imagine for my environment can be done directly on real hardware.

Step 5: Write a game

There is no point in investing all of this effort into software development tools if you don't plan to develop any software. I intend to port my MS-DOS game Neut Tower to the Apple II using this system. Neut Tower was written using a hand-rolled Forth system; I've built a simple Forth-like stack VM to allow for non-performance-critical code to be written compactly. Because my assembler is so easily extensible, I can also easily use simple Fennel code to generate VM bytecode, which means I can do without a huge amount of the overhead of a full Forth as all of the compiler-y bits live on my laptop. This VM can also be the basis of my interactive REPL, which will be much nicer to write than little assembly snippets.

Step 6: Tell people about it

It's fairly early stages for all of these steps – I have a good start in all of them, but there is still lots of work to be done. I'm really excited about this project, though, and I want to talk about it! Hopefully this blog will be a useful place to do that. I'm looking forward to continuing to share my progress.

#lisp #honeylisp #retrocomputing #apple2 #neuttower

So I should probably have a blog post that I can point to about this whole retrocomputing project that I've been up to the past year and a half.

I wrote a game on an MS-DOS 286 PC, using only tools I built myself or tools that were available during the era where they were still selling 286 PCs. It's called Neut Tower and you can play it on your MS-DOS PC, in DOSBox, or in your browser. As part of this project, I implemented a Forth system, and built most of my game and its tools using it.

My motivation at the start of the project was this: I was enjoying using my 286. I liked the single-tasking workflow; there were no distractions. I was downloading games and apps and it was fun! So I figured I'd take the next step and write a little game or something.

Read more...

Forth is perhaps the tiniest possible useful interactive programming language. It is tiny along a number of dimensions:

  • The amount of code required to implement it
  • The size of the code that is generated
  • The amount of memory used
  • The number of features it considers necessary for useful work

It is a language that makes complexity painful, but which reveals that a surprising amount can be accomplished without introducing any. Forth is the opposite of “bloat”. If you've ever been like “Oh my God this Electron-based chat app is taking up 10% of my CPU at idle, what the HELL is it DOING, modern computing has gone MAD”, Forth is there to tell you that computing went mad decades ago, and that programs could be doing SO MUCH MORE with SO MUCH LESS.

WHAT DO YOU MEAN, “FORTH”

There is an expression about Forth: “If you've seen one Forth, you've seen one Forth.” Forth isn't a strictly-defined language, though there is a standardized dialect; it's more a set of ideas that tend to work well together.

In the past month, I wrote a tiny Forth system on a 286 running MS-DOS using Turbo C++ 1.01. It is my first time using Forth in anger, though I read a lot about it 15 years ago. When I refer to my Forth, I am referring to a system literally thrown together in two weeks, written by someone who does not really know Forth that well. It is slow and wildly nonstandard and it doesn't do very much, but I have enjoyed the process of writing it very much. If you are a grizzled old Forth grognard, please let me know if I have misrepresented anything.

Read more...