diff --git a/Contributing.md b/Contributing.md index 6258ce523..8528997df 100644 --- a/Contributing.md +++ b/Contributing.md @@ -68,6 +68,7 @@ color := $0787 ## Assembly Sources * Op-code mnemonics must have lower-case letters. The names of instruction macroes may have upper-case letters. +* Op-codes must use their official and commonly used mnemonics, ie bcc and bcs and not bgt and blt * Hexadecimal number constants should be used except where decimal or binary numbers make much more sense in that constant's context. * Hexadecimal letters should be upper-case. * When you set two registers or two memory locations to an immediate 16-bit zero, you should use the expressions ```#<$0000``` and ```#>$0000``` (they make it obvious where you are putting the lower and upper bytes). diff --git a/asminc/atari7800.inc b/asminc/atari7800.inc index a7625aa8a..0f109ba64 100644 --- a/asminc/atari7800.inc +++ b/asminc/atari7800.inc @@ -6,3 +6,9 @@ .include "atari7800_tia.inc" .include "atari7800_riot.inc" .include "atari7800_maria.inc" + +; constants for the conio implementation +mono_charsperline = 40 +charsperline = 20 +screenrows = 28 + diff --git a/cfg/atari7800.cfg b/cfg/atari7800.cfg index 4d20ab0d9..1eed534f3 100644 --- a/cfg/atari7800.cfg +++ b/cfg/atari7800.cfg @@ -10,7 +10,7 @@ SYMBOLS { __ENCRYPT_BOTTOM__: value = $ff7a, type = export; __ENCRYPT_SIZE__: value = $80, type = export; __MEMORY_TOP__: value = __ENCRYPT_BOTTOM__, type = export; - __INIT_SIZE__: value = 121, type = export; + __INIT_SIZE__: value = 156, type = export; __MEMORY_INIT__: value = __MEMORY_TOP__ - __INIT_SIZE__, type = export; __MEMORY_BOTTOM__: value = $10000 - __CARTSIZE__, type = weak; __FREE_ROM_SIZE__: value = __MEMORY_INIT__ - __MEMORY_BOTTOM__, type = export; @@ -39,6 +39,7 @@ MEMORY { SEGMENTS { ZEROPAGE: load = ZP, type = zp; + EXTZP: load = ZP, type = zp; EXEHDR: load = HEADER, type = ro, optional = yes; STARTUP: load = ROMS, type = ro, define = yes; ONCE: load = ROMS, type = ro, define = yes; diff --git a/include/atari7800.h b/include/atari7800.h index 4fdaacfcc..3cbeedb8b 100644 --- a/include/atari7800.h +++ b/include/atari7800.h @@ -52,6 +52,8 @@ /* No support for dynamically loadable drivers */ #define DYN_DRV 0 +extern unsigned char get_tv(void); /* get TV system */ + #include <_tia.h> #define TIA (*(struct __tia*)0x0000) diff --git a/libsrc/atari7800/clrscr.s b/libsrc/atari7800/clrscr.s new file mode 100644 index 000000000..f9d4938b0 --- /dev/null +++ b/libsrc/atari7800/clrscr.s @@ -0,0 +1,27 @@ + + .include "atari7800.inc" + + .export _clrscr + + .import _screen + .import pushax, __bzero + .include "extzp.inc" + + .code + + .proc _clrscr + + lda #<_screen + ldx #>_screen + jsr pushax + ldx #>(charsperline * screenrows) + lda #<(charsperline * screenrows) + jmp __bzero + + .endproc + +;------------------------------------------------------------------------------- +; force the init constructor to be imported + + .import initconio +conio_init = initconio diff --git a/libsrc/atari7800/conio.s b/libsrc/atari7800/conio.s new file mode 100644 index 000000000..92cc7d8b1 --- /dev/null +++ b/libsrc/atari7800/conio.s @@ -0,0 +1,226 @@ +; +; 2022-04-02, Karri Kaksonen +; +; The Atari 7800 has only 4k of RAM. So for a generic conio implementation +; the best alternative is to use indirect tile mapping with a character +; frame buffer +; + + .constructor initconio + .include "atari7800.inc" + .include "extzp.inc" + .import _conio_font + .import _get_tv + .export _screen + .export _zones + .export _dll + + .bss +_screen: + .res charsperline * screenrows + +;---------------------------------------------------------------------------- +; Macros used to generate lists + +.macro DLLentry offset, addr + .byte offset + .byte >addr + .byte addr + .byte hpos +.endmacro + +.macro XHeader addr, flags, palwidth, hpos + .byte addr + .byte palwidth + .byte hpos +.endmacro + +.macro TextZone row + ; Text + .byte <(_screen + row * charsperline) + .byte $60 + .byte >(_screen + row * charsperline) + .byte 12 + .byte 0 + ; Cursor + .byte 254 + .byte 0 + .byte >_conio_font + .byte 0 +.endmacro + +;----------------------------------------------------------------------------- +; The Atari 7800 has only 4k of RAM. So for a generic conio implementation +; the best alternative is to use indirect tile mapping with a character +; frame buffer + .data + +_zones: +zone0: TextZone 0 +nh: NullHeader 0, 0 +zone1: TextZone 1 + NullHeader 0, 0 +zone2: TextZone 2 + NullHeader 0, 0 +zone3: TextZone 3 + NullHeader 0, 0 +zone4: TextZone 4 + NullHeader 0, 0 +zone5: TextZone 5 + NullHeader 0, 0 +zone6: TextZone 6 + NullHeader 0, 0 +zone7: TextZone 7 + NullHeader 0, 0 +zone8: TextZone 8 + NullHeader 0, 0 +zone9: TextZone 9 + NullHeader 0, 0 +zone10: TextZone 10 + NullHeader 0, 0 +zone11: TextZone 11 + NullHeader 0, 0 +zone12: TextZone 12 + NullHeader 0, 0 +zone13: TextZone 13 + NullHeader 0, 0 +zone14: TextZone 14 + NullHeader 0, 0 +zone15: TextZone 15 + NullHeader 0, 0 +zone16: TextZone 16 + NullHeader 0, 0 +zone17: TextZone 17 + NullHeader 0, 0 +zone18: TextZone 18 + NullHeader 0, 0 +zone19: TextZone 19 + NullHeader 0, 0 +zone20: TextZone 20 + NullHeader 0, 0 +zone21: TextZone 21 + NullHeader 0, 0 +zone22: TextZone 22 + NullHeader 0, 0 +zone23: TextZone 23 + NullHeader 0, 0 +zone24: TextZone 24 + NullHeader 0, 0 +zone25: TextZone 25 + NullHeader 0, 0 +zone26: TextZone 26 + NullHeader 0, 0 +zone27: TextZone 27 + NullHeader 0, 0 + +_dll: +PALscanlines: ; 25 lines + DLLentry 15, nh + DLLentry 8, nh + +Topscanlines: ; 9 lines + DLLentry 8, nh + +Displaylines: + DLLentry $80+7, zone0 ; NMI interrupt from end of prev zone + DLLentry 7, zone1 + DLLentry 7, zone2 + DLLentry 7, zone3 + DLLentry 7, zone4 + DLLentry 7, zone5 + DLLentry 7, zone6 + DLLentry 7, zone7 + DLLentry 7, zone8 + DLLentry 7, zone9 + DLLentry 7, zone10 + DLLentry 7, zone11 + DLLentry 7, zone12 + DLLentry 7, zone13 + DLLentry 7, zone14 + DLLentry 7, zone15 + DLLentry 7, zone16 + DLLentry 7, zone17 + DLLentry 7, zone18 + DLLentry 7, zone19 + DLLentry 7, zone20 + DLLentry 7, zone21 + DLLentry 7, zone22 + DLLentry 7, zone23 + DLLentry 7, zone24 + DLLentry 7, zone25 + DLLentry 7, zone26 + DLLentry 7, zone27 + +Bottomscanlines: + DLLentry $80+15, nh ; NMI interrupt at end of display + DLLentry 9, nh + DLLentry 15, nh + DLLentry 8, nh + +;----------------------------------------------------------------------------- +; Set up the screen to 320a mode +; + .segment "ONCE" + +CTRL_MODE160 .set 0 +CTRL_MODEAC .set 3 +CTRL_KANGOFF .set 0 +CTRL_BCBLACK .set 0 +CTRL_CHAR1B .set 0 +CTRL_CHAR2B .set $10 +CTRL_DMAON .set $40 +CTRL_CKOFF .set 0 + +;----------------------------------------------------------------------------- +; Initialize the conio display lists and zones +; + .proc initconio + + jsr _get_tv + bne pal + lda #Topscanlines + sta DPPH + jmp vblankon +pal: lda #PALscanlines + sta DPPH +vblankon: + lda MSTAT + bmi vblankon +vblankoff: + lda MSTAT + bpl vblankoff + lda #>_conio_font + sta CHBASE + lda #(CTRL_MODE160 | CTRL_KANGOFF | CTRL_BCBLACK | CTRL_CHAR2B | CTRL_DMAON | CTRL_CKOFF) + sta CTRL + lda #$00 ; Black background + sta BKGRND + sta CURS_X + sta CURS_Y + lda #$33 ; Red + sta P0C1 + lda #$c8 ; Green + sta P0C2 + lda #$0f ; White + sta P0C3 + rts + + .endproc + diff --git a/libsrc/atari7800/conio_font.s b/libsrc/atari7800/conio_font.s new file mode 100644 index 000000000..829e3e2ce --- /dev/null +++ b/libsrc/atari7800/conio_font.s @@ -0,0 +1,278 @@ +; The internal font structure for Atari7800 needs a full set of 128 +; characters. Each character is 16 x 8 bits. +; The font consists of 8 rows of data: +; row7 +; row6 +; row5 +; row4 +; row3 +; row2 +; row1 +; row0 +; Each row is 256 bytes long +; As we have 2 bits per pixel we need 2 bytes to represent +; one character. So we can fit 128 characters in this font +; When you later use the font you must address the characters as +; 0, 2, 4, 6, ... 254 +; Odd indices cannot be used. + + .export _conio_font + .rodata + .align 256 +_conio_font: + .byte $0, $0, $41, $41, $0, $0, $14, $0 + .byte $0, $0, $0, $0, $1, $40, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $82, $82 + .byte $0, $0, $28, $0, $0, $0, $0, $0 + .byte $2, $80, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $c3, $c3, $0, $0, $3c, $0 + .byte $0, $0, $0, $0, $3, $c0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $0, $0 + .byte $0, $0, $0, $0, $0, $0, $ff, $ff + .byte $0, $0, $11, $44, $5, $0, $5, $0 + .byte $0, $0, $5, $0, $1, $40, $15, $50 + .byte $55, $50, $55, $50, $15, $40, $1, $54 + .byte $15, $40, $15, $40, $5, $0, $15, $40 + .byte $15, $0, $50, $50, $55, $50, $5, $50 + .byte $55, $40, $55, $54, $55, $0, $5, $54 + .byte $50, $50, $15, $40, $15, $40, $54, $14 + .byte $55, $54, $50, $14, $50, $14, $5, $40 + .byte $55, $0, $1, $50, $54, $14, $15, $40 + .byte $15, $40, $55, $50, $5, $0, $50, $14 + .byte $50, $14, $15, $40, $55, $54, $22, $88 + .byte $a, $0, $a, $0, $0, $0, $a, $0 + .byte $2, $80, $2a, $a0, $aa, $a0, $aa, $a0 + .byte $2a, $80, $2, $a8, $2a, $80, $2a, $80 + .byte $a, $0, $2a, $80, $2a, $0, $a0, $a0 + .byte $aa, $a0, $a, $a0, $aa, $80, $aa, $a8 + .byte $aa, $0, $a, $a8, $a0, $a0, $2a, $80 + .byte $2a, $80, $a8, $28, $aa, $a8, $a0, $28 + .byte $a0, $28, $a, $80, $aa, $0, $2, $a0 + .byte $a8, $28, $2a, $80, $2a, $80, $aa, $a0 + .byte $a, $0, $a0, $28, $a0, $28, $2a, $80 + .byte $aa, $a8, $33, $cc, $f, $0, $f, $0 + .byte $0, $0, $f, $0, $3, $c0, $3f, $f0 + .byte $ff, $f0, $ff, $f0, $3f, $c0, $3, $fc + .byte $3f, $c0, $3f, $c0, $f, $0, $3f, $c0 + .byte $3f, $0, $f0, $f0, $ff, $f0, $f, $f0 + .byte $ff, $c0, $ff, $fc, $ff, $0, $f, $fc + .byte $f0, $f0, $3f, $c0, $3f, $c0, $fc, $3c + .byte $ff, $fc, $f0, $3c, $f0, $3c, $f, $c0 + .byte $ff, $0, $3, $f0, $fc, $3c, $3f, $c0 + .byte $3f, $c0, $ff, $f0, $f, $0, $f0, $3c + .byte $f0, $3c, $3f, $c0, $ff, $fc, $0, $0 + .byte $0, $0, $5, $50, $0, $0, $5, $0 + .byte $0, $0, $5, $0, $1, $40, $54, $14 + .byte $5, $0, $50, $50, $50, $50, $0, $50 + .byte $50, $50, $50, $50, $5, $0, $50, $50 + .byte $1, $40, $50, $50, $14, $14, $14, $14 + .byte $14, $50, $14, $4, $14, $0, $14, $14 + .byte $50, $50, $5, $0, $50, $50, $14, $14 + .byte $14, $14, $50, $14, $50, $14, $14, $50 + .byte $14, $0, $15, $40, $14, $14, $50, $50 + .byte $5, $0, $50, $50, $15, $40, $54, $54 + .byte $14, $50, $5, $0, $14, $14, $a, $a0 + .byte $0, $0, $a, $0, $0, $0, $a, $0 + .byte $2, $80, $a8, $28, $a, $0, $a0, $a0 + .byte $a0, $a0, $0, $a0, $a0, $a0, $a0, $a0 + .byte $a, $0, $a0, $a0, $2, $80, $a0, $a0 + .byte $28, $28, $28, $28, $28, $a0, $28, $8 + .byte $28, $0, $28, $28, $a0, $a0, $a, $0 + .byte $a0, $a0, $28, $28, $28, $28, $a0, $28 + .byte $a0, $28, $28, $a0, $28, $0, $2a, $80 + .byte $28, $28, $a0, $a0, $a, $0, $a0, $a0 + .byte $2a, $80, $a8, $a8, $28, $a0, $a, $0 + .byte $28, $28, $f, $f0, $0, $0, $f, $0 + .byte $0, $0, $f, $0, $3, $c0, $fc, $3c + .byte $f, $0, $f0, $f0, $f0, $f0, $0, $f0 + .byte $f0, $f0, $f0, $f0, $f, $0, $f0, $f0 + .byte $3, $c0, $f0, $f0, $3c, $3c, $3c, $3c + .byte $3c, $f0, $3c, $c, $3c, $0, $3c, $3c + .byte $f0, $f0, $f, $0, $f0, $f0, $3c, $3c + .byte $3c, $3c, $f0, $3c, $f0, $3c, $3c, $f0 + .byte $3c, $0, $3f, $c0, $3c, $3c, $f0, $f0 + .byte $f, $0, $f0, $f0, $3f, $c0, $fc, $fc + .byte $3c, $f0, $f, $0, $3c, $3c, $0, $0 + .byte $0, $0, $54, $15, $5, $0, $0, $0 + .byte $55, $55, $0, $0, $1, $40, $55, $14 + .byte $5, $0, $14, $0, $0, $50, $55, $54 + .byte $0, $50, $50, $50, $5, $0, $50, $50 + .byte $0, $50, $55, $50, $14, $14, $50, $0 + .byte $14, $14, $14, $40, $14, $40, $50, $54 + .byte $50, $50, $5, $0, $50, $50, $14, $50 + .byte $14, $4, $51, $14, $50, $54, $50, $14 + .byte $14, $0, $51, $50, $14, $50, $1, $50 + .byte $5, $0, $50, $50, $50, $50, $55, $54 + .byte $5, $40, $5, $0, $5, $4, $a8, $2a + .byte $a, $0, $0, $0, $aa, $aa, $0, $0 + .byte $2, $80, $aa, $28, $a, $0, $28, $0 + .byte $0, $a0, $aa, $a8, $0, $a0, $a0, $a0 + .byte $a, $0, $a0, $a0, $0, $a0, $aa, $a0 + .byte $28, $28, $a0, $0, $28, $28, $28, $80 + .byte $28, $80, $a0, $a8, $a0, $a0, $a, $0 + .byte $a0, $a0, $28, $a0, $28, $8, $a2, $28 + .byte $a0, $a8, $a0, $28, $28, $0, $a2, $a0 + .byte $28, $a0, $2, $a0, $a, $0, $a0, $a0 + .byte $a0, $a0, $aa, $a8, $a, $80, $a, $0 + .byte $a, $8, $fc, $3f, $f, $0, $0, $0 + .byte $ff, $ff, $0, $0, $3, $c0, $ff, $3c + .byte $f, $0, $3c, $0, $0, $f0, $ff, $fc + .byte $0, $f0, $f0, $f0, $f, $0, $f0, $f0 + .byte $0, $f0, $ff, $f0, $3c, $3c, $f0, $0 + .byte $3c, $3c, $3c, $c0, $3c, $c0, $f0, $fc + .byte $f0, $f0, $f, $0, $f0, $f0, $3c, $f0 + .byte $3c, $c, $f3, $3c, $f0, $fc, $f0, $3c + .byte $3c, $0, $f3, $f0, $3c, $f0, $3, $f0 + .byte $f, $0, $f0, $f0, $f0, $f0, $ff, $fc + .byte $f, $c0, $f, $0, $f, $c, $0, $0 + .byte $0, $0, $54, $15, $1, $40, $0, $0 + .byte $55, $55, $0, $0, $1, $40, $51, $54 + .byte $5, $0, $5, $40, $5, $40, $50, $50 + .byte $0, $50, $55, $40, $1, $40, $15, $40 + .byte $15, $50, $50, $50, $15, $50, $50, $0 + .byte $14, $14, $15, $40, $15, $40, $50, $0 + .byte $55, $50, $5, $0, $0, $50, $15, $40 + .byte $14, $0, $55, $54, $51, $54, $50, $14 + .byte $15, $50, $50, $50, $15, $50, $15, $0 + .byte $5, $0, $50, $50, $50, $50, $51, $14 + .byte $5, $40, $15, $40, $1, $40, $a8, $2a + .byte $2, $80, $0, $0, $aa, $aa, $0, $0 + .byte $2, $80, $a2, $a8, $a, $0, $a, $80 + .byte $a, $80, $a0, $a0, $0, $a0, $aa, $80 + .byte $2, $80, $2a, $80, $2a, $a0, $a0, $a0 + .byte $2a, $a0, $a0, $0, $28, $28, $2a, $80 + .byte $2a, $80, $a0, $0, $aa, $a0, $a, $0 + .byte $0, $a0, $2a, $80, $28, $0, $aa, $a8 + .byte $a2, $a8, $a0, $28, $2a, $a0, $a0, $a0 + .byte $2a, $a0, $2a, $0, $a, $0, $a0, $a0 + .byte $a0, $a0, $a2, $28, $a, $80, $2a, $80 + .byte $2, $80, $fc, $3f, $3, $c0, $0, $0 + .byte $ff, $ff, $0, $0, $3, $c0, $f3, $fc + .byte $f, $0, $f, $c0, $f, $c0, $f0, $f0 + .byte $0, $f0, $ff, $c0, $3, $c0, $3f, $c0 + .byte $3f, $f0, $f0, $f0, $3f, $f0, $f0, $0 + .byte $3c, $3c, $3f, $c0, $3f, $c0, $f0, $0 + .byte $ff, $f0, $f, $0, $0, $f0, $3f, $c0 + .byte $3c, $0, $ff, $fc, $f3, $fc, $f0, $3c + .byte $3f, $f0, $f0, $f0, $3f, $f0, $3f, $0 + .byte $f, $0, $f0, $f0, $f0, $f0, $f3, $3c + .byte $f, $c0, $3f, $c0, $3, $c0, $0, $0 + .byte $0, $0, $5, $50, $0, $50, $0, $0 + .byte $0, $0, $0, $0, $1, $40, $50, $54 + .byte $5, $0, $0, $50, $0, $50, $14, $50 + .byte $55, $40, $50, $0, $0, $50, $50, $50 + .byte $50, $50, $50, $50, $14, $14, $50, $0 + .byte $14, $14, $14, $40, $14, $40, $50, $0 + .byte $50, $50, $5, $0, $0, $50, $14, $50 + .byte $14, $0, $55, $54, $55, $14, $50, $14 + .byte $14, $14, $50, $50, $14, $14, $54, $0 + .byte $5, $0, $50, $50, $50, $50, $50, $14 + .byte $14, $50, $50, $50, $40, $50, $a, $a0 + .byte $0, $a0, $0, $0, $0, $0, $0, $0 + .byte $2, $80, $a0, $a8, $a, $0, $0, $a0 + .byte $0, $a0, $28, $a0, $aa, $80, $a0, $0 + .byte $0, $a0, $a0, $a0, $a0, $a0, $a0, $a0 + .byte $28, $28, $a0, $0, $28, $28, $28, $80 + .byte $28, $80, $a0, $0, $a0, $a0, $a, $0 + .byte $0, $a0, $28, $a0, $28, $0, $aa, $a8 + .byte $aa, $28, $a0, $28, $28, $28, $a0, $a0 + .byte $28, $28, $a8, $0, $a, $0, $a0, $a0 + .byte $a0, $a0, $a0, $28, $28, $a0, $a0, $a0 + .byte $80, $a0, $f, $f0, $0, $f0, $0, $0 + .byte $0, $0, $0, $0, $3, $c0, $f0, $fc + .byte $f, $0, $0, $f0, $0, $f0, $3c, $f0 + .byte $ff, $c0, $f0, $0, $0, $f0, $f0, $f0 + .byte $f0, $f0, $f0, $f0, $3c, $3c, $f0, $0 + .byte $3c, $3c, $3c, $c0, $3c, $c0, $f0, $0 + .byte $f0, $f0, $f, $0, $0, $f0, $3c, $f0 + .byte $3c, $0, $ff, $fc, $ff, $3c, $f0, $3c + .byte $3c, $3c, $f0, $f0, $3c, $3c, $fc, $0 + .byte $f, $0, $f0, $f0, $f0, $f0, $f0, $3c + .byte $3c, $f0, $f0, $f0, $c0, $f0, $0, $0 + .byte $0, $0, $11, $44, $50, $50, $0, $0 + .byte $0, $0, $0, $0, $1, $40, $50, $14 + .byte $15, $0, $50, $50, $50, $50, $5, $50 + .byte $50, $0, $14, $0, $50, $50, $50, $50 + .byte $50, $50, $15, $40, $14, $14, $14, $14 + .byte $14, $50, $14, $4, $14, $4, $14, $14 + .byte $50, $50, $5, $0, $0, $50, $14, $14 + .byte $14, $0, $54, $54, $54, $14, $14, $50 + .byte $14, $14, $50, $50, $14, $14, $50, $50 + .byte $45, $10, $50, $50, $50, $50, $50, $14 + .byte $50, $14, $50, $50, $50, $14, $22, $88 + .byte $a0, $a0, $0, $0, $0, $0, $0, $0 + .byte $2, $80, $a0, $28, $2a, $0, $a0, $a0 + .byte $a0, $a0, $a, $a0, $a0, $0, $28, $0 + .byte $a0, $a0, $a0, $a0, $a0, $a0, $2a, $80 + .byte $28, $28, $28, $28, $28, $a0, $28, $8 + .byte $28, $8, $28, $28, $a0, $a0, $a, $0 + .byte $0, $a0, $28, $28, $28, $0, $a8, $a8 + .byte $a8, $28, $28, $a0, $28, $28, $a0, $a0 + .byte $28, $28, $a0, $a0, $8a, $20, $a0, $a0 + .byte $a0, $a0, $a0, $28, $a0, $28, $a0, $a0 + .byte $a0, $28, $33, $cc, $f0, $f0, $0, $0 + .byte $0, $0, $0, $0, $3, $c0, $f0, $3c + .byte $3f, $0, $f0, $f0, $f0, $f0, $f, $f0 + .byte $f0, $0, $3c, $0, $f0, $f0, $f0, $f0 + .byte $f0, $f0, $3f, $c0, $3c, $3c, $3c, $3c + .byte $3c, $f0, $3c, $c, $3c, $c, $3c, $3c + .byte $f0, $f0, $f, $0, $0, $f0, $3c, $3c + .byte $3c, $0, $fc, $fc, $fc, $3c, $3c, $f0 + .byte $3c, $3c, $f0, $f0, $3c, $3c, $f0, $f0 + .byte $cf, $30, $f0, $f0, $f0, $f0, $f0, $3c + .byte $f0, $3c, $f0, $f0, $f0, $3c, $0, $0 + .byte $0, $0, $41, $41, $15, $40, $0, $0 + .byte $0, $0, $0, $0, $1, $40, $15, $50 + .byte $5, $0, $15, $40, $15, $40, $1, $50 + .byte $55, $50, $5, $40, $55, $50, $15, $40 + .byte $15, $40, $5, $0, $55, $50, $5, $50 + .byte $55, $40, $55, $54, $55, $54, $5, $50 + .byte $50, $50, $15, $40, $1, $54, $54, $14 + .byte $55, $0, $50, $14, $50, $14, $5, $40 + .byte $55, $50, $15, $40, $55, $50, $15, $40 + .byte $55, $50, $50, $50, $50, $50, $50, $14 + .byte $50, $14, $50, $50, $55, $54, $82, $82 + .byte $2a, $80, $0, $0, $0, $0, $0, $0 + .byte $2, $80, $2a, $a0, $a, $0, $2a, $80 + .byte $2a, $80, $2, $a0, $aa, $a0, $a, $80 + .byte $aa, $a0, $2a, $80, $2a, $80, $a, $0 + .byte $aa, $a0, $a, $a0, $aa, $80, $aa, $a8 + .byte $aa, $a8, $a, $a0, $a0, $a0, $2a, $80 + .byte $2, $a8, $a8, $28, $aa, $0, $a0, $28 + .byte $a0, $28, $a, $80, $aa, $a0, $2a, $80 + .byte $aa, $a0, $2a, $80, $aa, $a0, $a0, $a0 + .byte $a0, $a0, $a0, $28, $a0, $28, $a0, $a0 + .byte $aa, $a8, $c3, $c3, $3f, $c0, $0, $0 + .byte $0, $0, $0, $0, $3, $c0, $3f, $f0 + .byte $f, $0, $3f, $c0, $3f, $c0, $3, $f0 + .byte $ff, $f0, $f, $c0, $ff, $f0, $3f, $c0 + .byte $3f, $c0, $f, $0, $ff, $f0, $f, $f0 + .byte $ff, $c0, $ff, $fc, $ff, $fc, $f, $f0 + .byte $f0, $f0, $3f, $c0, $3, $fc, $fc, $3c + .byte $ff, $0, $f0, $3c, $f0, $3c, $f, $c0 + .byte $ff, $f0, $3f, $c0, $ff, $f0, $3f, $c0 + .byte $ff, $f0, $f0, $f0, $f0, $f0, $f0, $3c + .byte $f0, $3c, $f0, $f0, $ff, $fc, $0, $0 diff --git a/libsrc/atari7800/cputc.s b/libsrc/atari7800/cputc.s new file mode 100644 index 000000000..9ec84bfe5 --- /dev/null +++ b/libsrc/atari7800/cputc.s @@ -0,0 +1,137 @@ +; +; Mark Keates, Christian Groessler, Piotr Fusik, Karri Kaksonen +; +; void cputcxy (unsigned char x, unsigned char y, char c); +; void cputc (char c); +; + + .export _cputc + .import gotox, gotoy, pusha0 + .import pushax + .import _screen + .import txtcolor + + .include "atari7800.inc" + .include "extzp.inc" + + .code + +;--------------------------------------------------------------------------- +; 8x16 routine + +umula0: + ldy #8 ; Number of bits + lda #0 + lsr ptr7800 ; Get first bit into carry +@L0: bcc @L1 + + clc + adc ptrtmp + tax + lda ptrtmp+1 ; hi byte of left op + clc + adc ptr7800+1 + sta ptr7800+1 + txa + +@L1: ror ptr7800+1 + ror a + ror ptr7800 + dey + bne @L0 + tax + lda ptr7800 ; Load the result + rts + +;----------------------------------------------------------------------------- +; Put a character on screen +; +; The code will handle newlines that wrap to start of screen +; + .proc _cputc + + cmp #$0A ; LF + bne @L4 +@L1: lda CURS_Y ; newline + cmp #(screenrows-1) + bne @L2 + lda #0 + beq @L3 +@L2: clc + adc #1 +@L3: jsr gotoy + lda #0 + jmp gotox + +@L4: + cmp #$20 ; ' ' + bne @L5 + lda #$00 + jmp @L10 +@L5: + cmp #$3F ; '?' + bne @L6 + lda #$02 + jmp @L9 +@L6: + cmp #$7C ; '|' + bne @L7 + lda #$06 + jmp @L9 +@L7: + cmp #$41 ; >= 'A' + bcc @L8 + and #$5F ; make upper case + sec + sbc #($41 - 17) + jmp @L9 +@L8: + sec ; >= '*' + sbc #($2A - 1) +@L9: + clc + adc txtcolor +@L10: + asl + pha + + lda #0 + sta ptr7800+1 + sta ptrtmp+1 + lda CURS_Y ; Find position on screen buffer + sta ptr7800 + lda #charsperline + sta ptrtmp + jsr umula0 + clc + adc CURS_X + bcc @L11 + inx +@L11: clc + adc #<(_screen) + sta ptr7800 + bcc @L12 + inx +@L12: txa + clc + adc #>(_screen) + sta ptr7800+1 + + pla ; Print character on screen + ldy #0 + sta (ptr7800),y + + lda CURS_X ; Increment cursor + cmp #(charsperline-1) + beq @L1 + clc + adc #1 + jmp gotox + + .endproc + +;------------------------------------------------------------------------------- +; force the init constructor to be imported + + .import initconio +conio_init = initconio diff --git a/libsrc/atari7800/extra/mono.s b/libsrc/atari7800/extra/mono.s new file mode 100644 index 000000000..5d99fc02a --- /dev/null +++ b/libsrc/atari7800/extra/mono.s @@ -0,0 +1,28 @@ +; +; Groepaz/Hitmen, 19.10.2015 +; +; import/overload stubs for the monochrome conio implementation +; + + ; mono_conio.s + .import _mono_screen + .export _screen := _mono_screen + + ; mono_clrscr.s + .import _mono_clrscr + .export _clrscr := _mono_clrscr + + ; mono_cputc.s + .import _mono_cputc + .export _cputc := _mono_cputc + + ; mono_font.s + .import _mono_font + .export _font := _mono_font + + ; mono_setcursor.s + .import mono_gotoxy + .export gotoxy := mono_gotoxy + .import _mono_gotoxy + .export _gotoxy := _mono_gotoxy + diff --git a/libsrc/atari7800/extzp.inc b/libsrc/atari7800/extzp.inc new file mode 100644 index 000000000..5990b5c86 --- /dev/null +++ b/libsrc/atari7800/extzp.inc @@ -0,0 +1,15 @@ +; +; extzp.inc for the Atari 7800 +; +; Karri Kaksonen, 2022-04-05 +; +; Assembler include file that imports the runtime zero page locations used +; by the atari7800 runtime, ready for usage in asm code. +; + + .global ptr7800: zp + .global ptrtmp: zp + .global cursorzone: zp + .global CURS_X: zp + .global CURS_Y: zp + diff --git a/libsrc/atari7800/extzp.s b/libsrc/atari7800/extzp.s new file mode 100644 index 000000000..8e8b73459 --- /dev/null +++ b/libsrc/atari7800/extzp.s @@ -0,0 +1,15 @@ +; +; Karri Kaksonen, 2022-04-05 +; +; zeropage locations for exclusive use by the library +; + + .include "extzp.inc" + + .segment "EXTZP" : zeropage + +ptr7800: .res 2 +ptrtmp: .res 2 +cursorzone: .res 2 +CURS_X: .res 1 +CURS_Y: .res 1 diff --git a/libsrc/atari7800/mono_clrscr.s b/libsrc/atari7800/mono_clrscr.s new file mode 100644 index 000000000..19f1fdfd6 --- /dev/null +++ b/libsrc/atari7800/mono_clrscr.s @@ -0,0 +1,27 @@ + + .include "atari7800.inc" + + .export _mono_clrscr + + .import _mono_screen + .import pushax, __bzero + .include "extzp.inc" + + .code + + .proc _mono_clrscr + + lda #<_mono_screen + ldx #>_mono_screen + jsr pushax + ldx #>(mono_charsperline * screenrows) + lda #<(mono_charsperline * screenrows) + jmp __bzero + + .endproc + +;------------------------------------------------------------------------------- +; force the init constructor to be imported + + .import mono_initconio +conio_init = mono_initconio diff --git a/libsrc/atari7800/mono_conio.s b/libsrc/atari7800/mono_conio.s new file mode 100644 index 000000000..63849aea7 --- /dev/null +++ b/libsrc/atari7800/mono_conio.s @@ -0,0 +1,231 @@ +; +; 2022-04-02, Karri Kaksonen +; +; The Atari 7800 has only 4k of RAM. So for a generic conio implementation +; the best alternative is to use indirect tile mapping with a character +; frame buffer +; + + .constructor mono_initconio + .include "atari7800.inc" + .include "extzp.inc" + .import _mono_font + .import _get_tv + .export _mono_screen + .export _mono_zones + .export _mono_dll + + .bss +_mono_screen: + .res mono_charsperline * screenrows + +;---------------------------------------------------------------------------- +; Macros used to generate lists + +.macro DLLentry offset, addr + .byte offset + .byte >addr + .byte addr + .byte hpos +.endmacro + +.macro XHeader addr, flags, palwidth, hpos + .byte addr + .byte palwidth + .byte hpos +.endmacro + +.macro TextZone row + ; Text + .byte <(_mono_screen + row * mono_charsperline) + .byte $60 + .byte >(_mono_screen + row * mono_charsperline) + .byte 12 + .byte 0 + .byte <(_mono_screen + row * mono_charsperline + 20) + .byte $60 + .byte >(_mono_screen + row * mono_charsperline + 20) + .byte 12 + .byte 80 + ; Cursor + .byte 95 + .byte 0 + .byte >_mono_font + .byte 0 +.endmacro + +;----------------------------------------------------------------------------- +; The Atari 7800 has only 4k of RAM. So for a generic conio implementation +; the best alternative is to use indirect tile mapping with a character +; frame buffer + .data + +_mono_zones: +zone0: TextZone 0 +nh: NullHeader 0, 0 +zone1: TextZone 1 + NullHeader 0, 0 +zone2: TextZone 2 + NullHeader 0, 0 +zone3: TextZone 3 + NullHeader 0, 0 +zone4: TextZone 4 + NullHeader 0, 0 +zone5: TextZone 5 + NullHeader 0, 0 +zone6: TextZone 6 + NullHeader 0, 0 +zone7: TextZone 7 + NullHeader 0, 0 +zone8: TextZone 8 + NullHeader 0, 0 +zone9: TextZone 9 + NullHeader 0, 0 +zone10: TextZone 10 + NullHeader 0, 0 +zone11: TextZone 11 + NullHeader 0, 0 +zone12: TextZone 12 + NullHeader 0, 0 +zone13: TextZone 13 + NullHeader 0, 0 +zone14: TextZone 14 + NullHeader 0, 0 +zone15: TextZone 15 + NullHeader 0, 0 +zone16: TextZone 16 + NullHeader 0, 0 +zone17: TextZone 17 + NullHeader 0, 0 +zone18: TextZone 18 + NullHeader 0, 0 +zone19: TextZone 19 + NullHeader 0, 0 +zone20: TextZone 20 + NullHeader 0, 0 +zone21: TextZone 21 + NullHeader 0, 0 +zone22: TextZone 22 + NullHeader 0, 0 +zone23: TextZone 23 + NullHeader 0, 0 +zone24: TextZone 24 + NullHeader 0, 0 +zone25: TextZone 25 + NullHeader 0, 0 +zone26: TextZone 26 + NullHeader 0, 0 +zone27: TextZone 27 + NullHeader 0, 0 + +_mono_dll: +PALscanlines: ; 25 lines + DLLentry 15, nh + DLLentry 8, nh + +Topscanlines: ; 9 lines + DLLentry 8, nh + +Displaylines: + DLLentry $80+7, zone0 ; NMI interrupt from end of prev zone + DLLentry 7, zone1 + DLLentry 7, zone2 + DLLentry 7, zone3 + DLLentry 7, zone4 + DLLentry 7, zone5 + DLLentry 7, zone6 + DLLentry 7, zone7 + DLLentry 7, zone8 + DLLentry 7, zone9 + DLLentry 7, zone10 + DLLentry 7, zone11 + DLLentry 7, zone12 + DLLentry 7, zone13 + DLLentry 7, zone14 + DLLentry 7, zone15 + DLLentry 7, zone16 + DLLentry 7, zone17 + DLLentry 7, zone18 + DLLentry 7, zone19 + DLLentry 7, zone20 + DLLentry 7, zone21 + DLLentry 7, zone22 + DLLentry 7, zone23 + DLLentry 7, zone24 + DLLentry 7, zone25 + DLLentry 7, zone26 + DLLentry 7, zone27 + +Bottomscanlines: + DLLentry $80+15, nh ; NMI interrupt at end of display + DLLentry 9, nh + DLLentry 15, nh + DLLentry 8, nh + +;----------------------------------------------------------------------------- +; Set up the screen to 320a mode +; + .segment "ONCE" + +CTRL_MODE160 .set 0 +CTRL_MODEAC .set 3 +CTRL_KANGOFF .set 0 +CTRL_BCBLACK .set 0 +CTRL_CHAR1B .set 0 +CTRL_CHAR2B .set $10 +CTRL_DMAON .set $40 +CTRL_CKOFF .set 0 + +;----------------------------------------------------------------------------- +; Initialize the conio display lists and zones +; + .proc mono_initconio + + jsr _get_tv + bne pal + lda #Topscanlines + sta DPPH + jmp vblankon +pal: lda #PALscanlines + sta DPPH +vblankon: + lda MSTAT + bmi vblankon +vblankoff: + lda MSTAT + bpl vblankoff + lda #>_mono_font + sta CHBASE + lda #(CTRL_MODEAC | CTRL_KANGOFF | CTRL_BCBLACK | CTRL_CHAR1B | CTRL_DMAON | CTRL_CKOFF) + sta CTRL + lda #$00 ; Black background + sta BKGRND + sta CURS_X + sta CURS_Y + lda #$33 ; Red + sta P0C1 + lda #$c8 ; Green + sta P0C2 + lda #$0f ; White + sta P0C3 + rts + + .endproc + diff --git a/libsrc/atari7800/mono_cputc.s b/libsrc/atari7800/mono_cputc.s new file mode 100644 index 000000000..aa6787e05 --- /dev/null +++ b/libsrc/atari7800/mono_cputc.s @@ -0,0 +1,102 @@ +; +; Mark Keates, Christian Groessler, Piotr Fusik, Karri Kaksonen +; +; void cputcxy (unsigned char x, unsigned char y, char c); +; void cputc (char c); +; + + .export _mono_cputc + .import mono_gotox, mono_gotoy, pusha0 + .import pushax + .import _mono_screen + + .include "atari7800.inc" + .include "extzp.inc" + + .code + +;--------------------------------------------------------------------------- +; 8x16 routine + +umula0: + ldy #8 ; Number of bits + lda #0 + lsr ptr7800 ; Get first bit into carry +@L0: bcc @L1 + + clc + adc ptrtmp + tax + lda ptrtmp+1 ; hi byte of left op + clc + adc ptr7800+1 + sta ptr7800+1 + txa + +@L1: ror ptr7800+1 + ror a + ror ptr7800 + dey + bne @L0 + tax + lda ptr7800 ; Load the result + rts + +;----------------------------------------------------------------------------- +; Put a character on screen +; +; The code will handle newlines that wrap to start of screen +; + .proc _mono_cputc + + cmp #$0A ; LF + bne @L4 +@L1: lda #0 ; newline + jsr mono_gotox + lda CURS_Y + cmp #(screenrows-1) + bne @L2 + lda #0 + beq @L3 +@L2: clc + adc #1 +@L3: jmp mono_gotoy + +@L4: + pha + + lda #0 + sta ptr7800+1 + sta ptrtmp+1 + lda CURS_Y ; Find position on screen buffer + sta ptr7800 + lda #mono_charsperline + sta ptrtmp + jsr umula0 + clc + adc CURS_X + bcc @L11 + inx +@L11: clc + adc #<(_mono_screen) + sta ptr7800 + bcc @L12 + inx +@L12: txa + clc + adc #>(_mono_screen) + sta ptr7800+1 + + pla ; Print character on screen + ldy #0 + sta (ptr7800),y + + lda CURS_X ; Increment cursor + cmp #(mono_charsperline-1) + beq @L1 + clc + adc #1 + jmp mono_gotox + + .endproc + diff --git a/libsrc/atari7800/mono_font.s b/libsrc/atari7800/mono_font.s new file mode 100644 index 000000000..74307ccfb --- /dev/null +++ b/libsrc/atari7800/mono_font.s @@ -0,0 +1,2065 @@ +; The internal font structure for Atari7800 needs a full set of 256 +; characters. Each character is 8 x 8 bits. +; The font consists of 8 rows of data: +; row7 +; row6 +; row5 +; row4 +; row3 +; row2 +; row1 +; row0 +; Each row is 256 bytes long + + .export _mono_font + .segment "RODATA" + .align 256 +_mono_font: + .byte $00 + .byte $7e + .byte $7e + .byte $00 + .byte $00 + .byte $7c + .byte $7c + .byte $00 + .byte $ff + .byte $00 + .byte $ff + .byte $78 + .byte $18 + .byte $e0 + .byte $c0 + .byte $99 + .byte $00 + .byte $00 + .byte $18 + .byte $00 + .byte $00 + .byte $78 + .byte $00 + .byte $ff + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $60 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $60 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $ff + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $f8 + .byte $00 + .byte $00 + .byte $78 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $f0 + .byte $1e + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $f8 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $78 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $38 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $f8 + .byte $00 + .byte $00 + .byte $18 + .byte $00 + .byte $30 + .byte $c7 + .byte $70 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $0f + .byte $03 + .byte $00 + .byte $00 + .byte $00 + .byte $88 + .byte $aa + .byte $ee + .byte $18 + .byte $18 + .byte $18 + .byte $36 + .byte $36 + .byte $18 + .byte $36 + .byte $36 + .byte $36 + .byte $00 + .byte $00 + .byte $00 + .byte $18 + .byte $00 + .byte $00 + .byte $18 + .byte $18 + .byte $00 + .byte $18 + .byte $18 + .byte $36 + .byte $00 + .byte $36 + .byte $00 + .byte $36 + .byte $36 + .byte $00 + .byte $36 + .byte $00 + .byte $00 + .byte $18 + .byte $36 + .byte $00 + .byte $00 + .byte $18 + .byte $36 + .byte $36 + .byte $18 + .byte $00 + .byte $18 + .byte $ff + .byte $ff + .byte $f0 + .byte $0f + .byte $00 + .byte $00 + .byte $c0 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $c0 + .byte $00 + .byte $fc + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $c0 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $18 + .byte $70 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $1c + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $81 + .byte $ff + .byte $10 + .byte $10 + .byte $38 + .byte $38 + .byte $00 + .byte $ff + .byte $3c + .byte $c3 + .byte $cc + .byte $7e + .byte $f0 + .byte $e6 + .byte $5a + .byte $80 + .byte $02 + .byte $3c + .byte $66 + .byte $1b + .byte $cc + .byte $7e + .byte $18 + .byte $18 + .byte $18 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $30 + .byte $00 + .byte $6c + .byte $30 + .byte $c6 + .byte $76 + .byte $00 + .byte $18 + .byte $60 + .byte $00 + .byte $00 + .byte $30 + .byte $00 + .byte $30 + .byte $80 + .byte $7c + .byte $fc + .byte $fc + .byte $78 + .byte $1e + .byte $78 + .byte $78 + .byte $30 + .byte $78 + .byte $70 + .byte $30 + .byte $30 + .byte $18 + .byte $00 + .byte $60 + .byte $30 + .byte $78 + .byte $cc + .byte $fc + .byte $3c + .byte $f8 + .byte $fe + .byte $f0 + .byte $3e + .byte $cc + .byte $78 + .byte $78 + .byte $e6 + .byte $fe + .byte $c6 + .byte $c6 + .byte $38 + .byte $f0 + .byte $1c + .byte $e6 + .byte $78 + .byte $78 + .byte $fc + .byte $30 + .byte $c6 + .byte $c6 + .byte $78 + .byte $fe + .byte $78 + .byte $02 + .byte $78 + .byte $00 + .byte $00 + .byte $00 + .byte $76 + .byte $dc + .byte $78 + .byte $76 + .byte $78 + .byte $f0 + .byte $0c + .byte $e6 + .byte $78 + .byte $cc + .byte $e6 + .byte $78 + .byte $c6 + .byte $cc + .byte $78 + .byte $60 + .byte $0c + .byte $f0 + .byte $f8 + .byte $18 + .byte $76 + .byte $30 + .byte $6c + .byte $c6 + .byte $0c + .byte $fc + .byte $1c + .byte $18 + .byte $e0 + .byte $00 + .byte $fe + .byte $0c + .byte $7e + .byte $78 + .byte $3f + .byte $7e + .byte $7e + .byte $7e + .byte $0c + .byte $3c + .byte $78 + .byte $78 + .byte $78 + .byte $3c + .byte $78 + .byte $c6 + .byte $cc + .byte $fc + .byte $7f + .byte $ce + .byte $78 + .byte $78 + .byte $78 + .byte $7e + .byte $7e + .byte $0c + .byte $18 + .byte $78 + .byte $18 + .byte $fc + .byte $30 + .byte $c6 + .byte $d8 + .byte $7e + .byte $78 + .byte $78 + .byte $7e + .byte $cc + .byte $cc + .byte $00 + .byte $00 + .byte $78 + .byte $00 + .byte $00 + .byte $cc + .byte $cf + .byte $18 + .byte $00 + .byte $00 + .byte $22 + .byte $55 + .byte $db + .byte $18 + .byte $18 + .byte $18 + .byte $36 + .byte $36 + .byte $18 + .byte $36 + .byte $36 + .byte $36 + .byte $00 + .byte $00 + .byte $00 + .byte $18 + .byte $00 + .byte $00 + .byte $18 + .byte $18 + .byte $00 + .byte $18 + .byte $18 + .byte $36 + .byte $00 + .byte $36 + .byte $00 + .byte $36 + .byte $36 + .byte $00 + .byte $36 + .byte $00 + .byte $00 + .byte $18 + .byte $36 + .byte $00 + .byte $00 + .byte $18 + .byte $36 + .byte $36 + .byte $18 + .byte $00 + .byte $18 + .byte $ff + .byte $ff + .byte $f0 + .byte $0f + .byte $00 + .byte $76 + .byte $c0 + .byte $c0 + .byte $6c + .byte $fc + .byte $70 + .byte $60 + .byte $18 + .byte $30 + .byte $38 + .byte $ee + .byte $78 + .byte $00 + .byte $60 + .byte $38 + .byte $cc + .byte $00 + .byte $fc + .byte $fc + .byte $fc + .byte $18 + .byte $d8 + .byte $30 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $3c + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $99 + .byte $e7 + .byte $38 + .byte $38 + .byte $7c + .byte $7c + .byte $18 + .byte $e7 + .byte $66 + .byte $99 + .byte $cc + .byte $18 + .byte $70 + .byte $67 + .byte $3c + .byte $e0 + .byte $0e + .byte $7e + .byte $00 + .byte $1b + .byte $38 + .byte $7e + .byte $3c + .byte $18 + .byte $3c + .byte $18 + .byte $30 + .byte $fe + .byte $24 + .byte $ff + .byte $18 + .byte $00 + .byte $00 + .byte $00 + .byte $6c + .byte $f8 + .byte $66 + .byte $cc + .byte $00 + .byte $30 + .byte $30 + .byte $66 + .byte $30 + .byte $30 + .byte $00 + .byte $30 + .byte $c0 + .byte $e6 + .byte $30 + .byte $cc + .byte $cc + .byte $0c + .byte $cc + .byte $cc + .byte $30 + .byte $cc + .byte $18 + .byte $30 + .byte $30 + .byte $30 + .byte $fc + .byte $30 + .byte $00 + .byte $c0 + .byte $cc + .byte $66 + .byte $66 + .byte $6c + .byte $62 + .byte $60 + .byte $66 + .byte $cc + .byte $30 + .byte $cc + .byte $66 + .byte $66 + .byte $c6 + .byte $c6 + .byte $6c + .byte $60 + .byte $78 + .byte $66 + .byte $cc + .byte $30 + .byte $cc + .byte $78 + .byte $ee + .byte $6c + .byte $30 + .byte $66 + .byte $60 + .byte $06 + .byte $18 + .byte $00 + .byte $00 + .byte $00 + .byte $cc + .byte $66 + .byte $cc + .byte $cc + .byte $c0 + .byte $60 + .byte $7c + .byte $66 + .byte $30 + .byte $cc + .byte $6c + .byte $30 + .byte $d6 + .byte $cc + .byte $cc + .byte $7c + .byte $7c + .byte $60 + .byte $0c + .byte $34 + .byte $cc + .byte $78 + .byte $fe + .byte $6c + .byte $7c + .byte $64 + .byte $30 + .byte $18 + .byte $30 + .byte $00 + .byte $c6 + .byte $18 + .byte $cc + .byte $c0 + .byte $66 + .byte $cc + .byte $cc + .byte $cc + .byte $78 + .byte $60 + .byte $c0 + .byte $c0 + .byte $30 + .byte $18 + .byte $30 + .byte $c6 + .byte $fc + .byte $60 + .byte $cc + .byte $cc + .byte $cc + .byte $cc + .byte $cc + .byte $cc + .byte $cc + .byte $7c + .byte $3c + .byte $cc + .byte $7e + .byte $e6 + .byte $fc + .byte $cf + .byte $18 + .byte $cc + .byte $30 + .byte $cc + .byte $cc + .byte $cc + .byte $dc + .byte $7e + .byte $7c + .byte $cc + .byte $c0 + .byte $0c + .byte $66 + .byte $6f + .byte $18 + .byte $33 + .byte $cc + .byte $88 + .byte $aa + .byte $77 + .byte $18 + .byte $18 + .byte $18 + .byte $36 + .byte $36 + .byte $18 + .byte $36 + .byte $36 + .byte $36 + .byte $00 + .byte $00 + .byte $00 + .byte $18 + .byte $00 + .byte $00 + .byte $18 + .byte $18 + .byte $00 + .byte $18 + .byte $18 + .byte $36 + .byte $00 + .byte $36 + .byte $00 + .byte $36 + .byte $36 + .byte $00 + .byte $36 + .byte $00 + .byte $00 + .byte $18 + .byte $36 + .byte $00 + .byte $00 + .byte $18 + .byte $36 + .byte $36 + .byte $18 + .byte $00 + .byte $18 + .byte $ff + .byte $ff + .byte $f0 + .byte $0f + .byte $00 + .byte $dc + .byte $f8 + .byte $c0 + .byte $6c + .byte $cc + .byte $d8 + .byte $7c + .byte $18 + .byte $78 + .byte $6c + .byte $6c + .byte $cc + .byte $7e + .byte $7e + .byte $60 + .byte $cc + .byte $fc + .byte $00 + .byte $00 + .byte $00 + .byte $18 + .byte $d8 + .byte $30 + .byte $dc + .byte $00 + .byte $00 + .byte $00 + .byte $6c + .byte $00 + .byte $00 + .byte $3c + .byte $00 + .byte $00 + .byte $bd + .byte $c3 + .byte $7c + .byte $7c + .byte $fe + .byte $fe + .byte $3c + .byte $c3 + .byte $42 + .byte $bd + .byte $cc + .byte $3c + .byte $30 + .byte $63 + .byte $e7 + .byte $f8 + .byte $3e + .byte $18 + .byte $66 + .byte $1b + .byte $6c + .byte $7e + .byte $7e + .byte $18 + .byte $7e + .byte $0c + .byte $60 + .byte $c0 + .byte $66 + .byte $ff + .byte $3c + .byte $00 + .byte $30 + .byte $00 + .byte $fe + .byte $0c + .byte $30 + .byte $dc + .byte $00 + .byte $60 + .byte $18 + .byte $3c + .byte $30 + .byte $00 + .byte $00 + .byte $00 + .byte $60 + .byte $f6 + .byte $30 + .byte $60 + .byte $0c + .byte $fe + .byte $0c + .byte $cc + .byte $30 + .byte $cc + .byte $0c + .byte $00 + .byte $00 + .byte $60 + .byte $00 + .byte $18 + .byte $30 + .byte $de + .byte $fc + .byte $66 + .byte $c0 + .byte $66 + .byte $68 + .byte $68 + .byte $ce + .byte $cc + .byte $30 + .byte $cc + .byte $6c + .byte $62 + .byte $d6 + .byte $ce + .byte $c6 + .byte $60 + .byte $dc + .byte $6c + .byte $1c + .byte $30 + .byte $cc + .byte $cc + .byte $fe + .byte $38 + .byte $30 + .byte $32 + .byte $60 + .byte $0c + .byte $18 + .byte $00 + .byte $00 + .byte $00 + .byte $7c + .byte $66 + .byte $c0 + .byte $cc + .byte $fc + .byte $60 + .byte $cc + .byte $66 + .byte $30 + .byte $0c + .byte $78 + .byte $30 + .byte $fe + .byte $cc + .byte $cc + .byte $66 + .byte $cc + .byte $66 + .byte $78 + .byte $30 + .byte $cc + .byte $cc + .byte $fe + .byte $38 + .byte $cc + .byte $30 + .byte $30 + .byte $18 + .byte $30 + .byte $00 + .byte $c6 + .byte $78 + .byte $cc + .byte $fc + .byte $3e + .byte $7c + .byte $7c + .byte $7c + .byte $c0 + .byte $7e + .byte $fc + .byte $fc + .byte $30 + .byte $18 + .byte $30 + .byte $fe + .byte $cc + .byte $78 + .byte $7f + .byte $cc + .byte $cc + .byte $cc + .byte $cc + .byte $cc + .byte $cc + .byte $cc + .byte $66 + .byte $cc + .byte $c0 + .byte $60 + .byte $30 + .byte $c6 + .byte $18 + .byte $7c + .byte $30 + .byte $cc + .byte $cc + .byte $cc + .byte $fc + .byte $00 + .byte $00 + .byte $c0 + .byte $c0 + .byte $0c + .byte $33 + .byte $37 + .byte $18 + .byte $66 + .byte $66 + .byte $22 + .byte $55 + .byte $db + .byte $18 + .byte $f8 + .byte $f8 + .byte $f6 + .byte $fe + .byte $f8 + .byte $f6 + .byte $36 + .byte $f6 + .byte $fe + .byte $fe + .byte $f8 + .byte $f8 + .byte $1f + .byte $ff + .byte $ff + .byte $1f + .byte $ff + .byte $ff + .byte $1f + .byte $37 + .byte $3f + .byte $37 + .byte $ff + .byte $f7 + .byte $37 + .byte $ff + .byte $f7 + .byte $ff + .byte $ff + .byte $ff + .byte $ff + .byte $3f + .byte $1f + .byte $1f + .byte $3f + .byte $ff + .byte $ff + .byte $f8 + .byte $1f + .byte $ff + .byte $ff + .byte $f0 + .byte $0f + .byte $00 + .byte $c8 + .byte $cc + .byte $c0 + .byte $6c + .byte $60 + .byte $d8 + .byte $66 + .byte $18 + .byte $cc + .byte $c6 + .byte $6c + .byte $cc + .byte $db + .byte $db + .byte $c0 + .byte $cc + .byte $00 + .byte $30 + .byte $60 + .byte $18 + .byte $18 + .byte $18 + .byte $00 + .byte $76 + .byte $00 + .byte $18 + .byte $18 + .byte $ec + .byte $6c + .byte $78 + .byte $3c + .byte $00 + .byte $00 + .byte $81 + .byte $ff + .byte $fe + .byte $fe + .byte $fe + .byte $7c + .byte $3c + .byte $c3 + .byte $42 + .byte $bd + .byte $7d + .byte $66 + .byte $30 + .byte $63 + .byte $e7 + .byte $fe + .byte $fe + .byte $18 + .byte $66 + .byte $7b + .byte $6c + .byte $00 + .byte $18 + .byte $18 + .byte $18 + .byte $fe + .byte $fe + .byte $c0 + .byte $ff + .byte $7e + .byte $7e + .byte $00 + .byte $30 + .byte $00 + .byte $6c + .byte $78 + .byte $18 + .byte $76 + .byte $00 + .byte $60 + .byte $18 + .byte $ff + .byte $fc + .byte $00 + .byte $fc + .byte $00 + .byte $30 + .byte $de + .byte $30 + .byte $38 + .byte $38 + .byte $cc + .byte $0c + .byte $f8 + .byte $18 + .byte $78 + .byte $7c + .byte $00 + .byte $00 + .byte $c0 + .byte $00 + .byte $0c + .byte $18 + .byte $de + .byte $cc + .byte $7c + .byte $c0 + .byte $66 + .byte $78 + .byte $78 + .byte $c0 + .byte $fc + .byte $30 + .byte $0c + .byte $78 + .byte $60 + .byte $fe + .byte $de + .byte $c6 + .byte $7c + .byte $cc + .byte $7c + .byte $70 + .byte $30 + .byte $cc + .byte $cc + .byte $d6 + .byte $38 + .byte $78 + .byte $18 + .byte $60 + .byte $18 + .byte $18 + .byte $c6 + .byte $00 + .byte $00 + .byte $0c + .byte $7c + .byte $cc + .byte $7c + .byte $cc + .byte $f0 + .byte $cc + .byte $76 + .byte $30 + .byte $0c + .byte $6c + .byte $30 + .byte $fe + .byte $cc + .byte $cc + .byte $66 + .byte $cc + .byte $76 + .byte $c0 + .byte $30 + .byte $cc + .byte $cc + .byte $d6 + .byte $6c + .byte $cc + .byte $98 + .byte $e0 + .byte $00 + .byte $1c + .byte $00 + .byte $6c + .byte $cc + .byte $cc + .byte $cc + .byte $06 + .byte $0c + .byte $0c + .byte $0c + .byte $c0 + .byte $66 + .byte $cc + .byte $cc + .byte $30 + .byte $18 + .byte $30 + .byte $c6 + .byte $78 + .byte $60 + .byte $0c + .byte $fe + .byte $78 + .byte $78 + .byte $78 + .byte $cc + .byte $cc + .byte $cc + .byte $66 + .byte $cc + .byte $c0 + .byte $f0 + .byte $fc + .byte $fa + .byte $3c + .byte $0c + .byte $30 + .byte $78 + .byte $cc + .byte $f8 + .byte $ec + .byte $3e + .byte $38 + .byte $60 + .byte $fc + .byte $fc + .byte $de + .byte $db + .byte $18 + .byte $cc + .byte $33 + .byte $88 + .byte $aa + .byte $ee + .byte $18 + .byte $18 + .byte $18 + .byte $36 + .byte $00 + .byte $18 + .byte $06 + .byte $36 + .byte $06 + .byte $06 + .byte $36 + .byte $18 + .byte $00 + .byte $18 + .byte $18 + .byte $00 + .byte $18 + .byte $00 + .byte $18 + .byte $18 + .byte $36 + .byte $30 + .byte $30 + .byte $00 + .byte $00 + .byte $30 + .byte $00 + .byte $00 + .byte $00 + .byte $36 + .byte $00 + .byte $00 + .byte $36 + .byte $18 + .byte $18 + .byte $00 + .byte $36 + .byte $18 + .byte $18 + .byte $00 + .byte $ff + .byte $00 + .byte $f0 + .byte $0f + .byte $ff + .byte $dc + .byte $f8 + .byte $c0 + .byte $6c + .byte $30 + .byte $d8 + .byte $66 + .byte $18 + .byte $cc + .byte $fe + .byte $c6 + .byte $7c + .byte $db + .byte $db + .byte $f8 + .byte $cc + .byte $fc + .byte $30 + .byte $30 + .byte $30 + .byte $18 + .byte $18 + .byte $fc + .byte $00 + .byte $38 + .byte $18 + .byte $00 + .byte $0c + .byte $6c + .byte $60 + .byte $3c + .byte $00 + .byte $00 + .byte $a5 + .byte $db + .byte $fe + .byte $7c + .byte $38 + .byte $38 + .byte $18 + .byte $e7 + .byte $66 + .byte $99 + .byte $0f + .byte $66 + .byte $3f + .byte $7f + .byte $3c + .byte $f8 + .byte $3e + .byte $7e + .byte $66 + .byte $db + .byte $38 + .byte $00 + .byte $7e + .byte $7e + .byte $18 + .byte $0c + .byte $60 + .byte $c0 + .byte $66 + .byte $3c + .byte $ff + .byte $00 + .byte $78 + .byte $6c + .byte $fe + .byte $c0 + .byte $cc + .byte $38 + .byte $c0 + .byte $60 + .byte $18 + .byte $3c + .byte $30 + .byte $00 + .byte $00 + .byte $00 + .byte $18 + .byte $ce + .byte $30 + .byte $0c + .byte $0c + .byte $6c + .byte $f8 + .byte $c0 + .byte $0c + .byte $cc + .byte $cc + .byte $30 + .byte $30 + .byte $60 + .byte $fc + .byte $18 + .byte $0c + .byte $de + .byte $cc + .byte $66 + .byte $c0 + .byte $66 + .byte $68 + .byte $68 + .byte $c0 + .byte $cc + .byte $30 + .byte $0c + .byte $6c + .byte $60 + .byte $fe + .byte $f6 + .byte $c6 + .byte $66 + .byte $cc + .byte $66 + .byte $e0 + .byte $30 + .byte $cc + .byte $cc + .byte $c6 + .byte $6c + .byte $cc + .byte $8c + .byte $60 + .byte $30 + .byte $18 + .byte $6c + .byte $00 + .byte $18 + .byte $78 + .byte $60 + .byte $78 + .byte $0c + .byte $78 + .byte $60 + .byte $76 + .byte $6c + .byte $70 + .byte $0c + .byte $66 + .byte $30 + .byte $cc + .byte $f8 + .byte $78 + .byte $dc + .byte $76 + .byte $dc + .byte $7c + .byte $7c + .byte $cc + .byte $cc + .byte $c6 + .byte $c6 + .byte $cc + .byte $fc + .byte $30 + .byte $18 + .byte $30 + .byte $00 + .byte $38 + .byte $c0 + .byte $00 + .byte $78 + .byte $3c + .byte $78 + .byte $78 + .byte $78 + .byte $78 + .byte $3c + .byte $78 + .byte $78 + .byte $70 + .byte $38 + .byte $70 + .byte $6c + .byte $00 + .byte $fc + .byte $7f + .byte $cc + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $3c + .byte $cc + .byte $7e + .byte $64 + .byte $78 + .byte $cc + .byte $18 + .byte $78 + .byte $70 + .byte $00 + .byte $00 + .byte $00 + .byte $cc + .byte $6c + .byte $6c + .byte $30 + .byte $00 + .byte $00 + .byte $cc + .byte $cc + .byte $00 + .byte $66 + .byte $66 + .byte $22 + .byte $55 + .byte $db + .byte $18 + .byte $18 + .byte $f8 + .byte $36 + .byte $00 + .byte $f8 + .byte $f6 + .byte $36 + .byte $fe + .byte $f6 + .byte $36 + .byte $f8 + .byte $00 + .byte $18 + .byte $18 + .byte $00 + .byte $18 + .byte $00 + .byte $18 + .byte $1f + .byte $36 + .byte $37 + .byte $3f + .byte $f7 + .byte $ff + .byte $37 + .byte $ff + .byte $f7 + .byte $ff + .byte $36 + .byte $ff + .byte $00 + .byte $36 + .byte $1f + .byte $1f + .byte $00 + .byte $36 + .byte $ff + .byte $18 + .byte $00 + .byte $ff + .byte $00 + .byte $f0 + .byte $0f + .byte $ff + .byte $76 + .byte $cc + .byte $cc + .byte $6c + .byte $60 + .byte $7e + .byte $66 + .byte $dc + .byte $78 + .byte $c6 + .byte $c6 + .byte $18 + .byte $7e + .byte $7e + .byte $c0 + .byte $cc + .byte $00 + .byte $fc + .byte $18 + .byte $60 + .byte $1b + .byte $18 + .byte $00 + .byte $dc + .byte $6c + .byte $00 + .byte $00 + .byte $0c + .byte $6c + .byte $30 + .byte $3c + .byte $00 + .byte $00 + .byte $81 + .byte $ff + .byte $fe + .byte $38 + .byte $7c + .byte $10 + .byte $00 + .byte $ff + .byte $3c + .byte $c3 + .byte $07 + .byte $66 + .byte $33 + .byte $63 + .byte $5a + .byte $e0 + .byte $0e + .byte $3c + .byte $66 + .byte $db + .byte $63 + .byte $00 + .byte $3c + .byte $3c + .byte $18 + .byte $18 + .byte $30 + .byte $00 + .byte $24 + .byte $18 + .byte $ff + .byte $00 + .byte $78 + .byte $6c + .byte $6c + .byte $7c + .byte $c6 + .byte $6c + .byte $60 + .byte $30 + .byte $30 + .byte $66 + .byte $30 + .byte $00 + .byte $00 + .byte $00 + .byte $0c + .byte $c6 + .byte $70 + .byte $cc + .byte $cc + .byte $3c + .byte $c0 + .byte $60 + .byte $cc + .byte $cc + .byte $cc + .byte $30 + .byte $30 + .byte $30 + .byte $00 + .byte $30 + .byte $cc + .byte $c6 + .byte $78 + .byte $66 + .byte $66 + .byte $6c + .byte $62 + .byte $62 + .byte $66 + .byte $cc + .byte $30 + .byte $0c + .byte $66 + .byte $60 + .byte $ee + .byte $e6 + .byte $6c + .byte $66 + .byte $cc + .byte $66 + .byte $cc + .byte $b4 + .byte $cc + .byte $cc + .byte $c6 + .byte $c6 + .byte $cc + .byte $c6 + .byte $60 + .byte $60 + .byte $18 + .byte $38 + .byte $00 + .byte $30 + .byte $00 + .byte $60 + .byte $00 + .byte $0c + .byte $00 + .byte $6c + .byte $00 + .byte $60 + .byte $00 + .byte $00 + .byte $60 + .byte $30 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $30 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $30 + .byte $18 + .byte $30 + .byte $dc + .byte $10 + .byte $cc + .byte $cc + .byte $00 + .byte $c3 + .byte $00 + .byte $00 + .byte $30 + .byte $00 + .byte $c3 + .byte $00 + .byte $00 + .byte $00 + .byte $c6 + .byte $00 + .byte $38 + .byte $30 + .byte $00 + .byte $00 + .byte $6c + .byte $cc + .byte $cc + .byte $e0 + .byte $cc + .byte $e0 + .byte $cc + .byte $18 + .byte $00 + .byte $18 + .byte $6c + .byte $cc + .byte $cc + .byte $1b + .byte $00 + .byte $00 + .byte $1c + .byte $1c + .byte $f8 + .byte $00 + .byte $6c + .byte $6c + .byte $00 + .byte $00 + .byte $00 + .byte $c6 + .byte $c6 + .byte $18 + .byte $33 + .byte $cc + .byte $88 + .byte $aa + .byte $77 + .byte $18 + .byte $18 + .byte $18 + .byte $36 + .byte $00 + .byte $00 + .byte $36 + .byte $36 + .byte $00 + .byte $36 + .byte $36 + .byte $18 + .byte $00 + .byte $18 + .byte $18 + .byte $00 + .byte $18 + .byte $00 + .byte $18 + .byte $18 + .byte $36 + .byte $36 + .byte $00 + .byte $36 + .byte $00 + .byte $36 + .byte $00 + .byte $36 + .byte $18 + .byte $36 + .byte $00 + .byte $00 + .byte $36 + .byte $18 + .byte $00 + .byte $00 + .byte $36 + .byte $18 + .byte $18 + .byte $00 + .byte $ff + .byte $00 + .byte $f0 + .byte $0f + .byte $ff + .byte $00 + .byte $78 + .byte $fc + .byte $fe + .byte $cc + .byte $00 + .byte $66 + .byte $76 + .byte $30 + .byte $6c + .byte $6c + .byte $30 + .byte $00 + .byte $0c + .byte $60 + .byte $cc + .byte $fc + .byte $30 + .byte $30 + .byte $30 + .byte $1b + .byte $18 + .byte $30 + .byte $76 + .byte $6c + .byte $00 + .byte $00 + .byte $0c + .byte $6c + .byte $18 + .byte $00 + .byte $00 + .byte $00 + .byte $7e + .byte $7e + .byte $6c + .byte $10 + .byte $38 + .byte $10 + .byte $00 + .byte $ff + .byte $00 + .byte $ff + .byte $0f + .byte $3c + .byte $3f + .byte $7f + .byte $99 + .byte $80 + .byte $02 + .byte $18 + .byte $66 + .byte $7f + .byte $3e + .byte $00 + .byte $18 + .byte $18 + .byte $18 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $30 + .byte $6c + .byte $6c + .byte $30 + .byte $00 + .byte $38 + .byte $60 + .byte $18 + .byte $60 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $06 + .byte $7c + .byte $30 + .byte $78 + .byte $78 + .byte $1c + .byte $fc + .byte $38 + .byte $fc + .byte $78 + .byte $78 + .byte $00 + .byte $00 + .byte $18 + .byte $00 + .byte $60 + .byte $78 + .byte $7c + .byte $30 + .byte $fc + .byte $3c + .byte $f8 + .byte $fe + .byte $fe + .byte $3c + .byte $cc + .byte $78 + .byte $1e + .byte $e6 + .byte $f0 + .byte $c6 + .byte $c6 + .byte $38 + .byte $fc + .byte $78 + .byte $fc + .byte $78 + .byte $fc + .byte $cc + .byte $cc + .byte $c6 + .byte $c6 + .byte $cc + .byte $fe + .byte $78 + .byte $c0 + .byte $78 + .byte $10 + .byte $00 + .byte $30 + .byte $00 + .byte $e0 + .byte $00 + .byte $1c + .byte $00 + .byte $38 + .byte $00 + .byte $e0 + .byte $30 + .byte $0c + .byte $e0 + .byte $70 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $10 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $1c + .byte $18 + .byte $e0 + .byte $76 + .byte $00 + .byte $78 + .byte $00 + .byte $1c + .byte $7e + .byte $cc + .byte $e0 + .byte $30 + .byte $00 + .byte $7e + .byte $cc + .byte $e0 + .byte $cc + .byte $7c + .byte $e0 + .byte $c6 + .byte $30 + .byte $1c + .byte $00 + .byte $3e + .byte $78 + .byte $00 + .byte $00 + .byte $78 + .byte $00 + .byte $00 + .byte $c3 + .byte $cc + .byte $18 + .byte $38 + .byte $cc + .byte $f8 + .byte $0e + .byte $1c + .byte $38 + .byte $00 + .byte $00 + .byte $00 + .byte $fc + .byte $3c + .byte $38 + .byte $30 + .byte $00 + .byte $00 + .byte $c3 + .byte $c3 + .byte $18 + .byte $00 + .byte $00 + .byte $22 + .byte $55 + .byte $db + .byte $18 + .byte $18 + .byte $18 + .byte $36 + .byte $00 + .byte $00 + .byte $36 + .byte $36 + .byte $00 + .byte $36 + .byte $36 + .byte $18 + .byte $00 + .byte $18 + .byte $18 + .byte $00 + .byte $18 + .byte $00 + .byte $18 + .byte $18 + .byte $36 + .byte $36 + .byte $00 + .byte $36 + .byte $00 + .byte $36 + .byte $00 + .byte $36 + .byte $18 + .byte $36 + .byte $00 + .byte $00 + .byte $36 + .byte $18 + .byte $00 + .byte $00 + .byte $36 + .byte $18 + .byte $18 + .byte $00 + .byte $ff + .byte $00 + .byte $f0 + .byte $0f + .byte $ff + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .byte $fc + .byte $00 + .byte $00 + .byte $00 + .byte $fc + .byte $38 + .byte $38 + .byte $1c + .byte $00 + .byte $06 + .byte $38 + .byte $78 + .byte $00 + .byte $30 + .byte $60 + .byte $18 + .byte $0e + .byte $18 + .byte $30 + .byte $00 + .byte $38 + .byte $00 + .byte $00 + .byte $0f + .byte $78 + .byte $70 + .byte $00 + .byte $00 diff --git a/libsrc/atari7800/mono_setcursor.s b/libsrc/atari7800/mono_setcursor.s new file mode 100644 index 000000000..02e0308f6 --- /dev/null +++ b/libsrc/atari7800/mono_setcursor.s @@ -0,0 +1,214 @@ +; +; 2022-04-03, Karri Kaksonen +; +; setcursor (unsigned char on); +; +; The Atari 7800 does not have a hw cursor. +; This module emulates a cursor to be used with the conio +; implementation. +; +; The actual cursor display is included in the conio dll +; but every scanline has the element silenced by default +; at the end of every zone. +; +; The way the cursor works is to silence it before the cursor +; position changes and enable it afterwards. +; +; In order to get some performance we have a pointer to the +; cursor header structure. This structure is always at the +; end of the zone. So the pointer changes when CURS_Y changes. +; +; There is so many dependencies that it makes sense to +; deal with all CURS_X, CURS_Y stuff in this file and +; definitely not allow direct access to the variables. +; + + .export mono_gotoxy, _mono_gotoxy, mono_gotox, mono_gotoy + .constructor mono_init_cursor + .interruptor mono_blink_cursor + + .importzp sp + .import _zonecounter + .import _mono_zones + .import cursor + .import pusha, incsp1, pusha0, pushax, popa + .include "atari7800.inc" + .include "extzp.inc" + + .macpack generic + + .data +;----------------------------------------------------------------------------- +; The variables used by cursor functions +; + +blink_time: + .byte 200 + + .code + +;--------------------------------------------------------------------------- +; 8x16 routine + +umula0: + ldy #8 ; Number of bits + lda #0 + lsr ptr7800 ; Get first bit into carry +@L0: bcc @L1 + + clc + adc ptrtmp + tax + lda ptrtmp+1 ; hi byte of left op + adc ptr7800+1 + sta ptr7800+1 + txa + +@L1: ror ptr7800+1 + ror a + ror ptr7800 + dey + bne @L0 + tax + lda ptr7800 ; Load the result + rts + +;----------------------------------------------------------------------------- +; Calculate cursorzone address +; You also need to set the cursorzone to point to the correct cursor Header +; at the end of line CURS_Y. +; Offset to cursor zone 5. To next line offset 11 +; cursorzone points to _mono_zones + CURS_Y * 16 + 10 +; A = CURS_Y + .proc calccursorzone + + sta ptr7800 + lda #16 + sta ptrtmp + lda #0 + sta ptr7800+1 + sta ptrtmp+1 + jsr umula0 + clc + adc #10 + bcc @L1 + inx +@L1: clc + adc #<_mono_zones + sta cursorzone ; calculate new cursorzone + txa + adc #>_mono_zones + sta cursorzone+1 + rts + + .endproc + +;----------------------------------------------------------------------------- +; Set cursor to Y position. +; You also need to set the cursorzone to point to the correct cursor Header +; at the end of line CURS_Y. +; Offset to cursor zone 5. To next line offset 11 +; cursorzone points to _mono_zones + CURS_Y * 11 + 5 +; +; cursorzone[1] = 0 when not CURS_Y, 31 if CURS_Y +; +; Disable cursor +; cursorzone[1] = 0 +; +; Enable cursor +; if showcursor cursorzone[1] = 31 +; + .proc mono_gotoy + + pha + lda CURS_Y + jsr calccursorzone + ldy #1 + lda #0 + sta (cursorzone),y ; disable cursor + pla + sta CURS_Y + jsr calccursorzone + lda cursor + beq @L1 + lda #31 ; enable cursor +@L1: ldy #1 + sta (cursorzone),y + rts + + .endproc + +;----------------------------------------------------------------------------- +; Set cursor to X position. +; You also need to set the hpos offset to the correct value on this line +; cursorzone[3] = 4 * CURS_X? +; + .proc mono_gotox + + sta CURS_X + ldy #3 + clc + rol + rol + sta (cursorzone),y + rts + + .endproc + +;----------------------------------------------------------------------------- +; Set cursor to desired position (X,Y) +; + .proc _mono_gotoxy + + jsr mono_gotoy + jsr popa + jmp mono_gotox + + .endproc + + .proc mono_gotoxy + jsr popa + jmp _mono_gotoxy + .endproc + +;----------------------------------------------------------------------------- +; Initialize cursorzone at startup +; Offset to cursor zone 5. +; + .proc mono_blink_cursor + lda _zonecounter + and #01 + beq @L3 + inc blink_time + bne @L3 + lda #200 + sta blink_time + ldy #0 + lda (cursorzone),y + cmp #32 + bne @L1 + lda #95 + bne @L2 +@L1: lda #32 +@L2: sta (cursorzone),y +@L3: rts + .endproc + +;----------------------------------------------------------------------------- +; Initialize cursorzone at startup +; Offset to cursor zone 5. +; + .segment "ONCE" +mono_init_cursor: + lda #0 + jsr calccursorzone + lda #0 + sta blink_time + rts + + +;----------------------------------------------------------------------------- +; force the init constructor to be imported + + .import mono_initconio +conio_init = mono_initconio diff --git a/libsrc/atari7800/setcursor.s b/libsrc/atari7800/setcursor.s new file mode 100644 index 000000000..f438de24f --- /dev/null +++ b/libsrc/atari7800/setcursor.s @@ -0,0 +1,214 @@ +; +; 2022-04-03, Karri Kaksonen +; +; setcursor (unsigned char on); +; +; The Atari 7800 does not have a hw cursor. +; This module emulates a cursor to be used with the conio +; implementation. +; +; The actual cursor display is included in the conio dll +; but every scanline has the element silenced by default +; at the end of every zone. +; +; The way the cursor works is to silence it before the cursor +; position changes and enable it afterwards. +; +; In order to get some performance we have a pointer to the +; cursor header structure. This structure is always at the +; end of the zone. So the pointer changes when CURS_Y changes. +; +; There is so many dependencies that it makes sense to +; deal with all CURS_X, CURS_Y stuff in this file and +; definitely not allow direct access to the variables. +; + + .export gotoxy, _gotoxy, gotox, gotoy + .constructor init_cursor + .interruptor blink_cursor + + .importzp sp + .import _zonecounter + .import _zones + .import cursor + .import pusha, incsp1, pusha0, pushax, popa + .include "atari7800.inc" + .include "extzp.inc" + + .macpack generic + + .data +;----------------------------------------------------------------------------- +; The variables used by cursor functions +; + +blink_time: + .byte 200 + + .code + +;--------------------------------------------------------------------------- +; 8x16 routine + +umula0: + ldy #8 ; Number of bits + lda #0 + lsr ptr7800 ; Get first bit into carry +@L0: bcc @L1 + + clc + adc ptrtmp + tax + lda ptrtmp+1 ; hi byte of left op + clc + adc ptr7800+1 + sta ptr7800+1 + txa + +@L1: ror ptr7800+1 + ror a + ror ptr7800 + dey + bne @L0 + tax + lda ptr7800 ; Load the result + rts + +;----------------------------------------------------------------------------- +; Calculate cursorzone address +; You also need to set the cursorzone to point to the correct cursor Header +; at the end of line CURS_Y. +; Offset to cursor zone 5. To next line offset 11 +; cursorzone points to _zones + CURS_Y * 11 + 5 +; A = CURS_Y + .proc calccursorzone + + sta ptr7800 + lda #11 + sta ptrtmp + lda #0 + sta ptr7800+1 + sta ptrtmp+1 + jsr umula0 + clc + adc #5 + bcc @L1 + inx +@L1: clc + adc #<_zones + sta cursorzone ; calculate new cursorzone + txa + adc #>_zones + sta cursorzone+1 + rts + + .endproc + +;----------------------------------------------------------------------------- +; Set cursor to Y position. +; You also need to set the cursorzone to point to the correct cursor Header +; at the end of line CURS_Y. +; Offset to cursor zone 5. To next line offset 11 +; cursorzone points to _zones + CURS_Y * 11 + 5 +; +; cursorzone[1] = 0 when not CURS_Y, 30 if CURS_Y +; +; Disable cursor +; cursorzone[1] = 0 +; +; Enable cursor +; if showcursor cursorzone[1] = 30 +; + .proc gotoy + + pha + lda CURS_Y + jsr calccursorzone + ldy #1 + lda #0 + sta (cursorzone),y ; disable cursor + pla + sta CURS_Y + jsr calccursorzone + lda cursor + beq @L1 + lda #30 ; enable cursor +@L1: ldy #1 + sta (cursorzone),y + rts + + .endproc + +;----------------------------------------------------------------------------- +; Set cursor to X position. +; You also need to set the hpos offset to the correct value on this line +; cursorzone[3] = 8 * CURS_X +; + .proc gotox + + sta CURS_X + ldy #3 + clc + rol + rol + rol + sta (cursorzone),y + rts + + .endproc + +;----------------------------------------------------------------------------- +; Set cursor to desired position (X,Y) +; + .proc _gotoxy + + jsr gotoy + jsr popa + jsr gotox + rts + .endproc + + .proc gotoxy + jsr popa + jmp _gotoxy + .endproc + +;----------------------------------------------------------------------------- +; Initialize cursorzone at startup +; Offset to cursor zone 5. +; + .proc blink_cursor + lda _zonecounter + and #01 + beq @L3 + inc blink_time + bne @L3 + lda #200 + sta blink_time + ldy #0 + lda (cursorzone),y + bne @L1 + lda #254 + bne @L2 +@L1: lda #0 +@L2: sta (cursorzone),y +@L3: rts + .endproc + +;----------------------------------------------------------------------------- +; Initialize cursorzone at startup +; Offset to cursor zone 5. +; + .segment "ONCE" +init_cursor: + lda #0 + jsr calccursorzone + lda #0 + sta blink_time + rts + +;----------------------------------------------------------------------------- +; force the init constructor to be imported + + .import initconio +conio_init = initconio diff --git a/libsrc/atari7800/textcolor.s b/libsrc/atari7800/textcolor.s new file mode 100644 index 000000000..1f8efced5 --- /dev/null +++ b/libsrc/atari7800/textcolor.s @@ -0,0 +1,53 @@ +; +; Karri Kaksonen, 2022-04-16 +; +; + + .export _textcolor + .export txtcolor + + .include "atari7800.inc" + + .data +;----------------------------------------------------------------------------- +; Holder of the text colour offset +; 0 = red, 42 = green, 84 = white +; +txtcolor: + .byte 0 + + .code + +;----------------------------------------------------------------------------- +; Change the text colour +; +; Logical colour names are +; 0 = red +; 1 = green +; 2 = white +; +; The routine will also return the previous textcolor +; + .proc _textcolor + + beq @L2 + sec + sbc #1 + beq @L1 + lda #84 + jmp @L2 +@L1: lda #42 +@L2: ldy txtcolor + sta txtcolor ; Store new textcolor + ldx #0 + tya + bne @L3 + rts ; Old colour was 0 +@L3: sec + sbc #42 + bne @L4 + lda #1 + rts ; Old colour was 1 +@L4: lda #2 + rts ; Old colour was 2 + .endproc diff --git a/libsrc/atari7800/wherex.s b/libsrc/atari7800/wherex.s new file mode 100644 index 000000000..4926f1479 --- /dev/null +++ b/libsrc/atari7800/wherex.s @@ -0,0 +1,19 @@ +; +; 2022-04-16, Karri Kaksonen +; +; unsigned char wherex() +; + + .export _wherex + .include "extzp.inc" + +;----------------------------------------------------------------------------- +; Get cursor X position +; + .proc _wherex + + ldx #0 + lda CURS_X + rts + .endproc + diff --git a/libsrc/atari7800/wherey.s b/libsrc/atari7800/wherey.s new file mode 100644 index 000000000..f105975c0 --- /dev/null +++ b/libsrc/atari7800/wherey.s @@ -0,0 +1,19 @@ +; +; 2022-04-16, Karri Kaksonen +; +; unsigned char wherey() +; + + .export _wherey + .include "extzp.inc" + +;----------------------------------------------------------------------------- +; Get cursor Y position +; + .proc _wherey + + ldx #0 + lda CURS_Y + rts + .endproc + diff --git a/libsrc/telestrat/cgetc.s b/libsrc/telestrat/cgetc.s index cad8814af..b76c62ee0 100644 --- a/libsrc/telestrat/cgetc.s +++ b/libsrc/telestrat/cgetc.s @@ -5,24 +5,38 @@ .import cursor + .export store_char + .include "telestrat.inc" .proc _cgetc - ; this routine could be quicker if we wrote in page 2 variables, - ; but it's better to use telemon routine in that case, because telemon can manage 4 I/O - ldx cursor ; if cursor equal to 0, then switch off cursor + ; This routine could be quicker if we wrote in page 2 variables, + ; But it's better to use telemon routine in that case, because telemon can manage 4 I/O + ldx cursor ; If cursor equal to 0, then switch off cursor beq switchoff_cursor ldx #$00 ; x is the first screen - BRK_TELEMON(XCSSCR) ; display cursor - jmp loop ; could be replaced by a bne/beq but 'jmp' is cleaner than a bne/beq which could expect some matters + BRK_TELEMON(XCSSCR) ; Display cursor + jmp start ; Could be replaced by a bne/beq but 'jmp' is cleaner than a bne/beq which could expect some matters switchoff_cursor: - ; at this step X is equal to $00, X must be set, because it's the id of the screen (telestrat can handle 4 virtuals screen) - BRK_TELEMON(XCOSCR) ; switch off cursor + ; At this step X is equal to $00, X must be set, because it's the id of the screen (telestrat can handle 4 virtuals screen) + BRK_TELEMON(XCOSCR) ; Switch off cursor -loop: - BRK_TELEMON XRD0 ; waits until key is pressed - bcs loop + +start: + lda store_char ; Does kbhit store a value in store_char ? + bne @out ; Yes, we returns A and we reset store_char +@wait_key: + BRK_TELEMON XRD0 ; Waits until key is pressed + bcs @wait_key + ldx #$00 + rts +@out: + ldx #$00 + stx store_char rts .endproc +.bss +store_char: + .byte 0 diff --git a/libsrc/telestrat/kbhit.s b/libsrc/telestrat/kbhit.s index 54e4bf4d8..aea345036 100644 --- a/libsrc/telestrat/kbhit.s +++ b/libsrc/telestrat/kbhit.s @@ -6,12 +6,24 @@ .export _kbhit + .import store_char + .include "telestrat.inc" _kbhit: - BRK_TELEMON XRD0 + lda store_char ; Check if a key has been detected previously + beq @call_telemon ; No, calls Telemon routine + lda #$01 ; There is a key pressed previously, return 1 ldx #$00 - txa - rol - eor #$01 + rts +@call_telemon: + BRK_TELEMON XRD0 + + ldx #$00 + bcs @no_char_action + sta store_char + lda #$01 + rts +@no_char_action: + tax rts diff --git a/src/Makefile b/src/Makefile index c8028204b..75b92394e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2,6 +2,12 @@ ifneq ($(shell echo),) CMD_EXE = 1 endif +ifneq ($(V),1) + Q=@ +else + Q= +endif + PROGS = ar65 \ ca65 \ cc65 \ @@ -62,9 +68,9 @@ $(info BUILD_ID: $(BUILD_ID)) CFLAGS += -MMD -MP -O3 -I common \ -Wall -Wextra -Wno-char-subscripts $(USER_CFLAGS) \ - -DCA65_INC="$(CA65_INC)" -DCC65_INC="$(CC65_INC)" -DCL65_TGT="$(CL65_TGT)" \ - -DLD65_LIB="$(LD65_LIB)" -DLD65_OBJ="$(LD65_OBJ)" -DLD65_CFG="$(LD65_CFG)" \ - -DBUILD_ID="$(BUILD_ID)" + -DCA65_INC="\"$(CA65_INC)\"" -DCC65_INC="\"$(CC65_INC)\"" -DCL65_TGT="\"$(CL65_TGT)\"" \ + -DLD65_LIB="\"$(LD65_LIB)\"" -DLD65_OBJ="\"$(LD65_OBJ)\"" -DLD65_CFG="\"$(LD65_CFG)\"" \ + -DBUILD_ID="\"$(BUILD_ID)\"" LDLIBS += -lm @@ -147,7 +153,7 @@ endef # PROG_template ../wrk/%.o: %.c @echo $< - @$(CC) -c $(CFLAGS) -o $@ $< + $(Q)$(CC) -c $(CFLAGS) -o $@ $< ../bin: @$(call MKDIR,$@) diff --git a/src/ca65/incpath.c b/src/ca65/incpath.c index ff21b175d..42e54b2da 100644 --- a/src/ca65/incpath.c +++ b/src/ca65/incpath.c @@ -76,7 +76,7 @@ void FinishIncludePaths (void) /* Add some compiled-in search paths if defined at compile time. */ #if defined(CA65_INC) && !defined(_WIN32) - AddSearchPath (IncSearchPath, STRINGIZE (CA65_INC)); + AddSearchPath (IncSearchPath, CA65_INC); #endif /* Add paths relative to the parent directory of the Windows binary. */ diff --git a/src/cc65/incpath.c b/src/cc65/incpath.c index ab164d5ca..d32614cf9 100644 --- a/src/cc65/incpath.c +++ b/src/cc65/incpath.c @@ -77,7 +77,7 @@ void FinishIncludePaths (void) /* Add some compiled-in search paths if defined at compile time. */ #if defined(CC65_INC) && !defined(_WIN32) - AddSearchPath (SysIncSearchPath, STRINGIZE (CC65_INC)); + AddSearchPath (SysIncSearchPath, CC65_INC); #endif /* Add paths relative to the parent directory of the Windows binary. */ diff --git a/src/cl65/main.c b/src/cl65/main.c index e032baee4..701355904 100644 --- a/src/cl65/main.c +++ b/src/cl65/main.c @@ -1216,7 +1216,7 @@ static void OptPrintTargetPath (const char* Opt attribute ((unused)), SearchPaths* TargetPaths = NewSearchPath (); AddSubSearchPathFromEnv (TargetPaths, "CC65_HOME", "target"); #if defined(CL65_TGT) && !defined(_WIN32) - AddSearchPath (TargetPaths, STRINGIZE (CL65_TGT)); + AddSearchPath (TargetPaths, CL65_TGT); #endif AddSubSearchPathFromWinBin (TargetPaths, "target"); diff --git a/src/common/searchpath.h b/src/common/searchpath.h index 974886a67..f078c0799 100644 --- a/src/common/searchpath.h +++ b/src/common/searchpath.h @@ -48,10 +48,6 @@ -/* Convert argument to C string */ -#define _STRINGIZE(arg) #arg -#define STRINGIZE(arg) _STRINGIZE(arg) - /* A search path is a pointer to the list */ typedef struct Collection SearchPaths; diff --git a/src/common/version.c b/src/common/version.c index 992be45ee..2f19f0466 100644 --- a/src/common/version.c +++ b/src/common/version.c @@ -62,7 +62,7 @@ const char* GetVersionAsString (void) { static char Buf[60]; #if defined(BUILD_ID) - xsnprintf (Buf, sizeof (Buf), "%u.%u - %s", VER_MAJOR, VER_MINOR, STRINGIZE (BUILD_ID)); + xsnprintf (Buf, sizeof (Buf), "%u.%u - %s", VER_MAJOR, VER_MINOR, BUILD_ID); #else xsnprintf (Buf, sizeof (Buf), "%u.%u", VER_MAJOR, VER_MINOR); #endif diff --git a/src/ld65/filepath.c b/src/ld65/filepath.c index 17cd451de..f722ad34b 100644 --- a/src/ld65/filepath.c +++ b/src/ld65/filepath.c @@ -89,13 +89,13 @@ void InitSearchPaths (void) /* Add some compiled-in search paths if defined at compile time. */ #if defined(LD65_LIB) && !defined(_WIN32) - AddSearchPath (LibDefaultPath, STRINGIZE (LD65_LIB)); + AddSearchPath (LibDefaultPath, LD65_LIB); #endif #if defined(LD65_OBJ) && !defined(_WIN32) - AddSearchPath (ObjDefaultPath, STRINGIZE (LD65_OBJ)); + AddSearchPath (ObjDefaultPath, LD65_OBJ); #endif #if defined(LD65_CFG) && !defined(_WIN32) - AddSearchPath (CfgDefaultPath, STRINGIZE (LD65_CFG)); + AddSearchPath (CfgDefaultPath, LD65_CFG); #endif /* Add paths relative to the parent directory of the Windows binary. */