Saturday, August 1, 2015

Technicalities

If you're porting a program from the Commodore 64 to the 128, there are some gotchas. Some are obvious, while others are more subtle. These are ones I ran into in my attempt to hack DurexForth to run on a C128.

Where Do I Start

The memory maps of the two machines are obviously different. But the C128 is more than different, it's also more complicated.

The C128 has, as the name implies, 128K of RAM. This is tricky, because 64K is all a 6502/8502 can see or address at one time. It gets more tricky because, in addition to two banks of 64K of RAM, you also need some ROM (BASIC, Kernal, characters sets, etc.). And, the 6502 chip interacts with peripherals via memory-mapping, where other chips like video and I/O appear as part of the 6502 memory space. That's a lot of stuff to cram into a virtual 64K area.

The complexity of this is probably beyond the scope of this post, but there's one question that you'd always need to ask - where in memory should I start my own program? On the Commodore 64, that's at hexadecimal 0801 ($0801). On the Commodore 128, it's $1C01. This change is required anywhere that the starting address of the program is specified.

DurexForth makes use of a popular trick where the first few bytes of code are, in fact, a BASIC line with a single SYS call to the real start of the program. So to fix the start point, not only do you need to change where your program starts, but you need to change the text of the SYS command to call the correct new location in memory.

You Can Take That to the Bank

Like the C64, the C128 has some built-in Kernal routines for loading a file from disk into memory. Unlike the C64, the C128 has various banks of RAM. Before you load a file, you need to tell the C128 what bank the filename is located in, and what bank the file should be loaded into. You do this with the SETBNK kernal call. If you don't do it, sometimes your file goes nowhere, or goes into limbo, as happened with me.

Don't POKE Me There

Controlling the RAM/ROM layout of the C128 is done with some memory configuration registers starting at location $FF00. On the Commodore 64, it's done with some manipulation of the ports at $0000 and $0001. DurexForth had some references to the C64 memory control locations, and I needed to take those out, lest anything weird happen.

A More BASIC Problem

The reason DurexForth messed with the C64 memory layout was to bring BASIC back into view sometimes to call routines within the BASIC ROM. That's fine on a C64, but BASIC on the C128 takes up a gigantic chunk of memory space right in the middle of everything. Therefore, rather than try to bring C128 BASIC in for these tasks (e.g., reading a user input line into a RAM buffer), I rewrote the tasks in straight assembler.

Just In Case

Finally, some niceties I had to deal with including setting colors and changing to lowercase mode. This is also done differently on the C128, with just a simple character print, whereas on the C64, it's another POKE.

These are some of my learnings, and as I progress, I'm sure there will be more. This is actually a lot of fun, and is one of the reasons I love retro computers. They are simple, and with effort, you can become highly proficient in just about every aspect of a machine.

That's it for my Retrochallenge-related blogging. However, stay tuned for more entries here, because my work with Forth128 has just begun.

The Journey

My interest in Forth started late last decade. I don't even recall how I encountered it, but once I started to grok how Forth does things, I immediately found it intriguing. Once I'd played with it a bit and did some research on its history, I did an episode of Retrobits on the topic.

I mentioned in an earlier blog post why I decided to try to produce a working, native C128 Forth. The journey to get there was interesting, and sadly kept me sufficiently busy that I didn't have time to document it along the way. Let me correct that oversight while there's still time to get the blog entries in.

There were several choices about how to make a working Forth:

Build It Yourself

If I could sufficiently understand Forth internals, the 6502 (or 8502), and the Commodore 128 peculiarities, then I could write a Forth from scratch. That's a nice idea, but far too aggressive in the time allotted.

Make a Port of FigForth

As mentioned in an earlier post, FigForth was a wildly popular version of the Forth language, ported to many platforms. Virtually all our favorite computers (except, of course, the C128) have a version or derivative of FigForth, including both micros and minis (e.g., the PDP-11). FigForth is designed to be easy to port to other platforms, and is well documented. There's even a generic 6502 version that, with a few changes, can run on almost any 6502-based system.

FigForth has one attribute that I'm not wild about - it uses "indirect threading". To gain a better understanding of this would require quite a bit of reading, so I'll just say that indirect threading adds a layer of abstraction when one Forth "word" calls another. While there are still arguments about direct versus indirect threading, the simpler approach, direct threading, was appealing to me.

Make a Port of DurexForth

Ravelli of DUREX has produced a wonderful version of Forth for the Commodore 64. It's open source, direct-threaded, and quite fast. It has neat libraries of words for various Commodore capabilities, and it's actively updated - in fact, the last updates were only a week ago at the time of this writing.

The idea of making a C128 version of Forth has been with me for a while. I had emailed Ravelli some time ago, inquiring about my porting it to the C128. He graciously provided me with build instructions for producing a working DurexForth from source code. (It's pretty easy, but it does need Linux for the required version of the ACME assembler.)

Of these options, I chose to port DurexForth.

Crankin' Out The Code

While I love DurexForth, I'm not wild about ACME assembler. Hope I haven't insulted any ACME enthusiasts - it's a well known and loved assembler, but it's not my style. Of the options I've reviewed, I like KickAssembler the best.

Bit by bit, I started to port DurexForth code over to KickAssembler syntax, while simultaneously changing anything C64-specific to C128 architecture. As I tweeted a while back, I got the Forth "inner interpreter" - the thing that lets things in Forth call other things - working, and I actually cranked out most of that code on my own without doing a direct copy (pats self on back). However, this was also going too slow, and I wasn't going to make it to the Retrochallenge finish line with a working prototype.

So, I built a Linux box, downloaded ACME, and got a build chain up and running. Then I started hacking away at DurexForth with a machete, doing my best to excise C64 dependencies and replace them with the corresponding C128 idioms. (More on this in a technical post to come.) Naturally, the VICE emulator was a close friend during this process. Warp mode, combined with easy file copying, made it a LOT easier than moving stuff to the real thing for testing. There were a couple of challenges, but in the end, I got an OK prompt (Forth's "Ready"), and was able to type some working commands.

What's Next?

Seeing a working prototype was a real enthusiasm boost. Now I go back to an earlier phase, where I carefully take working concepts from DurexForth, re-implement them with KickAssembler for the C128, and begin to also add C128-specific capabilities. Some of my top goals are full use of the neat VDC video chip, and also 2 MHz mode, which cannot be done in 40 columns.

Next blog post later today will cover some of the technical details I encountered during the process.