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.

Thursday, July 30, 2015

The sweet smell of success

When I started this round's Retrochallenge, I stated my goal like this:

The Goal - have a working Forth kernel that accepts some interactive commands and does stuff, native to the C128. It might not be finished, and it might not be bug-free (almost certainly not) - but it will run.

I'm there.



Retrochallenge has always been about the journey, not the destination. And this journey is just beginning. My hack to get this running (which will be documented this weekend on the blog) isn't pretty, but it does set the stage.

For the first time I'm aware of, there is Forth running natively on a Commodore 128.

More to come!


Saturday, July 11, 2015

Achievements Unlocked

This has been a fun week of Forth! And today was particularly fruitful.

In the quest to make a native Forth interpreter for the Commodore 128, I've been reviewing quite a bit of documentation from a variety of angles:

Understanding Forth Internals

Coming to grips with how a system works is often like peeling back the layers of an onion. You just keep going until you reach the core, and then you can see how the whole thing is built. Forth is very much like an onion - it is a layering of words made of other words, working back towards a Forth core where the atomic pieces of the language are defined for the platform.

The Systems Guide to Fig Forth by C.H. Ting is a wonderful trip down the Forth rabbit hole. In this document, you learn how Fig Forth (a very popular early Forth) is constructed, from the wires on up. Looking at the word definitions has proven quite fruitful for my own comprehension.

DurexForth is an open-source implementation of Forth for the Commodore 64. The C64 isn't all THAT different than a C128, so checking out how DurexForth works has been quite enlightening. DurexForth differs from Fig Forth in an important respect - Fig Forth uses a word structure called indirect threading, while DurexForth uses direct threading.

Direct threading adds less layers of abstraction to the process when one word calls another word. For more information on this, check out another very helpful resource, the "Moving Forth" series of articles by Bradford J. Rodriguez. Part 1 of this series explains how the threading models work, and has diagrams to drive the points home.

Commodore 128 Assembly, Disk Access, and Memory Mapping

In a previous tweet, I'd indicated I had picked my development tool chain for this effort. One of Murphy's Laws of Combat states "No plan survives the first contact intact". Thus, I've already changed the tools I've using. For an editor, I'm going with one of my favorites, Notepad++. There is a Notepad++ add-on for KickAssembler that gives you syntax highlighting and easy invocation of the assembler. It's pretty slick.

The Commodore 128 has a lot of memory. It's just a bit tricky to use it effectively. For the Forth interpreter, I'd like to have BASIC out of the way, but keep other things like the Kernel and the I/O available. You can do this - it's just necessary to set the memory configuration register ($FF00) with the right value - in my case, $0E. Mapping the Commodore 128 and the Commodore 128 Programmer's Reference Guide are good references for how the RAM mapping works.

Also, I figured out how to do disk access from assembly - in particular, I wanted to load a disk file into RAM at a specified location. Doing this requires you to call several Kernel routines in order:

  • SETBNK tells the C128 what bank of RAM you want to load the file into, and which bank of RAM has the filename.
  • SETLFS tells the C128 the logical file number you want to use, the device you want to use (usually #8 for the disk drive) and whether you want to load the file to a user-specified RAM address.
  • SETNAM give the C128 the filename of the file you want to act on.
  • LOAD loads the file into RAM.
For all these Kernal calls, you need to set the 8502 registers (A, X, Y) ahead of time as parameters. Doing all this, I loaded a file into my selected area of RAM, then went into the Commodore 128 Monitor (a helpful utility built into ROM for doing assembly language stuff) to make sure it was there. It was!

Here's the source code for the program I wrote, using KickAssembler syntax:

// This program loads a copy of itself
// into RAM bank 0 at location $3000.

// Set some constants for kernel calls and memory locations

.const PRIMM = $FF7D
.const SETBNK = $FF68
.const SETLFS = $FFBA
.const SETNAM = $FFBD
.const LOAD = $FFD5
.const RAM_CONF = $FF00

// BASIC LOADER
// This section sets up a one-line BASIC program
// in the C128 with the line:
// 10 SYS 7184
// to call the assembly program that starts
// at $1C10 (7184 decimal).

.pc = $1C01 "Basic Loader"
.byte $0C, $1C, $0A, $00, $9E, $20, $37, $31, $38, $34
.byte $00, $00, $00

// ASSEMBLY PROGRAM

.pc = $1C10 "Assembly Program"

// Set memory configuration register for RAM at
// $1C10 to $C000, approximately 41K
// Bit 0, I/O range, = 0
// Bit 1, Lower BASIC ROM, = 1
// Bits 2 and 3, Upper BASIC ROM, = 1 1
// Bits 4 and 5, Other ROM, = 0 0
// Bits 6 and 7, RAM block, = 0 0
// TOTAL BYTE = 00001110 = $0E

lda #$0E
sta RAM_CONF

// Load a file into memory

lda #$00 // Load file to RAM bank 0
tax // File name RAM bank 0
jsr SETBNK
lda #$01 // Logical file number 1
ldx #$08 // Device #8 (disk drive)
ldy #$00 // Use address as specified in LOAD
jsr SETLFS
lda #$09 // Filename length is 9
ldx #<FILENAME // Low byte of filename address
ldy #>FILENAME // High byte of filename address
jsr SETNAM
lda #$00 // Set function to LOAD
ldx #$00 // Load file contents to
ldy #$30 // address $3000
jsr LOAD
bcc DONE
jsr PRIMM
.text "DISK ERROR."
.byte 0

DONE:

// Set memory configuration register
// for normal BASIC operation
// Bit 0, I/O range, = 0
// Bit 1, Lower BASIC ROM, = 0
// Bits 2 and 3, Upper BASIC ROM, = 0 0
// Bits 4 and 5, Other ROM, = 0 0
// Bits 6 and 7, RAM block, = 0 0
// TOTAL BYTE = 00000000 = $00

lda #$00
sta RAM_CONF

rts // Return to BASIC

// DATA

.pc = $2000 "Data area"
FILENAME:
.text "TEST1.PRG"


The VICE emulator has been very handy for all this.

More next time! Go Forth young man...


Wednesday, July 1, 2015

Tools Ready

I like to try new programming tools. It spices things up. So for this Retrochallenge, I'm going with a new (to me) build chain for Commodore 128 assembly.


This is a Java-based IDE that is purpose-built for Commodore assembly language programming. It supports a number of editing features that are very helpful, and also supports the unique syntax of several popular Commodore assemblers.

Assembler: KickAssembler

I've never used KickAssembler before for a personal project, but I've heard it kicks - well, you know. The clear and well layed-out documentation looks like a definite plus.

Emulator: VICE

Really, there isn't much other choice for a Commodore 128 emulator. I am using one of the recent nightly builds of VICE, so I get the cool new features and bug fixes, a couple of which are very important for the 128.

Test of the build chain

Here's my "Hello World" (more like, "A"):

.pc = $2000
lda #$41
jsr $ffd2
rts

Assemble, then from BASIC:

load "test.prg",8,1

searching for dooey.prg
loading
ready.
sys 8192
a
ready.

We are off to the races!

Tuesday, June 16, 2015

Going Forth on the Commodore 128

Forth is available for most vintage computer platforms; however, no native version exists for the Commodore 128.

I'd like to fix that.

It's surprising to me that a computer like the C128, with lots of RAM, 80 columns, and a 2 MHz-capable processor, never had a Forth implementation. It practically screams for one.

It's a few decades late, but better late than never!

Why Forth?


My first computer language was Fortran, and we had to walk five miles uphill, in the snow (punch cards) to program in it. When I first encountered an interactive system - BASIC on the Apple II - it was like the harps played and sunbeams shot down to Earth.

Once the glamour of immediate feedback wore off, I started to find the lack of named subroutines and spaghetti code in BASIC was a bummer compared to the more structured Fortran, and later Pascal. Something of a compromise would have been cool. Too bad I didn't know about Forth back then.

Forth is an odd bird. Backwards things in it you do. Despite it's quirky nature, it strangely both encourages top-down design while facilitating low-level experimentation. Some have complained the resulting code is write-only (hard to decipher), but if you do it right, it's actually pretty intuitive. Modern programming concepts such as loose coupling, tight cohesion of function, and data encapsulation were features of Forth from the beginning.

And it's fast. Much quicker than BASIC, and it often produces more efficient code than a high level language like C.

So, that's why. Now, how?


  • I've read "Starting Forth" by Leo Brodie to refamiliarize myself with Forth and its internals. Having finished, I'm now starting on "Thinking Forth", the sequel.
  • I've begun reading Forth Dimensions, the newsletter of the Forth Interest Group (FIG) from back in the day. This provides some historical perspective, and includes discussion on architectural choices (e.g., threading models). More on that in later posts.
  • Now is also the time to take another stroll through 6502 programming texts, starting with Lance Leventhal's "6502 Assembly Language Programming".
  • The Commodore 128 has a lot of memory - but it's not trivial to use it from assembly language. Understanding how the bank-switching works has been a bit tough, but I think I'm close to getting it. The book "Mapping the Commodore 128" has been invaluable.
  • I'll need to take full advantage of the VDC - the Commodore 128's awesome 80 column video chip. The Commodore 128 Programmer's Guide is a starting point, and there are other Internet sites where you can read more about the VDC and its wonders.

What Next?

The upcoming Retrochallenge 2015/07 is as good an excuse as any to get my posterior in gear. Hence, I'll be turning in my submission and taking a run at it. The Goal - have a working Forth kernel that accepts some interactive commands and does stuff, native to the C128. It might not be finished, and it might not be bug-free (almost certainly not) - but it will run.

Stay Tuned!