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 +