Emulator: separated terminal and status windows
This commit is contained in:
		@@ -12,6 +12,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define ROM_SIZE         0x8000 /* 32 KiB */
 | 
					#define ROM_SIZE         0x8000 /* 32 KiB */
 | 
				
			||||||
#define MEMORY_SIZE      0xFFFF /* 64 KiB */
 | 
					#define MEMORY_SIZE      0xFFFF /* 64 KiB */
 | 
				
			||||||
 | 
					#define TERMINAL_WIDTH   60
 | 
				
			||||||
 | 
					#define TERMINAL_HEIGHT  25
 | 
				
			||||||
 | 
					#define SPACING_BETWEEN_WINDOWS 3
 | 
				
			||||||
 | 
					#define INSTRUCTION_WINDOW_HEIGHT 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
        void* context;
 | 
					        void* context;
 | 
				
			||||||
@@ -23,6 +27,8 @@ typedef struct {
 | 
				
			|||||||
        zusize  cycles;
 | 
					        zusize  cycles;
 | 
				
			||||||
        zuint8  memory[65536];
 | 
					        zuint8  memory[65536];
 | 
				
			||||||
        Z80     cpu;
 | 
					        Z80     cpu;
 | 
				
			||||||
 | 
					        WINDOW  *terminal_win;
 | 
				
			||||||
 | 
					        WINDOW  *status_win;
 | 
				
			||||||
} Machine;
 | 
					} Machine;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -47,44 +53,59 @@ static zuint8 machine_cpu_in(Machine *self, zuint16 port) {
 | 
				
			|||||||
	if (decoded <= 0x1F) {
 | 
						if (decoded <= 0x1F) {
 | 
				
			||||||
		// Port 0 (0x00 to 0x1F): terminal
 | 
							// Port 0 (0x00 to 0x1F): terminal
 | 
				
			||||||
		// Read char from stin
 | 
							// Read char from stin
 | 
				
			||||||
                return getch();
 | 
					                char c = getch();
 | 
				
			||||||
 | 
					                // Intercept emulator commands
 | 
				
			||||||
 | 
					                switch (c) {
 | 
				
			||||||
 | 
					                        case 27:
 | 
				
			||||||
 | 
					                                // ESC: shutdown emulator
 | 
				
			||||||
 | 
					                                exit(0);        // TODO: Shutdown ncurses and emulator cleanly
 | 
				
			||||||
 | 
					                                return 0;
 | 
				
			||||||
 | 
					                        default:
 | 
				
			||||||
 | 
					                                // Deliver keypress to pat80
 | 
				
			||||||
 | 
					                                return c;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (decoded <=  0x3F) {
 | 
					        if (decoded <=  0x3F) {
 | 
				
			||||||
                // Port 1 (0x20 to 0x3F): sound card (sn76489)
 | 
					                // Port 1 (0x20 to 0x3F): sound card (sn76489)
 | 
				
			||||||
		printw("\nsound_cmd[IN]: Not supported!\n");
 | 
							wprintw(self->status_win, "sound_cmd[IN]: Not supported!\n");
 | 
				
			||||||
                return 0x00;
 | 
					                return 0x00;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (decoded <=  0x5F) {
 | 
					        if (decoded <=  0x5F) {
 | 
				
			||||||
                // Port 2 (0x40 to 0x5F)
 | 
					                // Port 2 (0x40 to 0x5F)
 | 
				
			||||||
                printw("IO_ERROR_IN: No device at port 2\n");
 | 
					                wprintw(self->status_win, "IO_ERROR_IN: No device at port 2\n");
 | 
				
			||||||
                return 0x00;
 | 
					                return 0x00;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (decoded <=  0x7F) {
 | 
					        if (decoded <=  0x7F) {
 | 
				
			||||||
                // Port 3 (0x60 to 0x7F)
 | 
					                // Port 3 (0x60 to 0x7F)
 | 
				
			||||||
                printw("IO_ERROR_IN: No device at port 3\n");
 | 
					                wprintw(self->status_win, "IO_ERROR_IN: No device at port 3\n");
 | 
				
			||||||
                return 0x00;
 | 
					                return 0x00;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (decoded <=  0x9F) {
 | 
					        if (decoded <=  0x9F) {
 | 
				
			||||||
                // Port 4 (0x80 to 0x9F)
 | 
					                // Port 4 (0x80 to 0x9F)
 | 
				
			||||||
                printw("IO_ERROR_IN: No device at port 4\n");
 | 
					                wprintw(self->status_win, "IO_ERROR_IN: No device at port 4\n");
 | 
				
			||||||
                return 0x00;
 | 
					                return 0x00;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (decoded <=  0x5F) {
 | 
					        if (decoded <=  0x5F) {
 | 
				
			||||||
                // Port 5 (0xA0 to 0xBF)
 | 
					                // Port 5 (0xA0 to 0xBF)
 | 
				
			||||||
                printw("IO_ERROR_IN: No device at port 5\n");
 | 
					                wprintw(self->status_win, "IO_ERROR_IN: No device at port 5\n");
 | 
				
			||||||
                return 0x00;
 | 
					                return 0x00;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (decoded <=  0x5F) {
 | 
					        if (decoded <=  0x5F) {
 | 
				
			||||||
                // Port 6 (0xC0 to 0xDF)
 | 
					                // Port 6 (0xC0 to 0xDF)
 | 
				
			||||||
                printw("IO_ERROR_IN: No device at port 6\n");
 | 
					                wprintw(self->status_win, "IO_ERROR_IN: No device at port 6\n");
 | 
				
			||||||
                return 0x00;
 | 
					                return 0x00;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (decoded <=  0x5F) {
 | 
					        if (decoded <=  0x5F) {
 | 
				
			||||||
                // Port 7 (0xE0 to 0xFF)
 | 
					                // Port 7 (0xE0 to 0xFF)
 | 
				
			||||||
                printw("IO_ERROR_IN: No device at port 7\n");
 | 
					                wprintw(self->status_win, "IO_ERROR_IN: No device at port 7\n");
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
                printw("IO_ERROR_IN: Invalid port address: %#04x\n", port);
 | 
					                wprintw(self->status_win, "IO_ERROR_IN: Invalid port address: %#04x\n", port);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // TODO: place this in a refresh cycle between CPU instructions
 | 
				
			||||||
 | 
					        refresh();
 | 
				
			||||||
 | 
					        wrefresh(self->terminal_win);
 | 
				
			||||||
 | 
					        wrefresh(self->status_win);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -97,33 +118,36 @@ static void machine_cpu_out(Machine *self, zuint16 port, zuint8 value) {
 | 
				
			|||||||
        int decoded = port & bitmask;
 | 
					        int decoded = port & bitmask;
 | 
				
			||||||
	if (decoded <= 0x1F) {
 | 
						if (decoded <= 0x1F) {
 | 
				
			||||||
		// Port 0 (0x00 to 0x1F): terminal
 | 
							// Port 0 (0x00 to 0x1F): terminal
 | 
				
			||||||
                attron(A_BOLD);
 | 
							wprintw(self->terminal_win, "%c", value);
 | 
				
			||||||
		printw("%c", value);
 | 
					 | 
				
			||||||
                attroff(A_BOLD);
 | 
					 | 
				
			||||||
	} else if (decoded <= 0x3F) {
 | 
						} else if (decoded <= 0x3F) {
 | 
				
			||||||
                // Port 1 (0x20 to 0x3F): sound card (sn76489)
 | 
					                // Port 1 (0x20 to 0x3F): sound card (sn76489)
 | 
				
			||||||
		printw("\nsound_cmd[%#04x]\n", value);
 | 
							wprintw(self->status_win, "sound_cmd[%#04x]\n", value);
 | 
				
			||||||
        } else if (decoded <= 0x5F) {
 | 
					        } else if (decoded <= 0x5F) {
 | 
				
			||||||
                // Port 2 (0x40 to 0x5F)
 | 
					                // Port 2 (0x40 to 0x5F)
 | 
				
			||||||
                printw("IO_ERROR_OUT: No device at port 2\n");
 | 
					                wprintw(self->status_win, "IO_ERROR_OUT: No device at port 2\n");
 | 
				
			||||||
        } else if (decoded <= 0x7F) {
 | 
					        } else if (decoded <= 0x7F) {
 | 
				
			||||||
                // Port 3 (0x60 to 0x7F)
 | 
					                // Port 3 (0x60 to 0x7F)
 | 
				
			||||||
                printw("IO_ERROR_OUT: No device at port 3\n");
 | 
					                wprintw(self->status_win, "IO_ERROR_OUT: No device at port 3\n");
 | 
				
			||||||
        } else if (decoded <= 0x9F) {
 | 
					        } else if (decoded <= 0x9F) {
 | 
				
			||||||
                // Port 4 (0x80 to 0x9F)
 | 
					                // Port 4 (0x80 to 0x9F)
 | 
				
			||||||
                printw("IO_ERROR_OUT: No device at port 4\n");
 | 
					                wprintw(self->status_win, "IO_ERROR_OUT: No device at port 4\n");
 | 
				
			||||||
        } else if (decoded <= 0x5F) {
 | 
					        } else if (decoded <= 0x5F) {
 | 
				
			||||||
                // Port 5 (0xA0 to 0xBF)
 | 
					                // Port 5 (0xA0 to 0xBF)
 | 
				
			||||||
                printw("IO_ERROR_OUT: No device at port 5\n");
 | 
					                wprintw(self->status_win, "IO_ERROR_OUT: No device at port 5\n");
 | 
				
			||||||
        } else if (decoded <= 0x5F) {
 | 
					        } else if (decoded <= 0x5F) {
 | 
				
			||||||
                // Port 6 (0xC0 to 0xDF)
 | 
					                // Port 6 (0xC0 to 0xDF)
 | 
				
			||||||
                printw("IO_ERROR_OUT: No device at port 6\n");
 | 
					                wprintw(self->status_win, "IO_ERROR_OUT: No device at port 6\n");
 | 
				
			||||||
        } else if (decoded <= 0x5F) {
 | 
					        } else if (decoded <= 0x5F) {
 | 
				
			||||||
                // Port 7 (0xE0 to 0xFF)
 | 
					                // Port 7 (0xE0 to 0xFF)
 | 
				
			||||||
                printw("IO_ERROR_OUT: No device at port 7\n");
 | 
					                wprintw(self->status_win, "IO_ERROR_OUT: No device at port 7\n");
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
                printw("IO_ERROR_OUT: Invalid port address: %#04x\n", port);
 | 
					                wprintw(self->status_win, "IO_ERROR_OUT: Invalid port address: %#04x\n", port);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // TODO: place this in a refresh cycle between CPU instructions
 | 
				
			||||||
 | 
					        refresh();
 | 
				
			||||||
 | 
					        wrefresh(self->terminal_win);
 | 
				
			||||||
 | 
					        wrefresh(self->status_win);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -177,13 +201,36 @@ int main(int argc, char *argv[]) {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        char* romFilePath = argv[1];
 | 
					        char* romFilePath = argv[1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Init ncurses
 | 
				
			||||||
 | 
						initscr();			// Start curses mode
 | 
				
			||||||
 | 
						raw();				// Line buffering disabled (get character without waiting for ENTER key)
 | 
				
			||||||
 | 
						keypad(stdscr, TRUE);		// We get F1, F2 etc..
 | 
				
			||||||
 | 
						noecho();			// Don't echo() while we do getch
 | 
				
			||||||
 | 
					        start_color();                  // Use colors
 | 
				
			||||||
 | 
					        init_pair(1, COLOR_WHITE, COLOR_BLUE); // Terminal window color
 | 
				
			||||||
 | 
					        init_pair(2, COLOR_YELLOW, COLOR_BLACK); // Status window color
 | 
				
			||||||
 | 
					        int x,y;
 | 
				
			||||||
 | 
					        getmaxyx(stdscr, y,x);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Setup virtual Pat80 computer
 | 
					        // Setup virtual Pat80 computer
 | 
				
			||||||
        Z80 pat80Cpu = {};
 | 
					        Z80 pat80Cpu = {};
 | 
				
			||||||
        Machine pat80 = {
 | 
					        Machine pat80 = {
 | 
				
			||||||
                /*zusize*/  .cycles = 0,
 | 
					                /*zusize*/  .cycles = 0,
 | 
				
			||||||
                /*Z80*/     .cpu = pat80Cpu
 | 
					                /*Z80*/     .cpu = pat80Cpu,
 | 
				
			||||||
 | 
					                .terminal_win = newwin(TERMINAL_HEIGHT, TERMINAL_WIDTH, INSTRUCTION_WINDOW_HEIGHT, 0),
 | 
				
			||||||
 | 
					                .status_win = newwin(y, x - TERMINAL_WIDTH - SPACING_BETWEEN_WINDOWS, INSTRUCTION_WINDOW_HEIGHT, TERMINAL_WIDTH + SPACING_BETWEEN_WINDOWS)
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        wbkgd(pat80.terminal_win, COLOR_PAIR(1));       // Ncurses: set terminal window color
 | 
				
			||||||
 | 
					        wbkgd(pat80.status_win, COLOR_PAIR(2));
 | 
				
			||||||
 | 
					        scrollok(pat80.terminal_win, TRUE);             // Ncurses: Allow scrolling when reached end of window
 | 
				
			||||||
 | 
					        scrollok(pat80.status_win, TRUE);
 | 
				
			||||||
 | 
					        attron(A_BOLD);                                 // Print instructions
 | 
				
			||||||
 | 
					        printw("Emulator commands\n");
 | 
				
			||||||
 | 
					        attroff(A_BOLD);
 | 
				
			||||||
 | 
					        printw("ESC: Exit");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        machine_initialize(&pat80);
 | 
					        machine_initialize(&pat80);
 | 
				
			||||||
        machine_power(&pat80, Z_TRUE);
 | 
					        machine_power(&pat80, Z_TRUE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -197,18 +244,13 @@ int main(int argc, char *argv[]) {
 | 
				
			|||||||
        fread(&pat80.memory,ROM_SIZE,1,romFile); // load rom from file into memory, up >
 | 
					        fread(&pat80.memory,ROM_SIZE,1,romFile); // load rom from file into memory, up >
 | 
				
			||||||
        fclose(romFile);
 | 
					        fclose(romFile);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Init ncurses
 | 
					 | 
				
			||||||
	initscr();			// Start curses mode
 | 
					 | 
				
			||||||
	raw();				// Line buffering disabled (get character without waiting for ENTER key)
 | 
					 | 
				
			||||||
	keypad(stdscr, TRUE);		// We get F1, F2 etc..
 | 
					 | 
				
			||||||
	noecho();			// Don't echo() while we do getch
 | 
					 | 
				
			||||||
        scrollok(stdscr, TRUE);         // Allow scrolling when reached end of window
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Start emulated computer
 | 
					        // Start emulated computer
 | 
				
			||||||
        machine_reset(&pat80);
 | 
					        machine_reset(&pat80);
 | 
				
			||||||
        machine_run(&pat80);
 | 
					        machine_run(&pat80);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Stop ncurses
 | 
					        // Stop ncurses
 | 
				
			||||||
	endwin();			/* End curses mode		  */
 | 
					        delwin(pat80.terminal_win);
 | 
				
			||||||
 | 
					        delwin(pat80.status_win);
 | 
				
			||||||
 | 
					        endwin();
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user