diff --git a/lib/tms9918.h b/lib/tms9918.h index a07edbc..c3c1d23 100644 --- a/lib/tms9918.h +++ b/lib/tms9918.h @@ -1,3 +1,13 @@ +// TODO a bitmapped text writing routine (double size ecc) +// TODO console like text output in screen 2 +// TODO more fonts (C64 and PET/VIC20) +// TODO how to switch fonts? +// TODO do fonts need to start from 32 or 0? +// TODO sprite routines +// TODO test the interrupt routines +// TODO provide a single .h file (tms_lib.h or tms9918.h?) +// TODO finalize hexdump.js and update README.md + #pragma encoding(ascii) // encode strings in plain ascii #ifdef APPLE1 @@ -47,6 +57,22 @@ const byte COLOR_MAGENTA = 0xD; const byte COLOR_GREY = 0xE; const byte COLOR_WHITE = 0xF; +// The library has a fixed VRAM memory layout valid for SCREEN 1 and 2 +// +// 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 TMS_NAME_TABLE = 0x3800; +const word TMS_COLOR_TABLE = 0x2000; +const word TMS_PATTERN_TABLE = 0x0000; +const word TMS_SPRITE_ATTRS = 0x3b00; +const word TMS_SPRITE_PATTERNS = 0x1800; + // macro for combining foreground and background into a single byte value #define FG_BG(f,b) (((f)<<4)|(b)) @@ -62,6 +88,14 @@ const byte COLOR_WHITE = 0xF; #define TMS_READ_CTRL_PORT (*VDP_REG); #define TMS_READ_DATA_PORT (*VDP_DATA); +// buffer containing the last register values, because TMS registers are write only +byte tms_regs_latch[8]; + +// cursor coordinates for the console functions +byte tms_cursor_x; +byte tms_cursor_y; +byte tms_reverse; + // sets the VRAM address on the TMS9918 for a write operation void tms_set_vram_write_addr(word addr) { TMS_WRITE_CTRL_PORT(LOBYTE(addr)); @@ -74,9 +108,6 @@ void tms_set_vram_read_addr(word addr) { TMS_WRITE_CTRL_PORT((HIBYTE(addr) & HIADDRESS_MASK)|READ_FROM_VRAM); } -// buffer containing the last register values, because TMS registers are write only -byte tms_regs_latch[8]; - // writes a value to a TMS9918 register (0-7) void tms_write_reg(byte regnum, byte val) { TMS_WRITE_CTRL_PORT(val); diff --git a/lib/tms_screen1.h b/lib/tms_screen1.h index 2471106..1d2348c 100644 --- a/lib/tms_screen1.h +++ b/lib/tms_screen1.h @@ -1,51 +1,134 @@ -byte SCREEN1_TABLE[8] = { - 0x00, 0xc0, 0x05, 0x80, 0x01, 0x20, 0x00, 0x25 -}; +byte SCREEN1_TABLE[8] = { 0x00, 0xc0, 0x0e, 0x80, 0x00, 0x76, 0x03, 0x25 }; -// 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); +const word SCREEN1_SIZE = (32*24); // loads the font on the pattern table void screen1_load_font() { - byte *source = FONT; // start writing into VRAM from space character (32..127) - tms_set_vram_write_addr(SCREEN1_PATTERN_TABLE+(32*8)); + tms_set_vram_write_addr(TMS_PATTERN_TABLE+(32*8)); for(word i=768;i!=0;i--) { TMS_WRITE_DATA_PORT(*source++); } // reverse font (32..127) source = FONT; - tms_set_vram_write_addr(SCREEN1_PATTERN_TABLE+((128+32)*8)); + tms_set_vram_write_addr(TMS_PATTERN_TABLE+((128+32)*8)); for(word i=768;i!=0;i--) { TMS_WRITE_DATA_PORT(~(*source++)); } } -// holds the cursor location for the putchar routine -word screen1_cursor; +void screen1_cls() { + // fills name table with spaces (32) + tms_set_vram_write_addr(TMS_NAME_TABLE); + for(word i=SCREEN1_SIZE;i!=0;i--) { + TMS_WRITE_DATA_PORT(32); + } + tms_cursor_x = 0; + tms_cursor_y = 0; +} + +void screen1_scroll_up() { + word source = TMS_NAME_TABLE + 1*32; + word dest = TMS_NAME_TABLE + 0*32; + word count = 768-32; + for(;count!=0;source++,dest++,count--) { + tms_set_vram_read_addr(source); + byte c = TMS_READ_DATA_PORT; + tms_set_vram_write_addr(dest); + TMS_WRITE_DATA_PORT(c); + } + + // fill last line with spaces + for(word i=0;i<32;i++) { + TMS_WRITE_DATA_PORT(32); NOP; NOP; NOP; NOP; + } +} + +void screen1_prepare() { + // fill name table with spaces (32) + screen1_cls(); + + // fill pattern table with 0 + tms_set_vram_write_addr(TMS_PATTERN_TABLE); + for(word i=256*8;i!=0;i--) { + TMS_WRITE_DATA_PORT(0); + } + + // fill color table with black on white + tms_set_vram_write_addr(TMS_COLOR_TABLE); + for(byte i=32;i!=0;i--) { + TMS_WRITE_DATA_PORT(FG_BG(COLOR_BLACK,COLOR_WHITE)); + } +} + +#ifdef VIC20 +#define CHR_BACKSPACE 20 +#else +#define CHR_BACKSPACE 8 +#endif + +#define CHR_HOME 11 +#define CHR_CLS 12 +#define CHR_REVERSE_ON 15 +#define CHR_RETURN 13 +#define CHR_REVERSE_OFF 14 +#define CHR_SPACE 32 +#define CHR_REVSPACE (32+128) + +#define HOME "\x0b" +#define CLS "\x0c" +#define REVERSE_OFF "\x0e" +#define REVERSE_ON "\x0f" // prints character to TMS (SCREEN 1 MODE) void screen1_putc(byte c) { - tms_set_vram_write_addr(screen1_cursor++); - TMS_WRITE_DATA_PORT(c); + if(c==CHR_CLS) { + screen1_cls(); + } + else if(c==CHR_HOME) { + tms_cursor_x = 0; + tms_cursor_y = 0; + } + else if(c==CHR_REVERSE_OFF) { + // shift out as reverse off + tms_reverse = 0; + } + else if(c==CHR_REVERSE_ON) { + // shift in as reverse on + tms_reverse = 1; + } + else if(c==CHR_BACKSPACE) { + // backspace + if(tms_cursor_x!=0) { + tms_cursor_x--; + } + else { + if(tms_cursor_y!=0) { + tms_cursor_y--; + tms_cursor_x = 31; + } + } + } + else { + if(c=='\r'||c=='\n') { + tms_cursor_x=31; + } + else { + if(tms_reverse) c |= 128; + word addr = TMS_NAME_TABLE + (word) tms_cursor_y * 32 + tms_cursor_x; + tms_set_vram_write_addr(addr); + TMS_WRITE_DATA_PORT(c); + } + if(tms_cursor_x==31) { + tms_cursor_x=0; + if(tms_cursor_y==23) screen1_scroll_up(); + else tms_cursor_y++; + } + else tms_cursor_x++; + } } // prints a 0 terminated string to TMS (SCREEN 1 MODE) @@ -56,31 +139,40 @@ void screen1_puts(byte *s) { } } -void screen1_home() { - screen1_cursor = SCREEN1_NAME_TABLE; +inline void screen1_locate(byte x, byte y) { + tms_cursor_x = x; + tms_cursor_y = y; } -void screen1_locate(byte x, byte y) { - screen1_cursor = SCREEN1_NAME_TABLE + ((word)y)*32 + x; -} - -void screen1_prepare() { - // fills name table with spaces (32) - tms_set_vram_write_addr(SCREEN1_NAME_TABLE); - for(word i=SCREEN1_SIZE;i!=0;i--) { - TMS_WRITE_DATA_PORT(32); - } - - // fill pattern table with 0 - tms_set_vram_write_addr(SCREEN1_PATTERN_TABLE); - for(word i=256*8;i!=0;i--) { - TMS_WRITE_DATA_PORT(0); - } - - // fill color table with black on white - tms_set_vram_write_addr(SCREEN1_COLOR_TABLE); - for(byte i=32;i!=0;i--) { - TMS_WRITE_DATA_PORT(FG_BG(COLOR_BLACK,COLOR_WHITE)); +void screen1_strinput(byte *buffer, byte max_length) { + byte pos=0; + screen1_putc(CHR_REVSPACE); + screen1_putc(CHR_BACKSPACE); + while(1) { + byte key = apple1_getkey(); + if(key==CHR_RETURN) { + buffer[pos] = 0; + screen1_putc(CHR_SPACE); + screen1_putc(CHR_BACKSPACE); + return; + } + else if(key==CHR_BACKSPACE) { + if(pos!=0) { + pos--; + screen1_putc(CHR_BACKSPACE); + screen1_putc(CHR_REVSPACE); + screen1_putc(CHR_SPACE); + screen1_putc(CHR_BACKSPACE); + screen1_putc(CHR_BACKSPACE); + } + } + else if(key>=32 && key<=128) { + if(pos < max_length) { + buffer[pos++] = key; + screen1_putc(key); + screen1_putc(CHR_REVSPACE); + screen1_putc(CHR_BACKSPACE); + } + } } } - diff --git a/lib/tms_screen2.h b/lib/tms_screen2.h index e2361e3..0d0d417 100644 --- a/lib/tms_screen2.h +++ b/lib/tms_screen2.h @@ -1,34 +1,17 @@ -byte SCREEN2_TABLE[8] = { - 0x02, 0xc0, 0x0e, 0xff, 0x03, 0x76, 0x03, 0x25 -}; +byte SCREEN2_TABLE[8] = { 0x02, 0xc0, 0x0e, 0xff, 0x03, 0x76, 0x03, 0x25 }; -// 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); +const word SCREEN2_SIZE = (32*24); // prepare the screen 2 to be used as a bitmap void screen2_init_bitmap(byte color) { // erase the first sprite pattern - tms_set_vram_write_addr(SCREEN2_SPRITE_PATTERNS); // start writing in the sprite patterns + tms_set_vram_write_addr(TMS_SPRITE_PATTERNS); // start writing in the sprite patterns for(byte i=0;i<8;i++) { TMS_WRITE_DATA_PORT(0); NOP; } // set all sprite coordinates to 0 - tms_set_vram_write_addr(SCREEN2_SPRITE_ATTRS); // start writing in the sprite attribute + tms_set_vram_write_addr(TMS_SPRITE_ATTRS); // start writing in the sprite attribute for(byte i=0;i<32;i++) { TMS_WRITE_DATA_PORT(0); NOP; // y coordinate TMS_WRITE_DATA_PORT(0); NOP; // x coordinate @@ -37,21 +20,21 @@ void screen2_init_bitmap(byte color) { } // fill pattern table with 0 (clear screen) - tms_set_vram_write_addr(SCREEN2_PATTERN_TABLE); + tms_set_vram_write_addr(TMS_PATTERN_TABLE); for(word i=768*8;i!=0;i--) { TMS_WRITE_DATA_PORT(0); NOP; } // fill color table with black on white - tms_set_vram_write_addr(SCREEN2_COLOR_TABLE); + tms_set_vram_write_addr(TMS_COLOR_TABLE); for(word i=768*8;i!=0;i--) { TMS_WRITE_DATA_PORT(color); NOP; } // fills name table x3 with increasing numbers - tms_set_vram_write_addr(SCREEN2_NAME_TABLE); + tms_set_vram_write_addr(TMS_NAME_TABLE); for(word i=0;i