Thursday, October 1, 2020

Something New

It has been a while since I have written anything here. Between some manufactured antagonism in the CoCo world and the COVID-19 affair in the real world, my capacity for fun has been zapped for months. I do not want to claim to have been "depressed", solely because I do not want to belittle the experiences of those who regularly struggle with such issues. But, I have been feeling the weight of the world for some time.

Starting Something

I have been lamenting that I do not have a current retrocomputing project in progress. Even without a lot of dedicated time, an open project can be an invitation to steal away for a few moments here and there to try some experiment or to implement some new feature or another. But I often find that starting a project from nothing can be an ordeal. Perhaps I am just averse to building a string of unfinished projects? But for whatever reason, I have had trouble getting started on much of anything for some time.

I have a few ideas for CoCo projects -- mostly games. But what type of game? What sort of game mechanics? What graphics resolutions? Do I target the CoCo3? Or is the base CoCo and its various clones good enough? Should I make use of any specific hardware or controllers? Will the game be a demonstration of my skill and prowess as a 6809 programmer? Or just something fun to do? So many questions!!


With my lingering indecision and looming depression, I still have no CoCo project to which I am committed. Still, I feel the need to get something underway. For now, I have decided to start with something simple. Using some older projects for boilerplate code, I will start experimenting. I have a couple of directions to explore and experiments to try. I am hoping that I will at least learn something in the process, and maybe something will spark.

Wish me luck!?!?!


Wednesday, March 6, 2019

RC2019/03 -- All About The Data

My project for RC2019/03 is to write a chip tune player for the Tandy Color Computer (CoCo) that utilizes the SN76489 chip on the Game Master Cartridge (GMC). This is not a tool for creation but a utility for consumption. So, what will it consume?

VGM Files

The VGM file format is capable of representing audio intended for a variety of audio devices, most of which are generally in the category of programmable sound generators. Information about which chips are supported by a given VGM file is encoded in that VGM file. A quick glance at the format specification reveals lots of details about decoding such files. At the very least, supporting VGM files only for the SN76489 will require not only ignoring much of this information, but also knowing which bits of information can be safely ignored. Moreover, part of the information in a VGM file for the SN76489 indicates not only the proper rate for updating register values but also the input clock rate used to calibrate those register values.

Writing a tool merely to simplify a VGM file's data for playback would be worthy of it's own RetroChallenge project! Fortunately for me, someone has already provided a tool which does exactly that -- vgm-convertor is a "Python script for processing SN76489 PSG based VGM files". Along with being able to adjust the SN76489 data not only for different clock input values (including the 4 MHz used by both the BBC Micro and the GMC) but also for several different playback rates (including both 50 and 60 Hz), vgm-convertor is able to output a "raw" data format that is very easy to parse for playback. At least for now, processing VGM files with vgm-convertor will be a requirement for users of this CoCo chiptune player.

Simple Playback

Let's walk through my ROM-based player to get a feel for the overall task at hand. The program starts with some simple housekeeping (e.g. relocating the stack, setting-up interrupts, and clearing the screen), and then it silences the SN76489 tone and noise channels. (These default to being active when the power is applied to the chip, so it makes sense to turn them off.) The program then enables sound output from the cartridge to play through the CoCo. Finally, the program copies part of itself from ROM to RAM. (The copy from ROM to RAM is necessary since the program allows for music data to cross ROM bank boundaries. If the program is executing from ROM when a bank switch occurs, then the program would disappear from the address space and cause a crash.)

This program has to know in advance how many songs are represented in the song data that is part of the program. That number is used to control a loop in which each song is played in sequence. For each song, the title and author information is retrieved from the song data and displayed on the CoCo screen while the song is played. The remaining song data for each song defines the sequence of tone and noise channel settings, which are read from the song data and written to the SN76489 during the timing defined by the horizontal sync interrupt period. The only other notable bit of the program is the bounds checking done after each read of song data. This is used to determine when to switch to the next ROM bank.

This program has been used for a number of small demonstrations of the audio capabilities of the GMC, most notably at CoCoFEST! and on a variety of YouTube videos.


As it stands the software described is sufficient to allow me to download a VGM file, to convert it for use on the GMC, and to build a ROM image that will play the song in question. This works fine for demonstrating the hardware, but it is a bit tedious for chiptune enjoyment. Processing VGM files with vgm-convertor may be a necessity, but building and using ROM images for every song or small group of songs is too awkward for normal use.

Instead I want to write something for the CoCo to load song data from a diskette (or diskette image). The file handling might be done in BASIC, or maybe not. The player will need to be modified to match the file handling and it might benefit from other feature additions (e.g. fast-forward and rewind). If you have any other suggestions, then feel free to offer them in the comments below.

So, still interested in where this is going? If so, then you will definitely need to stay tuned...

Tuesday, March 5, 2019

RC2019/03 -- Getting Started

It's RetroChallenge time once again! In fact, we are already five days into the contest, and I still haven't posted a "start" entry. I reckon it is time to fix that... 

Project Description 

I'm going to work on a Tandy Color Computer (CoCo) project that enables the use of the CoCo's Game Master Cartridge hardware as a means for playing a variety of "chiptunes". That sounds simple enough, but let me break it down a bit further.

I designed the Game Master Cartridge (GMC) hardware _specifically_ to be a platform for distributing games on cartridge. This would seem to solve the "chicken and egg" problem of having a game require an audio hardware upgrade, since that exact upgrade is provided in the same hardware package as the game that uses it. Alas, some in the CoCo community are averse to distributing software on cartridge due to (IMHO exaggerated) concerns about cost (as if there is no cost to an independent "sound card" or no advantage to pairing the hardware with the software on cartridge)...

I have been somewhat reluctant to promote the GMC as a stand-along sound card technology. This has primarily been due to the GMC's reliance on the inherently "slot based" addressing associated with the ^SCS signal on the expansion bus. My opinion is that a properly independent sound card should use a fully decoded address like the Orchestra-90, Speech/Sound Pak, Deluxe RS-232 Pak, and other CoCo add-on cards. Nevertheless, contemporary alternatives for CoCo audio hardware (e.g. CoCoPSG and the MegaMiniMPI) have chosen to rely on ^SCS-based addressing. So, why shouldn't I? What is good for the goose is good for the gander! 

Where Things Stand 

Dozens of GMC cards are already in the hands of the public, having been sold to "developers" either as kits or pre-assembled. Dozens more will soon be made available in the form of "Fahrfall: Master Edition" cartridges that can also be used as a sound card by other software. This project is intended to illustrate how to make use of this hardware on a CoCo and to provide an extra resource that adds value to those cartridges.

Many people will want to make noises with their GMC using the built-in BASIC on the CoCo. Even those using assembly language or some other programming environment will benefit from some simple examples of how to setup the cartridge and how to drive it. In fact, some time ago I made BASIC sources available to that effect. I have also published a video, demonstrating the use of those programs.

Chiptunes that target the SN76489 on the GMC are commonly available. These seem to be concentrated in the Video Game Music (VGM) format, but your mileage may vary. At it's core, VGM represents music as a timed sequence of register value and is relatively simple to handle as input data for a music player. In fact, I have already demonstrated a player which embeds VGM data into a ROM image.

What remains is to implement something with more flexibility, such as the ability to load music files from a diskette. Some concessions to "ease of use" may be appropriate as well.

Want to see where I take this project this month? Well, then I guess you will just have to stay tuned...

Friday, September 7, 2018

ASL/LSL -- more defense of the obvious...

In the previous post, I explained the difference of intent between "logical" and "arithmetic" shift operations in assembly language. I also demonstrated that for two's complement binary numbers, the bitwise effects of logical-shift-left and arithmetic-shift-left are actually identical. This makes the choice to implement a single physical instruction that covers both operations a completely legitimate option, which explains why that choice was made for x86, Z80, MIPS, ARM, SPARC, RCA1802, CP1610, and of course the various Motorola 68xx CPUs.

The previous post would seem to be an unnecessary defense of the obvious truth, except that it was a response to a statement made on a podcast by someone operating in a teaching capacity. Random statements are easy to ignore, but authoritative claims can pollute conversations for long afterward. So, I posted my correction in hopes of clearing the air. Alas, so far all indications are that the errant speaker remains unabashed. Given the situation, perhaps a bit more discussion is in order?

Overflow Example

It is important to consider what happens when values grow beyond the capacity of a single byte to store them. An arithmetic-shift-left is a multiplication by a factor of two, and there are only so many bits in a byte. Let's look at a couple of examples...

First, let's look at a 16-bit value, say the equivalent of decimal 32. The values in the A and B registers are shown below. The states of the Carry and oVerflow flags are unknown at the start of the example, but they will be shown in the indicated places as the example continues below.

          A Reg.   B Reg.   C   V
          ------   ------   -   -
         00000000 00100000  X   X

We will now perform a left-shift operation across the 16-bit value held in the A and B registers. This must be done 8 bits at a time, therefore two instructions are used. Since we are shifting left, we must first shift from B (with the highest bit of B going to the Carry flag) and then rotate into A (with the value of the Carry flag rotated into the lowest bit of A).

ASLB --> 00000000 01000000  0   0
ROLA --> 00000000 01000000  0   0

The value is exactly as expected: instead of 10 zeros, a single 1, and 5 more zeros, we now have 9 zeros, a single 1, and 6 more zeros. The left most bit (i.e. bit 7) in B was a zero, so now the Carry flag is zero. The two's complement sign of B was unchanged, so the oVerflow flag was zero after each of the two instructions.

Let's do another round!

ASLB --> 00000000 10000000  0   1

Here again, the leftmost bit (i.e. bit 7) in B was a zero, so now the Carry flag remains zero. Also, we see that the two's complement sign of B changes, which causes the oVerflow bit to be set. If we were confined to signed, 8-bit numbers then we could check for the V flag here and then branch to some error handling code. But since we are dealing with a 16-bit value we just continue the operation we already started.

ROLA --> 00000000 10000000  0   0

With the Carry flag as zero, the ROLA shifts the bits in A to the left and rotates the zero from Carry into the rightmost bit.

Let's try one more round...

ASLB --> 00000000 00000000  1   1

Now the leftmost bit in B was a one, so the Carry flag becomes a one. The two's complement sign of B changed, so the oVerflow flag is also a one. Again, if we were dealing with an 8-bit number then we could branch to some error handling code at this point. But since we are dealing with a 16-bit value...

ROLA --> 00000001 00000000  0   0

...we continue with the ROLA. This instruction again shifts the bits in A to the left, but in this case a one is rotated from Carry into the rightmost bit.

Hopefully the above demonstrates that while the arithmetic-left-shift may seem to do funny things at first glance when viewed only in terms of an 8-bit number, the truth is that a) the behavior is advantageous when dealing with 16-bit (or larger) numbers; and b) the flags indicate when the 8-bit results become problematic and therefore the flags can be used for handlilng those situations as required. may ask about negative numbers! Let's try another (hopefully less verbose) example. Let's start with the equivalent of decimal - 96:

          A Reg.   B Reg.   C   V
          ------   ------   -   -
         11111111 10100000  X   X
ASLB --> 11111111 01000000  1   1
ROLA --> 11111111 01000000  1   0
ASLB --> 11111111 10000000  0   1
ROLA --> 11111110 10000000  1   0

Unsurprisingly, after two ASLB/ROLA combinations (i.e. two left shifts within a 16-bit value) then the -96 value has become -384 (i.e. "4 time -96"). Also, please note that the oVerflow bit is always clear after the final rotate instruction in these examples. The value of the V bit after the first ASLB instruction is irrelevant for the overall 16-bit value being computed. Obviously this behavior is only guaranteed if proper two's complement encoding is observed across an entire 16-bit value.

Multiplication or Addition

So it seems reasonable to demand that if an arithmetic shift to the left is equivalent to multiplication by two, then the result of such an operation should be the same as the result of adding the starting value to itself:

          A Reg.                      A Reg.
         --------                    --------
         00001000                    00001000
ASLA --> 00010000        ADDA #8 --> 00010000

Another example, this time with a negative value:

          A Reg.                      A Reg.
         --------                    --------
         11000000                    11000000
ASLA --> 10000000    ADDA #(-64) --> 10000000

I'll stop here because to be honest, it is tiresome to continue thinking-up examples that are interesting enough to be worth typing. ASL as implemented on the 6809 "just works". Anyone that still needs convincing is either being dishonest or just plainly doesn't understand two's complement binary math.

That's Enough

As if the first blog post wasn't already too much time wasted on such a stupid controversy, I've now burnt another one. My original hope was that by illustrating the mathematical facts involved, we might avoid spreading misinformation among those in the retrocomputing community that were honestly trying to learn something about assembly language for the 6809. Consequently, the facts have been presented, demonstrated, and even illustrated across two different postings to this blog.

If you want to learn the truth, it's all here for you. Really, there isn't much more to say...keep hope alive!

Tuesday, September 4, 2018

Yes, LSL and ASL really are the same operation...

Recently I was listening to a retrocomputing-themed podcast, as I am often wont to do... This particular podcast has a recurring segment wherein a game developer from the good old days is presenting some relatively simple lessons on programming in assembly language for the Motorola 6809. This particular lesson was about shift and rotate instructions, which are used both for manipulation of data bits within a data byte and for performing the fundamental operations of multiplication and/or division by exact powers of the number 2.

I do not intend to critique the presentation as a whole. But there was one bit of misinformation presented that I feel the need to address. During the talk, the fact was mentioned that when designing the instruction set for the 6809, Motorola had chosen to implement both logical-shift-left (LSL) and arithmetic-shift-left (ASL) with the same physical machine instruction. The assertion was that this was wrong, that LSL and ASL are different operations, and that due to Motorola's failure to recognize such, one should never use that instruction. This assertion being made by one acting in a teaching capacity is so clearly wrong that I feel compelled to clarify the record.

Did the CPU architects at Motorola get it wrong? Spoiler alert: No! Neither did architects for Intel, MIPS, Sparc, ARM, or any of the other CPUs that similarly implement a single instruction for both operations. The fact is that when operating on two's-complement numbers, logical-shift-left and arithmetic-shift-left are, in fact, exactly the same operation.

Signed Binary

This (supposed) controversy is rooted in how negative numbers are represented in digital computers. As you are probably aware, digital computers represent numbers using binary numbers. For positive, whole numbers the mapping to representation in binary is obvious. But there is no obvious extension to binary numbers to account for either fractional or negative numbers. (Fractional numbers are outside this particular conversation...)

Negative numbers can be represented in binary in at least three ways: two's complement (which nearly every digital computer uses), one's complement, and signed magnitude, among others. Two's complement encoding has the advantage that basic operations like addition and subtraction between signed and unsigned values "just work" with the same hardware that is already needed for unsigned operations. Plus, two's complement does not suffer from having multiple ways of encoding the number zero. Consequently, two's complement is the encoding system used by Motorola on the 6809 (and most other designers on most other digital computers up to this day and beyond).

One point to note: although for human communication we usually do not write leading zeros on numbers, most of us are at least vaguely aware of the idea of them. More importantly, computers tend to have fixed-width places to store numbers, like registers or bytes in memory. In those cases, every bit (leading or otherwise) is either a zero or a one. For the discussion below, it is important to realize that positive numbers will start with one or more (i.e. possibly several) leading zeros while negative numbers will start with one or more (i.e. possibly several) leading ones.

Logical vs. Arithmetic

As noted above, shift operations can be used to manipulate isolated bits of information stored within a larger byte. But they can also be used for power-of-2 multiplication and division. The former of those two categories is called logical shifting, while the latter is called arithmetic shifting. The appropriate handling of the leading zeros and ones in two's complement numbers accounts for the differences between the two type of shifting.

In logical shifting, the bits in a byte are shifted left or right as a group like beads on an abacus. Bits farthest in the direction of the shift effectively "fall off" that edge, and they are replaced by zeros entering from the opposite side. This mechanical manipulation of bits can be quite useful when converting small data values embedded in "bit fields" to and from actual register values usable for math operations on the CPU. Nevertheless, careless application of logical shifts could prove quite destructive to a two's complement number where adding a zero at the wrong end could drastically change the meaning of the binary value.

Arithmetic shifting preserves the sign (i.e. positive or negative) aspect of a two's complement number while still transforming its magnitude. Right shifts reduce magnitude (i.e. numbers get closer to zero), while left shifts increase magnitude. So, how is this magic performed?

For a shift to the right, the rightmost bit is dropped leaving the leftmost bit temporarily vacant. For a logical shift, the vacant leftmost bit is filled with a zero -- but this would be wrong for a two's complement number. For example, -128 shifted right would become 64!

10000000 --> _1000000 (left bit vacated) 
         --> 01000000 (filled with zero -- wrong!) 

In order to maintain the sign of the shifted value, an arithmetic shift to the right will replicate the value of the leftmost bit. This yields correct values for both positive and negative two's complement values.

10000000 --> _1000000 (left bit vacated)
         --> 11000000 (filled with one -- correct!)

Notice how continued shifts will increase the number of leading ones as the magnitude of a negative number decreases (i.e. gets closer to zero):

         --> 11100000 (-32)
         --> 11110000 (-16)
         --> 11111000 (-8 )
         --> 11111100 (-4 )
         --> 11111110 (-2 )
         --> 11111111 (-1 )

So we see now that the sign must be preserved while shifting. So what does an arithmetic shift to the left do to preserve the sign? Let's visualize by implementing the above table in reverse:

             11111111 (-1  )
         --> 11111110 (-2  )
         --> 11111100 (-4  )
         --> 11111000 (-8  )
         --> 11110000 (-16 )
         --> 11100000 (-32 )
         --> 11000000 (-64 )
         --> 10000000 (-128)

As you can see, the arithmetic left shift is done by dropping the leftmost bit, shifting every other bit to the left, and filling the vacated bit on the right with a zero. While no action is taken to preserve the sign bit, it is nevertheless maintained at the same value by subsequent leading ones. Positive values are handled the same way, with equally correct results. In either case, the magnitude of the result (i.e. the distance from zero) is increased.

With that explained, please demonstrate for me how an arithmetic left shift on a two's complement binary number differs in any way from a logical left shift. I'll wait...hopefully we now agree that arithmetic left shift and logical left shift are the same operation!

Carry and Overflow

By now, some of you will have had an "a ha!" moment...what happens when a value is such that the leftmost (i.e. sign) bit isn't re-filled properly by the following bit in the left shift? This can happen, but only for values between -65 and -128 -- feel free to do some two's complement encoding exercises to convince yourself of this fact, if necessary. Multiplying those values by two (i.e. the purpose of the arithmetic left shift) would yield values that are too large to fit in a byte anyway. At that point, no amount of maintaining the sign would undo the fact that the resulting value would still be wrong.

So what is done in this case? Well for one thing, the bit that gets dropped off the left of the value is retained in the Carry flag, where it can be retrieved by a following rotate operation. This facility can be used to shift the "lost" bit onto the right side of the next byte in a multi-byte value. This operation is quite common when handling multi-byte values.

The other thing that happens when a "too negative" value (i.e. a negative value with too large a magnitude) is shifted left is that the oVerflow flag is set. By checking the V flag after a left shift, one can determine whether or not the sign of the value is changed by the shift. At that point, the programmer can take whatever action is deemed appropriate either to fail the operation or to correct the apparent error.

Above I have demonstrated that for two's complement binary numbers, the mechanics of a logical left shift and an arithmetic left shift are exactly the same. This is not controversial, and would never have been in question had it not been for some random comments on a podcast. Given that the comments in question amount to misinformation and that said podcast has an audience which significantly overlaps with my own podcast, I felt it necessary to provide a defense of the facts with the demonstration above. Feel free to do your own research, but what I have presented above is absolutely true.

For further reference:

Hopefully that proves the point...Q.E.D.

Monday, February 12, 2018

Z Intepreter Source for CoCo Recovered

In November 2017, The CoCo Crew Podcast interviewed Brian Moriarty. Professor Moriarty (a.k.a. the Professor) was not only an author of several well-known games both at Infocom and elsewhere, but in particular he was the author and maintainer of some of Infocom's Z interpreter software used on a variety of microcomputers. In particular, that includes the Z interpreter software for the Tandy Color Computer. During the interview, the Professor hinted that he might have preserved the source code for that software in some form.

One of our listeners, Carlos Camacho, contacted the Professor in pursuit of that software. This eventually resulted in an email message to the CoCo mailing list indicating that Carlos was in possession of Infocom source code. As of this writing, that sourcecode is now available at the TRS-80 Color Computer Archive website.

(NOTE: What follows should be taken as pursuit of an academic/educational interest and an investigation into a historical aspect of the history of Infocom and the Tandy Color computer. The intellectual property of Infocom belongs to Infocom's legal heirs, and I am not in any way advocating otherwise.)

Preparations to Build

Let's begin by creating a fresh code repository in git and extracting the Infocom source into it:

mkdir coco_infocom
cd coco_infocom/
git init .
unzip ../Infocom\ Adventure\ Games\ Interpreter\ Source\ Code\ \(Infocom\).zip
chmod 644 *
git add *
git commit -m 'Initial commit of pristine CoCo ZIP source from Infocom'

At this point, we are mostly ready to build the code with lwasm or some other assembler. For fun, lets go ahead and try to build the boot track for use with the DOS command:

lwasm -9 -l -f raw -o boot.trk boot.src

That didn't work! Instead we see a bunch of ouput like this:

boot.src(105) : ERROR : Bad opcode
boot.src:00105 ERRM:    DB    $0D

What's going on? Well...unfortunately, many assemblers take some liberties with the naming of pseudo-ops. The assembler used by Infocom does exactly that, and at least lwasm is unsure what to do with a number of those pseudo-ops as they are used in the pristine code from Infocom. In the error shown above, lwasm needs to see ".DB $0D" (or certain other variants) instead of "DB $0D".

Fortunately, some simple transliterations in the source code are sufficient to make lwasm happy. Rather than describe them all here, I have provided a patch that can be applied to your local git tree:

git am lwasm-compat.patch
lwasm -9 -l -f raw -o boot.trk boot.src

You will now see a 597-byte file named boot.trk. The binary data in that file matches what you will find on the boot track of the Infocom diskette images in the Color Computer Archive with the Version C interpreter.

Make Things Easier

Many people do not like typing command lines to use a computer for anything. Even those that don't mind typing a few commands can tire of typing long command lines over and over again. As you can see above, the lwasm command line can be a bit complicated. Serious developers tend to use some sort of build script or a tool like make to control their software builds. To that end, I have provided a patch that adds a Makefile to the repository as well:

git am add-makefile.patch

You will now also see a 5824-byte file named cocozip.img. The binary data in that file matches what you will find on the first several tracks of the Infocom diskette images in the Color Computer Archive with the Version C interpreter.

On to Version D

One of the interestings that I noted in an earlier blog entry is that there are different versions of the Infocom Z interpreter represented among the various Infocom diskette images in the Color Computer Archive. The newly recovered Infocom source matches Version C of the interpreter. But what about the (apparently) later version D?

The ability to build the Version C source and compare the results to the various binaries made a reasonable task out of isolating the differences between the Version C and Version D binaries. I patched the code with the binary differences, then I disassembled those differences to reveal reasonable interpretations of what the original source must have been doing. This was a non-trivial effort, but it is already done! I am making those patches available too:

git am remove-tandy-bit.patch
git am update-to-version-D.patch

Why two different patches? Well, the first patch simply removes the part of the interpreter that sets the "Tandy bit". This little piece of censorship/marketing from Tandy is an interesting historical footnote. Some may choose to apply this single patch but otherwise use the version C interpreter for whatever reason suits them. Others may choose to use version D but otherwise omit that single patch in order to preserve the experience Tandy would have preferred to give them. That change is given its own identity to enable such choices or for further investigation.

The bulk of the version D update is contained in the second patch. With both patches applied, the resulting binaries from the build will match the corresponding bits from those Infocom diskette images in the Color Computer Archive that have the Version D interpreter.

Questions Raised or Answered?

For the record, the Professor seems to have been unaware of the existence of version D of the interpreter. This raises the question of whether version D might have been the work of some lone hacker or whatever. The fact that most of the version D changes seem to be simple features and bug fixes suggests that this is the sort of mundane work that we might expect from a typical software house as it continues to operate its business. That coupled with the several copies of version D in the repository being identical leads me to believe that version D was simply a maintenance update from Infocom.

However, the removal of the "Tandy bit" in version D seems noteworthy. Why would Infocom simply remove this piece of the Z interpreter? Was there some change in the corporate relationship between Infocom and Tandy that made Infocom want to revert this piece of Tandy-specific functionality? Or perhaps that unknown Infocom maintenance programmer was offended by this single bit (literally) of censorship, and simply removed it to soothe his own conscience? We may never know.

Having access to the source for this historic piece of software has been amazing. Interesting code structures and techniques and tantalizing comments abound. Beyond that, I have identified a number of places to make code changes for certain fixes and enhancements, like support for lowercase characters, different text screen dimensions, Drivewire support, etc. I plan to have more patches before long, but CoCoFEST! is'll just have to stay tuned!

Monday, November 20, 2017

Building Infocom Disk Images for CoCo

In the previous posts in this series, I have discussed pairing original Infocom Z interpreter software with new Z code story files in order to enable new interactive fiction games to run on the CoCo. In this post, I intend to tie-up some loose ends and to detail the actual process involved.

Image Issues

The outcome of this whole process will be to build a diskette image. The resulting image can be used as-is in MAME or another emulator, it can be loaded on a real CoCo with a CoCoSDC device or using DriveWire, or it can be used to write an actual physical diskette. Choosing and following the appropriate process for any of the above will be left as an exercise or the reader.

This post will focus on producing what is known as a "JVC" diskette image. In its simplest form, this format is merely a sequential arrangement of sector data arranged sequentially by track, yielding a 161280 byte file representing a single-sided disk with 35 tracks, 18 sectors per track, and 256 bytes per sector. This simple, sequential data layout makes reading and writing specific track data by offset into the disk image very simple.

Filesystem Concerns

The Disk Extended Color BASIC (DECB) code on the CoCo reserves track 17 of the disk for storing the disk's directory. Depending on how a disk is used (i.e. how programs are started), a valid directory may not be required. However, at least some versions of the Infocom Z interpreter rely on being loaded via LOADM and therefore require a valid directory to be present on track 17 of the disk image.

Many CoCo games (including some versions of the Infocom Z interpreter) depend on being started by the DOS command in DECB. The DOS command loads data from track 34 of the disk into a fixed location in memory, checks for a simple signature at the head of that data, and then jumps into the loaded program if the proper signature is found. Care must be taken to preserve the contents of track 34 if use of the DOS command is required to start the game.

Interpreter Differences

I loaded each of the Infocom games from the disk images at the Color Computer Archive. After starting each game, I issued the $VERSION command in order to collect version information from each interpreter. As shown in the table below, at least three interpreter versions were shown to be used by Infocom to package their games for the CoCo!

Result of $VERSION Command by Game
Game Version
CutthroatsCOCO 2 VERSION C
Enchanter, TheCOCO VERSION D
Hitchhiker's Guide to the GalaxyCOCO 2 VERSION C
Lurking Horror, TheCOCO 2 VERSION C
PlanetfallCOCO 2 VERSION C
Sea StalkerVERSION A
SpellbreakerCOCO 2 VERSION C
StationfallCOCO 2 VERSION C
SuspendedVERSION A
WishbringerCOCO 2 VERSION C

Oddly enough, no interpreter found reported anything like "VERSION B". Was a version "B" ever released? What about a version "E" or other later version? Also, if we relate the alphabetical version order to the original release dates of the games above, the release order of the games does not seem to match the version order for the CoCo Z machine interpreters. Were the CoCo versions released in a different order than the original game release order? Or perhaps the diskettes imaged on the Color Computer Archive were purchased in random order over a period of time, while the diskettes sold were sent with whatever version of the CoCo Z machine interpreter was current at the time?

If you have an original Infocom game disk for the CoCo, please boot it up and issue the "$VERSION" command. If you get different results than shown in the table above, then _PLEASE_ let me know in the comments below or however else you may know to reach me!

Given the above, a decision must be made as to which interpreter version to use. The "VERSION A" interpreters are not started via the DOS command, but instead require either the standard "LOADM : EXEC" combo or a BASIC program to do the same. My personal preference for starting via the DOS command and my (baseless?) presumption that higher versions are later and hopefully better (i.e. more features and fewer bugs) causes me to select to use the "COCO VERSION D" interpreter taken from the Ballyhoo disk image.

Command Performance

Starting here, I will presume that you have a "version 3" Z machine story file available called "newgame.z3" and an image of the original Infocom Ballyhoo diskette called "ballyhoo.dsk". So, let's start by using the Toolshed decb command to create a clean disk image called "newgame.dsk":

rm -f newgame.dsk
decb dskini newgame.dsk

Next, copy the Z machine interpreter from Ballyhoo to the new disk image. This is done by copying the first 9216 bytes (i.e. two tracks, eighteen 256-byte sectors each) from one disk image to the other:

dd if=ballyhoo.dsk of=newgame.dsk conv=notrunc bs=1 count=9216

While pillaging the Ballyhoo image, also copy over the boot track code. This is done by copying the contents of track 34 (at byte offset 156672) from one disk image to the other. The size could be as much as an entire track (4608 bytes):

dd if=ballyhoo.dsk of=newgame.dsk conv=notrunc bs=1 \
     count=4608 skip=156672 seek=156672

The final missing piece is the new story file. But there is a problem. While there are now 142848 unused bytes on the new disk image, track 17 (i.e. the directory track) is roughly in the middle of the unused space. So, any story file above a certain size (i.e. exactly 64512 bytes) will need to be written to the disk image in two parts. Given that, two commands are needed to write a large story file:

dd if=newgame.z3 of=newgame.dsk conv=notrunc bs=1 \
     seek=9216 count=64512

dd if=newgame.z3 of=newgame.dsk conv=notrunc bs=1 \
     skip=64512 seek=82944

Mischief Managed

Well, that's about it. The directory track remains empty -- enterprising hacker's could copy the directory track from the original Ballyhoo disk, enabling users to see a LOADM'able BIN file for the game (in case they don't have the DOS command available). Or, the directory track could be modified to show other messages as desired by the hacker. Such directory modifications will also be left as an exercise for the reader.

Beyond that, there remains a moral issue -- technically, doing the project as described amounts to software piracy. While I doubt that any Infocom lawyers will come knocking on your door, those who feel strongly about the issue may have objections to "borrowing" the Infocom code in this way (or at all). You'll have to resolve that issue for yourself, of course. But if nothing else, this is a fun way to consume exising Interactive Fiction on the CoCo!

Writing a new Z machine interpreter from scratch is not an unreasonable task, even for an old machine like the CoCo. Maybe if some people start consuming Inform content as described above, that will encourage someone to write a more modern Z machine interpreter for the CoCo? Then we could all be happy and our consciences could be free. Who is up for the challenge? Let me know! I'll stay tuned...