Now that the hardware for my 65C02 computer is more or less complete, it’s time to start working on the software. I’ve been very interested in the Forth language since discovering it a couple years ago due to its relative simplicity, low size requirements, efficiency, and departure from many conventions seen in other programming languages.
Writing Forth interpreters from scratch has been done many times online, and the implementations don’t seem super complex (at least simple enough for me to figure out how to write my own). The plan is to write an operating system implementing a Forth REPL for my 6502 computer.
Disclaimer: This is my first big project in assembly, and I am by no means an expert. I’d always welcome tips/suggestions from more experienced people along the way!
Setting up a Development Environment
Two of the biggest lessons I’ve learned from programming are:
- Always tackle problems one at a time if you can.
- Never assume your code works perfectly until you’ve thoroughly tested it.
As much as I’d like to think that I’ve wired up my computer perfectly and everything will work great immediately, I have a sneaking suspicion that I’ll discover some errors/problems when I start getting software to run on my new 8-bit machine. As I mentioned in (1), I’d really like to avoid having to simultaneously solve problems in hardware while also dealing with inevitable bugs in software (see (2)).
Instead, I’m going to put my computer to the side for a bit while I develop the software to run on it. I’m instead using Symon, a 6502 simulator that has been thoroughly tested to make sure it works correctly. The default simulator’s memory map allocates addresses
$0000-$7FFF for RAM and
$C000-$FFFF for ROM, which is identical to my build. It also implements a 65C22 VIA and a 65C51 ACIA for serial output just like my computer. I’m pretty sure the memory map for I/O is a little different than mine, but that can be solved later on.
The code for this project is hosted on GitHub at https://github.com/ahl27/FORTH, and I’m initially going to be following the SECND implementation of Forth developed by Paul Dourish for the 65C02, at least until my implementation gets off the ground.
Writing the Interpreter: Memory, Variables, and Initialization
Forth interpreters are small relative to how much work it takes to write an interpreter for most modern languages, but it’s still a nontrivial amount of work to get the system operational. For now, I’m just going to start by allocating my variables and writing some placeholder code for the rest. These first posts will likely involve a lot of code with very little outputs, but that’s part of the process!
All we’re doing here is initializing some variables, then jumping to an initialization routine. Most of these values are based off of the SECND implementation, compiled with
xa <file.asm> -M. I was going to use
vasm as in Ben Eater’s videos, but
xa seems to be easier with better documentation available.
Next, we have to initialize the system.
Nothing crazy is happening here either, we’re just loading in some initial values for the pointers declared in the previous section, then jumping to a test routine. The final section here initializes our initial dictionary of built in words, which currently just has a single word with no associated code. We finish by implementing the
testcode routine, which is also an infinite loop of nothing (for the time being).
This project is far from even being functional, but it’s a good start! The next steps are going to be to implement the critical foundational Forth words
dolit. From there, I’ll probably implement some basic arithmetic words and then start testing to see if the basic underlying code functions properly. Stay tuned!