(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:
- At the top of the screen to set the PRIOR register to render GTIA mode 10
- At the start of the base of the Tetris well to alter the color registers used in the tiles.
- 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:
- Edit the PL65 source file using vim
- 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.
- Use the -record, -playback, and max-speed features of the “atari800” emulator to automate the keyboard entry needed to compile the source.
- 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.
- 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.