[Coco] Special coding in WAR

Allen Huffman alsplace at pobox.com
Sat Jul 2 14:07:57 EDT 2022


> On Jul 2, 2022, at 8:56 AM, Robert Gault via Coco <coco at maltedmedia.com> wrote:
> 
> An author of games for Tandy, James Garon, put some lines in the Basic game WAR which is on colorcomputerarchive.com . The code is in lines 60000 and up which can't be LISTed with a CoCo3 but can be read with a CoCo2. 
> The lines in question contain PRINT commands which when listed with a CoCo2, look like the data inside the quotes have been converted into Basic commands. You can also see this if you use imgtool or wimgtool to extract the program from the .dsk image. 
> These lines generate PMODE graphics for the title screen. Do anyone have a clue as to how these Basic lines work?


(Robert knows the details of 6809 assembly, but I’m adding notes here for anyone else interested…)

Now the assembly part in line 60030...

0 S=PEEK(25)*256+PEEK(26)
1 E=PEEK(27)*256+PEEK(28)
2 FOR A=S TO E:PRINT USING("### ");PEEK(A);:NEXT
3 END
4 '*****
60030 A$="RUN!SUBELSE,NEXTENDFORTHENFORDIM/!9”

I know whatever I find between the 34s (after the 42 42 42 42 sequence) is likely the string in quotes:

 34 142   3 255  48   1 166 132  44   4 139  16 138 128 167 128 140   6   1  47 241  57  34 

So the bytes from 142 to 57 are 6809. I recognize 57 as an RTS (return from subroutine) op code so this makes sense.

I don’t feel like looking up every byte value to figure out what the op codes are, so I thought I’d use the online 6809 simulator:

http://6809.uk

I changed those data bytes in to “FCB” data statements for assembly:

warasm fcb 142,3,255,48,1,166,132,44,4,139,16,138,128,167,128,140,6,1,47,241,57

Then I pasted that in the 6809.uk <http://6809.uk/> code editor and did an assemble. It will then show those bytes back as op codes in the disassembly:

4000:	8E 03 FF       	LDX #$03FF
4003:	30 01          	LEAX $01,X
4005:	A6 84          	LDA ,X
4007:	2C 04          	BGE $400D
4009:	8B 10          	ADDA #$10
400B:	8A 80          	ORA #$80
400D:	A7 80          	STA ,X+
400F:	8C 06 01       	CMPX #$0601
4012:	2F F1          	BLE $4005
4014:	39             	RTS

And here it is, with comments in the style of BASIC:

    LDX #$03FF  * X=&H3FF (1023, byte before screen)
    LEAX $01,X  * X=X+1
 L4005
    LDA ,X      * A=PEEK(X)
    BGE L400D   * IF A<128 GOTO L400D
    ADDA #$10   * A=A+&H10:IF A>&HFF THEN A=A-&HFF
    ORA #$80    * A=A OR &H80
L400D
    STA ,X+     * POKE X,A:X=X+1
    CMPX #$0601 * Compare X to &H601 (two bytes past end)
    BLE L4005   * IF X<=&H601 GOTO L4005
    RTS         * RETURN

And here it is as BASIC:

100 X=&H3FF
110 X=X+1
120 A=PEEK(X)
130 IF A<128 GOTO 160 'L400D
140 A=A+&H10:IF A>&HFF THEN A=A-&HFF
150 A=A OR &H80
160 POKE A,X:X=X+1
170 'Compare X to &H601
180 IF X<=&H601 GOTO 120 'L4005
190 RETURN

A few changes had to be done for BASIC. With an 8-bit value in assembly, when you add and it goes past the 0-255 range, it just rolls over.  255 + 1 would turn to 0.  So in assembly:

 ADDA $10

Is adding hex 10 (&H10, or 16 in decimal) to the value in register A, as if:

A=A+16

But in BASIC, the value just goes higher and higher, not rolling over, so I had to modify it to do the rollover:

A=A+16:IF A>255 THEN A=A-255

Also, there is a BGE - branch if greater than. That looks like it should be:

LDA ,X
BGE somewhere

to

A=PEEK(A)
IF A>0 THEN GOTO somewhere

But I am guessing BGE is the branch that works on signed values… Where the value isn’t 0-255, but -127 to 128, using the high bit to indicate negative. (?)  This check is to see if the character on the screen is a graphics block, with the high bit set:

0xxxxxxxx - text characters 0-127
1xxxxxxxx - graphics blocks 128-255

So BGE is probably seeing anything with the high bit as negative, so below zero, thus if it’s not negative (high bit set), it skips.


Thus, in WAR.BAS, one line is just some CHR$ values POKEd in, which he could have just built a string and done it without a trick like this. And the second is an embedded assembly language program, stored inside a string. It’s tricky knowing where you can safely store assembly without it being overwritten by BASIC, but it seems that would have been simpler.

Was the author just showing off? Or was there a need to save the bytes to do it this way?

Also, for the assembly, the routine I came up with for my attract screen blog posts was similar:


WAR.BAS:

    LDX #$03FF  * X=&H3FF (1023, byte before screen)
    LEAX $01,X  * X=X+1
 L4005
    LDA ,X      * A=PEEK(X)
    BGE L400D   * IF A<128 GOTO L400D
    ADDA #$10   * A=A+&H10:IF A>&HFF THEN A=A-&HFF
    ORA #$80    * A=A OR &H80
L400D
    STA ,X+     * POKE X,A:X=X+1
    CMPX #$0601 * Compare X to &H601 (two bytes past end)
    BLE L4005   * IF X<=&H601 GOTO L4005
    RTS         * RETURN

MINE:

start
    ldx #1024   X points to top left of 32-col screen
loop
    lda ,x+     load A with what X points to and inc X
    bpl skip    if not >128, skip
    adda #16    add 16, changing to next color
    ora #$80    make sure high gfx bit is set
    sta -1,x    save at X-1
skip
    cmpx #1536  compare X with last byte of screen
    bne loop    if not there, repeat
    rts         done

I notice that when he skips, he jumps to the store (storing a byte that isn’t being changed), probably so he can move the X pointer up. In mine, I load and increment, since I always have to load, then when I store, I store one byte before where X points.

Using LWASM to check cycle counts, his method is one cycle faster than mine, it seems.

Mine:
        start
(3)         ldx #1024   X points to top left of 32-col screen
                loop
(5)     5           lda ,x+     load A with what X points to and inc
(3)     8           bpl skip    if not >128, skip
(2)     10          adda #16    add 16, changing to next color
(2)     12          ora #$80    make sure high gfx bit is set
(5)     17          sta -1,x    save at X-1
                skip
(3)     20          cmpx #1536  compare X with last byte of screen
(3)     23          bne loop    if not there, repeat
(4)         rts         done

My loop is 23 cycles.

His:
(3)         LDX #$03FF  * X=&H3FF 
(5)         LEAX $01,X  * X=X+1
                L4005
(4)     4           LDA ,X      * 
(3)     7           BGE L400D   * 
(2)     9           ADDA #$10   * 
(2)     11          ORA #$80    * 
                L400D
(5)     16          STA ,X+     * 
(3)     19          CMPX #$0601 * 
(3)     22          BLE L4005   * 
(4)         RTS         * RETURN

Looks like his is 22 cycles, though the total routine is larger.

I’m not sure why he starts like this:
        LDX #$03FF
        LEAX $01,X

Seems LDX #$400 (top left of screen) would be the same, since nothing ever jumps to the LEAX.


Well, that was quite the rabbit hole.

Neat program, too. I’m curious how he is drawing all the text on the PMODE4 screen, as well.

--
Allen Huffman - PO Box 7634 - Urbandale IA 50323 - 515-999-0227 (vmail/TXT only)
http://www.subethasoftware.com - https://www.facebook.com/subethasoftware




More information about the Coco mailing list