Saturday, January 14, 2023

Software Sprite

As often discussed, the Motorola 6847 VDG offers little in terms of assistance for game programmers or other software authors. While many contemporary video chips offered assistance in scrolling backgrounds or in moving objects in the foreground of a display, the 6847 hardware merely provides access to a static framebuffer. As we have seen prviously, anything beyond a still image requires work from the CPU. Fortunately for CoCo people, the Motorola 6809 CPU is reasonably capable, and when used properly it can provide at least some of these video effects.

 

Get Things Moving

Of course  the only way to start is to draw something in the framebuffer memory by using the CPU's usual load and store instructions to copy data out of program storage and into the framebuffer. To create the illusion of motion this must be done rapidly and repeatedly. If care is not taken between draws to remove the previous image then "movement" will create a trail across the screen, corrupting the background image. Various methods exist for doing that cleanup (e.g. saving and restoring the background as part of the sprite draw operation), but this takes both program development time and execution time. The latter in particular is at a premium when so much data is already being moved for the background.

Mask Mandate 

In the 6847's RG3 (4 color, 2 bit per pixel) graphics mode, each byte of buffer memory represents 4 pixels. Since memory writes happen one byte at a time, any image that uses less than 4 pixels in each byte it occupies will interfere with those extra pixels unless care is taken. This is typically observable as the movable object appearing a bit like a postage stamp laid on top of the display.  Unless the object being displayed is rectangular with a pixel width that is a multiple of 4 pixels, then part of the draw operation must include masking. This involves reading the background, using a bitwise mask of the object to combine the object's pixels with the background pixels then writing the resulting data. This operation performs the trimming necessary to preserve the background. There is some execution time lost for the masking, and storing the mask data doubles the amount of memory necessary for storing the graphics objects. But there really is no way around this part.

No Background Check

With the scrolling background demonstration as a base, we can now show a foreground item on top. Since both the foreground item and the background image move in relation to each other, this is not a single draw (or mask and draw) operation. With a normal static framebuffer, displaying a moving foreground itme would require some action to restore any background bits eclipsed by the foreground when the foreground moves. This might require regenerating the background algorithmically or saving the background before drawing the foreground and restoring the background after the foreground is moved. If we draw the foreground item in our source or "render" buffer, then all of the above would be true. But by drawing the foreground item directly in the current "display" buffer, we know that the background will be copied from the render buffer to the next display buffer at the next buffer switch. Since the background is already being redrawn for every frame, we don't need to maintain the background at all, saving all that time that would have been used for maintaining the background image!

So while redrawing the entire background initially seems expensive, that operation turns out to be cheaper than tracking damage to the background image and redrawing the background over and over again. It took me a while to wrap my head around this feature, but hopefully the explanation above makes things clear for you? I hope so.

Hopefully I can keep finding time to turn this discussion into an actual CoCo game. If you want to see where this all goes, then be sure to stay tuned!

Tuesday, January 10, 2023

Scrolling Engine

Well, it's been a while!  Despite the boredom and isolation that came along with the COVID years, I didn't do much that was very impressive in terms of retro programming during that time. In a cruel twist of fate, the boredom (and an ongoing spat with another CoCo media figure) seems to have robbed me of inspiration during that time.  Despite that, I did manage to produce a little technology demo to demonstrate scrolling a full graphical background on a CoCo. Some have asked for more information on how this was done. If that interests you, then please continue reading!


So Much Work

Scrolling a background image with the 6847 VDG is not by itself a huge technical problem. All that is required is to move a lot of data from where it starts to a new location. For a CG3 (128x96) screen that means 3 KB or 3072 bytes of data moved for each frame of video. Many video chips roughly contemporary with the 6847 provided hardware support that allow (usually at the expense of some memory usage) for the illusion of movement by changing the source of the video data between frames. The SAM/VDG combination used in the CoCo offers a rudimentary version of this, but the frame-to-frame jumps would be too coarse and the memory demands too great to be useful by itself for smooth animation.

So Little Time

With no useful hardware support available, brute force must be used to copy bytes around in the video buffer. Computers are fast, but not infinitely fast. How much time do we have? And how long does it the 6809 take to copy 3072 bytes? The VDG generates just under 60 video frames per second. With the normal 0.89 MHz clock speed of the CoCo, that leaves us less than 15000 clocks to move the data for each frame. Unless the CPU can move one byte in five clock cycles (which it cannot), then there is just not enough time.  Even at just 30 frames per second, we still wouldn't be very close.

Switch Things Up

The 6847 generates video output at just under 60 frames per second, and the SAM/VDG combination used in the CoCo does offer a "screen flip" capability. Combining those two details allows us to "double buffer", or to draw in one buffer while the other is used as the display source and then to switch between the buffers. Using two buffers effectively halves our video frame rate but doubles the amount of time available for video data movement and gets us back to a manageable 30 frame updates per second.

Blast Away

One unique feature of the 6809 CPU architecture is the User stack. This provides an efficient means for moving data, particularly when combined with the System stack and used for what is colloquially known as "stack blasting". This feature allows for moving up to 8 bytes at a time in as little as 26 cycles for just two instructions. This would potentially allow us to move a frame's worth of data in roughtly 10000 cycles (depending on the actual code implementation). My implementation depends on some looping and is not quite that efficient. But it does suffice to keep the video update well within the 30 frame per second limit while leaving a generous amount of time available for doing something else (e.g. handling I/O or implementing game logic).

Single Source

The two buffers mentioned above are merely tools for keeping the display looking correct and up-to-date. But both buffers are completely ephemeral. A third buffer is kept for rendering the actual video frame. This buffer is the source for the stack blast copies described above. since both of those buffers will be overdrawn almost immediately, any "permanent" change to the display needs to be done in this "render" buffer. Consequently this is the perfect place to draw any static background items (e.g. anything to be scrolled).

I think that mostly covers it. I originally implemented this back in the Summer of 2020, so hopefully I am not overlooking any big details. But I believe the main points are covered. This technique gets the job done, and it has a few advantages that I hope to exploit in the near future...stay tuned!

Thursday, January 30, 2020

Space Assault Port to 6800

Now, on to the bigger project I've been hinting at... :-)



So...Space Assault is a clone of the well known arcade hit Space Invaders, produced for the Tandy Color Computer by The Image Producers, (written by Lou Haehn?) and released in 1981. Some time ago, Darren Atkinson took it upon himself to disassemble the Space Assault ROM image for the CoCo and to do a binary translation of the 6809 code into a version for the 6803-based Tandy MC-10. The MC-10 version plays very much like the CoCo version, with modifications from Darren to accommodate use of the MC-10 keyboard in place of the CoCo joystick.

It occurred to me that this bit of MC-10 magic might be a good candidate for porting to my Micro Chroma 68 (uchroma68), so I sent Darren an email requesting access to his MC-10 Space Assault source. Darren was nice enough to oblige, so I immediately checked his source into a git repository and set about to making the initial superficial changes necessary to reproduce his MC-10 Space Assault binary using my chosen assembler, the old Motorola Freeware BBS assembler.

6803 > 6808

Working MC-10 code seems like a good place to start for a uchroma68 port, but some more preparation work is still required. The problem is that not all code that runs on the 6803 CPU in the MC-10 will also run on the 6808 CPU in the uchroma68. The 6808 (and the related 6802) execute the same instruction set as the earlier 6800, without any additions. But the 6803 (and the related 6801) use a somewhat improved architecture that supports a number of instructions that are not supported by their 6800/6802/6808 cousins. Not only are these extra instructions quite useful, they also make the 6803 a bit more like the 6809 architecturally. It is no surprise to learn that Darren used a number of these new instructions when porting Space Assault from the 6809 to the MC-10's 6803. Porting the MC-10 version of Space Assault to run on the uchroma68's 6808 will involve replacing these 6801/6803 instructions with 6800/6802/6808-compatible sequences.

Macro-like Translations


Several of the new 6801/6803 instructions involve an architectural change that allows the 8-bit A and B accumulators to be grouped together as the 16-bit D accumulator. Instructions like "LDD" and "STD" are easily replaced with "LDAA/LDAB" and "STAA/STAB" combinations, just as "ADDD" is easily replaced with an "ADDB/ADCA" combination. Using a macro processor (either built-in to an assembler or something external like m4) should make these substitutions trivial, requiring no changes to the source code at all. But as I am using the quite primitive assembler from Motorola, I simply made these changes directly in the source code -- the triviality made this more worthwhile than introducing an m4 pass in the Makefile.

Emulation Functions

Some of the other new 6801/6803 instructions are not so easily replaced. Equivalent instruction sequences are lengthy, and require allocation of memory for temporary storage of registers used in those sequences. Instructions such as "PSHX", "PULX", and "ABX" are in this category, and they are so useful that again it is no surprise that Darren makes hearty use of them in his MC-10 port of Space Assault. In this effort, I found that replacing these instructions with equivalent subroutine calls provided good results while only requiring six bytes for temporary storage of the D, X, and S registers and a few bytes for a temporary stack. (The S register storage and the temporary stack were required to avoid data corruption in a couple of places where an emulated "ABX" was required within a routine that was using S as a pointer for data movement.)

EMUSAVS    rmb       2            ; temp storage of S for 6801/6803 emu
EMUSAVX    rmb       2            ; temp storage of X for 6801/6803 emu
EMUSAVD    rmb       2            ; temp storage of D for 6801/6803 emu

EMUSTACK   rmb       3            ; temp stack for 6801/6803 emu calls
EMUSTKTOP rmb       1

emu_abx
          pshb
          psha
          stx        EMUSAVX
          clra
          addb     EMUSAVX+1
          adca     EMUSAVX
          staa      EMUSAVX
          stab      EMUSAVX+1
          ldx        EMUSAVX
          pula
          pulb
          rts

emu_pshx
          stx        EMUSAVX             ; save X
          tsx
          staa      EMUSAVD             ; save A & B
          stab      EMUSAVD+1
          ldaa      ,x                  ; get return address from stack
          ldab      1,x
          pshb                          ; push return address onto stack
          psha                          ; - also adjusts stack pointer
          ldaa      EMUSAVX             ; retrieve X value
          ldab      EMUSAVX+1
          staa      ,x                  ; save X value onto stack
          stab      1,x
          ldaa      EMUSAVD             ; restore A & B
          ldab      EMUSAVD+1
          ldx        EMUSAVX             ; restore X value
          rts

emu_pulx
          tsx
          staa      EMUSAVD             ; save A & B
          stab      EMUSAVD+1
          ldab      3,x                 ; get X from stack
          ldaa      2,x
          staa      EMUSAVX             ; save X
          stab      EMUSAVX+1
          pula                          ; get return address from stack
          pulb                          ; - also adjusts stack pointer
          stab      3,x                 ; save return address onto stack
          staa      2,x
          ldaa      EMUSAVD             ; restore A & B
          ldab      EMUSAVD+1
          ldx        EMUSAVX             ; set new X value
          rts

Simple Rewrite

Perhaps the most complicated new 6801/6803 instruction is "MUL", which of course multiplies the 8-bit accumulators A and B to produce a 16-bit product in the D accumulator. I anticipated coding a lengthy routine to emulate this instruction, but I found that the code was only doing a multiply by a fixed value of 5! Two left shifts and a single add produced equivalent results, so "MUL" was no longer an issue... :-)

More To Come

I think that covers the remaining "prep" work for the uchroma68 port of Space Assault. At this point, I have code for a machine that does not exist: an MC-10 with a 6800 CPU. The result, of course, will run on a normal MC-10 -- but that would be a pointless objective. I would show a demo video here, but the result is virtually indistinguishable from Darren's original code. Hopefully you can just trust me -- it works. ;-)

The next step will be accounting for differences between the board-level architectures of the MC-10 and the uchroma68. This involves differing locations for video memory, and for where the code and data are loaded and stored. It also involves accounting for I/O differences, such as reading inputs from the keyboard and possibly making sounds. It will all be very much "in the weeds", of course...stay tuned!


Monday, January 27, 2020

Micro Chroma 68 Tape Storage

In my previous post, I showed video of me loading and running code on an emulated Micro Chroma 68 (aka uchroma68) machine, and hinted at a bigger project. I intended to be back sooner to describe the code loading process and then move-on to the bigger project. But, I got started on the bigger project and neglected the next blog update -- time to get back on track!

Audio-Encoded Data

Code can be loaded onto the uchroma68 in a variety of ways, including from the keyboard input or over an audio-encoded interface intended for using "compact cassettes" for mass storage. For real hardware, other options include modifications to use an ACIA for serial input or modern interfaces to drive the keyboard interface from a remote computer. But since our objective includes targeting the unmodified MAME-emulated uchroma68, it seems best to pursue only standard options for loading code.

So, how to convert object coded into appropriate audio?

Kansas City Standard

The Kansas City standard (KCS), or Byte standard, is a way of storing digital data on standard Compact Audio Cassettes at data rates of 300 to 2400 bits per second (at 300–2400 baud) that was first defined in 1976. It originated in a symposium sponsored by Byte magazine in November 1975 in Kansas City, Missouri to develop a standard for storage of digital microcomputer data on inexpensive consumer quality cassettes.
The uchroma68 uses the Kansas City Standard for audio data encoding. This old standard defined how to transfer bits and bytes as audio, suitable for storage on consumer audio tape. Fortunately for me, open source tools (e.g. py-kcs) already exist for encoding and decoding such audio. Unfortunately, some of those tools presume to deal only with ASCII-encoded test files (e.g. BASIC programs). Since I needed to deal with binary data, I did have to write a patch to allow for handling binary input to the KCS encoder:
 diff --git a/kcs_encode.py b/kcs_encode.py
index 21bbf080917d..1f078dd0b537 100755
--- a/kcs_encode.py
+++ b/kcs_encode.py
@@ -52,7 +52,7 @@ def kcs_encode_byte(byteval):

 # Write a WAV file with encoded data. leader and trailer specify the
 # number of seconds of carrier signal to encode before and after the data
-def kcs_write_wav(filename,data,leader,trailer):
+def kcs_write_wav(filename,data,leader,trailer,binary):
     w = wave.open(filename,"wb")
     w.setnchannels(1)
     w.setsampwidth(1)
@@ -64,7 +64,7 @@ def kcs_write_wav(filename,data,leader,trailer):
     # Encode the actual data
     for byteval in data:
         w.writeframes(kcs_encode_byte(byteval))
-        if byteval == 0x0d:
+        if not binary and byteval == 0x0d:
             # If CR, emit a short pause (10 NULL bytes)
             w.writeframes(null_pulse)
   
@@ -74,16 +74,29 @@ def kcs_write_wav(filename,data,leader,trailer):

 if __name__ == '__main__':
     import sys
-    if len(sys.argv) != 3:
-        print("Usage : %s infile outfile" % sys.argv[0],file=sys.stderr)
+    import optparse
+
+    p = optparse.OptionParser()
+    p.add_option("-b",action="store_true",dest="binary")
+    p.add_option("--binary",action="store_true",dest="binary")
+    p.set_defaults(binary=False)
+
+    opts, args = p.parse_args()
+    if len(args) != 2:
+        print("Usage : %s [-b] infile outfile" % sys.argv[0],file=sys.stderr)
         raise SystemExit(1)

-    in_filename = sys.argv[1]
-    out_filename = sys.argv[2]
-    data = open(in_filename,"U").read()
-    data = data.replace('\n','\r\n')         # Fix line endings
-    rawdata = bytearray(data.encode('latin-1'))
-    kcs_write_wav(out_filename,rawdata,5,5)
+    in_filename = args[0]
+    out_filename = args[1]
+    if opts.binary:
+        data = open(in_filename, 'rb').read()
+        rawdata = bytearray(data)
+    else:
+        data = open(in_filename, 'r', newline=None).read()
+        data = data.replace('\n','\r\n')         # Fix line endings
+        rawdata = bytearray(data.encode('latin-1'))
+
+    kcs_write_wav(out_filename,rawdata,5,5,opts.binary)
With that, I could encode audio data for the uchroma68 by using the '-b' option which I added to kcs_encode.py. But what about the logical format of that data?

JBUG-Compatible Format

Knowing how to send 0's and 1's is not too helpful until one knows what 0's and 1's to send. Even a program binary still needs to be accompanied by information such as where to write the program in memory and perhaps protocol data used to manage the transfer. The TVBUG firmware on the uchroma68 uses a format for binary data that is compatible with the format used by the JBUG firmware from the MEK6800D2 board which had preceded it, although TVBUG allows for an extension to the format that provides for the program name to be encoded along with the program data. Based on information from the TVBUG and JBUG manuals and some reading of the assembly language listings of those programs, I was able to write a script that converts a binary program file into a hex dump representing the data prepared for audio encoding:
#!/bin/sh

###########################################################
# Convert a binary to hexdump of JBUG logical tape format
#       (used by both JBUG and TVBUG)
###########################################################

usage() {
        cat <<USAGE
usage: $(basename $0) [-l <loadaddr>] [-n <progname>] [-p] <filename>

        -l <loadaddr>   base load address
        -n <progname>   output program name
        -p              pad tape output with 0xff characters
        <filename>      input data file
USAGE
}

while getopts ":l:n:p" opt
do
        case ${opt} in
        l)
                LOADADDR=$OPTARG
                ;;
        n)
                PROGNAME=$OPTARG
                ;;
        p)
                PADOUT=1
                ;;
        \?)
                echo "Invalid option: $OPTARG" 1>&2
                ;;
        :)
                echo "Invalid option: $OPTARG requires an argument" 1>&2
                ;;
        esac
done
shift $((OPTIND-1))

# Set default load address of zero (if not specified on command-line)
LOADADDR=${LOADADDR:-0}

if [ $# -ne 1 ]
then
        usage
        exit 1
fi

INFILE=$1
INSIZE=$(stat -c %s $INFILE)

if [ x$PADOUT = x1 ]
then
        for i in $(seq 1 1024)
        do
                echo -n 'ff'
        done
        echo
fi

if [ -n "$PROGNAME" ]
then
        echo -n $PROGNAME | xxd -p
        echo '0d'
fi

OUTSIZE=0
while [ $OUTSIZE -lt $INSIZE ]
do
        BLOCKSIZE=$(($INSIZE - $OUTSIZE))
        if [ $BLOCKSIZE -gt 256 ]
        then
                BLOCKSIZE=256
        fi

        echo -n 'ff'
        echo -n '42'
        printf '%x' $(($BLOCKSIZE - 1))
        printf '%04x' $(($LOADADDR + $OUTSIZE))

        xxd -p -g 1 -l $BLOCKSIZE -s $OUTSIZE $INFILE

        OUTSIZE=$(($OUTSIZE + $BLOCKSIZE))
done

if [ x$PADOUT = x1 ]
then
        for i in $(seq 1 144)
        do
                echo -n 'ff'
        done
fi

echo -n 'ff'
echo '47'
The hex dump output can be fed to the xxd utility (e.g. 'xxd -p -r'), captured, and then encoded to Kansas City Standard format audio.

Demo

In my earlier post, I mentioned "a text-based animation that I originally ported from a VZ-200 C program to assembly language for the MC-10 which I had always suspected would be easy to get on the uchroma68". Well, I was right -- changing two "equ" statements (one for the load address and one for the screen address) was all that was required...


But wait -- there's more! The bigger project involves more porting from the MC-10 to the Micro Chroma 68, this time porting some code that originated on the Tandy Color Computer before being ported by Darren Atkinson.

Intrigued? Then stay tuned...

Tuesday, December 31, 2019

Micro Chroma 68 Revisited

About six years ago, on this blog I documented the build of an original Motorola Micro Chroma 68 (aka "uchroma68") kit. The "kit" was intended as an evaluation platform for the 6847 VDG and consisted of a PCB and the major ICs like the 6808 CPU, 6847 VDG, etc. (I had to acquire the various other bits, mosty passive components.) I enjoyed the build process and even hoped to target the machine for some retro games development. Nevertheless, the overall lack of available hardware made this platform seem too niche to be a priority for development. After I wrote a simple program to demonstrate the machine working, I essentially set aside the uhroma68 and largely ignored it.

Virtual Reality

Of course, I never forgot about the uchroma68. Recently in my Internet wanderings, I came across the news that MAME had added uchroma68 support:


This bit of news was exciting enough to inspire me to install the proper ROM images and update my MAME installation in order to try out the emulation. Having done so, I decided to pursue how to get my old example program running on the emulator:


Whet Your Appetite

Getting this far was fun and not without some challenges. I'll save those details for the next post! Plus, I have a text-based animation that I originally ported from a VZ-200 C program to assembly language for the MC-10 which I had always suspected would be easy to get on the uchroma68. That might provide a better taste of the uchroma68 platform and how it is similar to the MC-10.

Beyond that, I have another porting project in the works that involves a headstart provided by a very clever partner. I think you will enjoy that one, and it might bring us the best game to come to the uchroma68 so far. Intrigued? Well...stay tuned!

Saturday, January 30, 2016

RC2016/01 Wrap-Up

Here we are at the end of RC2016/01, and what have we got? Well in my case I have a port of Xmas Rush for the TRS-80 MC-10 -- very exciting stuff! At the end of my last post on the topic, there was still some timer stuff to handle and some "odds and ends". So, let's see how that went...


Pause To Experiment

Early on I had thought that precision timing might not really be necessary, that perhaps the video glitches would be spread so thin that it would hardly be noticeable. Later, someone else made a similar suggestion. So I conducted an experiment that changed the game's time base to just a bit more than the time required for a single frame of video. This did have the predicted effect of spreading the video glitches around so as to make them less objectionable, but they were still both noticeable and constantly recurring. While I did not pursue any algorithmic changes to the drawing routines that might have made this even less objectionable, the experiment cemented my belief that stable timing synchronized with the video hardware remained a worthwhile pursuit.


Help From Afar!

I implemented the timing synchronization by enlisting help from the user to position a marker off-screen. This marker represented the time the video hardware was not actively drawing the screen, and moving it off-screen equated to synchronizing the program to do its animation while the hardware was not actively drawing. This solution is quite effective, and I don't think it is objectionable for the user to do this once when starting the game.

The timing I am seeing here at home is the roughly 60Hz timing of NTSC video. Of course, in much of the world the video standards are timed for 50 Hz vertical refresh rates. By adding a user choice between 50Hz and 60Hz and a corresponding variable used for timer setting, I was able to accommodate that situation. However, I don't have an MC-10 that uses PAL video or one of the French MC-10 clones, the Matra Alice. Luckily I was able to reach out for testing help on the Yahoo MC-10 group. There I found confirmation that my 50Hz timer synchronization was working too.

One Last Bug...

Along with that testing came a report that in some cases the snowmen would overlap and disappear! Worse, even in this vanished state they could still capture the player, causing him to lose...what was going on?

The moving objects in Xmas Rush are drawn using an XOR operation against the existing screen data.  The primary reason for this is to highlight the case when a snowman captures the player, but a side effect is that when two snowmen exactly overlap then they cancel each other out on the screen and seemingly disappear. In order to counteract that I have a series of tests in the snowmen movement routines that were intended to prevent an exact overlap. However, those test were clearly not working...

The original 6809 code for the snowman position tests used a CMPD instruction to do a 16-bit comparison against the D register (i.e. the A register and B register together). The 6803 lacks such an instruction, so in the conversion process I compared 8-bits against A and the other 8-bits against B. This changed the flow just enough that I confused myself, and I ended-up checking each snowman's position against the position of only one other snowman, allowing overlaps to occur with the other two! Once I found that problem it was easy to correct, and now snowmen should generally be unable to eclipse one another.

That's A Wrap

So anyway, that's about it for Xmas Rush on the MC-10. I'll get the MC-10 binaries added to the Xmas Rush web page and then I'll call it a month. I am really happy to have finally taken the time to learn more about the MC-10 and to put it to a decent use, and I hope you have enjoyed monitoring my progress along the way. I will probably have Xmas Rush on display at the 25th annual "Last" Chicago CoCoFEST! this April, if you want to stop and give it a go.

Until next time, I hope you will find your own excuse to get out your retro computing gear and make it do something fun, useful, or otherwise enjoyable. And as always, I hope you will stay tuned!

Saturday, January 23, 2016

Checking My List

Another week down and roughly one more left to go in the Retrochallenge RC2016/01 event. I got off to a bit of a slow start this month, but since then things have progressed well. It looks like things are shaping-up nicely for my port of Xmas Rush to the TRS-80 MC-10!


Time Is On My Side

One of my main concerns with this port has been the lack of a vertical sync signal available to the CPU on the MC-10. A direct port of the drawing algorithms from the CoCo version of Xmas Rush resulted in objects sometimes disappearing completely within certain vertical ranges of the screen. I considered altering the basic drawing algorithms in hopes of minimizing the screen problems, but that really seemed like a "band aid" solution at best.

The MC-10's Motorola 6803 CPU does have a hardware timer circuit, so precision timing is possible. The problem remains as to where (actually when) to anchor the timer settings. Since we know how long the screen is actively drawing and how long each frame lasts, we can derive the anchor point by interacting with the user. The timer is used to divide the screen into two periods, representing the active and inactive drawing times. A visual indicator is used to indicate the temporal position of the inactive period, and the user is asked to provide input that is used to relocate the inactive period until it's visual indicator is not visible. Once that temporal anchor is established, all that is required is to never miss a frame timer expiration... :-)


Watch Your Step

Xmas Rush uses a bitwise map to represent the scrubby trees that comprise the playfield terrain. At game time, that map is also used to generate a data structure used to detect potential collisions between that terrain and the player and snowmen. Converting the original 6809 code to 6803 code was a bit tricky, since the 6809 code made use of the extra index register available on that CPU. The conversion made a lot more use of the stack, reminding me of a Towers of Hanoi game gone terribly wrong... Anyway, I eventually managed to sort that out and objects were suitably constrained from moving across the tree-filled terrain.

With the player now moving about, it seemed like a good time to introduce the pitter-patter sound used during player motion. The CoCo version used the horizontal sync signal for timing square wave generation, but the MC-10 is as equally unhelpful for horizontal sync as it is for vertical sync. I had hoped that I could do some tricky hardware timer manipulations to use the timer both for the vertial sync emulation and for sound timing, but I couldn't seem to master that feat. Instead, the sound timing is based around cycle-counted loops representing horizontal sync periods. This proved to be satisfactory for all of the sound generation in Xmas Rush.

BTW, the pitter-patter sound is not a normal tone. Each up-down transition of the square wave is governed by the output of a linear feedback shift register (LFSR) used to generate pseudo-random data. In a very real sense, the pitter-patter sound is more of a noise than an actual tone.


Win Or Lose

It is important to be able to tell when the moving objects collide. This causes the player to lose when he collides with one of the snowmen, and it is a prerequisite for a win that the player must seize the evergreen tree. Xmas Rush does not have any special data structure for detecting sprite collisions. With so few sprites, it was easiest just to check each sprite position to see if it overlaps with the player.

A set of flags is used within the game code to indicate which snowmen are active and whether or not the evergreen tree has been seized by the player. These flags are used in the drawing routines to control what is drawn in a given frame. The "seized" flag is also used in coordination with the player's position to detect a "win" condition.


The last, big missing piece was the movement of the snowmen. Since the game loop erases and redraws every sprite during every frame, movement is nearly trivial -- just change the draw location and the object moves! Each of the four snowmen has its own movement strategy and a corresponding routine to implement that strategy. I won't divulge them here, but each strategy is fairly simple, and the snowmen can be manipulated into trapping themselves behind parts of the terrain as they pursue their personal strategy.

Anyway, with moving snowmen the game is largely complete. All that remains is integration of the timer calibration code into the main program, and a few odds and ends. This week should see a successful end to this project...I hope you will stay tuned!