diff --git a/KickC/c.bat b/KickC/c.bat deleted file mode 100644 index 1d254c1..0000000 --- a/KickC/c.bat +++ /dev/null @@ -1,6 +0,0 @@ -@echo *** APPLE 1 *** -call kickc -t asm6502 -D=APPLE1 test.c -o test_apple1.prg -e -copy test.prg test_apple1.prg -@echo *** VIC20 *** -call kickc -t VIC20 -D=VIC20 test.c -o test_vic20.prg -e -copy test.prg test_vic20.prg diff --git a/KickC/test.c b/KickC/test.c deleted file mode 100644 index bf0082f..0000000 --- a/KickC/test.c +++ /dev/null @@ -1,305 +0,0 @@ -#ifdef APPLE1 - // APPLE1 - const word WOZMON = 0xFF1F; // enters monitor - const word ECHO = 0xFFEF; // output ascii character in A (A not destroyed) - const word PRBYTE = 0xFFDC; // print hex byte in A (A destroyed) - const word VDP_DATA = 0xC000; // TMS9918 data port (VRAM) - const word VDP_REG = 0xC001; // TMS9918 register port (write) or status (read) -#else - // VIC20 - const word ECHO = 0xFFD2; // chrout routine in kernal rom - const word VDP_DATA = 0xA000; // TMS9918 data port (VRAM) - const word VDP_REG = 0xA001; // TMS9918 register port (write) or status (read) -#endif - -// typedef unsigned char byte; -// typedef unsigned int word; - -// TMS9918 interface flags -const byte WRITE_TO_REG = 0b10000000; -const byte WRITE_TO_VRAM = 0b01000000; -const byte READ_FROM_VRAM = 0b00000000; - -#define POKE(a,b) (*((byte *)(a))=(byte)(b)) -#define PEEK(a) (*((byte *)(a))) - -// puts a character on the apple1 screen using the WOZMON routine -void woz_putc(byte c) { - asm { - lda c - jsr ECHO - } -} - -// returns to WOZMON prompt -void woz_mon() { - #ifdef APPLE1 - asm { - jmp WOZMON - } - #endif -} - -// sets the VRAM address on the TMS9918 -void set_vram_addr(word addr) { - POKE(VDP_REG,addr & 0b00111111)|WRITE_TO_VRAM); -} - -// sets the VRAM address on the TMS9918 -void set_vram_read_addr(word addr) { - POKE(VDP_REG,addr & 0b00111111)|READ_FROM_VRAM); -} - -// writes a value to a TMS9918 register (0-7) -void write_reg(byte regnum, byte val) { - // nops are not required - POKE(VDP_REG, val); - POKE(VDP_REG, (regnum & 0b00001111)|WRITE_TO_REG); -} - -word tms_cursor; - -#include "laser500_font.ascii.c" - -// SCREEN 1 VALUES - -// sprite patterns: $0000 -// pattern table: $0800 (256*8) -// sprite attributes: $1000 -// unused: $1080 -// name table: $1400 (32*24) -// unused: $1800 -// color table: $2000 (32) -// unused $2020-$3FFF - -const word SCREEN1_PATTERN_TABLE = 0x0800; -const word SCREEN1_NAME_TABLE = 0x1400; -const word SCREEN1_COLOR_TABLE = 0x2000; -const word SCREEN1_SPRITE_PATTERNS = 0x0000; -const word SCREEN1_SPRITE_ATTRS = 0x1000; -const word SCREEN1_SIZE = (32*24); - -byte SCREEN1_TABLE[8] = { - 0x00, 0xc0, 0x05, 0x80, 0x01, 0x20, 0x00, 0x25 -}; - -// loads the Laser 500 font on the pattern table -void SCREEN1_LOAD_FONT() { - - static byte *source = FONT; - static word i; - - // start writing into VRAM from space character - set_vram_addr(SCREEN1_PATTERN_TABLE+(32*8)); - for(i=0;i<768;i++) { - POKE(VDP_DATA, *source++); - } - - // reverse font - source = FONT; - set_vram_addr(SCREEN1_PATTERN_TABLE+((128+32)*8)); - for(i=0;i<768;i++) { - POKE(VDP_DATA, ~(*source++)); - } -} - -// prints character to TMS (SCREEN 1 MODE) -void SCREEN1_PUTCHAR(byte c) { - set_vram_addr(tms_cursor++); - POKE(VDP_DATA, c); -} - -// prints 0 terminated string pointed by YA -void SCREEN1_PUTS(byte *s) { - while(*s) { - SCREEN1_PUTCHAR(*s++); - } -} - -void SCREEN1_HOME() { - tms_cursor = SCREEN1_NAME_TABLE; -} - -void SCREEN1_LOCATEXY(byte x, byte y) { - tms_cursor = SCREEN1_NAME_TABLE + ((word)y)*32 + x; -} - -void SCREEN1_INIT() { - for(byte i=0;i<8;i++) { - write_reg(i, SCREEN1_TABLE[i]); - } -} - -void SCREEN1_FILL() { - // fills name table with spaces (32) - set_vram_addr(SCREEN1_NAME_TABLE); - for(word i=0;i> (x%8); - byte data; - - set_vram_read_addr(paddr); - data = PEEK(VDP_DATA); - set_vram_addr(paddr); - POKE(VDP_DATA,data | pattern); -} - -void screen1_square_sprites() { - // fills first sprite pattern with 255 - set_vram_addr(SCREEN1_SPRITE_PATTERNS); // start writing in the sprite patterns - for(byte i=0;i<8;i++) { - POKE(VDP_DATA, 255); - } - - // set sprite coordinates - set_vram_addr(SCREEN1_SPRITE_ATTRS); // start writing in the sprite attribute - for(byte i=0;i<32;i++) { - POKE(VDP_DATA,(6+i)*8); // y coordinate - POKE(VDP_DATA,(6+i)*8); // x coordinate - POKE(VDP_DATA,0); // name - POKE(VDP_DATA,i); // color - } -} - -void screen2_square_sprites() { - // fills first sprite pattern with 255 - set_vram_addr(SCREEN2_SPRITE_PATTERNS); // start writing in the sprite patterns - for(byte i=0;i<8;i++) { - POKE(VDP_DATA, 0); - } - - // set sprite coordinates - set_vram_addr(SCREEN2_SPRITE_ATTRS); // start writing in the sprite attribute - for(byte i=0;i<32;i++) { - POKE(VDP_DATA,0); // y coordinate - POKE(VDP_DATA,0); // x coordinate - POKE(VDP_DATA,0); // name - POKE(VDP_DATA,i); // color - } -} - -void main() { - if(1) { - SCREEN1_INIT(); - SCREEN1_FILL(); - SCREEN1_LOAD_FONT(); - - SCREEN1_HOME(); SCREEN1_PUTS("*** P-LAB VIDEO CARD SYSTEM ***"); - SCREEN1_LOCATEXY(0, 2); SCREEN1_PUTS("16K VRAM BYTES FREE"); - SCREEN1_LOCATEXY(0, 4); SCREEN1_PUTS("READY."); - - SCREEN1_LOCATEXY(0, 10); - for(word i=0;i<256;i++) SCREEN1_PUTCHAR((byte)i); - - screen1_square_sprites(); - } - - if(0) { - SCREEN2_INIT(); - SCREEN2_FILL(); - screen2_square_sprites(); - //SCREEN2_PUTC(65,1,1,0x1F); - - SCREEN2_PUTS(0,0,0x1F,"*** P-LAB VIDEO CARD SYSTEM ***"); - SCREEN2_PUTS(0,2,0x1F,"16K VRAM BYTES FREE"); - SCREEN2_PUTS(0,4,0x1F,"READY."); - - for(byte i=0;i<16;i++) { - SCREEN2_PUTS(5,(byte)(6+i),(byte)(((15-i)<<4)+i)," COLOR "); - } - - for(byte i=0;i<192;i++) { - SCREEN2_PSET((byte)i ,(byte)i/2); - SCREEN2_PSET((byte)i ,(byte)i); - SCREEN2_PSET((byte)i/2,(byte)i); - } - } - - woz_putc(42); - woz_mon(); -} - diff --git a/README.md b/README.md index 7883eb7..7bb2890 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,10 @@ Library and demos for the Apple-1 TMS9918 video card by P-LAB. # USAGE (Windows) -- `env.bat` sets CC65 path variable (run it once) +- `env_kick.bat` sets KickC compiler path variable (run it once) - `c.bat` compiles `test.c` for both VIC-20 and Apple-1 - `test_vic20.prg` runs on the "hybrid" VIC-20 emulator -- `node hexdump` gives the output in WOZMON format for the Apple-1 +- `node hexdump` puts `test_apple1.prg` into WOZMON format for the Apple-1 Note: Apple-1 start address is $4000, with TMS address range $C000-$C001 diff --git a/c.bat b/c.bat index 1819642..f69fb91 100644 --- a/c.bat +++ b/c.bat @@ -1,4 +1,8 @@ -cl65 -D APPLE1 --target none --start-addr $4000 -O test.c -o test_apple1.prg -cl65 --listing test.lst -D VIC20 --target vic20 -O test.c -o test_vic20.prg - +@echo ======================== APPLE 1 ================================================= +call kickc -t asm6502 -D=APPLE1 test.c -o test_apple1.prg -e +copy test.prg test_apple1.prg +@echo ======================== VIC20 =================================================== +call kickc -t VIC20 -D=VIC20 test.c -o test_vic20.prg -e +rem call kickc -vasmoptimize -vasmout -vcreate -vfragment -vliverange -vloop -vnonoptimize -voptimize -vparse -vsequence -vsizeinfo -vunroll -vuplift -t VIC20 -D=VIC20 test.c -o test_vic20.prg -e +copy test.prg test_vic20.prg diff --git a/cc65/c.bat b/cc65/c.bat new file mode 100644 index 0000000..1819642 --- /dev/null +++ b/cc65/c.bat @@ -0,0 +1,4 @@ +cl65 -D APPLE1 --target none --start-addr $4000 -O test.c -o test_apple1.prg +cl65 --listing test.lst -D VIC20 --target vic20 -O test.c -o test_vic20.prg + + diff --git a/cbm_ascii_charmap.h b/cc65/cbm_ascii_charmap.h similarity index 100% rename from cbm_ascii_charmap.h rename to cc65/cbm_ascii_charmap.h diff --git a/env.bat b/cc65/env.bat similarity index 100% rename from env.bat rename to cc65/env.bat diff --git a/KickC/laser500_font.ascii.c b/cc65/laser500_font.ascii.c similarity index 100% rename from KickC/laser500_font.ascii.c rename to cc65/laser500_font.ascii.c diff --git a/screen1.c b/cc65/screen1.c similarity index 100% rename from screen1.c rename to cc65/screen1.c diff --git a/screen2.c b/cc65/screen2.c similarity index 100% rename from screen2.c rename to cc65/screen2.c diff --git a/cc65/test.c b/cc65/test.c new file mode 100644 index 0000000..30f18ae --- /dev/null +++ b/cc65/test.c @@ -0,0 +1,157 @@ +#ifdef APPLE1 + #define WOZMON 0xFF1F // enters monitor + #define ECHO 0xFFEF // output ascii character in A (A not destroyed) + #define PRBYTE 0xFFDC // print hex byte in A (A destroyed) + #define VDP_DATA 0xC000 // TMS9918 data port (VRAM) + #define VDP_REG 0xC001 // TMS9918 register port (write) or status (read) +#endif + +#ifdef VIC20 + #define ECHO 0xFFD2 // chrout routine in kernal rom + #define VDP_DATA 0xA000 // TMS9918 data port (VRAM) + #define VDP_REG 0xA001 // TMS9918 register port (write) or status (read) + + #include "cbm_ascii_charmap.h" // allow VIC-20 to work with pure ASCII + +#endif + +// TMS9918 interface flags +#define WRITE_TO_REG 0b10000000 +#define WRITE_TO_VRAM 0b01000000 +#define READ_FROM_VRAM 0b00000000 + +// utils +typedef unsigned char byte; +typedef unsigned int word; + +#define POKE(a,b) (*((byte *)(a))=(byte)(b)) +#define PEEK(a) (*((byte *)(a))) + +// puts a character on the apple1 screen using the WOZMON routine +void fastcall woz_putc(byte c) { + asm("jsr %w", ECHO); +} + +// returns to WOZMON prompt +void woz_mon() { + #ifdef APPLE1 + asm("jmp %w", WOZMON); + #endif +} + +// sets the VRAM address on the TMS9918 +void fastcall set_vram_addr(word addr) { + asm("sta %w", VDP_REG); // write address low byte + // nops here ? + asm("txa"); // X = addres high byte + asm("and #%b", 0b00111111); // mask address high byte + asm("ora #%b", WRITE_TO_VRAM); // set "write to vram" flag bits "01" upper bits ("00" for read) + asm("sta %w", VDP_REG); // write flags and address high byte + // nops here ? +} + +// sets the VRAM address on the TMS9918 +void fastcall set_vram_read_addr(word addr) { + asm("sta %w", VDP_REG); // write address low byte + // nops here ? + asm("txa"); // X = addres high byte + asm("and #%b", 0b00111111); // mask address high byte + asm("ora #%b", READ_FROM_VRAM); // set "write to vram" flag bits "01" upper bits ("00" for read) + asm("sta %w", VDP_REG); // write flags and address high byte + // nops here ? +} + +// writes a value to a TMS9918 register (0-7) +void write_reg(byte regnum, byte val) { + // nops are not required + POKE(VDP_REG, val); + POKE(VDP_REG, (regnum & 0b00001111)|WRITE_TO_REG); +} + +static word tms_cursor; + +#include "laser500_font.ascii.c" +#include "screen1.c" +#include "screen2.c" + +void screen1_square_sprites() { + static byte i; + + // fills first sprite pattern with 255 + set_vram_addr(SCREEN1_SPRITE_PATTERNS); // start writing in the sprite patterns + for(i=0;i<8;i++) { + POKE(VDP_DATA, 255); + } + + // set sprite coordinates + set_vram_addr(SCREEN1_SPRITE_ATTRS); // start writing in the sprite attribute + for(i=0;i<32;i++) { + POKE(VDP_DATA,(6+i)*8); // y coordinate + POKE(VDP_DATA,(6+i)*8); // x coordinate + POKE(VDP_DATA,0); // name + POKE(VDP_DATA,i); // color + } +} + +void screen2_square_sprites() { + static byte i; + + // fills first sprite pattern with 255 + set_vram_addr(SCREEN2_SPRITE_PATTERNS); // start writing in the sprite patterns + for(i=0;i<8;i++) { + POKE(VDP_DATA, 0); + } + + // set sprite coordinates + set_vram_addr(SCREEN2_SPRITE_ATTRS); // start writing in the sprite attribute + for(i=0;i<32;i++) { + POKE(VDP_DATA,0); // y coordinate + POKE(VDP_DATA,0); // x coordinate + POKE(VDP_DATA,0); // name + POKE(VDP_DATA,i); // color + } +} + +void main() { + word i; + + if(0) { + SCREEN1_INIT(); + SCREEN1_FILL(); + SCREEN1_LOAD_FONT(); + + SCREEN1_HOME(); SCREEN1_PUTS("*** P-LAB VIDEO CARD SYSTEM ***"); + SCREEN1_LOCATEXY(0, 2); SCREEN1_PUTS("16K VRAM BYTES FREE"); + SCREEN1_LOCATEXY(0, 4); SCREEN1_PUTS("READY."); + + SCREEN1_LOCATEXY(0, 10); + for(i=0;i<256;i++) SCREEN1_PUTCHAR(i); + + screen1_square_sprites(); + } + + if(1) { + SCREEN2_INIT(); + SCREEN2_FILL(); + screen2_square_sprites(); + //SCREEN2_PUTC(65,1,1,0x1F); + + SCREEN2_PUTS(0,0,0x1F,"*** P-LAB VIDEO CARD SYSTEM ***"); + SCREEN2_PUTS(0,2,0x1F,"16K VRAM BYTES FREE"); + SCREEN2_PUTS(0,4,0x1F,"READY."); + + for(i=0;i<16;i++) { + SCREEN2_PUTS(5,6+i,((15-i)<<4)+i," COLOR "); + } + + for(i=0;i<192;i++) { + SCREEN2_PSET(i,i/2); + SCREEN2_PSET(i,i); + SCREEN2_PSET(i/2,i); + } + } + + woz_putc(42); + woz_mon(); +} + diff --git a/KickC/env_kickc.bat b/env_kickc.bat similarity index 100% rename from KickC/env_kickc.bat rename to env_kickc.bat diff --git a/test.c b/test.c index 30f18ae..4cd4b3c 100644 --- a/test.c +++ b/test.c @@ -1,156 +1,337 @@ +// TODO verificare NOPs + #ifdef APPLE1 - #define WOZMON 0xFF1F // enters monitor - #define ECHO 0xFFEF // output ascii character in A (A not destroyed) - #define PRBYTE 0xFFDC // print hex byte in A (A destroyed) - #define VDP_DATA 0xC000 // TMS9918 data port (VRAM) - #define VDP_REG 0xC001 // TMS9918 register port (write) or status (read) + // APPLE1 + #pragma start_address(0x4000) + const word WOZMON = 0xFF1F; // enters monitor + const word ECHO = 0xFFEF; // output ascii character in A (A not destroyed) + const word PRBYTE = 0xFFDC; // print hex byte in A (A destroyed) + const word KEY_DATA = 0xd010; // read key + const word KEY_CTRL = 0xd011; // control port + const word TERM_DATA = 0xd012; // write ascii + const word TERM_CTRL = 0xd013; // control port + + const byte *VDP_DATA = 0xC000; // TMS9918 data port (VRAM) + const byte *VDP_REG = 0xC001; // TMS9918 register port (write) or status (read) +#else + // VIC20 + const word ECHO = 0xFFD2; // chrout routine in kernal rom + const word GETIN = 0xFFE4; // GETIN keyboard read routine + const byte *VDP_DATA = 0xA000; // TMS9918 data port (VRAM) + const byte *VDP_REG = 0xA001; // TMS9918 register port (write) or status (read) #endif -#ifdef VIC20 - #define ECHO 0xFFD2 // chrout routine in kernal rom - #define VDP_DATA 0xA000 // TMS9918 data port (VRAM) - #define VDP_REG 0xA001 // TMS9918 register port (write) or status (read) - - #include "cbm_ascii_charmap.h" // allow VIC-20 to work with pure ASCII - -#endif +// typedef unsigned char byte; +// typedef unsigned int word; // TMS9918 interface flags -#define WRITE_TO_REG 0b10000000 -#define WRITE_TO_VRAM 0b01000000 -#define READ_FROM_VRAM 0b00000000 - -// utils -typedef unsigned char byte; -typedef unsigned int word; +const byte WRITE_TO_REG = 0b10000000; +const byte WRITE_TO_VRAM = 0b01000000; +const byte READ_FROM_VRAM = 0b00000000; #define POKE(a,b) (*((byte *)(a))=(byte)(b)) #define PEEK(a) (*((byte *)(a))) +#define NOP asm { nop } + +#define TMS_WRITE_REG(a) (*VDP_REG=(byte)(a)); +#define TMS_WRITE_DATA(a) (*VDP_DATA=(byte)(a)); +#define TMS_READ_DATA (*VDP_DATA); + // puts a character on the apple1 screen using the WOZMON routine -void fastcall woz_putc(byte c) { - asm("jsr %w", ECHO); +void woz_putc(byte c) { + asm { + lda c + jsr ECHO + } } // returns to WOZMON prompt void woz_mon() { #ifdef APPLE1 - asm("jmp %w", WOZMON); + asm { + jmp WOZMON + } #endif } -// sets the VRAM address on the TMS9918 -void fastcall set_vram_addr(word addr) { - asm("sta %w", VDP_REG); // write address low byte - // nops here ? - asm("txa"); // X = addres high byte - asm("and #%b", 0b00111111); // mask address high byte - asm("ora #%b", WRITE_TO_VRAM); // set "write to vram" flag bits "01" upper bits ("00" for read) - asm("sta %w", VDP_REG); // write flags and address high byte - // nops here ? +// reads a key from the apple-1 keyboard +byte woz_getkey() { + #ifdef APPLE1 + while((unsigned byte)PEEK(KEY_CTRL)>0); + return PEEK(KEY_DATA) & 0x7f; + #else + byte key; + byte const *keyptr = &key; + kickasm(uses keyptr, uses GETIN) {{ + __wait: + jsr GETIN + cmp #0 + beq __wait + sta keyptr + }} + return key; + #endif } -// sets the VRAM address on the TMS9918 -void fastcall set_vram_read_addr(word addr) { - asm("sta %w", VDP_REG); // write address low byte - // nops here ? - asm("txa"); // X = addres high byte - asm("and #%b", 0b00111111); // mask address high byte - asm("ora #%b", READ_FROM_VRAM); // set "write to vram" flag bits "01" upper bits ("00" for read) - asm("sta %w", VDP_REG); // write flags and address high byte - // nops here ? +// sets the VRAM write address on the TMS9918 +void set_vram_write_addr(word addr) { + TMS_WRITE_REG(addr & 0b00111111)|WRITE_TO_VRAM); +} + +// sets the VRAM read address on the TMS9918 +void set_vram_read_addr(word addr) { + TMS_WRITE_REG(addr & 0b00111111)|READ_FROM_VRAM); } // writes a value to a TMS9918 register (0-7) void write_reg(byte regnum, byte val) { // nops are not required - POKE(VDP_REG, val); - POKE(VDP_REG, (regnum & 0b00001111)|WRITE_TO_REG); + TMS_WRITE_REG(val); + TMS_WRITE_REG((regnum & 0b00001111)|WRITE_TO_REG); } -static word tms_cursor; +word screen1_cursor; #include "laser500_font.ascii.c" -#include "screen1.c" -#include "screen2.c" + +// SCREEN 1 VALUES + +// sprite patterns: $0000 +// pattern table: $0800 (256*8) +// sprite attributes: $1000 +// unused: $1080 +// name table: $1400 (32*24) +// unused: $1800 +// color table: $2000 (32) +// unused $2020-$3FFF + +const word SCREEN1_PATTERN_TABLE = 0x0800; +const word SCREEN1_NAME_TABLE = 0x1400; +const word SCREEN1_COLOR_TABLE = 0x2000; +const word SCREEN1_SPRITE_PATTERNS = 0x0000; +const word SCREEN1_SPRITE_ATTRS = 0x1000; +const word SCREEN1_SIZE = (32*24); + +byte SCREEN1_TABLE[8] = { + 0x00, 0xc0, 0x05, 0x80, 0x01, 0x20, 0x00, 0x25 +}; + +// loads the Laser 500 font on the pattern table +void SCREEN1_LOAD_FONT() { + + static byte *source = FONT; + static word i; + + // start writing into VRAM from space character (32..127) + set_vram_write_addr(SCREEN1_PATTERN_TABLE+(32*8)); + for(i=768;i!=0;i--) { + TMS_WRITE_DATA(*source++); + } + + // reverse font (32..127) + source = FONT; + set_vram_write_addr(SCREEN1_PATTERN_TABLE+((128+32)*8)); + for(i=768;i!=0;i--) { + TMS_WRITE_DATA(~(*source++)); + } +} + +// prints character to TMS (SCREEN 1 MODE) +void SCREEN1_PUTCHAR(byte c) { + set_vram_write_addr(screen1_cursor++); + TMS_WRITE_DATA(c); +} + +// prints 0 terminated string pointed by YA +void SCREEN1_PUTS(byte *s) { + byte c; + while(c=*s++) { + SCREEN1_PUTCHAR(c); + } +} + +void SCREEN1_HOME() { + screen1_cursor = SCREEN1_NAME_TABLE; +} + +void SCREEN1_LOCATEXY(byte x, byte y) { + screen1_cursor = SCREEN1_NAME_TABLE + ((word)y)*32 + x; +} + +void SCREEN1_FILL() { + // fills name table with spaces (32) + set_vram_write_addr(SCREEN1_NAME_TABLE); + for(word i=SCREEN1_SIZE;i!=0;i--) { + TMS_WRITE_DATA(32); + } + + // fill pattern table with 0 + set_vram_write_addr(SCREEN1_PATTERN_TABLE); + for(word i=256*8;i!=0;i--) { + TMS_WRITE_DATA(0); + } + + // fill color table with $1F + set_vram_write_addr(SCREEN1_COLOR_TABLE); + for(byte i=32;i!=0;i--) { + TMS_WRITE_DATA(0x1f); + } +} + +// SCREEN 2 VALUES + +// pattern table: $0000-$17FF (256*8*3) +// sprite patterns: $1800-$19FF +// color table: $2000-$27FF (256*8*3) +// name table: $3800-$3AFF (32*24 = 256*3 = 768) +// sprite attributes: $3B00-$3BFF +// unused $3C00-$3FFF +// + +const word SCREEN2_PATTERN_TABLE = 0x0000; +const word SCREEN2_NAME_TABLE = 0x3800; +const word SCREEN2_COLOR_TABLE = 0x2000; +const word SCREEN2_SPRITE_PATTERNS = 0x1800; +const word SCREEN2_SPRITE_ATTRS = 0x3b00; +const word SCREEN2_SIZE = (32*24); + +byte SCREEN2_TABLE[8] = { + 0x02, 0xc0, 0x0e, 0xff, 0x03, 0x76, 0x03, 0x25 +}; + +void SCREEN_INIT(byte *table) { + for(byte i=0;i<8;i++) { + write_reg(i, table[i]); + } +} + +void SCREEN2_FILL() { + // fills name table x3 with increasing numbers + set_vram_write_addr(SCREEN2_NAME_TABLE); + for(word i=0;iSCREEN2_TABLE + sta.z SCREEN_INIT.table+1 + jsr SCREEN_INIT + jsr SCREEN2_FILL + jsr screen2_square_sprites + lda #$1f + sta.z SCREEN2_PUTS.col + lda #0 + sta.z SCREEN2_PUTS.y + sta.z SCREEN2_PUTS.x + lda #s + sta.z SCREEN2_PUTS.s+1 + jsr SCREEN2_PUTS + lda #$1f + sta.z SCREEN2_PUTS.col + lda #2 + sta.z SCREEN2_PUTS.y + lda #0 + sta.z SCREEN2_PUTS.x + lda #s1 + sta.z SCREEN2_PUTS.s+1 + jsr SCREEN2_PUTS + lda #$1f + sta.z SCREEN2_PUTS.col + lda #4 + sta.z SCREEN2_PUTS.y + lda #0 + sta.z SCREEN2_PUTS.x + lda #s2 + sta.z SCREEN2_PUTS.s+1 + jsr SCREEN2_PUTS + lda #0 + sta.z i + __b1: + lda.z i + cmp #$10 + bcc __b2 + lda #0 + sta.z i1 + __b3: + lda.z i1 + cmp #$c0 + bcc __b4 + rts + __b4: + lda.z i1 + lsr + tax + lda.z i1 + sta.z SCREEN2_PSET.x + jsr SCREEN2_PSET + lda.z i1 + sta.z SCREEN2_PSET.x + ldx.z i1 + jsr SCREEN2_PSET + lda.z i1 + lsr + sta.z SCREEN2_PSET.x + ldx.z i1 + jsr SCREEN2_PSET + inc.z i1 + jmp __b3 + __b2: + lax.z i + axs #-[6] + stx.z SCREEN2_PUTS.y + lda #$f + sec + sbc.z i + asl + asl + asl + asl + clc + adc.z i + sta.z SCREEN2_PUTS.col + lda #5 + sta.z SCREEN2_PUTS.x + lda #s3 + sta.z SCREEN2_PUTS.s+1 + jsr SCREEN2_PUTS + inc.z i + jmp __b1 + .segment Data + s3: .text " SCREEN 2 " + .byte 0 +} +.segment Code +prova_screen1: { + .label i = 4 + lda #SCREEN1_TABLE + sta.z SCREEN_INIT.table+1 + jsr SCREEN_INIT + jsr SCREEN1_FILL + jsr SCREEN1_LOAD_FONT + lda #SCREEN1_NAME_TABLE + sta.z screen1_cursor+1 + lda #s + sta.z SCREEN1_PUTS.s+1 + jsr SCREEN1_PUTS + lda #2 + jsr SCREEN1_LOCATEXY + lda #s1 + sta.z SCREEN1_PUTS.s+1 + jsr SCREEN1_PUTS + lda #4 + jsr SCREEN1_LOCATEXY + lda #s2 + sta.z SCREEN1_PUTS.s+1 + jsr SCREEN1_PUTS + lda #$a + jsr SCREEN1_LOCATEXY + lda #<0 + sta.z i + sta.z i+1 + __b1: + lda.z i+1 + cmp #>$100 + bcc __b2 + bne !+ + lda.z i + cmp #<$100 + bcc __b2 + !: + jsr screen1_square_sprites + rts + __b2: + lda.z i + tay + jsr SCREEN1_PUTCHAR + inc.z i + bne !+ + inc.z i+1 + !: + jmp __b1 +} +// SCREEN_INIT(byte* zp($14) table) +SCREEN_INIT: { + .label table = $14 + ldy #0 + __b1: + cpy #8 + bcc __b2 + rts + __b2: + tya + tax + lda (table),y + jsr write_reg + iny + jmp __b1 +} +SCREEN2_FILL: { + .label i = 4 + .label i1 = $14 + .label i2 = 9 + // fills name table x3 with increasing numbers + lda #SCREEN2_NAME_TABLE + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + lda #<0 + sta.z i + sta.z i+1 + __b1: + lda.z i+1 + cmp #>SCREEN2_SIZE + bcc __b2 + bne !+ + lda.z i + cmp #SCREEN2_PATTERN_TABLE + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + lda #<$300*8 + sta.z i1 + lda #>$300*8 + sta.z i1+1 + __b4: + lda.z i1 + ora.z i1+1 + bne __b5 + // fill color table with $1F + lda #SCREEN2_COLOR_TABLE + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + lda #<$300*8 + sta.z i2 + lda #>$300*8 + sta.z i2+1 + __b7: + lda.z i2 + ora.z i2+1 + bne __b8 + rts + __b8: + lda #$1f + sta VDP_DATA + lda.z i2 + bne !+ + dec.z i2+1 + !: + dec.z i2 + jmp __b7 + __b5: + lda #0 + sta VDP_DATA + lda.z i1 + bne !+ + dec.z i1+1 + !: + dec.z i1 + jmp __b4 + __b2: + lda #$ff + and.z i + sta VDP_DATA + inc.z i + bne !+ + inc.z i+1 + !: + jmp __b1 +} +screen2_square_sprites: { + // fills first sprite pattern with 255 + lda #SCREEN2_SPRITE_PATTERNS + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + ldx #0 + // start writing in the sprite patterns + __b1: + cpx #8 + bcc __b2 + // set sprite coordinates + lda #SCREEN2_SPRITE_ATTRS + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + ldx #0 + // start writing in the sprite attribute + __b4: + cpx #$20 + bcc __b5 + rts + __b5: + lda #0 + sta VDP_DATA + sta VDP_DATA + sta VDP_DATA + stx VDP_DATA + inx + jmp __b4 + __b2: + lda #0 + sta VDP_DATA + inx + jmp __b1 +} +// SCREEN2_PUTS(byte zp(8) x, byte zp(6) y, byte zp(7) col, byte* zp(9) s) +SCREEN2_PUTS: { + .label s = 9 + .label x = 8 + .label y = 6 + .label col = 7 + __b1: + ldy #0 + lda (s),y + inc.z s + bne !+ + inc.z s+1 + !: + cmp #0 + bne __b2 + rts + __b2: + tay + lda.z x + sta.z SCREEN2_PUTC.x + lda.z y + sta.z SCREEN2_PUTC.y + ldx.z col + jsr SCREEN2_PUTC + inc.z x + jmp __b1 +} +// SCREEN2_PSET(byte zp($12) x, byte register(X) y) +SCREEN2_PSET: { + .label __1 = $f + .label __3 = $14 + .label __4 = $f + .label __12 = $14 + .label paddr = $f + .label data = $13 + .label x = $12 + lda #$f8 + and.z x + sta.z __1 + lda #0 + sta.z __1+1 + txa + and #$f8 + sta.z __12 + lda #0 + sta.z __12+1 + asl.z __3 + rol.z __3+1 + asl.z __3 + rol.z __3+1 + asl.z __3 + rol.z __3+1 + asl.z __3 + rol.z __3+1 + asl.z __3 + rol.z __3+1 + lda.z __4 + clc + adc.z __3 + sta.z __4 + lda.z __4+1 + adc.z __3+1 + sta.z __4+1 + txa + and #8-1 + clc + adc.z paddr + sta.z paddr + bcc !+ + inc.z paddr+1 + !: + lda.z paddr + sta.z set_vram_read_addr.addr + lda.z paddr+1 + sta.z set_vram_read_addr.addr+1 + jsr set_vram_read_addr + lda VDP_DATA + sta.z data + jsr set_vram_write_addr + lda #8-1 + and.z x + tay + lda pow2_table,y + ora.z data + sta VDP_DATA + rts + .segment Data + pow2_table: .byte $80, $40, $20, $10, 8, 4, 2, 1 +} +.segment Code +SCREEN1_FILL: { + .label i = $14 + .label i1 = 9 + // fills name table with spaces (32) + lda #SCREEN1_NAME_TABLE + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + lda #SCREEN1_SIZE + sta.z i+1 + __b1: + lda.z i + ora.z i+1 + bne __b2 + // fill pattern table with 0 + lda #SCREEN1_PATTERN_TABLE + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + lda #<$100*8 + sta.z i1 + lda #>$100*8 + sta.z i1+1 + __b4: + lda.z i1 + ora.z i1+1 + bne __b5 + // fill color table with $1F + lda #SCREEN1_COLOR_TABLE + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + ldx #$20 + __b7: + cpx #0 + bne __b8 + rts + __b8: + lda #$1f + sta VDP_DATA + dex + jmp __b7 + __b5: + lda #0 + sta VDP_DATA + lda.z i1 + bne !+ + dec.z i1+1 + !: + dec.z i1 + jmp __b4 + __b2: + lda #$20 + sta VDP_DATA + lda.z i + bne !+ + dec.z i+1 + !: + dec.z i + jmp __b1 +} +// loads the Laser 500 font on the pattern table +SCREEN1_LOAD_FONT: { + // reverse font (32..127) + .label source = 9 + .label i = $14 + // reverse font (32..127) + .label source_1 = $d + .label i_1 = $b + // start writing into VRAM from space character (32..127) + lda #SCREEN1_PATTERN_TABLE+$20*8 + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + lda #FONT + sta.z source+1 + lda #<$300 + sta.z i + lda #>$300 + sta.z i+1 + __b1: + lda.z i + ora.z i+1 + bne __b2 + lda #SCREEN1_PATTERN_TABLE+($80+$20)*8 + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + lda #FONT + sta.z source_1+1 + lda #<$300 + sta.z i_1 + lda #>$300 + sta.z i_1+1 + __b4: + lda.z i_1 + ora.z i_1+1 + bne __b5 + rts + __b5: + ldy #0 + lda (source_1),y + eor #$ff + sta VDP_DATA + inc.z source_1 + bne !+ + inc.z source_1+1 + !: + lda.z i_1 + bne !+ + dec.z i_1+1 + !: + dec.z i_1 + jmp __b4 + __b2: + ldy #0 + lda (source),y + sta VDP_DATA + inc.z source + bne !+ + inc.z source+1 + !: + lda.z i + bne !+ + dec.z i+1 + !: + dec.z i + jmp __b1 +} +// prints 0 terminated string pointed by YA +// SCREEN1_PUTS(byte* zp($b) s) +SCREEN1_PUTS: { + .label s = $b + __b1: + ldy #0 + lda (s),y + inc.z s + bne !+ + inc.z s+1 + !: + cmp #0 + bne __b2 + rts + __b2: + tay + jsr SCREEN1_PUTCHAR + jmp __b1 +} +// SCREEN1_LOCATEXY(byte register(A) y) +SCREEN1_LOCATEXY: { + .label __0 = $d + .label __3 = $d + sta.z __3 + lda #0 + sta.z __3+1 + asl.z __0 + rol.z __0+1 + asl.z __0 + rol.z __0+1 + asl.z __0 + rol.z __0+1 + asl.z __0 + rol.z __0+1 + asl.z __0 + rol.z __0+1 + clc + lda.z screen1_cursor + adc #SCREEN1_NAME_TABLE + sta.z screen1_cursor+1 + rts +} +screen1_square_sprites: { + // fills first sprite pattern with 255 + lda #SCREEN1_SPRITE_PATTERNS + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + ldx #0 + // start writing in the sprite patterns + __b1: + cpx #8 + bcc __b2 + // set sprite coordinates + lda #SCREEN1_SPRITE_ATTRS + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + ldy #0 + // start writing in the sprite attribute + __b4: + cpy #$20 + bcc __b5 + rts + __b5: + tya + clc + adc #6 + asl + asl + asl + sta VDP_DATA + tya + clc + adc #6 + asl + asl + asl + sta VDP_DATA + lda #0 + sta VDP_DATA + sty VDP_DATA + iny + jmp __b4 + __b2: + lda #$ff + sta VDP_DATA + inx + jmp __b1 +} +// prints character to TMS (SCREEN 1 MODE) +// SCREEN1_PUTCHAR(byte register(Y) c) +SCREEN1_PUTCHAR: { + lda.z screen1_cursor + sta.z set_vram_write_addr.addr + lda.z screen1_cursor+1 + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + inc.z screen1_cursor + bne !+ + inc.z screen1_cursor+1 + !: + sty VDP_DATA + rts +} +// writes a value to a TMS9918 register (0-7) +// write_reg(byte register(X) regnum, byte register(A) val) +write_reg: { + sta VDP_REG + txa + and #$f + ora #WRITE_TO_REG + sta VDP_REG + rts +} +// sets the VRAM write address on the TMS9918 +// set_vram_write_addr(word zp($f) addr) +set_vram_write_addr: { + .label addr = $f + lda.z addr + sta VDP_REG + lda.z addr+1 + and #$3f + ora #WRITE_TO_VRAM + sta VDP_REG + rts +} +// SCREEN2_PUTC(byte register(Y) ch, byte zp($12) x, byte zp($13) y, byte register(X) col) +SCREEN2_PUTC: { + .label __1 = $14 + .label __4 = $16 + .label __12 = $14 + .label source = $14 + .label addr = $16 + .label x = $12 + .label y = $13 + tya + sec + sbc #$20 + sta.z __12 + lda #0 + sta.z __12+1 + asl.z __1 + rol.z __1+1 + asl.z __1 + rol.z __1+1 + asl.z __1 + rol.z __1+1 + clc + lda.z source + adc #FONT + sta.z source+1 + lda.z x + asl + asl + asl + tay + lda.z y + sta.z __4+1 + lda #0 + sta.z __4 + tya + clc + adc.z addr + sta.z addr + bcc !+ + inc.z addr+1 + !: + lda.z addr + sta.z set_vram_write_addr.addr + lda.z addr+1 + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + ldy #0 + __b1: + cpy #8 + bcc __b2 + clc + lda.z addr + adc #SCREEN2_COLOR_TABLE + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + ldy #0 + __b4: + cpy #8 + bcc __b5 + rts + __b5: + stx VDP_DATA + iny + jmp __b4 + __b2: + lda (source),y + sta VDP_DATA + iny + jmp __b1 +} +// sets the VRAM read address on the TMS9918 +// set_vram_read_addr(word zp($16) addr) +set_vram_read_addr: { + .label addr = $16 + lda.z addr + sta VDP_REG + lda.z addr+1 + and #$3f + sta VDP_REG + rts +} +.segment Data + FONT: .byte 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 0, 8, 0, $14, $14, $14, 0, 0, 0, 0, 0, $14, $14, $3e, $14, $3e, $14, $14, 0, 8, $1e, $28, $1c, $a, $3c, 8, 0, $30, $32, 4, 8, $10, $26, 6, 0, $10, $28, $28, $10, $2a, $24, $1a, 0, 8, 8, 8, 0, 0, 0, 0, 0, 8, $10, $20, $20, $20, $10, 8, 0, 8, 4, 2, 2, 2, 4, 8, 0, 8, $2a, $1c, 8, $1c, $2a, 8, 0, 0, 8, 8, $3e, 8, 8, 0, 0, 0, 0, 0, 0, 8, 8, $10, 0, 0, 0, 0, $3e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 2, 4, 8, $10, $20, 0, 0, $1c, $22, $26, $2a, $32, $22, $1c, 0, 8, $18, 8, 8, 8, 8, $1c, 0, $1c, $22, 2, $c, $10, $20, $3e, 0, $3e, 2, 4, $c, 2, $22, $1c, 0, 4, $c, $14, $24, $3e, 4, 4, 0, $3e, $20, $3c, 2, 2, $22, $1c, 0, $e, $10, $20, $3c, $22, $22, $1c, 0, $3e, 2, 4, 8, $10, $20, $20, 0, $1c, $22, $22, $1c, $22, $22, $1c, 0, $1c, $22, $22, $1e, 2, 4, $38, 0, 0, 0, 8, 0, 8, 0, 0, 0, 0, 0, 8, 0, 8, 8, $10, 0, 4, 8, $10, $20, $10, 8, 4, 0, 0, 0, $3e, 0, $3e, 0, 0, 0, $10, 8, 4, 2, 4, 8, $10, 0, $1c, $22, 4, 8, 8, 0, 8, 0, $1c, $22, $2a, $2e, $2c, $20, $1c, 0, 8, $14, $22, $22, $3e, $22, $22, 0, $3c, $22, $22, $3c, $22, $22, $3c, 0, $1c, $22, $20, $20, $20, $22, $1c, 0, $38, $24, $22, $22, $22, $24, $38, 0, $3e, $20, $20, $38, $20, $20, $3e, 0, $3e, $20, $20, $38, $20, $20, $20, 0, $1e, $20, $20, $20, $26, $22, $1e, 0, $22, $22, $22, $3e, $22, $22, $22, 0, $1c, 8, 8, 8, 8, 8, $1c, 0, 2, 2, 2, 2, 2, $22, $1c, 0, $22, $24, $28, $30, $28, $24, $22, 0, $20, $20, $20, $20, $20, $20, $3e, 0, $22, $36, $2a, $2a, $22, $22, $22, 0, $22, $22, $32, $2a, $26, $22, $22, 0, $1c, $22, $22, $22, $22, $22, $1c, 0, $3c, $22, $22, $3c, $20, $20, $20, 0, $1c, $22, $22, $22, $2a, $24, $1a, 0, $3c, $22, $22, $3c, $28, $24, $22, 0, $1c, $22, $20, $1c, 2, $22, $1c, 0, $3e, 8, 8, 8, 8, 8, 8, 0, $22, $22, $22, $22, $22, $22, $1c, 0, $22, $22, $22, $22, $22, $14, 8, 0, $22, $22, $22, $2a, $2a, $36, $22, 0, $22, $22, $14, 8, $14, $22, $22, 0, $22, $22, $14, 8, 8, 8, 8, 0, $3e, 2, 4, 8, $10, $20, $3e, 0, $3e, $30, $30, $30, $30, $30, $3e, 0, 0, $20, $10, 8, 4, 2, 0, 0, $3e, 6, 6, 6, 6, 6, $3e, 0, 8, $14, $22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, $3e, $10, 8, 4, 0, 0, 0, 0, 0, 0, 0, $1c, 2, $1e, $22, $1e, 0, $20, $20, $3c, $22, $22, $22, $3c, 0, 0, 0, $1e, $20, $20, $20, $1e, 0, 2, 2, $1e, $22, $22, $22, $1e, 0, 0, 0, $1c, $22, $3e, $20, $1e, 0, $c, $12, $10, $3c, $10, $10, $10, 0, 0, 0, $1c, $22, $22, $1e, 2, $1c, $20, $20, $3c, $22, $22, $22, $22, 0, 8, 0, $18, 8, 8, 8, $1c, 0, 2, 0, 6, 2, 2, 2, $12, $c, $20, $20, $22, $24, $38, $24, $22, 0, $18, 8, 8, 8, 8, 8, $1c, 0, 0, 0, $34, $2a, $2a, $2a, $22, 0, 0, 0, $3c, $22, $22, $22, $22, 0, 0, 0, $1c, $22, $22, $22, $1c, 0, 0, 0, $3c, $22, $22, $3c, $20, $20, 0, 0, $1e, $22, $22, $1e, 2, 2, 0, 0, $2e, $30, $20, $20, $20, 0, 0, 0, $1e, $20, $1c, 2, $3c, 0, $10, $10, $3c, $10, $10, $12, $c, 0, 0, 0, $22, $22, $22, $26, $1a, 0, 0, 0, $22, $22, $22, $14, 8, 0, 0, 0, $22, $22, $2a, $2a, $14, 0, 0, 0, $22, $14, 8, $14, $22, 0, 0, 0, $22, $24, $14, $18, 8, $30, 0, 0, $3e, 4, 8, $10, $3e, 0, 6, 8, 8, $30, 8, 8, 6, 0, 8, 8, 8, 8, 8, 8, 8, 8, $30, 8, 8, 6, 8, 8, $30, 0, $1a, $2c, 0, 0, 0, 0, 0, 0 + .fill 8, 0 + SCREEN1_TABLE: .byte 0, $c0, 5, $80, 1, $20, 0, $25 + SCREEN2_TABLE: .byte 2, $c0, $e, $ff, 3, $76, 3, $25 + s: .text "*** P-LAB VIDEO CARD SYSTEM ***" + .byte 0 + s1: .text "16K VRAM BYTES FREE" + .byte 0 + s2: .text "READY." + .byte 0 diff --git a/test_vic20.asm b/test_vic20.asm new file mode 100644 index 0000000..0a698f7 --- /dev/null +++ b/test_vic20.asm @@ -0,0 +1,853 @@ +// TODO verificare NOPs + // Commodore VIC 20 executable PRG file +.file [name="test.prg", type="prg", segments="Program"] +.segmentdef Program [segments="Basic, Code, Data"] +.segmentdef Basic [start=$1001] +.segmentdef Code [start=$100d] +.segmentdef Data [startAfter="Code"] +.segment Basic +:BasicUpstart(main) + // VIC20 + .const ECHO = $ffd2 + // chrout routine in kernal rom + .const GETIN = $ffe4 + // TMS9918 interface flags + .const WRITE_TO_REG = $80 + .const WRITE_TO_VRAM = $40 + // sprite patterns: $0000 + // pattern table: $0800 (256*8) + // sprite attributes: $1000 + // unused: $1080 + // name table: $1400 (32*24) + // unused: $1800 + // color table: $2000 (32) + // unused $2020-$3FFF + .const SCREEN1_PATTERN_TABLE = $800 + .const SCREEN1_NAME_TABLE = $1400 + .const SCREEN1_COLOR_TABLE = $2000 + .const SCREEN1_SPRITE_PATTERNS = 0 + .const SCREEN1_SPRITE_ATTRS = $1000 + .const SCREEN1_SIZE = $20*$18 + // pattern table: $0000-$17FF (256*8*3) + // sprite patterns: $1800-$19FF + // color table: $2000-$27FF (256*8*3) + // name table: $3800-$3AFF (32*24 = 256*3 = 768) + // sprite attributes: $3B00-$3BFF + // unused $3C00-$3FFF + // + .const SCREEN2_PATTERN_TABLE = 0 + .const SCREEN2_NAME_TABLE = $3800 + .const SCREEN2_COLOR_TABLE = $2000 + .const SCREEN2_SPRITE_PATTERNS = $1800 + .const SCREEN2_SPRITE_ATTRS = $3b00 + .const SCREEN2_SIZE = $20*$18 + // GETIN keyboard read routine + .label VDP_DATA = $a000 + // TMS9918 data port (VRAM) + .label VDP_REG = $a001 + .label screen1_cursor = $d +.segment Code +main: { + lda #<0 + sta.z screen1_cursor + sta.z screen1_cursor+1 + ldx #'1' + __b1: + cpx #'1' + beq __b2 + cpx #'2' + beq __b3 + cpx #$d + beq __b4 + stx.z woz_putc.c + jsr woz_putc + __b5: + jsr woz_getkey + tax + jmp __b1 + __b4: + lda #$2a + sta.z woz_putc.c + jsr woz_putc + rts + __b3: + jsr prova_screen2 + jmp __b5 + __b2: + jsr prova_screen1 + jmp __b5 +} +// puts a character on the apple1 screen using the WOZMON routine +// woz_putc(byte zp($11) c) +woz_putc: { + .label c = $11 + lda c + jsr ECHO + rts +} +// reads a key from the apple-1 keyboard +woz_getkey: { + .label keyptr = key + .label key = $12 + lda #0 + sta.z key + __wait: + jsr GETIN + cmp #0 + beq __wait + sta keyptr + + rts +} +prova_screen2: { + .label i = 2 + .label i1 = 3 + lda #SCREEN2_TABLE + sta.z SCREEN_INIT.table+1 + jsr SCREEN_INIT + jsr SCREEN2_FILL + jsr screen2_square_sprites + lda #$1f + sta.z SCREEN2_PUTS.col + lda #0 + sta.z SCREEN2_PUTS.y + sta.z SCREEN2_PUTS.x + lda #s + sta.z SCREEN2_PUTS.s+1 + jsr SCREEN2_PUTS + lda #$1f + sta.z SCREEN2_PUTS.col + lda #2 + sta.z SCREEN2_PUTS.y + lda #0 + sta.z SCREEN2_PUTS.x + lda #s1 + sta.z SCREEN2_PUTS.s+1 + jsr SCREEN2_PUTS + lda #$1f + sta.z SCREEN2_PUTS.col + lda #4 + sta.z SCREEN2_PUTS.y + lda #0 + sta.z SCREEN2_PUTS.x + lda #s2 + sta.z SCREEN2_PUTS.s+1 + jsr SCREEN2_PUTS + lda #0 + sta.z i + __b1: + lda.z i + cmp #$10 + bcc __b2 + lda #0 + sta.z i1 + __b3: + lda.z i1 + cmp #$c0 + bcc __b4 + rts + __b4: + lda.z i1 + lsr + tax + lda.z i1 + sta.z SCREEN2_PSET.x + jsr SCREEN2_PSET + lda.z i1 + sta.z SCREEN2_PSET.x + ldx.z i1 + jsr SCREEN2_PSET + lda.z i1 + lsr + sta.z SCREEN2_PSET.x + ldx.z i1 + jsr SCREEN2_PSET + inc.z i1 + jmp __b3 + __b2: + lax.z i + axs #-[6] + stx.z SCREEN2_PUTS.y + lda #$f + sec + sbc.z i + asl + asl + asl + asl + clc + adc.z i + sta.z SCREEN2_PUTS.col + lda #5 + sta.z SCREEN2_PUTS.x + lda #s3 + sta.z SCREEN2_PUTS.s+1 + jsr SCREEN2_PUTS + inc.z i + jmp __b1 + .segment Data + s3: .text " SCREEN 2 " + .byte 0 +} +.segment Code +prova_screen1: { + .label i = 4 + lda #SCREEN1_TABLE + sta.z SCREEN_INIT.table+1 + jsr SCREEN_INIT + jsr SCREEN1_FILL + jsr SCREEN1_LOAD_FONT + lda #SCREEN1_NAME_TABLE + sta.z screen1_cursor+1 + lda #s + sta.z SCREEN1_PUTS.s+1 + jsr SCREEN1_PUTS + lda #2 + jsr SCREEN1_LOCATEXY + lda #s1 + sta.z SCREEN1_PUTS.s+1 + jsr SCREEN1_PUTS + lda #4 + jsr SCREEN1_LOCATEXY + lda #s2 + sta.z SCREEN1_PUTS.s+1 + jsr SCREEN1_PUTS + lda #$a + jsr SCREEN1_LOCATEXY + lda #<0 + sta.z i + sta.z i+1 + __b1: + lda.z i+1 + cmp #>$100 + bcc __b2 + bne !+ + lda.z i + cmp #<$100 + bcc __b2 + !: + jsr screen1_square_sprites + rts + __b2: + lda.z i + tay + jsr SCREEN1_PUTCHAR + inc.z i + bne !+ + inc.z i+1 + !: + jmp __b1 +} +// SCREEN_INIT(byte* zp($15) table) +SCREEN_INIT: { + .label table = $15 + ldy #0 + __b1: + cpy #8 + bcc __b2 + rts + __b2: + tya + tax + lda (table),y + jsr write_reg + iny + jmp __b1 +} +SCREEN2_FILL: { + .label i = 4 + .label i1 = $15 + .label i2 = 9 + // fills name table x3 with increasing numbers + lda #SCREEN2_NAME_TABLE + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + lda #<0 + sta.z i + sta.z i+1 + __b1: + lda.z i+1 + cmp #>SCREEN2_SIZE + bcc __b2 + bne !+ + lda.z i + cmp #SCREEN2_PATTERN_TABLE + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + lda #<$300*8 + sta.z i1 + lda #>$300*8 + sta.z i1+1 + __b4: + lda.z i1 + ora.z i1+1 + bne __b5 + // fill color table with $1F + lda #SCREEN2_COLOR_TABLE + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + lda #<$300*8 + sta.z i2 + lda #>$300*8 + sta.z i2+1 + __b7: + lda.z i2 + ora.z i2+1 + bne __b8 + rts + __b8: + lda #$1f + sta VDP_DATA + lda.z i2 + bne !+ + dec.z i2+1 + !: + dec.z i2 + jmp __b7 + __b5: + lda #0 + sta VDP_DATA + lda.z i1 + bne !+ + dec.z i1+1 + !: + dec.z i1 + jmp __b4 + __b2: + lda #$ff + and.z i + sta VDP_DATA + inc.z i + bne !+ + inc.z i+1 + !: + jmp __b1 +} +screen2_square_sprites: { + // fills first sprite pattern with 255 + lda #SCREEN2_SPRITE_PATTERNS + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + ldx #0 + // start writing in the sprite patterns + __b1: + cpx #8 + bcc __b2 + // set sprite coordinates + lda #SCREEN2_SPRITE_ATTRS + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + ldx #0 + // start writing in the sprite attribute + __b4: + cpx #$20 + bcc __b5 + rts + __b5: + lda #0 + sta VDP_DATA + sta VDP_DATA + sta VDP_DATA + stx VDP_DATA + inx + jmp __b4 + __b2: + lda #0 + sta VDP_DATA + inx + jmp __b1 +} +// SCREEN2_PUTS(byte zp(8) x, byte zp(6) y, byte zp(7) col, byte* zp(9) s) +SCREEN2_PUTS: { + .label s = 9 + .label x = 8 + .label y = 6 + .label col = 7 + __b1: + ldy #0 + lda (s),y + inc.z s + bne !+ + inc.z s+1 + !: + cmp #0 + bne __b2 + rts + __b2: + tay + lda.z x + sta.z SCREEN2_PUTC.x + lda.z y + sta.z SCREEN2_PUTC.y + ldx.z col + jsr SCREEN2_PUTC + inc.z x + jmp __b1 +} +// SCREEN2_PSET(byte zp($13) x, byte register(X) y) +SCREEN2_PSET: { + .label __1 = $f + .label __3 = $15 + .label __4 = $f + .label __12 = $15 + .label paddr = $f + .label data = $14 + .label x = $13 + lda #$f8 + and.z x + sta.z __1 + lda #0 + sta.z __1+1 + txa + and #$f8 + sta.z __12 + lda #0 + sta.z __12+1 + asl.z __3 + rol.z __3+1 + asl.z __3 + rol.z __3+1 + asl.z __3 + rol.z __3+1 + asl.z __3 + rol.z __3+1 + asl.z __3 + rol.z __3+1 + lda.z __4 + clc + adc.z __3 + sta.z __4 + lda.z __4+1 + adc.z __3+1 + sta.z __4+1 + txa + and #8-1 + clc + adc.z paddr + sta.z paddr + bcc !+ + inc.z paddr+1 + !: + lda.z paddr + sta.z set_vram_read_addr.addr + lda.z paddr+1 + sta.z set_vram_read_addr.addr+1 + jsr set_vram_read_addr + lda VDP_DATA + sta.z data + jsr set_vram_write_addr + lda #8-1 + and.z x + tay + lda pow2_table,y + ora.z data + sta VDP_DATA + rts + .segment Data + pow2_table: .byte $80, $40, $20, $10, 8, 4, 2, 1 +} +.segment Code +SCREEN1_FILL: { + .label i = $15 + .label i1 = 9 + // fills name table with spaces (32) + lda #SCREEN1_NAME_TABLE + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + lda #SCREEN1_SIZE + sta.z i+1 + __b1: + lda.z i + ora.z i+1 + bne __b2 + // fill pattern table with 0 + lda #SCREEN1_PATTERN_TABLE + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + lda #<$100*8 + sta.z i1 + lda #>$100*8 + sta.z i1+1 + __b4: + lda.z i1 + ora.z i1+1 + bne __b5 + // fill color table with $1F + lda #SCREEN1_COLOR_TABLE + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + ldx #$20 + __b7: + cpx #0 + bne __b8 + rts + __b8: + lda #$1f + sta VDP_DATA + dex + jmp __b7 + __b5: + lda #0 + sta VDP_DATA + lda.z i1 + bne !+ + dec.z i1+1 + !: + dec.z i1 + jmp __b4 + __b2: + lda #$20 + sta VDP_DATA + lda.z i + bne !+ + dec.z i+1 + !: + dec.z i + jmp __b1 +} +// loads the Laser 500 font on the pattern table +SCREEN1_LOAD_FONT: { + // reverse font (32..127) + .label source = 9 + .label i = $15 + // reverse font (32..127) + .label source_1 = $d + .label i_1 = $b + // start writing into VRAM from space character (32..127) + lda #SCREEN1_PATTERN_TABLE+$20*8 + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + lda #FONT + sta.z source+1 + lda #<$300 + sta.z i + lda #>$300 + sta.z i+1 + __b1: + lda.z i + ora.z i+1 + bne __b2 + lda #SCREEN1_PATTERN_TABLE+($80+$20)*8 + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + lda #FONT + sta.z source_1+1 + lda #<$300 + sta.z i_1 + lda #>$300 + sta.z i_1+1 + __b4: + lda.z i_1 + ora.z i_1+1 + bne __b5 + rts + __b5: + ldy #0 + lda (source_1),y + eor #$ff + sta VDP_DATA + inc.z source_1 + bne !+ + inc.z source_1+1 + !: + lda.z i_1 + bne !+ + dec.z i_1+1 + !: + dec.z i_1 + jmp __b4 + __b2: + ldy #0 + lda (source),y + sta VDP_DATA + inc.z source + bne !+ + inc.z source+1 + !: + lda.z i + bne !+ + dec.z i+1 + !: + dec.z i + jmp __b1 +} +// prints 0 terminated string pointed by YA +// SCREEN1_PUTS(byte* zp($b) s) +SCREEN1_PUTS: { + .label s = $b + __b1: + ldy #0 + lda (s),y + inc.z s + bne !+ + inc.z s+1 + !: + cmp #0 + bne __b2 + rts + __b2: + tay + jsr SCREEN1_PUTCHAR + jmp __b1 +} +// SCREEN1_LOCATEXY(byte register(A) y) +SCREEN1_LOCATEXY: { + .label __0 = $d + .label __3 = $d + sta.z __3 + lda #0 + sta.z __3+1 + asl.z __0 + rol.z __0+1 + asl.z __0 + rol.z __0+1 + asl.z __0 + rol.z __0+1 + asl.z __0 + rol.z __0+1 + asl.z __0 + rol.z __0+1 + clc + lda.z screen1_cursor + adc #SCREEN1_NAME_TABLE + sta.z screen1_cursor+1 + rts +} +screen1_square_sprites: { + // fills first sprite pattern with 255 + lda #SCREEN1_SPRITE_PATTERNS + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + ldx #0 + // start writing in the sprite patterns + __b1: + cpx #8 + bcc __b2 + // set sprite coordinates + lda #SCREEN1_SPRITE_ATTRS + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + ldy #0 + // start writing in the sprite attribute + __b4: + cpy #$20 + bcc __b5 + rts + __b5: + tya + clc + adc #6 + asl + asl + asl + sta VDP_DATA + tya + clc + adc #6 + asl + asl + asl + sta VDP_DATA + lda #0 + sta VDP_DATA + sty VDP_DATA + iny + jmp __b4 + __b2: + lda #$ff + sta VDP_DATA + inx + jmp __b1 +} +// prints character to TMS (SCREEN 1 MODE) +// SCREEN1_PUTCHAR(byte register(Y) c) +SCREEN1_PUTCHAR: { + lda.z screen1_cursor + sta.z set_vram_write_addr.addr + lda.z screen1_cursor+1 + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + inc.z screen1_cursor + bne !+ + inc.z screen1_cursor+1 + !: + sty VDP_DATA + rts +} +// writes a value to a TMS9918 register (0-7) +// write_reg(byte register(X) regnum, byte register(A) val) +write_reg: { + sta VDP_REG + txa + and #$f + ora #WRITE_TO_REG + sta VDP_REG + rts +} +// sets the VRAM write address on the TMS9918 +// set_vram_write_addr(word zp($f) addr) +set_vram_write_addr: { + .label addr = $f + lda.z addr + sta VDP_REG + lda.z addr+1 + and #$3f + ora #WRITE_TO_VRAM + sta VDP_REG + rts +} +// SCREEN2_PUTC(byte register(Y) ch, byte zp($13) x, byte zp($14) y, byte register(X) col) +SCREEN2_PUTC: { + .label __1 = $15 + .label __4 = $17 + .label __12 = $15 + .label source = $15 + .label addr = $17 + .label x = $13 + .label y = $14 + tya + sec + sbc #$20 + sta.z __12 + lda #0 + sta.z __12+1 + asl.z __1 + rol.z __1+1 + asl.z __1 + rol.z __1+1 + asl.z __1 + rol.z __1+1 + clc + lda.z source + adc #FONT + sta.z source+1 + lda.z x + asl + asl + asl + tay + lda.z y + sta.z __4+1 + lda #0 + sta.z __4 + tya + clc + adc.z addr + sta.z addr + bcc !+ + inc.z addr+1 + !: + lda.z addr + sta.z set_vram_write_addr.addr + lda.z addr+1 + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + ldy #0 + __b1: + cpy #8 + bcc __b2 + clc + lda.z addr + adc #SCREEN2_COLOR_TABLE + sta.z set_vram_write_addr.addr+1 + jsr set_vram_write_addr + ldy #0 + __b4: + cpy #8 + bcc __b5 + rts + __b5: + stx VDP_DATA + iny + jmp __b4 + __b2: + lda (source),y + sta VDP_DATA + iny + jmp __b1 +} +// sets the VRAM read address on the TMS9918 +// set_vram_read_addr(word zp($17) addr) +set_vram_read_addr: { + .label addr = $17 + lda.z addr + sta VDP_REG + lda.z addr+1 + and #$3f + sta VDP_REG + rts +} +.segment Data + FONT: .byte 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 0, 8, 0, $14, $14, $14, 0, 0, 0, 0, 0, $14, $14, $3e, $14, $3e, $14, $14, 0, 8, $1e, $28, $1c, $a, $3c, 8, 0, $30, $32, 4, 8, $10, $26, 6, 0, $10, $28, $28, $10, $2a, $24, $1a, 0, 8, 8, 8, 0, 0, 0, 0, 0, 8, $10, $20, $20, $20, $10, 8, 0, 8, 4, 2, 2, 2, 4, 8, 0, 8, $2a, $1c, 8, $1c, $2a, 8, 0, 0, 8, 8, $3e, 8, 8, 0, 0, 0, 0, 0, 0, 8, 8, $10, 0, 0, 0, 0, $3e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 2, 4, 8, $10, $20, 0, 0, $1c, $22, $26, $2a, $32, $22, $1c, 0, 8, $18, 8, 8, 8, 8, $1c, 0, $1c, $22, 2, $c, $10, $20, $3e, 0, $3e, 2, 4, $c, 2, $22, $1c, 0, 4, $c, $14, $24, $3e, 4, 4, 0, $3e, $20, $3c, 2, 2, $22, $1c, 0, $e, $10, $20, $3c, $22, $22, $1c, 0, $3e, 2, 4, 8, $10, $20, $20, 0, $1c, $22, $22, $1c, $22, $22, $1c, 0, $1c, $22, $22, $1e, 2, 4, $38, 0, 0, 0, 8, 0, 8, 0, 0, 0, 0, 0, 8, 0, 8, 8, $10, 0, 4, 8, $10, $20, $10, 8, 4, 0, 0, 0, $3e, 0, $3e, 0, 0, 0, $10, 8, 4, 2, 4, 8, $10, 0, $1c, $22, 4, 8, 8, 0, 8, 0, $1c, $22, $2a, $2e, $2c, $20, $1c, 0, 8, $14, $22, $22, $3e, $22, $22, 0, $3c, $22, $22, $3c, $22, $22, $3c, 0, $1c, $22, $20, $20, $20, $22, $1c, 0, $38, $24, $22, $22, $22, $24, $38, 0, $3e, $20, $20, $38, $20, $20, $3e, 0, $3e, $20, $20, $38, $20, $20, $20, 0, $1e, $20, $20, $20, $26, $22, $1e, 0, $22, $22, $22, $3e, $22, $22, $22, 0, $1c, 8, 8, 8, 8, 8, $1c, 0, 2, 2, 2, 2, 2, $22, $1c, 0, $22, $24, $28, $30, $28, $24, $22, 0, $20, $20, $20, $20, $20, $20, $3e, 0, $22, $36, $2a, $2a, $22, $22, $22, 0, $22, $22, $32, $2a, $26, $22, $22, 0, $1c, $22, $22, $22, $22, $22, $1c, 0, $3c, $22, $22, $3c, $20, $20, $20, 0, $1c, $22, $22, $22, $2a, $24, $1a, 0, $3c, $22, $22, $3c, $28, $24, $22, 0, $1c, $22, $20, $1c, 2, $22, $1c, 0, $3e, 8, 8, 8, 8, 8, 8, 0, $22, $22, $22, $22, $22, $22, $1c, 0, $22, $22, $22, $22, $22, $14, 8, 0, $22, $22, $22, $2a, $2a, $36, $22, 0, $22, $22, $14, 8, $14, $22, $22, 0, $22, $22, $14, 8, 8, 8, 8, 0, $3e, 2, 4, 8, $10, $20, $3e, 0, $3e, $30, $30, $30, $30, $30, $3e, 0, 0, $20, $10, 8, 4, 2, 0, 0, $3e, 6, 6, 6, 6, 6, $3e, 0, 8, $14, $22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, $3e, $10, 8, 4, 0, 0, 0, 0, 0, 0, 0, $1c, 2, $1e, $22, $1e, 0, $20, $20, $3c, $22, $22, $22, $3c, 0, 0, 0, $1e, $20, $20, $20, $1e, 0, 2, 2, $1e, $22, $22, $22, $1e, 0, 0, 0, $1c, $22, $3e, $20, $1e, 0, $c, $12, $10, $3c, $10, $10, $10, 0, 0, 0, $1c, $22, $22, $1e, 2, $1c, $20, $20, $3c, $22, $22, $22, $22, 0, 8, 0, $18, 8, 8, 8, $1c, 0, 2, 0, 6, 2, 2, 2, $12, $c, $20, $20, $22, $24, $38, $24, $22, 0, $18, 8, 8, 8, 8, 8, $1c, 0, 0, 0, $34, $2a, $2a, $2a, $22, 0, 0, 0, $3c, $22, $22, $22, $22, 0, 0, 0, $1c, $22, $22, $22, $1c, 0, 0, 0, $3c, $22, $22, $3c, $20, $20, 0, 0, $1e, $22, $22, $1e, 2, 2, 0, 0, $2e, $30, $20, $20, $20, 0, 0, 0, $1e, $20, $1c, 2, $3c, 0, $10, $10, $3c, $10, $10, $12, $c, 0, 0, 0, $22, $22, $22, $26, $1a, 0, 0, 0, $22, $22, $22, $14, 8, 0, 0, 0, $22, $22, $2a, $2a, $14, 0, 0, 0, $22, $14, 8, $14, $22, 0, 0, 0, $22, $24, $14, $18, 8, $30, 0, 0, $3e, 4, 8, $10, $3e, 0, 6, 8, 8, $30, 8, 8, 6, 0, 8, 8, 8, 8, 8, 8, 8, 8, $30, 8, 8, 6, 8, 8, $30, 0, $1a, $2c, 0, 0, 0, 0, 0, 0 + .fill 8, 0 + SCREEN1_TABLE: .byte 0, $c0, 5, $80, 1, $20, 0, $25 + SCREEN2_TABLE: .byte 2, $c0, $e, $ff, 3, $76, 3, $25 + s: .text "*** P-LAB VIDEO CARD SYSTEM ***" + .byte 0 + s1: .text "16K VRAM BYTES FREE" + .byte 0 + s2: .text "READY." + .byte 0