From e2f4e398c33f30f9b03448fb6687b7e06a65f21f Mon Sep 17 00:00:00 2001 From: Ian C Date: Sun, 22 Mar 2020 21:28:09 +0000 Subject: Added load/save and some extra instructions. --- doc/instruction.txt | 20 ++++++ src/Makefile | 1 + src/czx81.c | 172 +++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 186 insertions(+), 7 deletions(-) diff --git a/doc/instruction.txt b/doc/instruction.txt index a399cd7..530dab9 100644 --- a/doc/instruction.txt +++ b/doc/instruction.txt @@ -44,6 +44,9 @@ KEYBOARD BACKSPACE - Emulate the RUBOUT key (shift 0) DELETE - Emulate the RUBOUT key (shift 0) + When emulating the keyboard the key is held down for a default of one frame. + This can be altered in the runtime menu. + LOADING AND SAVING ------------------ @@ -58,6 +61,23 @@ LOADING AND SAVING be enabled. See the CONFIGURATION FILE section. +RUNTIME MENU +------------ + + When you press ESCAPE the runtime menu is displayed and offers the following + options: + + F1 - Toggle tracing on and off. When on tracing will display the + disassembly at the PC and the state of the Z80 registers. + + F2 - Alter the number of frames the key is held down following a + keypress. The default of 1 works OK for BASIC. + + F3 - Reset the ZX81. + + F4 - Quit the emulator. + + CONFIGURATION FILE ------------------ diff --git a/src/Makefile b/src/Makefile index 9fc766e..e1aa066 100644 --- a/src/Makefile +++ b/src/Makefile @@ -17,6 +17,7 @@ TARGET=czx81 # This library may need to be set to one of these: +# curses # cursesw # ncursesw CURSES=-lncurses diff --git a/src/czx81.c b/src/czx81.c index 27bfe5b..55bae6a 100644 --- a/src/czx81.c +++ b/src/czx81.c @@ -111,6 +111,9 @@ static int current_key = -1; static int trace = FALSE; +static char snappath[4096] = "."; +static int allow_save = FALSE; + static struct { int key; /* The curses keycode */ @@ -291,6 +294,101 @@ static void RenderScreen(void) } +static FILE *OpenTapeFile(Z80Word addr, const char *mode) +{ + static const char zx_chars[] = "\"#$:?()><=+-*/;,." + "0123456789" + "abcdefghijklmnopqrstuvwxyz"; + char full_fn[4096]; + char fn[4096]; + int f; + int done; + + done = FALSE; + f = 0; + + while(!done) + { + int ch; + + ch = mem[addr++]; + + if (ch & 0x80) + { + done = TRUE; + ch &= 0x7f; + } + + if (ch >= 11 && ch <=63) + { + fn[f++] = zx_chars[ch - 11]; + } + } + + fn[f] = 0; + + sprintf(full_fn, "%s/%s", snappath, fn); + + return fopen(full_fn, mode); +} + + +static void ReadConfig(void) +{ + char fn[4096] = {0}; + char *env; + FILE *fp; + + if ((env = getenv("HOME"))) + { + strcpy(fn, env); + strcat(fn, "/"); + } + + strcat(fn, ".czx81rc"); + + if ((fp = fopen(fn, "r"))) + { + char s[4096]; + + while(fgets(s, sizeof s, fp)) + { + size_t l; + char *tok1 = NULL; + char *tok2 = NULL; + + l = strlen(s); + + while(l && s[l - 1] == '\n') + { + s[--l] = 0; + } + + tok1 = strtok(s, " \t"); + + if (tok1) + { + tok2 = strtok(NULL, " \t"); + } + + if (strcmp(tok1, "snappath") == 0) + { + if (tok2) + { + strcpy(snappath, tok2); + } + } + else if (strcmp(tok1, "allowsave") == 0) + { + allow_save = TRUE; + } + } + + fclose(fp); + } +} + + /* -------------------------------------------------- ZX81 CODE */ static void RomPatch(const Z80Byte patch[], Z80Word addr) @@ -552,14 +650,34 @@ static void PressKey(int key) static int EDCallback(Z80 *z80, Z80Val data) { - Z80Word pause; - switch((Z80Byte)data) { case ED_SAVE: - if (z80->DE.w < 0x8000) + if (allow_save && z80->DE.w < 0x8000) { - /* TODO: Save */ + FILE *fp; + + fp = OpenTapeFile(z80->HL.w, "wb"); + + if (fp) + { + int f; + int end; + + f = 0x4009; + end = PEEKW(E_LINE); + + while(f <= end) + { + fputc(mem[f++], fp); + } + + fclose(fp); + } + else + { + sprintf(message, "Failed to open file"); + } } break; @@ -567,7 +685,28 @@ static int EDCallback(Z80 *z80, Z80Val data) case ED_LOAD: if (z80->DE.w < 0x8000) { - /* TODO: Load */ + FILE *fp; + + fp = OpenTapeFile(z80->DE.w, "rb"); + + if (fp) + { + int c; + Z80Byte *a; + + a = mem + 0x4009; + + while((c = getc(fp)) != EOF) + { + *a++ = c; + } + + fclose(fp); + } + else + { + sprintf(message, "Failed to open file"); + } } mem[CDFLAG] = 0xc0; @@ -584,20 +723,37 @@ static int EDCallback(Z80 *z80, Z80Val data) break; case ED_PAUSE: + { + Z80Word pause; + struct timespec start; + waitkey = TRUE; pause = z80->BC.w; while(pause-- && !(mem[CDFLAG]&1)) { + struct timespec end; + struct timespec pause = {0}; + ClearScreen(); PressKey(getch()); CheckTimers(z80, FRAME_TSTATES); RenderScreen(); + + clock_gettime(CLOCK_MONOTONIC, &end); + start = end; + pause.tv_nsec = 20000000 - TimeDiff(&start, &end); + + if (pause.tv_nsec > 0 && FRAME_TSTATES != FAST_TSTATES) + { + nanosleep(&pause, NULL); + } } waitkey = FALSE; break; + } } return TRUE; @@ -840,6 +996,8 @@ int main(void) setlocale(LC_ALL, ""); + ReadConfig(); + z80 = Z80Init(ZX81ReadMem, ZX81WriteMem, ZX81ReadPort, @@ -862,14 +1020,14 @@ int main(void) clock_gettime(CLOCK_MONOTONIC, &start); - ClearScreen(); - while(!quit) { struct timespec end; struct timespec pause = {0}; int ch; + ClearScreen(); + Z80Exec(z80); ch = getch(); -- cgit v1.2.3