2015 Retrochallenge Winter Warmup, Retrochallenge

Retrochallenge 2015/01 – Post 02

(This is part two of the chronicle of my Retrochallenge 2015/01 submission, which is to port the modern-day Apple II game, Structris, to the Atari 8-bit home computer using an obscure language called PL65. The mediocrity starts here.)

Arrrrrrgggghhh!

This week I’ve been wading into the cold water of PL65 programming for the Atari 8-bit. There are moments when I’m lulled into thinking I’m really using a modern language to cross-develop for the Atari. And then there are moments when I want to throw my laptop through the wall. I’ve lost a lot of time fighting what I perceive as bugs in PL65. Though I wouldn’t be surprised to find one day that the bugs were in my code and not in PL65.

I’ve been having fun, but I’m a little disappointed that my efforts don’t correspond to progress. Granted, I have been able to explore a lot of  territory new to me, like creating a custom display list (graphics mode) and implementing display list interrupts (to change graphics mode and color registers on-the-fly as the electron gun is traveling down the screen), but for sure I thought I’d to this point after the first weekend.

The only time computers irritate me is when they don’t appear to be acting logical.

A couple of examples:

  • Calling the string function STR$(val) to convert a numeric value to a string is inexplicably affecting my custom display mode, switching from GTIA mode 10 (9 Hues/9 Intensities) to GTIA mode 11 (16 Hues/1 Intensity). I was able to prove that by itself, the inclusion of the most trivial call to STR$() would cause my program to go awry. The PL65 source code for the STR$() function is on public display in the STRING.LIB library.
  • My original idea was to implement 3 display list interrupts:
  1. At the top of the screen to set the PRIOR register to render GTIA mode 10
  2. At the start of the base of the Tetris well to alter the color registers used in the tiles.
  3. At the bottom of the Tetris well base to turn off the GTIA settings so the 4-line text window displays properly.

With 3 display list interrupts (DLIs), the graphics mode became unstable. The DLIs were running in the wrong region. For many hours, I thought this was on me, but like the STR$() problem, it looked to me like calling unrelated PL65 functions was altering the graphics registers. In the end, I had to concede and use only two DLIs.

Paranoia, The Destroya

So now I don’t completely trust the system. I feel compelled to run a tedious compile/run/test cycle for each new line of code so I know which pieces of code might result in new odd behavior.

I know that dealing with display lists and DLIs are extremely sensitive to timing, so it’s possible a logical explanation exists. I just hope nothing else freaks-out. Otherwise I’ll need to come up with a different challenge – or try doing this in Action!.

“Cross-Compiling” using vim, make, and the Atari800 Emulator

Despite the very nice KED full-screen editor, doing the development on a real Atari 800 would be too painful. By now I’ve run a thousand edit/compile/run/debug cycles so I’m glad I spent some time up front to have a Linux-based toolchain. To compile my PL65 code, I run “make”. The basic idea is:

  1. Edit the PL65 source file using vim
  2. Run “make” to convert/move the source file to a Unix directory that is mapped as a hard-drive device within the “atari800” emulator and launch the emulator.
  3. Use the -record, -playback, and max-speed features of the “atari800” emulator to automate the keyboard entry needed to compile the source.
  4. When testing on the Atari, use BeweDOS’s STARTUP.BAT to launch the executable.

Here my toolchain is in action:

vim Syntax file

Here is my vim syntax file. Mostly just syntax-highlighting, however there is a feature with binary numbers which will change color only after 8 bits have been typed.

  1. Copy/paste this text to the file ~/.vim/syntax/pl65.vim
" Vim syntax file
" Language: PL65 for Atari 8-bit computers
" Maintainer: Michael Sternberg
" Latest Revision: 02 January 2015

if version < 600
    syntax clear
elseif exists("b:current_syntax")
    finish
endif

" Todo.
syn keyword pl65Todo TODO FIXME XXX DEBUG NOTE

" pl65CommentGroup allows adding matches for special things in comments.
syn cluster pl65CommentGroup  contains=pl65Todo

" Keywords
syn keyword pl65Command PROC FUNC INTERRUPT BODY CONST LINK INCLUDE 
syn keyword pl65Command BEGIN END LINK FORWARD MAIN ENDFILE

syn keyword pl65Type BYTE INT STRING POINTER BASED

syn keyword pl65Conditional IF THEN ELSE ENDIF 

syn keyword pl65State WHILE DO ENDWHILE REPEAT FOREVER UNTIL
syn keyword pl65State FOR TO STEP NEXT DOWNTO
syn keyword pl65State CASE OF ENDOF ENDCASE GOTO TRAP NOTRAP RETURN

syn keyword pl65Mneumonic BNE BEQ BMI BPL BCC BCS BVS BVC JMP JSR
syn keyword pl65Mneumonic INX DEX INY DEY PHA PLA PHP PLP ASLA LSA 
syn keyword pl65Mneumonic RORA ROLA TSX TXA TAX TYA TAY NOP BRK RTS 
syn keyword pl65Mneumonic RTI SED CLD SEC CLC SEI CLI CLV LDA STA LDX 
syn keyword pl65Mneumonic STX LDY STY CMP CPX CPY AND ORA EOR BIT ASL 
syn keyword pl65Mneumonic LSR ROL ROR INC DEC ADC SBC 

syn region pl65String start='"' end='"'

syn match pl65Comment "!.*$"
syn match pl65Comment "!.*!$"

syn match   pl65Label          display "[:]<w+>"
syn match   cexprNumber        display "<d+>"
syn match   cexprNumberHex     display "[$]<[0123456789ABCDEFabcdef]+>"
syn match   cexprNumberBin     display "[%]<[01][01][01][01][01][01][01][01]>"

syn region  pl65CommentL start="!" skip="\$" end="$" keepend contains=@pl65CommentGroup,@Spell

" Define the default highlighting.
" For version 5.x and earlier, only when not done already.
" For version 5.8 and later, only when and item doesn't have highlighting
" yet.
if version >= 508 || !exists("did_pl1_syn_inits")
    if version < 508
        let did_pl1_syn_inits = 1
        command -nargs=+ HiLink hi link <args>
    else
        command -nargs=+ HiLink hi def link <args>
    endif

    hi def link pl65Command         PreProc
    hi def link pl65Type            Type
    hi def link cexprNumber         Number
    hi def link pl65State           Statement
    hi def link pl65Mneumonic       Statement
    hi def link pl65Conditional     Statement
    hi def link pl65Todo            Todo
    hi def link pl65Label           Label
    hi def link cexprNumberHex      Special
    hi def link cexprNumberBin      Special
    hi def link pl65String          String
    hi def link pl65CommentL        pl65Comment
    hi def link pl65Comment         Comment

    delcommand HiLink
endif

let b:current_syntax = "pl65"

Then copy this text to the file ~/.vim/ftdetect/pl65.vim
This allows files with a .pl65 extension to have syntax-highlighting automatically applied.

au BufRead,BufNewFile *.pl65 set filetype=pl65

Makefile

The makefile supports the following targets.

Command Description
make Convert source file to Atari format and launch emulator with PL65 in D1: and target diskette in D2: using keyboard playback
make run Launch emulator with diskette containing target executable
make record Launch emulator with keyboard recording enabled
make edit Launch vim with project-specific preferences, such as 2-space indentation
BAS=STRUCTRS
IMG=../Disks/$(BAS).atr

TAR=$(BAS).PRG
SRC=$(BAS).pl65
UTL=pl65_to_prg

all:	$(IMG)

$(IMG):	$(TAR)
	atari800 -atari -playback build.rec ../Disks/PL65_BW.atr $(IMG) 2> /dev/null

$(TAR): $(SRC) $(UTL)
	./pl65_to_prg $(SRC) > ../Work/$(TAR)

$(UTL): $(UTL).c
	gcc -o $(UTL) $(UTL).c

.PHONY: run
run:
	atari800 -atari $(IMG)

.PHONY: record
record:
	atari800 -atari -record build.rec ../Disks/PL65_BW.atr $(IMG)

.PHONY: edit
edit:
	vim -u ./.vimrc $(SRC)

.PHONY: norun
norun:
	atari800 -atari ../Disks/PL65_BW.atr $(IMG)

Utility for Converting PL65 source from Unix to Atari

This C program converts a Unix text file to have Atari end-of-line characters. It also strips out PL65 comments, but doesn’t support comments on the same line as PL65 code. Instead it makes a mess of things.

/* Convert EOL from Unix to Atari
   Also skip PL65 comments "! this is a comment"
   Note: Does not support comments on same line as code.
 */
#include <stdio.h>

void display_usage(void);

#define A8_EOL 0x9b

int main (int argc, char* argv[])
{
    FILE* fp; 
    unsigned char ch;
    char state = 0;

    if (argc != 2)
    {
        display_usage();
        return(1);
    }

    fp = fopen(argv[1], "r");

    if (fp == NULL)
    {
        fprintf (stderr, "Unable to open [%s] for readn", argv[1]);
        return(1);
    }

    /* while (!feof(fp)) */
    while (state >= 0)
    {
        ch = fgetc(fp);
        if (feof(fp)) { state = -1; }
        else
        {
            /* Convert Unix EOL to Atari 8-bit EOL */
            if (ch == 'n') { ch = A8_EOL; }

            if (state == 0 && ch == '"') 
                state = 1;
            else if (state == 1 && (ch == '"' || ch == A8_EOL))
                state = 0;
            else if (state == 0 && ch == '!') 
                state = 2;
            else if (state == 2 && (ch == A8_EOL))
                state = 3;
            else if (state == 3 && (ch == '!'))
                state = 2;
            else if (state == 3 && (ch != '!'))
                state = 0;

            /* Skip comments (!) */
            if (state == 0 || state == 1) fputc(ch, stdout);
        }
    }

    fclose(fp);

    return(0);
}

void display_usage(void)
{
    fprintf(stderr, "Usage: pl65_to_prg <filename>n");
    fprintf(stderr, "Output sent to stdoutn");
    return;
}

 Up Next…

Mimicking (well, closely enough) the Apple’s Lo-Res graphics mode on the Atari 8-bit. This time. I promise.