From d9beac69eb3b1c3678a3ac9498adff99cde4a8c6 Mon Sep 17 00:00:00 2001 From: Ian C Date: Fri, 20 Mar 2020 21:18:16 +0000 Subject: Basic keys added and now being read. --- src/czx81.c | 517 +++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 387 insertions(+), 130 deletions(-) diff --git a/src/czx81.c b/src/czx81.c index 1e50c5c..6d2f60f 100644 --- a/src/czx81.c +++ b/src/czx81.c @@ -66,6 +66,8 @@ /* -------------------------------------------------- GLOBALS */ +static int quit = FALSE; + static Z80Val FRAME_TSTATES = FAST_TSTATES; static Z80Byte mem[0x10000]; @@ -103,68 +105,130 @@ static wchar_t scrcode[0x40] = L'W', L'X', L'Y', L'Z', /* 3c - 3f */ }; +static int key_press_frames = 1; +static int current_key_press_frame = 0; +static int current_key = -1; -/* -------------------------------------------------- ZX81 CODE -*/ -static void RomPatch(const Z80Byte patch[], Z80Word addr) +static int trace = FALSE; + +static struct { - int f; + int key; /* The curses keycode */ + int no; /* The number of keys to press */ + int row[5]; /* The rows for each keypress */ + int bit[5]; /* The bit number for each keypress */ +} keymap[] = +{ + {'1', 1, {3}, {0x01}}, + {'2', 1, {3}, {0x02}}, + {'3', 1, {3}, {0x04}}, + {'4', 1, {3}, {0x08}}, + {'5', 1, {3}, {0x10}}, + + {'6', 1, {4}, {0x10}}, + {'7', 1, {4}, {0x08}}, + {'8', 1, {4}, {0x04}}, + {'9', 1, {4}, {0x02}}, + {'0', 1, {4}, {0x01}}, + + {'q', 1, {2}, {0x01}}, + {'w', 1, {2}, {0x02}}, + {'e', 1, {2}, {0x04}}, + {'r', 1, {2}, {0x08}}, + {'t', 1, {2}, {0x10}}, + + {'y', 1, {5}, {0x10}}, + {'u', 1, {5}, {0x08}}, + {'i', 1, {5}, {0x04}}, + {'o', 1, {5}, {0x02}}, + {'p', 1, {5}, {0x01}}, + + {'a', 1, {1}, {0x01}}, + {'s', 1, {1}, {0x02}}, + {'d', 1, {1}, {0x04}}, + {'f', 1, {1}, {0x08}}, + {'g', 1, {1}, {0x10}}, + + {'h', 1, {6}, {0x10}}, + {'j', 1, {6}, {0x08}}, + {'k', 1, {6}, {0x04}}, + {'l', 1, {6}, {0x02}}, + {'\n', 1, {6}, {0x01}}, + + /* Shift key skipped */ + /* {'', 1, {0}, {0x01}}, */ + {'z', 1, {0}, {0x02}}, + {'x', 1, {0}, {0x04}}, + {'c', 1, {0}, {0x08}}, + {'v', 1, {0}, {0x10}}, + + {'b', 1, {6}, {0x10}}, + {'n', 1, {6}, {0x08}}, + {'m', 1, {6}, {0x04}}, + {'.', 1, {6}, {0x02}}, + {' ', 1, {6}, {0x01}}, + + {ERR, 0, {0}, {0}} +}; - for(f = 0; patch[f] != 0xff; f++) - { - mem[addr++] = patch[f]; - } -} +static char message[1024]; -static int EDCallback(Z80 *z80, Z80Val data) +/* -------------------------------------------------- UTILS +*/ +static long TimeDiff(const struct timespec *start, + const struct timespec *end) { - Z80Word pause; + long diff; - switch((Z80Byte)data) - { - case ED_SAVE: - if (z80->DE.w < 0x8000) - { - /* TODO: Save */ - } + diff = (end->tv_nsec - start->tv_nsec) + + (end->tv_sec - start->tv_sec) * 1000000000L; - break; + return diff; +} - case ED_LOAD: - if (z80->DE.w < 0x8000) - { - /* TODO: Load */ - } - mem[CDFLAG] = 0xc0; +static void ClearScreen(void) +{ + clear(); +} - break; - case ED_WAITKEY: - waitkey = TRUE; - started = TRUE; - break; +static void RenderScreen(void) +{ + static int message_delay = 0; - case ED_ENDWAITKEY: - waitkey = FALSE; - break; + mvprintw(0, 40, "Message:"); - case ED_PAUSE: - waitkey = TRUE; + if (message[0] && message_delay == 0) + { + message_delay = 250; + } - pause = z80->BC.w; + if (message_delay > 0) + { + mvprintw(1, 40, message); + + if (--message_delay == 0) + { + message[0] = 0; + } + } - while(pause-- && !(mem[CDFLAG]&1)) - { - /* TODO: Pause code */ - } + refresh(); +} - waitkey = FALSE; - break; - } - return TRUE; +/* -------------------------------------------------- ZX81 CODE +*/ +static void RomPatch(const Z80Byte patch[], Z80Word addr) +{ + int f; + + for(f = 0; patch[f] != 0xff; f++) + { + mem[addr++] = patch[f]; + } } @@ -239,16 +303,108 @@ static void ZX81HouseKeeping(void) mem[CDFLAG] &= ~1; } - mem[LASTK1] = lastk1^0xff; - mem[LASTK2] = lastk2^0xff; + mem[LASTK1] = lastk1 ^ 0xff; + mem[LASTK2] = lastk2 ^ 0xff; prev_lk1 = lastk1; prev_lk2 = lastk2; } +static void DrawScreen(void) +{ + int fast; + int x,y; + + fast = (FRAME_TSTATES == FAST_TSTATES); + + if (fast) + { + for(y = 0; y < TXT_H; y++) + { + for(x = 0; x < TXT_W; x++) + { + mvprintw(y, x, "%lc", L'\u2592'); + } + } + } + else + { + Z80Byte *scr; + + scr = mem + PEEKW(DFILE); + y = 0; + + while(y < TXT_H) + { + scr++; + x = 0; + + while(*scr != 118 && x < TXT_W) + { + Z80Byte ch = *scr++; + + if (ch & 0x80) + { + attron(A_REVERSE); + } + + mvprintw(y, x, "%lc", scrcode[ch & 0x3f]); + + if (ch & 0x80) + { + attroff(A_REVERSE); + } + + x++; + } + + y++; + } + } +} + +static void Trace(void) +{ + Z80Word addr = z80->PC; + int f; + + for(f = 3; f < 24; f++) + { + mvprintw(f, 40, "%4.4x:", addr); + mvprintw(f, 45, "%-35.35s", Z80Disassemble(z80, &addr)); + } + + f = 26; + + if (f < LINES) mvprintw(f++, 0, "AF = %4.4x", z80->AF.w); + if (f < LINES) mvprintw(f++, 0, "BC = %4.4x", z80->BC.w); + if (f < LINES) mvprintw(f++, 0, "DE = %4.4x", z80->DE.w); + if (f < LINES) mvprintw(f++, 0, "HL = %4.4x", z80->HL.w); + if (f < LINES) mvprintw(f++, 0, "IX = %4.4x", z80->IX.w); + if (f < LINES) mvprintw(f++, 0, "IY = %4.4x", z80->IY.w); + if (f < LINES) mvprintw(f++, 0, "SP = %4.4x", z80->SP); + if (f < LINES) mvprintw(f++, 0, "MATRIX = %2.2x/%2.2x/%2.2x/%2.2x/%2.2x" + "/%2.2x/%2.2x/%2.2x", matrix[0], + matrix[1], + matrix[2], + matrix[3], + matrix[4], + matrix[5], + matrix[6], + matrix[7]); + + refresh(); +} + + static int CheckTimers(Z80 *z80, Z80Val val) { + if (trace) + { + Trace(); + } + if (val >= FRAME_TSTATES) { Z80ResetCycles(z80, val - FRAME_TSTATES); @@ -262,6 +418,8 @@ static int CheckTimers(Z80 *z80, Z80Val val) FRAME_TSTATES = FAST_TSTATES; } + DrawScreen(); + if (z80->SP < 0x8000) { ZX81HouseKeeping(); @@ -276,6 +434,104 @@ static int CheckTimers(Z80 *z80, Z80Val val) } +static void PressKey(int key) +{ + int f; + + if (current_key_press_frame > 0) + { + if (--current_key_press_frame <= 0) + { + current_key_press_frame = 0; + + for(f = 0; f < keymap[current_key].no; f++) + { + matrix[keymap[current_key].row[f]] |= + keymap[current_key].bit[f]; + } + + current_key = -1; + } + } + else + { + if (key != ERR) + { + int n; + + for(n = 0; keymap[n].key != ERR && current_key == -1; n++) + { + if (keymap[n].key == key) + { + current_key_press_frame = key_press_frames; + current_key = n; + + for(f = 0; f < keymap[current_key].no; f++) + { + matrix[keymap[current_key].row[f]] &= + ~keymap[current_key].bit[f]; + } + } + } + } + } +} + + +static int EDCallback(Z80 *z80, Z80Val data) +{ + Z80Word pause; + + switch((Z80Byte)data) + { + case ED_SAVE: + if (z80->DE.w < 0x8000) + { + /* TODO: Save */ + } + + break; + + case ED_LOAD: + if (z80->DE.w < 0x8000) + { + /* TODO: Load */ + } + + mem[CDFLAG] = 0xc0; + + break; + + case ED_WAITKEY: + waitkey = TRUE; + started = TRUE; + break; + + case ED_ENDWAITKEY: + waitkey = FALSE; + break; + + case ED_PAUSE: + waitkey = TRUE; + + pause = z80->BC.w; + + while(pause-- && !(mem[CDFLAG]&1)) + { + ClearScreen(); + PressKey(getch()); + CheckTimers(z80, FRAME_TSTATES); + RenderScreen(); + } + + waitkey = FALSE; + break; + } + + return TRUE; +} + + static Z80Byte ZX81ReadMem(Z80 *z80, Z80Word addr) { return mem[addr]; @@ -295,6 +551,8 @@ static Z80Byte ZX81ReadPort(Z80 *z80, Z80Word port) { Z80Byte b = 0; + sprintf(message,"IN() called with %4.4x MARGIN=%d", port, mem[MARGIN]); + switch(port & 0xff) { case 0xfe: @@ -342,11 +600,42 @@ static Z80Byte ZX81ReadPort(Z80 *z80, Z80Word port) } -void ZX81WritePort(Z80 *z80, Z80Word port, Z80Byte val) +static void ZX81WritePort(Z80 *z80, Z80Word port, Z80Byte val) { } +static void ZX81Reset(void) +{ + int f; + + Z80Reset(z80); + + /* 16K of memory + */ + RAMBOT = 0x4000; + RAMTOP = RAMBOT + 0x4000; + + for(f = RAMBOT; f <= RAMTOP; f++) + { + mem[f] = 0; + } + + /* Keyboard matrix + */ + for(f = 0; f < 8; f++) + { + matrix[f] = 0x1f; + } + + /* Fill the upper 32K with RET opcodes for ULA reads + */ + for(f = 0x8000; f < 0x10000; f++) + { + mem[f] = 0xc9; + } +} + static void ZX81Init(void) { static const Z80Byte save[]= @@ -387,8 +676,6 @@ static void ZX81Init(void) 0xff /* End of patch */ }; - int f; - /* Load and patch ROM */ memcpy(mem, ZX81ROM, ROMLEN); @@ -414,106 +701,65 @@ static void ZX81Init(void) */ memcpy(mem + ROMLEN, mem, ROMLEN); - /* 16K of memory - */ - RAMBOT = 0x4000; - RAMTOP = RAMBOT + 0x4000; - - for(f = RAMBOT; f <= RAMTOP; f++) - { - mem[f] = 0; - } - - /* Keyboard matrix - */ - for(f = 0; f < 8; f++) - { - matrix[f] = 0x1f; - } - - /* Fill the upper 32K with RET opcodes for ULA reads - */ - for(f = 0x8000; f < 0x10000; f++) - { - mem[f] = 0xc9; - } + ZX81Reset(); } -static void DrawScreen(void) +/* -------------------------------------------------- MENU +*/ +static void Menu() { - int fast; - int x,y; + int done = FALSE; - fast = (FRAME_TSTATES == FAST_TSTATES); + erase(); - if (fast) + while(!done) { - for(y = 0; y < TXT_H; y++) - { - for(x = 0; x < TXT_W; x++) - { - mvprintw(y, x, "%lc", L'\u2592'); - } - } - } - else - { - Z80Byte *scr; - - scr = mem + PEEKW(DFILE); - y = 0; + int ch; - while(y < TXT_H) - { - scr++; - x = 0; + mvprintw(0, 0, "F1 .. Tracing %s", trace ? "ON ":"OFF"); + mvprintw(2, 0, "F2 .. Frames per key press: %2d", key_press_frames); + mvprintw(4, 0, "F3 .. Quit"); + mvprintw(6, 0, "Press ESCAPE to resume"); - while(*scr != 118 && x < TXT_W) - { - Z80Byte ch = *scr++; + refresh(); - if (ch & 0x80) - { - attron(A_REVERSE); - } + ch = getch(); - mvprintw(y, x, "%lc", scrcode[ch & 0x3f]); + switch(ch) + { + case KEY_F(1): + trace = !trace; + break; - if (ch & 0x80) + case KEY_F(2): + if (++key_press_frames == 10) { - attroff(A_REVERSE); + key_press_frames = 1; } + break; - x++; - } + case KEY_F(3): + quit = TRUE; + done = TRUE; + break; - y++; + case 27: + done = TRUE; + break; + + default: + break; } } } -/* -------------------------------------------------- UTILS -*/ -static long TimeDiff(const struct timespec *start, - const struct timespec *end) -{ - long diff; - - diff = (end->tv_nsec - start->tv_nsec) + - (end->tv_sec - start->tv_sec) * 1000000000L; - - return diff; -} - - /* -------------------------------------------------- MAIN */ int main(void) { struct timespec start; - int quit = FALSE; setlocale(LC_ALL, ""); @@ -539,6 +785,8 @@ int main(void) clock_gettime(CLOCK_MONOTONIC, &start); + ClearScreen(); + while(!quit) { struct timespec end; @@ -547,18 +795,27 @@ int main(void) Z80Exec(z80); - clear(); - - DrawScreen(); - ch = getch(); - if (ch == 3) + switch(ch) { - quit = TRUE; + case 3: + quit = TRUE; + break; + + case 27: + nodelay(stdscr, FALSE); + Menu(); + ClearScreen(); + nodelay(stdscr, TRUE); + break; + + default: + PressKey(ch); + break; } - refresh(); + RenderScreen(); clock_gettime(CLOCK_MONOTONIC, &end); start = end; -- cgit v1.2.3