Loading

Amiga Hardware Programming using the Forth Language

In one of my earlier posts, I mentioned a passing interest in the Forth programming language as a child. Due to 13 year old me (or whatever age I was) not understanding any of it, I’ve had this lifelong itch I’ve been obsessed with scratching. Forth has always intrigued me, although it has never been relevant enough for me to want to spend any time on it.

Several months ago I began to wonder : for those machines capable of it, would developing in a high level language, instead of assembly, have increased my productivity back in the day – or were those games so much simpler that they didn’t really need it.

For the Amiga, C was for sure used by some developers and I am sure it increased productivity for them. I came back however to thinking about my young experience with Forth. Could I have used this for 8-bits, where C might not have worked out so well as it could have for games. C might not have been viable for this prior to the 16-bit era.

Truth be told, I looked at my old White Lighting Forth package for the ZX Spectrum and had a tinker. I quickly realized that while it might have been a faithful implementation of Forth, it was buggy. Sometimes I would type in legal Forth words and it would balk, even when typing in samples from the manual. I wondered if the delete key not working was a problem with the emulation but I had the same problem on multiple emulators. Worst of all, it would unpredictably crash.

I postponed the idea of testing these thoughts out in an 8-bit development environment and came back to the Amiga. I am fairly certain that for the Amiga, I would have chosen C over Forth. But…

…as I said, I like to tinker. I also like the Amiga hardware. Manipulating it directly in Forth sounded like fun.

Unlike my 8-bit frustrations, I found the experience somewhat pleasant. While I had almost no experience with Forth and the Amiga JForth environment, I found that once I had figured out the @ and ! commands were not writing to the addresses I might expect (unlike my 8-bit Forth, in JForth, they are relative to the program location in memory which makes sense for a multi-tasking OS), I found myself somewhat productive and able to POKE around to setup a display and copper list.

The resulting program looks like this:

Now if you run this program you’ll notice there is some kind of ‘corruption’ on the screen (not in the above screenshots) and this is because for the purposes of filling it in later, I left the DMA enabled for the bitplane and sprite memory, without actually setting this functionality up. This is intentional – I want to come back and fill it in later and I kind of like something that looks like a defect but is 100% explainable – the system and my program is working as I would expect. Not a bad thing to know.

I didn’t use a real Amiga to develop this program, but ran it on A500 and A1200 emulations. I compiled the Forth words and debugged in this environment, although my source was on my PC. The emulator referenced the source through a virtual directory. Pretty good combo – I get a modern text editor.

The bulk of the program is setting up a game like environment – controlling interrupts, DMA and shutting out other programs from their attempts at multitasking. Most of this I developed in Forth, but some in assembly just for ease of lifting 30 year old source code I saw little value in re-writing.

Developing the copper list was really the most involved part of this stunt and I eventually built up a small library that I could see myself upfactoring in the future. Upfactoring…yes I just made a word up there. I ended up with copper list functions to initialize, populate, kick (execute) and list out/debug. The latter I used to make sure my Forth was actually doing what it was supposed to – filling in a copper list of 16-bit words in a 32-bit Forth environment.

The copper list in the demo, first sets the screen to the lower resolution and a 4 bit-plane screen display (despite the fact I did not set up the bit-plane pointers to the screen memory – which again is some of the artifacting at play). I set color 0 to black, wait a few lines and then set it to green. This is nothing other than me making sure I’ve got control over the system. After that I wait a little longer five more times and on each occasion I deploy a copper bar.

After my initial tests I eventually developed a Forth word to deploy the five copper bars. This is how Forth programming is supposed to work – you develop software and create a new word based on your experiments. The you use the word, perhaps replacing prior line by line code. You then create more words that use those words. Forth can be hard to read, but you are supposed to enhance readability by wrapping everything into words. Thus, a program starts off as a chunk of instructions and perhaps might become more readable and maintainable over time.

Of course, my method to develop that copper function was exactly the above. I first made a copper bar manually. I wrapped the words, creating loops and other words as necessary. Then I used the word four times to deploy four coppers bars. Then for kicks, I added some more a parameters enhancing color control and size. I then added the last copper that is a different size to the others.

When I dabbled with the ZX Spectrum Forth package, as much as 13 year old me was disappointed I realized you could only write very basic games with that. It was a great software package, but very restricted. With Forth on the Amiga and direct access to all the hardware, I don’t see why you couldn’t have authored a fully competitive game that was up to date with the times.

Would I have chosen to do that? No. Fact is, Forth is very low-level still but it is not sufficiently high level above enough assembly language to make it worthwhile…for Amiga game programming, for me. Maybe not for you. IMHO 68000 assembly is very readable and it’s just as easy to manipulate the bits of the Amiga hardware programming in one or two instructions than it is with Forth dictionary words and a stack. Sometimes easier actually. Don’t get me wrong, I love the idea of making words and making an even more readable, but if I don’t feel I _need_ that for 68000 bit twiddling work.

There are other considerations too. I disassembled some of the Forth words. While they were not inefficient for what they were doing, the constant references to the stack made for extra instructions that would simply not even be considered in assembly language. I was surprised how much adding 2 to the number at the top of the stack blew up in comparison to the 68000 equivalent. I even thought using “2+” instead of “2 +” might generate a more direct manipulation of the stack top, but no. Even a C disassembly would prove out more optimal than this. Shame…but you have to remember the original Amiga was 7.14mhz. It seemed fast at the time and I never had an issue with the games I authored, but if the way of programming in Forth is to create words from other words, there is an awful lot of overhead from word to word. One or two lines of assembly becomes three or four times more. Such overhead is a big deal to a game on that kind of hardware and could easily see you throwing away the power of the machine and making it run more like an 8-bit game. It was all about instruction counts after all.

Thus, for Amiga game development…the language of choice I think was correct with 68000 but I concede, had I been a C developer at that time in my career I think I would’ve likely made more games in the time I had AND been financially better off for the extra productivity.

Forth sure is fun though. I do wonder if I had succeeded in learning Forth at an early age, whether it might have been a great distraction in my Amiga years. I actually think there’s pretty good case for mixing Assembly and Forth. Assembly alone, or C and Assembly would still win.

Oh…I put the source here and I may follow up with the Forth to initialize bitplanes and sprites too.