Plotting Characters to the Commodore 128 80-column (8563) chip.

You can find the below source code at https://github.com/stringsn88keys/unnecessary-computer-things/blob/main/episodes/2021/001/commodore-128/CHASXYCOSINE.BAS and watch here for demonstration of the run time vs. the TRS-80 Model 16 emulator (a computer for which I never realized had a graphics mode when I had access to one). The BASIC and disassembly is also available on page 312 of the Commodore 128: Programmer’s Reference Guide… but beware, the OCR versions translate the “1”s occasionally to lowercase “l”s (which wouldn’t exist in a Commodore program listing unless all lowercase) and the “O”s to “0”s (but inconsistently).

Why is this a post?

If you’re here, you probably wrote some Commodore screen plotting code in which the screen was mappable via POKE commands for the contiguous video RAM (22×23 for VIC-20, 80×25 for Commodore 64/128) or by DRAW commands in graphics mode for the Commodore 128. (Also bitmap POKEable for the Commodore 64, if I recall correctly… haven’t sorted out the VIC-20’s situation yet… that’s another day.)

Well, the 80-column MOS 8563 chip has its own video ram. And given the 16-bit address space (yeah, there are BANKs to switch for the 128), it’s not readily addressable in contiguous address pointer space. Actually, it’s NOT ADDRESSABLE AT ALL by address space. Instead, there’s a convoluted process to write to it. (Thanks to this video for helping me “get it” fully)

The process

  • High memory byte write
    • Store video register number 18 for the 8563 high memory address byte in register X (register X = 18)
    • Store 8563 high memory address in register A (register A = [8563 address] / 256)
    • Write value of X to location $D600 (location 54784 in decimal)
    • Wait until $D600‘s high bit flips (instructions: do a bit test, check for “bit plus” (sign bit is bit 7, so loop if it’s still zero)
    • Write value of A to location $D601 (location 54785 in decimal)
  • Low memory byte write
    • Store video register number 19 for the 8563 low memory address byte in register X (register X = 19)
    • Store 8563 high memory address in register A (register A = [8563 address] AND 255)
    • Write value of X to location $D600
    • Wait until $D600‘s high bit flips
    • Write value of A to location $D601
  • Write the actual content!
    • Store video register number 31 in register X to signal that you want to interact with data in the address set by the last two steps.
    • Store byte you want to write in register A
    • Write value of X to location $D600
    • Wait until $D600‘s high bit flips
    • Write value of A to location $D601

The code

This can probably be done with POKE and PEEK, but this process is tedious enough for machine code. You can assemble it this way:

0180c 8e 00 d6  stx $d600
0180f 2c 00 d6  bit $d600
01812 10 fb     bpl $180f
01814 8d 01 d6  sta $d601
01817 60        rts

Or store it in data and have your basic routine load it into memory. The former is a lot saner for actual entry because you at least get the assembly mnemonics.

Invoking the code

100 addr = (x * 80) + y : rem x = 0 to 79, y = 0 to 24
110 c = 209 : rem the filled disc
120 gosub 11010
9999 end
10000 vo=dec("180c")
11000 rem vo is output routine location, addr address, c character to output
11010 sys vo, addr/256,18
11020 sys vo, addrand255,19
11030 sys vo, c, 31
11040 return

Further Challenges

You’ll notice in the video that the filled disc characters are reversed. That’s because while the characters in video RAM are in $0000$07FF (0-2047), the attributes are in $0800$0FFF. I haven’t confirmed, but I believe there are three different registers to set those as well.


Running a Commodore VICE emulator on a remote Ubuntu Linux machine with Xfvb

The Challenge

I want to have a Commodore 128 VICE emulator start up, run some arbitrary BASIC code, and get a snapshot of the output. There are a few settings configurable from the command line to accomplish this:

  • +sound (without this option you will get and error "pa_simple_new(): Connection refused" because you’re *probably* not going to have a PulseAudio option for your remote linux box)
  • -limitcycles 10000000 (intentionally timeout the machine after 10 million cycles… ~10 seconds)
  • -exitscreenscreenshotvicii – this is just -exitscreenshot for non-128 emulators
  • -keybuf so that you can “type” in your program to the BASIC emulator

Installing and Running VICE

In Ubuntu the VICE package can be installed with sudo apt install vice. You still have a couple of issues: First you have nothing to send your display to. I remedied this with Xfvb (the package is lowercase x, but the executable is uppercase)

sudo apt install vice xfvb 
Xfvb :1 & # if you exit your session, you'll have to kill this off or point to it again
export DISPLAY=:1 # use Xfvb for your "display"

At this point, if you try to run on Ubuntu, you’ll be missing ROMs for the various components (basic and the kernal are two of them). They don’t install with the vice package because they’re not appropriately licensed (understatement) for the Ubuntu distro. If you try to run the emulator without them, you’ll get something like the following:

*** VICE Version 3.4 ***

Welcome to x128, the free portable C128 Emulator.

Current VICE team members:
Marco van den Heuvel, Fabrizio Gennari, Groepaz, Errol Smith, Olaf Seibert,
Marcus Sutton, Kajtar Zsolt, AreaScout, Bas Wassink, Michael C. Martin,
David Hogan.

This is free software with ABSOLUTELY NO WARRANTY.
See the "About VICE" command for more info.

C128MEM: Error - Couldn't load kernal ROM `kernal'.
Error - Machine initialization failed.

Exiting...
Segmentation fault

Getting and installing the ROMs

You can download the ROMs from the release source file on the project page. I used the vice-3.4 source. Download/upload the file to your Ubuntu machine and then untar and copy the rom files from the vice-{version}/data directory to /usb/lib/vice:

tar -zxvf vice-3.4.tar.gz
cd vice-3.4/data
sudo ls **/* | grep  -v '\.' | sudo xargs -I {} cp -Rp --parents {} /usr/lib/vice

Run a test script

The following code should have the emulator draw a circle and then capture to the horribly named haha.png:

x128 -keybuf "10 graphic 1
20 scnclr
30 circle 1,100,100,30
run
" -sound -limitcycles 10000000 -exitscreenshotvicii haha.png

Next Steps

I don’t know… Hook up a lambda? Write a crude server that listens on a COM port? One thing I’m happy about discovering is the -keybuf argument, because I know now that I can inject BASIC (keystrokes to enter BASIC) into an emulator from a source code file without having to worry about the disk or tape image formats.