19 #define XEP128_NEED_SDL_WMINFO
25 #include "rom/ep128/xep_rom_syms.h"
40 #include <sysinfoapi.h>
58 static const char TOO_LONG_OUTPUT_BUFFER[] =
" ...%s*** Too long output%s";
59 static const char *_dave_ws_descrs[4] = {
60 "all",
"M1",
"no",
"no"
63 static volatile int is_queued_command = 0;
64 static char queued_command[256];
66 static char input_buffer[256];
68 static char *output_p;
69 static char *output_limit;
70 static const char *output_nl;
72 static Uint16 dump_addr1 = 0;
73 static Uint8 dump_addr2 = 0;
74 static int dump_pagerel = 0;
75 static Uint16 disasm_addr1 = 0;
76 static Uint8 disasm_addr2 = 0;
77 static int disasm_pagerel = 0;
81 #define MPRINTF(...) do { \
82 char __mprintf__buffer__[0x4000]; \
83 snprintf(__mprintf__buffer__, sizeof __mprintf__buffer__, __VA_ARGS__); \
84 __mprintf_append_helper(__mprintf__buffer__); \
92 static void __mprintf_append_helper (
char *s )
95 if (output_p >= output_limit) {
96 sprintf(output_limit - strlen(TOO_LONG_OUTPUT_BUFFER), TOO_LONG_OUTPUT_BUFFER, output_nl, output_nl);
102 const char *n = output_nl;
104 *(output_p++) = *(n++);
107 *(output_p++) = *(s++);
114 static char *get_mon_arg (
int limitrangecode )
117 while (*input_p && *input_p <= 32)
122 while (*input_p >= limitrangecode)
131 static int get_mon_arg_hex (
int *hex1,
int *hex2 )
133 char *h = get_mon_arg(
ARG_ONE);
137 return sscanf(h,
"%x:%x", hex1, hex2);
142 static void cmd_testargs (
void ) {
144 r = get_mon_arg_hex(&h1, &h2);
145 MPRINTF(
"Tried to parse first arg as hex, result: r=%d, h1=%x, h2=%x\n",
149 char *p = get_mon_arg(
ARG_ONE);
151 MPRINTF(
"No more args found!\n");
154 MPRINTF(
"Another arg found: \"%s\"\n", p);
159 #define SEGMENT_OF_Z80_ADDR(n) ports[0xB0 | (((n) & 0xFFFF) >> 14)]
162 static void set_memaddr_by_arg (
Uint16 *da1,
Uint8 *da2,
int *dm )
165 get_mon_arg_hex(&h1, &h2);
171 MPRINTF(
"; Absolute addresses from %04X:%02X\n", *da1, *da2);
172 }
else if (h1 >= 0) {
173 MPRINTF(
"; CPU paging relative from %04X\n", *da1);
182 static void cmd_memdump (
void )
185 set_memaddr_by_arg(&dump_addr1, &dump_addr2, &dump_pagerel);
186 for (row = 0; row < 10; row++) {
191 dump_pagerel ?
'*' :
'=',
194 for (col = 0; col < 16; col++) {
195 Uint8 byte =
memory[(dump_addr2 << 14) | (dump_addr1 & 0x3FFF)];
196 asciibuf[col] = (
byte >= 32 &&
byte < 127) ?
byte :
'.';
199 if (!(dump_addr1 & 0x3FFF)) {
218 return memory[((disasm_addr2 << 14) + (disasm_addr1 & 0x3FFF) + (
addr - disasm_addr1)) & 0x3FFFFF];
223 static void cmd_disasm (
void )
226 set_memaddr_by_arg(&disasm_addr1, &disasm_addr2, &disasm_pagerel);
227 for (lines = 0; lines < 10; lines++) {
228 char dasm_out_buffer[128];
229 char hex_out_buffer[32];
230 char asc_out_buffer[16];
231 int t_states, t_states2,
r, h;
234 r =
z80ex_dasm(dasm_out_buffer,
sizeof dasm_out_buffer, 0, &t_states, &t_states2, byte_reader, disasm_addr1);
235 if (byte_reader(disasm_addr1) == 0xF7) {
236 h = byte_reader(disasm_addr1 + 1);
238 snprintf(dasm_out_buffer,
sizeof dasm_out_buffer,
"EXOS $%02X", h);
240 for (h = 0, hex_out_buffer[0] = 0, asc_out_buffer[0] =
'\''; h <
r; h++) {
241 Uint8 byte = byte_reader(disasm_addr1 + h);
242 sprintf(hex_out_buffer + h * 3,
"%02X ",
byte);
243 asc_out_buffer[h + 1] = (
byte >= 32 &&
byte < 127) ?
byte :
'.';
244 asc_out_buffer[h + 2] =
'\0';
246 strcat(asc_out_buffer,
"'");
247 p = strchr(dasm_out_buffer,
' ');
250 MPRINTF(
"%04X:%c%02X %-12s%-4s %-16s ; %-6s L=%d T=%d/%d\n",
252 disasm_pagerel ?
'*' :
'=',
258 r, t_states, t_states2
260 if (disasm_addr1 >> 14 != ((disasm_addr1 +
r) >> 14)) {
272 static void cmd_registers (
void ) {
274 "AF =%04X BC =%04X DE =%04X HL =%04X IX=%04X IY=%04X F=%c%c%c%c%c%c%c%c IM=%d IFF=%d,%d\n"
275 "AF'=%04X BC'=%04X DE'=%04X HL'=%04X PC=%04X SP=%04X Prefix=%02X P=%02X,%02X,%02X,%02X\n",
277 (
Z80_F & 0x80) ?
'S' :
's',
278 (
Z80_F & 0x40) ?
'Z' :
'z',
279 (
Z80_F & 0x20) ?
'1' :
'0',
280 (
Z80_F & 0x10) ?
'H' :
'h',
281 (
Z80_F & 0x08) ?
'1' :
'0',
282 (
Z80_F & 0x04) ?
'V' :
'v',
283 (
Z80_F & 0x02) ?
'N' :
'n',
284 (
Z80_F & 0x01) ?
'C' :
'c',
288 ports[0xB0], ports[0xB1], ports[0xB2], ports[0xB3]
295 static void cmd_setdate (
void ) {
298 MPRINTF(
"EXOS time set: %s\n", buffer);
303 static void cmd_ddn (
void ) {
304 char *arg = get_mon_arg(
ARG_ONE);
308 MPRINTF(
"Command needs an argument, the default device name to be set\n");
313 static void cmd_ram (
void ) {
314 char *arg = get_mon_arg(
ARG_ONE);
315 int r = arg ? *arg : 0;
318 MPRINTF(
"%s\nDave: WS=%s CLK=%dMHz P=%02X/%02X/%02X/%02X\n\n",
320 _dave_ws_descrs[(ports[0xBF] >> 2) & 3],
321 ports[0xBF] & 1 ? 12 : 8,
322 ports[0xB0], ports[0xB1], ports[0xB2], ports[0xB3]
326 INFO_WINDOW(
"Setting total sum of RAM size to %dKbytes\nEP will reboot now!\nYou can use :XEP EMU command then to check the result.",
ep_set_ram_config(arg + 1) << 4);
331 "*** Bad command syntax.\nUse no parameter to query or !128 to set 128K memory, "
332 "or even !@E0,E3-E5 (no spaces ever!) to specify given RAM segments. Using '!' is "
333 "only for safity not to re-configure or re-boot your EP with no intent. Not so "
334 "much error handling is done on the input!\n"
342 static void cmd_cpu (
void ) {
344 char *arg = get_mon_arg(
ARG_ONE);
346 if (!strcasecmp(arg,
"z80"))
348 else if (!strcasecmp(arg,
"z80c"))
351 else if (!strcasecmp(arg,
"z180")) {
354 z180_port_write(0x32, 0x00);
355 z180_port_write(0x3F, 0x40);
359 int clk = atof(arg) * 1000000;
360 if (clk < 1000000 || clk > 12000000)
361 MPRINTF(
"*** Unknown CPU type to set or it's not a clock value either (1-12 is OK in MHz): %s\n", arg);
369 MPRINTF(
"CPU : %s %s @ %.2fMHz\n",
371 z80ex.z180 ?
"Z180" :
"Z80",
382 static void cmd_emu (
void )
385 char wd[PATH_MAX + 1];
386 if (!getcwd(wd,
sizeof wd))
390 DWORD siz =
sizeof buf;
396 GetComputerNameEx(ComputerNamePhysicalNetBIOS,
buf, &siz);
397 #define OS_KIND "Win32"
399 gethostname(
buf,
sizeof buf);
400 #define OS_KIND "POSIX"
403 "Run by: %s@%s %s %s\n"
405 "SDL c/l: %d.%d.%d %d.%d.%d\n"
406 "Base path: %s\nPref path: %s\nStart dir: %s\nSD img: %s [%dM]\n",
412 buf,
OS_KIND, SDL_GetPlatform(), SDL_GetCurrentVideoDriver(), SDL_GetCurrentAudioDriver(),
422 #ifdef XEMU_ARCH_HTML
424 MPRINTF(
"Browser: %s\n", getenv(
"XEMU_EN_BROWSER"));
425 MPRINTF(
"Origin: %s\n", getenv(
"XEMU_EN_ORIGIN"));
431 static void cmd_exit (
void )
433 INFO_WINDOW(
"XEP ROM/monitor command directs shutting down.");
439 static void cmd_mouse (
void )
441 char *arg = get_mon_arg(
ARG_ONE);
442 int c = arg ? *arg : 0;
445 case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
451 MPRINTF(
"*** Give values 1 ... 6 for mode, or no parameter for query.\n");
460 static void cmd_audio (
void )
468 static void cmd_primo (
void )
471 MPRINTF(
"*** Primo ROM not found in the loaded ROM set.\n");
479 static void cmd_showkeys (
void )
482 MPRINTF(
"SDL show keys info has been turned %s.\n",
show_keys ?
"ON" :
"OFF");
486 static void cmd_close (
void )
493 static void cmd_romname (
void )
499 static void cmd_exos (
void )
502 MPRINTF(
"*** XEP ROM was not called yet\n");
504 char status_line[41];
512 static void cmd_lpt (
void )
515 __mprintf_append_helper(p);
520 static void cmd_pause (
void )
523 OSD(-1, -1,
"Emulation %s",
paused ?
"paused" :
"resumed");
527 static void cmd_sdl (
void )
529 SDL_RendererInfo info;
530 SDL_Renderer *rendererp;
531 SDL_DisplayMode display;
532 const char *subsystem;
534 MPRINTF(
"Available SDL renderers:\n");
535 for (a = 0; a < SDL_GetNumRenderDrivers(); a++ ) {
536 int r = SDL_GetRenderDriverInfo(a, &info);
538 MPRINTF(
" (%d) *** CANNOT QUERY ***\n", a);
540 MPRINTF(
" (%d) \"%s\"\n", a, info.name);
542 rendererp = SDL_GetRenderer(
sdl_win);
543 if (rendererp && !SDL_GetRendererInfo(rendererp, &info))
544 MPRINTF(
" used: \"%s\"\n", info.name);
545 MPRINTF(
"Available SDL video drivers:");
546 for (a = 0; a < SDL_GetNumVideoDrivers(); a++ )
547 MPRINTF(
" (%d)%s", a, SDL_GetVideoDriver(a) ? SDL_GetVideoDriver(a) :
"*** CANNOT QUERY ***");
548 MPRINTF(
"\n used: \"%s\"\n", SDL_GetCurrentVideoDriver());
549 MPRINTF(
"Available SDL audio drivers:");
550 for (a = 0; a < SDL_GetNumAudioDrivers(); a++ )
551 MPRINTF(
" (%d)%s", a, SDL_GetAudioDriver(a) ? SDL_GetAudioDriver(a) :
"*** CANNOT QUERY ***");
552 MPRINTF(
"\n used: \"%s\"\n", SDL_GetCurrentAudioDriver());
553 for (a = 0; a < SDL_GetNumDisplayModes(0); a++ )
554 if (!SDL_GetCurrentDisplayMode(a, &display))
555 MPRINTF(
"Display #%d %dx%dpx @ %dHz %i bpp (%s)\n", a, display.w, display.h, display.refresh_rate,
556 SDL_BITSPERPIXEL(display.format), SDL_GetPixelFormatName(display.format)
558 #if defined(XEMU_ARCH_OSX)
560 #elif defined(XEMU_ARCH_WIN)
561 subsystem =
"Windows";
562 #elif defined(XEMU_ARCH_HTML)
563 subsystem =
"Web-browser";
564 #elif defined(XEMU_ARCH_LINUX)
579 static void cmd_ports (
void )
582 MPRINTF(
" 0 1 2 3 4 5 6 7 8 9 A B C D E F");
583 for (a = 0; a < 0x100; a++) {
593 static void cmd_cd (
void )
598 char cwd_old[PATH_MAX + 1];
599 char *r_scwd = getcwd(cwd_old, PATH_MAX);
615 MPRINTF(
"*** Cannot change directory to %s\n", arg);
622 static void cmd_dir (
void )
624 struct dirent *entry;
627 MPRINTF(
"*** DIR command does not have parameter\n");
636 while ((entry = readdir(
dir))) {
637 char fn[PATH_MAX + 1];
639 if (entry->d_name[0] ==
'.')
643 if (!stat(
fn, &
st)) {
645 if (S_ISDIR(
st.st_mode))
646 strcpy(size_info,
"<dir>");
647 else if (
st.st_size < 65536)
648 snprintf(size_info,
sizeof size_info,
"%d", (
int)
st.st_size);
652 MPRINTF(
"%-12s %6s\n", entry->d_name, size_info);
660 static void cmd_help (
void );
663 {
"AUDIO",
"", 3,
"Tries to turn crude audio emulation", cmd_audio },
664 {
"CD",
"", 3,
"Host OS directory change/query for FILE:", cmd_cd },
665 {
"CLOSE",
"", 3,
"Close console/monitor window", cmd_close },
666 {
"CPU",
"", 3,
"Set/query CPU type/clock", cmd_cpu },
667 {
"DDN",
"", 1,
"Set default device name via EXOS 19", cmd_ddn },
668 {
"DIR",
"", 3,
"Directory listing from host OS for FILE:", cmd_dir },
669 {
"DISASM",
"D", 3,
"Disassembly memory", cmd_disasm },
670 {
"EMU",
"", 3,
"Emulation info", cmd_emu },
671 {
"EXIT",
"", 3,
"Exit Xep128", cmd_exit },
672 {
"EXOS",
"", 3,
"EXOS information", cmd_exos },
673 {
"HELP",
"?", 3,
"Guess, what ;-)", cmd_help },
674 {
"LPT",
"", 3,
"Shows LPT (can be long!)", cmd_lpt },
675 {
"MEMDUMP",
"M", 3,
"Memory dump", cmd_memdump },
676 {
"MOUSE",
"", 3,
"Configure or query mouse mode", cmd_mouse },
677 {
"PAUSE",
"", 2,
"Pause/resume emulation", cmd_pause },
678 {
"PORTS",
"", 3,
"I/O port values (written)", cmd_ports },
679 {
"PRIMO",
"", 3,
"Primo emulation", cmd_primo },
680 {
"RAM",
"", 3,
"Set RAM size/report", cmd_ram },
681 {
"REGS",
"R", 3,
"Show Z80 registers", cmd_registers },
682 {
"ROMNAME",
"", 3,
"ROM id string", cmd_romname },
683 {
"SDL",
"", 3,
"Get SDL related info", cmd_sdl },
684 {
"SETDATE",
"", 1,
"Set EXOS time/date by emulator" , cmd_setdate },
685 {
"SHOWKEYS",
"", 3,
"Show/hide PC/SDL key symbols", cmd_showkeys },
686 {
"TESTARGS",
"", 3,
"Just for testing monitor statement parsing, not so useful for others", cmd_testargs },
687 { NULL, NULL,0, NULL, NULL }
689 static const char help_for_all_desc[] =
"\nFor help on all comamnds: (:XEP) HELP\n";
693 static void cmd_help (
void ) {
695 char *arg = get_mon_arg(
ARG_ONE);
698 if ((!strcasecmp(arg, cmds->
name) || !strcasecmp(arg, cmds->
alias)) && cmds->
help) {
709 MPRINTF(
"*** No help/command found '%s'%s", arg, help_for_all_desc);
711 MPRINTF(
"Helper ROM: %s %s %s\nBuilt on: %s\n%s\nGIT: %s\nCompiler: %s %s\n\nCommands:",
718 cmds->
alias[0] ?
"[" :
"",
720 cmds->
alias[0] ?
"]" :
""
724 MPRINTF(
"\n\nFor help on a command: (:XEP) HELP CMD\n");
730 void monitor_execute (
char *in_input_buffer,
int in_source,
char *in_output_buffer,
int in_output_max_size,
const char *in_output_nl )
735 output_p = in_output_buffer;
737 output_limit = output_p + in_output_max_size;
738 output_nl = in_output_nl;
740 strcpy(input_buffer, in_input_buffer);
741 input_p = input_buffer;
743 cmd_name = get_mon_arg(
ARG_ONE);
746 MPRINTF(
"*** Use: XEP HELP\n");
750 if (!strcasecmp(cmds->
name, cmd_name) || !strcasecmp(cmds->
alias, cmd_name)) {
752 return (
void)(cmds->
handler)();
754 MPRINTF(
"*** Command cannot be used here: %s\n", cmd_name);
760 MPRINTF(
"*** Unknown command: %s\n", cmd_name);
768 if (is_queued_command) {
771 #ifdef XEMU_ARCH_HTML
773 Module.Xemu.getFromMonitor(Pointer_stringify($0));
776 printf(
"%s", buffer);
778 is_queued_command = 0;
786 return is_queued_command;
795 is_queued_command = 1;
796 strcpy(queued_command, buffer);
821 # ifndef XEMU_HAS_READLINE
822 # error "We need libreadline for this target/platform, but XEMU_HAS_READLINE is not defined. Maybe libreadline cannot be detected?"
824 # include <readline/readline.h>
825 # include <readline/history.h>
828 #define USE_MONITOR 1
830 static volatile int monitor_running = 0;
831 static SDL_Thread *mont = NULL;
840 static int console_monitor_thread (
void *ptr )
842 printf(
"Welcome to " XEP128_NAME " monitor. Use \"help\" for help" NL);
843 while (monitor_running) {
848 p = fgets(buffer,
sizeof buffer, stdin);
858 #ifndef XEMU_ARCH_WIN
879 ERROR_WINDOW(
"Cannot get system console to run monitor program on");
884 mont = SDL_CreateThread(console_monitor_thread,
XEP128_NAME " monitor", NULL);
893 return (mont != NULL);
900 if (!monitor_running)
905 printf(
NL NL "*** PRESS ENTER TO EXIT ***" NL);
908 SDL_WaitThread(mont, &ret);
910 DEBUGPRINT(
"MONITOR: thread joined, status code is %d" NL, ret);