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!


5 comments:

  1. I thought the heavy use of ABX might be a performance killer in the converted code. Did you catch the FCB $21 used to insert a BRN opcode? I'm pretty sure the 6808 does not have BRN.

    ReplyDelete
    Replies
    1. Ah, yes...those tricky little NOPs disguised as FCBs in the instruction stream. I noticed those and set them aside for "later". I guess I'm not quite ready for that "6800-based MC-10" after all!

      Thanks for the reminder. I'll have to analyze those a bit more to see if I can branch around them or something...

      Delete
  2. I don't know how you feel about self-modifying code, but it could be used to speed up the PSHX and PULX implementations:

    pshx_macro:
    des
    sts *+5
    des
    stx $FFFF *modified

    pulx_macro:
    ins
    sts *+4
    ldx $FFFF *modified
    ins

    You could also slightly optimize the ABX replacement by not using accumulator A, eliminating the PSHA/PULA pair:

    emu_abx:
    pshb
    stx EMUSAVX
    addb EMUSAVX+1
    stab EMUSAVX+1
    ldab #0
    adcb EMUSAVX
    stab EMUSAVX
    ldx EMUSAVX
    pulb
    rts

    It should be noted that none of these leave the condition-codes register intact like the real 6803 instructions, but that particular behaviour is not relied upon by the Space Assault code.

    ReplyDelete
  3. On second thought, no need for self-modifying code for PULX. Just use:

    tsx
    ldx 0,x
    ins
    ins

    ReplyDelete
  4. Great project to port to the APF computer! Test in an emulator.

    ReplyDelete