Zolatron 64: Writing an OS for a 6502 homebrew computer

I’ve said it before and I’ll say it again: I have no idea how you write an operating system. Even though I’ve sort-of written one. I’m calling it ZolOS.

The Zolatron 64 6502 homebrew computer project started as idle curiosity that just got out of hand. I figured I’d be happy if I could get as far as writing ‘Hello world’ to an LCD display. But things then snowballed.

All of my early code was what you might describe as improvisational and expedient. I’d manage to get the computer to do one thing and then thought, hmm, I wonder if it can also do this. In other words, there was no planning and no structure.

And yet it’s amazing what you can achieve just by bumbling along. Interestingly, Version 1.0 of the code was the first version that did anything even the slightest bit useful. With Version 3.1, things really started to take off. And that was the exact same story with Windows, except it took Microsoft years to go from 1.0 to 3.1, and I did it in just a few months. 😉

I’ve written before about how I’m using vectors (on memory page 2) to provide hooks allowing user programs in RAM to invoke OS commands in the ROM. I now have about 42 of these. Because I’ve given over all of page 2 to these vectors, and each is two bytes, I have room for 128, which should be enough.

[UPDATE: I’ve now started putting together proper documentation for this project. You can see the list of OS system calls here.]

Having so many ready-made functions really speeds along app development.

In command

[Click for a larger version]

Meanwhile, on the command line, I’ve added to the number of commands I can type in.

Here’s what currently works (the ones in parentheses are in development):

  • ? <addr> : A simple PEEK command. It shows the contents of the memory address provided. (See PEEK below).
  • ! <addr> <hexbyte> : A POKE command. It sets the value of the address provided.
  • BRK : Does a soft break, resetting some registers and values (like input and output buffer indexes).
  • CLEAR : Clears the current user program from memory. Actually, all it does is write zeroes into the first 16 bytes of RAM at the start of user memory ($0800). I’m using header data in my programs – something I plan to write about soon – and this erases that metadata so that any check for an existing program will come up empty.
  • DEL <filename> : Deletes the file from the filesystem (without further prompting or warning). Requires the full filename, including extension.
  • DUMP <start_addr> <end_addr> <filename> : Saves the contents of memory from start address to end address. The filename should not have an extension (.BIN is added automatically).
  • HELP : Prints out a list of these commands, with no further helpful information!
  • JMP <addr> : Does what it says on the tin – jumps to the given address and starts execution from there.
  • LM <start_addr> <end_addr> : Does an on-screen hex dump from start address to end address. With LP (below) this has proven to be an invaluable debugging tool.
  • LOAD <filename> : Loads an executable (program) file to RAM, starting at USR_START ($0800). No extension is needed (.EXE is assumed).
  • LP <page> : Does an on-screen hex dump for a single page (256 bytes) of memory. You enter the upper byte of the address, so LP 08 displays the 256 bytes starting at $0800. This is even more useful than LM because it’s so quick to use.
  • LS : List storage. Lists the files on the filesystem.
  • (MV <curr_name> <new_name>) : In progress. Equivalent to Unix’s mv command – ie, renames a file. I’m still debating whether to call this REN.
  • PEEK <addr> : Currently a synonym for ?, but I’m thinking of making this operate slightly differently – ie, after displaying the first value, it will increment the address and display its value each time you hit <return>.
  • POKE <addr> <byte> : A synonym for !.
  • (PRT <filename>) : Work in progress. It’ll print a text file to my dot matrix printer … or something.
  • RUN : Execute the program currently loaded into user memory.
  • SAVE <filename> : Save the contents of RAM from USR_START ($0800) to LOMEM (the first byte after the currently loaded program). In other words, it saves a copy of the current user program. Not sure why, but that’s what it does.
  • Typing the command XLS shows what’s loaded into the 16 banks. The version of Zumpus in bank 3 is a ROM.

    STAT : Prints some handy stats about registers & whatnot.

  • VERS : Prints the version number of the OS. This was the first command I implemented and I never use it.
  • XCLR <bank> : Clear the contents of the designated extended memory bank. Like CLEAR above, it actually just zeroes out the first 16 bytes, erasing the file metadata.
  • XLOAD <filename> : Load an executable file into the currently selected extended memory bank. No filename extension is needed (.EXE is assumed).
  • XLS : List the contents of the extended memory banks.
  • XOPEN <filename> : Opens a data file and loads its contents into the currently selected extended memory bank. No filename extension is needed (.DAT is assumed).
  • XRUN : Executives the code in the currently selected extended memory bank.
  • XSEL <bank> : Selects an extended memory bank (0-15) as the currently active bank.

With that lot, I have a surprisingly usable computer. All I need to do now is write some software that actually does something.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.