19 #define XEP128_NEED_SDL_WMINFO
23 #include "xemu/../rom/ep128/xep_rom_syms.h"
41 #include <SDL_syswm.h>
44 #include <sysinfoapi.h>
62 static const char SHORT_HELP[] =
"XEP version " VERSION " (Xep128 EMU)\n";
63 static const char TOO_LONG_OUTPUT_BUFFER[] =
" ...%s*** Too long output%s";
64 static const char *_dave_ws_descrs[4] = {
65 "all",
"M1",
"no",
"no"
68 static volatile int is_queued_command = 0;
69 static char queued_command[256];
71 static char input_buffer[256];
73 static char *output_p;
74 static char *output_limit;
75 static const char *output_nl;
77 static Uint16 dump_addr1 = 0;
78 static Uint8 dump_addr2 = 0;
79 static int dump_pagerel = 0;
80 static Uint16 disasm_addr1 = 0;
81 static Uint8 disasm_addr2 = 0;
82 static int disasm_pagerel = 0;
86 #define MPRINTF(...) do { \
87 char __mprintf__buffer__[0x4000]; \
88 snprintf(__mprintf__buffer__, sizeof __mprintf__buffer__, __VA_ARGS__); \
89 __mprintf_append_helper(__mprintf__buffer__); \
97 static void __mprintf_append_helper (
char *s )
100 if (output_p >= output_limit) {
101 sprintf(output_limit - strlen(TOO_LONG_OUTPUT_BUFFER), TOO_LONG_OUTPUT_BUFFER, output_nl, output_nl);
104 }
else if (!output_p)
107 const char *n = output_nl;
109 *(output_p++) = *(n++);
112 *(output_p++) = *(s++);
119 static char *get_mon_arg (
int limitrangecode )
122 while (*input_p && *input_p <= 32)
127 while (*input_p >= limitrangecode)
136 static int get_mon_arg_hex (
int *hex1,
int *hex2 )
138 char *h = get_mon_arg(
ARG_ONE);
142 return sscanf(h,
"%x:%x", hex1, hex2);
147 static void cmd_testargs (
void ) {
149 r = get_mon_arg_hex(&h1, &h2);
150 MPRINTF(
"Tried to parse first arg as hex, result: r=%d, h1=%x, h2=%x\n",
154 char *p = get_mon_arg(
ARG_ONE);
156 MPRINTF(
"No more args found!\n");
159 MPRINTF(
"Another arg found: \"%s\"\n", p);
164 #define SEGMENT_OF_Z80_ADDR(n) ports[0xB0 | (((n) & 0xFFFF) >> 14)]
167 static void set_memaddr_by_arg (
Uint16 *da1,
Uint8 *da2,
int *dm )
170 get_mon_arg_hex(&h1, &h2);
176 MPRINTF(
"; Absolute addresses from %04X:%02X\n", *da1, *da2);
177 }
else if (h1 >= 0) {
178 MPRINTF(
"; CPU paging relative from %04X\n", *da1);
187 static void cmd_memdump (
void )
190 set_memaddr_by_arg(&dump_addr1, &dump_addr2, &dump_pagerel);
191 for (row = 0; row < 10; row++) {
196 dump_pagerel ?
'*' :
'=',
199 for (col = 0; col < 16; col++) {
200 Uint8 byte =
memory[(dump_addr2 << 14) | (dump_addr1 & 0x3FFF)];
201 asciibuf[col] = (
byte >= 32 &&
byte < 127) ?
byte :
'.';
204 if (!(dump_addr1 & 0x3FFF)) {
223 return memory[((disasm_addr2 << 14) + (disasm_addr1 & 0x3FFF) + (
addr - disasm_addr1)) & 0x3FFFFF];
228 static void cmd_disasm (
void )
231 set_memaddr_by_arg(&disasm_addr1, &disasm_addr2, &disasm_pagerel);
232 for (lines = 0; lines < 10; lines++) {
233 char dasm_out_buffer[128];
234 char hex_out_buffer[32];
235 char asc_out_buffer[16];
236 int t_states, t_states2,
r, h;
239 r =
z80ex_dasm(dasm_out_buffer,
sizeof dasm_out_buffer, 0, &t_states, &t_states2, byte_reader, disasm_addr1);
240 if (byte_reader(disasm_addr1) == 0xF7) {
241 h = byte_reader(disasm_addr1 + 1);
243 snprintf(dasm_out_buffer,
sizeof dasm_out_buffer,
"EXOS $%02X", h);
245 for (h = 0, hex_out_buffer[0] = 0, asc_out_buffer[0] =
'\''; h <
r; h++) {
246 Uint8 byte = byte_reader(disasm_addr1 + h);
247 sprintf(hex_out_buffer + h * 3,
"%02X ",
byte);
248 asc_out_buffer[h + 1] = (
byte >= 32 &&
byte < 127) ?
byte :
'.';
249 asc_out_buffer[h + 2] =
'\0';
251 strcat(asc_out_buffer,
"'");
252 p = strchr(dasm_out_buffer,
' ');
255 MPRINTF(
"%04X:%c%02X %-12s%-4s %-16s ; %-6s L=%d T=%d/%d\n",
257 disasm_pagerel ?
'*' :
'=',
263 r, t_states, t_states2
265 if (disasm_addr1 >> 14 != ((disasm_addr1 +
r) >> 14)) {
277 static void cmd_registers (
void ) {
279 "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"
280 "AF'=%04X BC'=%04X DE'=%04X HL'=%04X PC=%04X SP=%04X Prefix=%02X P=%02X,%02X,%02X,%02X\n",
282 (
Z80_F & 0x80) ?
'S' :
's',
283 (
Z80_F & 0x40) ?
'Z' :
'z',
284 (
Z80_F & 0x20) ?
'1' :
'0',
285 (
Z80_F & 0x10) ?
'H' :
'h',
286 (
Z80_F & 0x08) ?
'1' :
'0',
287 (
Z80_F & 0x04) ?
'V' :
'v',
288 (
Z80_F & 0x02) ?
'N' :
'n',
289 (
Z80_F & 0x01) ?
'C' :
'c',
293 ports[0xB0], ports[0xB1], ports[0xB2], ports[0xB3]
300 static void cmd_setdate (
void ) {
303 MPRINTF(
"EXOS time set: %s\n", buffer);
308 static void cmd_ddn (
void ) {
309 char *arg = get_mon_arg(
ARG_ONE);
313 MPRINTF(
"Command needs an argument, the default device name to be set\n");
318 static void cmd_ram (
void ) {
319 char *arg = get_mon_arg(
ARG_ONE);
320 int r = arg ? *arg : 0;
323 MPRINTF(
"%s\nDave: WS=%s CLK=%dMHz P=%02X/%02X/%02X/%02X\n\n",
325 _dave_ws_descrs[(ports[0xBF] >> 2) & 3],
326 ports[0xBF] & 1 ? 12 : 8,
327 ports[0xB0], ports[0xB1], ports[0xB2], ports[0xB3]
331 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);
336 "*** Bad command syntax.\nUse no parameter to query or !128 to set 128K memory, "
337 "or even !@E0,E3-E5 (no spaces ever!) to specify given RAM segments. Using '!' is "
338 "only for safity not to re-configure or re-boot your EP with no intent. Not so "
339 "much error handling is done on the input!\n"
347 static void cmd_cpu (
void ) {
349 char *arg = get_mon_arg(
ARG_ONE);
351 if (!strcasecmp(arg,
"z80"))
353 else if (!strcasecmp(arg,
"z80c"))
356 else if (!strcasecmp(arg,
"z180")) {
359 z180_port_write(0x32, 0x00);
360 z180_port_write(0x3F, 0x40);
364 int clk = atof(arg) * 1000000;
365 if (clk < 1000000 || clk > 12000000)
366 MPRINTF(
"*** Unknown CPU type to set or it's not a clock value either (1-12 is OK in MHz): %s\n", arg);
374 MPRINTF(
"CPU : %s %s @ %.2fMHz\n",
376 z80ex.z180 ?
"Z180" :
"Z80",
387 static void cmd_emu (
void )
392 DWORD siz =
sizeof buf;
398 GetComputerNameEx(ComputerNamePhysicalNetBIOS,
buf, &siz);
399 #define OS_KIND "Win32"
401 gethostname(
buf,
sizeof buf);
402 #define OS_KIND "POSIX"
405 "Run by: %s@%s %s %s\n"
407 "SDL c/l: %d.%d.%d %d.%d.%d\n"
408 "Base path: %s\nPref path: %s\nStart dir: %s\nSD img: %s [%dM]\n",
414 buf,
OS_KIND, SDL_GetPlatform(), SDL_GetCurrentVideoDriver(), SDL_GetCurrentAudioDriver(),
424 #ifdef __EMSCRIPTEN__
426 MPRINTF(
"Browser: %s\n", getenv(
"XEMU_EN_BROWSER"));
427 MPRINTF(
"Origin: %s\n", getenv(
"XEMU_EN_ORIGIN"));
433 static void cmd_exit (
void )
435 INFO_WINDOW(
"XEP ROM/monitor command directs shutting down.");
441 static void cmd_mouse (
void )
443 char *arg = get_mon_arg(
ARG_ONE);
444 int c = arg ? *arg : 0;
447 case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
453 MPRINTF(
"*** Give values 1 ... 6 for mode, or no parameter for query.\n");
462 static void cmd_audio (
void )
470 static void cmd_primo (
void )
473 MPRINTF(
"*** Primo ROM not found in the loaded ROM set.\n");
481 static void cmd_showkeys (
void )
484 MPRINTF(
"SDL show keys info has been turned %s.\n",
show_keys ?
"ON" :
"OFF");
488 static void cmd_close (
void )
494 static void cmd_romname (
void )
500 static void cmd_exos (
void )
503 MPRINTF(
"*** XEP ROM was not called yet\n");
505 char status_line[41];
513 static void cmd_lpt (
void )
516 __mprintf_append_helper(p);
521 static void cmd_pause (
void )
524 OSD(
"Emulation %s",
paused ?
"paused" :
"resumed");
528 static void cmd_sdl (
void )
530 SDL_RendererInfo info;
531 SDL_Renderer *rendererp;
532 SDL_DisplayMode display;
533 const char *subsystem;
535 MPRINTF(
"Available SDL renderers:\n");
536 for (a = 0; a < SDL_GetNumRenderDrivers(); a++ ) {
537 int r = SDL_GetRenderDriverInfo(a, &info);
539 MPRINTF(
" (%d) *** CANNOT QUERY ***\n", a);
541 MPRINTF(
" (%d) \"%s\"\n", a, info.name);
543 rendererp = SDL_GetRenderer(
sdl_win);
544 if (rendererp && !SDL_GetRendererInfo(rendererp, &info))
545 MPRINTF(
" used: \"%s\"\n", info.name);
546 MPRINTF(
"Available SDL video drivers:");
547 for (a = 0; a < SDL_GetNumVideoDrivers(); a++ )
548 MPRINTF(
" (%d)%s", a, SDL_GetVideoDriver(a) ? SDL_GetVideoDriver(a) :
"*** CANNOT QUERY ***");
549 MPRINTF(
"\n used: \"%s\"\n", SDL_GetCurrentVideoDriver());
550 MPRINTF(
"Available SDL audio drivers:");
551 for (a = 0; a < SDL_GetNumAudioDrivers(); a++ )
552 MPRINTF(
" (%d)%s", a, SDL_GetAudioDriver(a) ? SDL_GetAudioDriver(a) :
"*** CANNOT QUERY ***");
553 MPRINTF(
"\n used: \"%s\"\n", SDL_GetCurrentAudioDriver());
554 for (a = 0; a < SDL_GetNumDisplayModes(0); a++ )
555 if (!SDL_GetCurrentDisplayMode(a, &display))
556 MPRINTF(
"Display #%d %dx%dpx @ %dHz %i bpp (%s)\n", a, display.w, display.h, display.refresh_rate,
557 SDL_BITSPERPIXEL(display.format), SDL_GetPixelFormatName(display.format)
561 case SDL_SYSWM_UNKNOWN:
562 subsystem =
"Unknown System";
564 case SDL_SYSWM_WINDOWS: subsystem =
"Microsoft Windows(TM)";
break;
565 case SDL_SYSWM_X11: subsystem =
"X Window System";
break;
566 case SDL_SYSWM_WINRT: subsystem =
"WinRT";
break;
567 case SDL_SYSWM_DIRECTFB:subsystem =
"DirectFB";
break;
568 case SDL_SYSWM_COCOA: subsystem =
"Apple OS X";
break;
569 case SDL_SYSWM_UIKIT: subsystem =
"UIKit";
break;
570 case SDL_SYSWM_WAYLAND: subsystem =
"Wayland";
break;
571 case SDL_SYSWM_MIR: subsystem =
"Mir";
break;
572 case SDL_SYSWM_ANDROID: subsystem =
"Android";
break;
585 static void cmd_ports (
void )
588 MPRINTF(
" 0 1 2 3 4 5 6 7 8 9 A B C D E F");
589 for (a = 0; a < 0x100; a++) {
599 static void cmd_cd (
void )
604 char cwd_old[PATH_MAX + 1];
605 char *r_scwd = getcwd(cwd_old, PATH_MAX);
621 MPRINTF(
"*** Cannot change directory to %s\n", arg);
628 static void cmd_dir (
void )
630 struct dirent *entry;
633 MPRINTF(
"*** DIR command does not have parameter\n");
642 while ((entry = readdir(
dir))) {
643 char fn[PATH_MAX + 1];
645 if (entry->d_name[0] ==
'.')
649 if (!stat(
fn, &
st)) {
651 if (S_ISDIR(
st.st_mode))
652 strcpy(size_info,
"<dir>");
653 else if (
st.st_size < 65536)
654 snprintf(size_info,
sizeof size_info,
"%d", (
int)
st.st_size);
658 MPRINTF(
"%-12s %6s\n", entry->d_name, size_info);
666 static void cmd_help (
void );
669 {
"AUDIO",
"", 3,
"Tries to turn crude audio emulation", cmd_audio },
670 {
"CD",
"", 3,
"Host OS directory change/query for FILE:", cmd_cd },
671 {
"CLOSE",
"", 3,
"Close console/monitor window", cmd_close },
672 {
"CPU",
"", 3,
"Set/query CPU type/clock", cmd_cpu },
673 {
"DDN",
"", 1,
"Set default device name via EXOS 19", cmd_ddn },
674 {
"DIR",
"", 3,
"Directory listing from host OS for FILE:", cmd_dir },
675 {
"DISASM",
"D", 3,
"Disassembly memory", cmd_disasm },
676 {
"EMU",
"", 3,
"Emulation info", cmd_emu },
677 {
"EXIT",
"", 3,
"Exit Xep128", cmd_exit },
678 {
"EXOS",
"", 3,
"EXOS information", cmd_exos },
679 {
"HELP",
"?", 3,
"Guess, what ;-)", cmd_help },
680 {
"LPT",
"", 3,
"Shows LPT (can be long!)", cmd_lpt },
681 {
"MEMDUMP",
"M", 3,
"Memory dump", cmd_memdump },
682 {
"MOUSE",
"", 3,
"Configure or query mouse mode", cmd_mouse },
683 {
"PAUSE",
"", 2,
"Pause/resume emulation", cmd_pause },
684 {
"PORTS",
"", 3,
"I/O port values (written)", cmd_ports },
685 {
"PRIMO",
"", 3,
"Primo emulation", cmd_primo },
686 {
"RAM",
"", 3,
"Set RAM size/report", cmd_ram },
687 {
"REGS",
"R", 3,
"Show Z80 registers", cmd_registers },
688 {
"ROMNAME",
"", 3,
"ROM id string", cmd_romname },
689 {
"SDL",
"", 3,
"Get SDL related info", cmd_sdl },
690 {
"SETDATE",
"", 1,
"Set EXOS time/date by emulator" , cmd_setdate },
691 {
"SHOWKEYS",
"", 3,
"Show/hide PC/SDL key symbols", cmd_showkeys },
692 {
"TESTARGS",
"", 3,
"Just for testing monitor statement parsing, not so useful for others", cmd_testargs },
693 { NULL, NULL, 0, NULL, NULL }
695 static const char help_for_all_desc[] =
"\nFor help on all comamnds: (:XEP) HELP\n";
699 static void cmd_help (
void ) {
701 char *arg = get_mon_arg(
ARG_ONE);
704 if ((!strcasecmp(arg, cmds->
name) || !strcasecmp(arg, cmds->
alias)) && cmds->
help) {
715 MPRINTF(
"*** No help/command found '%s'%s", arg, help_for_all_desc);
717 MPRINTF(
"Helper ROM: %s%s %s %s\nBuilt on: %s\n%s\nGIT: %s\nCompiler: %s %s\n\nCommands:",
724 cmds->
alias[0] ?
"[" :
"",
726 cmds->
alias[0] ?
"]" :
""
730 MPRINTF(
"\n\nFor help on a command: (:XEP) HELP CMD\n");
736 void monitor_execute (
char *in_input_buffer,
int in_source,
char *in_output_buffer,
int in_output_max_size,
const char *in_output_nl )
741 output_p = in_output_buffer;
743 output_limit = output_p + in_output_max_size;
744 output_nl = in_output_nl;
746 strcpy(input_buffer, in_input_buffer);
747 input_p = input_buffer;
749 cmd_name = get_mon_arg(
ARG_ONE);
752 MPRINTF(
"*** Use: XEP HELP\n");
756 if (!strcasecmp(cmds->
name, cmd_name) || !strcasecmp(cmds->
alias, cmd_name)) {
758 return (
void)(cmds->
handler)();
760 MPRINTF(
"*** Command cannot be used here: %s\n", cmd_name);
766 MPRINTF(
"*** Unknown command: %s\n", cmd_name);
774 if (is_queued_command) {
777 #ifdef __EMSCRIPTEN__
779 Module.Xemu.getFromMonitor(Pointer_stringify($0));
782 printf(
"%s", buffer);
784 is_queued_command = 0;
792 return is_queued_command;
801 is_queued_command = 1;
802 strcpy(queued_command, buffer);