summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/czx81.c517
1 files 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;