Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
emu_monitor.c
Go to the documentation of this file.
1 /* Minimalistic Enterprise-128 emulator with focus on "exotic" hardware
2  Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
3  Copyright (C)2015-2020 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
18 
19 #define XEP128_NEED_SDL_WMINFO
20 
21 #include "xemu/emutools.h"
22 #include "xemu/emutools_config.h"
23 #include "enterprise128.h"
24 #include "emu_monitor.h"
25 #include "rom/ep128/xep_rom_syms.h"
26 #include "xemu/z80_dasm.h"
27 #include "cpu.h"
28 #include "z180.h"
29 #include "emu_rom_interface.h"
30 #include "fileio.h"
31 #include "nick.h"
32 #include "input_devices.h"
33 #include "primoemu.h"
34 #include "dave.h"
35 #include "sdext.h"
36 
37 //#include <SDL_syswm.h>
38 
39 #ifdef XEMU_ARCH_WIN
40 #include <sysinfoapi.h>
41 #endif
42 
43 #include <dirent.h>
44 #include <sys/stat.h>
45 #include <unistd.h>
46 
47 
48 
49 
50 struct commands_st {
51  const char *name;
52  const char *alias;
53  const int allowed;
54  const char *help;
55  void (*handler)(void);
56 };
57 
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"
61 };
62 
63 static volatile int is_queued_command = 0;
64 static char queued_command[256];
65 
66 static char input_buffer[256];
67 static char *input_p;
68 static char *output_p;
69 static char *output_limit;
70 static const char *output_nl;
71 
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;
78 
79 
80 
81 #define MPRINTF(...) do { \
82  char __mprintf__buffer__[0x4000]; \
83  snprintf(__mprintf__buffer__, sizeof __mprintf__buffer__, __VA_ARGS__); \
84  __mprintf_append_helper(__mprintf__buffer__); \
85 } while(0)
86 
87 #define ARG_ONE 33
88 #define ARG_SPACE 32
89 
90 
91 
92 static void __mprintf_append_helper ( char *s )
93 {
94  while (*s) {
95  if (output_p >= output_limit) {
96  sprintf(output_limit - strlen(TOO_LONG_OUTPUT_BUFFER), TOO_LONG_OUTPUT_BUFFER, output_nl, output_nl);
97  output_p = NULL;
98  return;
99  } else if (!output_p)
100  return;
101  if (*s == '\n') {
102  const char *n = output_nl;
103  while (*n)
104  *(output_p++) = *(n++);
105  s++;
106  } else
107  *(output_p++) = *(s++);
108  }
109  *output_p = '\0';
110 }
111 
112 
113 // Use ARG_ONE to return one parameter, or ARG_SPACE (can contain space(s) but not eg TAB)
114 static char *get_mon_arg ( int limitrangecode )
115 {
116  char *r;
117  while (*input_p && *input_p <= 32)
118  input_p++;
119  if (!*input_p)
120  return NULL; // no argument left
121  r = input_p; // remember position of first printable character ...
122  while (*input_p >= limitrangecode)
123  input_p++;
124  if (*input_p)
125  *(input_p++) = '\0'; // terminate argument
126  return r;
127 }
128 
129 
130 
131 static int get_mon_arg_hex ( int *hex1, int *hex2 )
132 {
133  char *h = get_mon_arg(ARG_ONE);
134  *hex1 = *hex2 = -1;
135  if (h == NULL)
136  return 0;
137  return sscanf(h, "%x:%x", hex1, hex2);
138 }
139 
140 
141 
142 static void cmd_testargs ( void ) {
143  int h1, h2, r;
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",
146  r, h1, h2
147  );
148  for (;;) {
149  char *p = get_mon_arg(ARG_ONE);
150  if (!p) {
151  MPRINTF("No more args found!\n");
152  break;
153  }
154  MPRINTF("Another arg found: \"%s\"\n", p);
155  }
156 }
157 
158 
159 #define SEGMENT_OF_Z80_ADDR(n) ports[0xB0 | (((n) & 0xFFFF) >> 14)]
160 
161 
162 static void set_memaddr_by_arg ( Uint16 *da1, Uint8 *da2, int *dm )
163 {
164  int h1, h2;
165  get_mon_arg_hex(&h1, &h2);
166  if (h1 >= 0)
167  *da1 = h1;
168  if (h2 >= 0) {
169  *dm = 0;
170  *da2 = 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);
174  *dm = 1;
175  }
176  if (*dm)
177  *da2 = SEGMENT_OF_Z80_ADDR(*da1);
178 }
179 
180 
181 
182 static void cmd_memdump ( void )
183 {
184  int row;
185  set_memaddr_by_arg(&dump_addr1, &dump_addr2, &dump_pagerel);
186  for (row = 0; row < 10; row++) {
187  int col;
188  char asciibuf[17];
189  MPRINTF("%04X:%c%02X ",
190  dump_addr1,
191  dump_pagerel ? '*' : '=',
192  dump_addr2
193  );
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 : '.';
197  MPRINTF(" %02X", byte);
198  dump_addr1++;
199  if (!(dump_addr1 & 0x3FFF)) {
200  if (dump_pagerel)
201  dump_addr2 = SEGMENT_OF_Z80_ADDR(dump_addr1);
202  else
203  dump_addr2++;
204  }
205  }
206  asciibuf[col] = 0;
207  MPRINTF(" %s\n", asciibuf);
208  }
209 }
210 
211 
212 
213 static Z80EX_BYTE byte_reader ( Z80EX_WORD addr ) {
214  if (disasm_pagerel)
215  return memory[(SEGMENT_OF_Z80_ADDR(addr) << 14) | (addr & 0x3FFF)];
216  else
217  //return memory[((int)user_data + addr - disasm_addr1) & 0x3FFFFF];
218  return memory[((disasm_addr2 << 14) + (disasm_addr1 & 0x3FFF) + (addr - disasm_addr1)) & 0x3FFFFF];
219 }
220 
221 
222 
223 static void cmd_disasm ( void )
224 {
225  int lines;
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;
232  //int disasm_base = (disasm_addr2 << 14) | (disasm_addr1 & 0x3FFF);
233  char *p;
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) { // the EXOS call hack!
236  h = byte_reader(disasm_addr1 + 1);
237  r = 2;
238  snprintf(dasm_out_buffer, sizeof dasm_out_buffer, "EXOS $%02X", h);
239  }
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';
245  }
246  strcat(asc_out_buffer, "'");
247  p = strchr(dasm_out_buffer, ' ');
248  if (p)
249  *(p++) = '\0';
250  MPRINTF("%04X:%c%02X %-12s%-4s %-16s ; %-6s L=%d T=%d/%d\n",
251  disasm_addr1,
252  disasm_pagerel ? '*' : '=',
253  disasm_addr2,
254  hex_out_buffer,
255  dasm_out_buffer,
256  p ? p : "",
257  asc_out_buffer,
258  r, t_states, t_states2
259  );
260  if (disasm_addr1 >> 14 != ((disasm_addr1 + r) >> 14)) {
261  if (disasm_pagerel)
262  disasm_addr2 = SEGMENT_OF_Z80_ADDR(disasm_addr1 + r);
263  else
264  disasm_addr2++;
265  }
266  disasm_addr1 += r;
267  }
268 }
269 
270 
271 
272 static void cmd_registers ( void ) {
273  MPRINTF(
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',
285  Z80_IM, Z80_IFF1 ? 1 : 0, Z80_IFF2 ? 1 : 0,
287  z80ex.prefix,
288  ports[0xB0], ports[0xB1], ports[0xB2], ports[0xB3]
289  );
290 
291 }
292 
293 
294 
295 static void cmd_setdate ( void ) {
296  char buffer[64];
297  xep_set_time_consts(buffer);
298  MPRINTF("EXOS time set: %s\n", buffer);
299 }
300 
301 
302 
303 static void cmd_ddn ( void ) {
304  char *arg = get_mon_arg(ARG_ONE);
305  if (arg) {
307  } else
308  MPRINTF("Command needs an argument, the default device name to be set\n");
309 }
310 
311 
312 
313 static void cmd_ram ( void ) {
314  char *arg = get_mon_arg(ARG_ONE);
315  int r = arg ? *arg : 0;
316  switch (r) {
317  case 0:
318  MPRINTF("%s\nDave: WS=%s CLK=%dMHz P=%02X/%02X/%02X/%02X\n\n",
319  mem_desc,
320  _dave_ws_descrs[(ports[0xBF] >> 2) & 3],
321  ports[0xBF] & 1 ? 12 : 8,
322  ports[0xB0], ports[0xB1], ports[0xB2], ports[0xB3]
323  );
324  break;
325  case '!':
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);
327  ep_reset();
328  return;
329  default:
330  MPRINTF(
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"
335  );
336  break;
337  }
338 }
339 
340 
341 
342 static void cmd_cpu ( void ) {
343  //char buf[512] = "";
344  char *arg = get_mon_arg(ARG_ONE);
345  if (arg) {
346  if (!strcasecmp(arg, "z80"))
348  else if (!strcasecmp(arg, "z80c"))
350 #ifdef CONFIG_Z180
351  else if (!strcasecmp(arg, "z180")) {
353  // Zozo's EXOS would set this up, but our on-the-fly change is something can't happen for real, thus we fake it here:
354  z180_port_write(0x32, 0x00);
355  z180_port_write(0x3F, 0x40);
356  }
357 #endif
358  else {
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);
362  else {
363  INFO_WINDOW("Setting CPU clock to %.2fMHz",
364  set_cpu_clock(clk) / 1000000.0
365  );
366  }
367  }
368  }
369  MPRINTF("CPU : %s %s @ %.2fMHz\n",
370 #ifdef CONFIG_Z180
371  z80ex.z180 ? "Z180" : "Z80",
372 #else
373  "Z80",
374 #endif
375  z80ex.nmos ? "NMOS" : "CMOS",
376  CPU_CLOCK / 1000000.0
377  );
378 }
379 
380 
381 
382 static void cmd_emu ( void )
383 {
384  char buf[1024];
385  char wd[PATH_MAX + 1];
386  if (!getcwd(wd, sizeof wd))
387  strcpy(wd, "???");
388 #ifdef XEMU_ARCH_WIN
389 
390  DWORD siz = sizeof buf;
391 #endif
392  //SDL_VERSION(&sdlver_c);
393  //SDL_GetVersion(&sdlver_l);
394 #ifdef XEMU_ARCH_WIN
395  //GetUserName(buf, &siz);
396  GetComputerNameEx(ComputerNamePhysicalNetBIOS, buf, &siz);
397 #define OS_KIND "Win32"
398 #else
399  gethostname(buf, sizeof buf);
400 #define OS_KIND "POSIX"
401 #endif
402  MPRINTF(
403  "Run by: %s@%s %s %s\n"
404  "Drivers: %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",
407 #ifdef XEMU_ARCH_WIN
408  getenv("USERNAME"),
409 #else
410  getenv("USER"),
411 #endif
412  buf, OS_KIND, SDL_GetPlatform(), SDL_GetCurrentVideoDriver(), SDL_GetCurrentAudioDriver(),
413  sdlver_compiled.major, sdlver_compiled.minor, sdlver_compiled.patch,
414  sdlver_linked.major, sdlver_linked.minor, sdlver_linked.patch,
417  sdimg_path, (int)(sd_card_size >> 20)
418 #else
419  "<not-supported>", 0
420 #endif
421  );
422 #ifdef XEMU_ARCH_HTML
423  // This assumes, that the "JS booter" sets these ENV variables ...
424  MPRINTF("Browser: %s\n", getenv("XEMU_EN_BROWSER"));
425  MPRINTF("Origin: %s\n", getenv("XEMU_EN_ORIGIN"));
426 #endif
427 }
428 
429 
430 
431 static void cmd_exit ( void )
432 {
433  INFO_WINDOW("XEP ROM/monitor command directs shutting down.");
434  XEMUEXIT(0);
435 }
436 
437 
438 
439 static void cmd_mouse ( void )
440 {
441  char *arg = get_mon_arg(ARG_ONE);
442  int c = arg ? *arg : 0;
443  char buffer[256];
444  switch (c) {
445  case '1': case '2': case '3': case '4': case '5': case '6':
446  mouse_setup(c - '0');
447  break;
448  case '\0':
449  break;
450  default:
451  MPRINTF("*** Give values 1 ... 6 for mode, or no parameter for query.\n");
452  return;
453  }
454  mouse_mode_description(0, buffer);
455  MPRINTF("%s\n", buffer);
456 }
457 
458 
459 
460 static void cmd_audio ( void )
461 {
462  audio_init(1); // NOTE: later it shouldn't be here!
463  audio_start();
464 }
465 
466 
467 
468 static void cmd_primo ( void )
469 {
470  if (primo_rom_seg == -1) {
471  MPRINTF("*** Primo ROM not found in the loaded ROM set.\n");
472  return;
473  }
475 }
476 
477 
478 
479 static void cmd_showkeys ( void )
480 {
481  show_keys = !show_keys;
482  MPRINTF("SDL show keys info has been turned %s.\n", show_keys ? "ON" : "OFF");
483 }
484 
485 
486 static void cmd_close ( void )
487 {
488  monitor_stop();
489  sysconsole_close(NULL);
490 }
491 
492 
493 static void cmd_romname ( void )
494 {
495  MPRINTF("XEP version %s\n", XEMU_BUILDINFO_CDATE);
496 }
497 
498 
499 static void cmd_exos ( void )
500 {
501  if (exos_version == 0)
502  MPRINTF("*** XEP ROM was not called yet\n");
503  else {
504  char status_line[41];
505  exos_get_status_line(status_line);
506  MPRINTF("EXOS version: %d.%d\nStatus line: %s\n", exos_version >> 4, exos_version & 0xF, status_line);
507  MPRINTF("Working/non-working RAM segs: %d / %d\n", exos_info[5], exos_info[6]);
508  }
509 }
510 
511 
512 static void cmd_lpt ( void )
513 {
514  char *p = nick_dump_lpt("\n");
515  __mprintf_append_helper(p);
516  free(p);
517 }
518 
519 
520 static void cmd_pause ( void )
521 {
522  paused = !paused;
523  OSD(-1, -1, "Emulation %s", paused ? "paused" : "resumed");
524 }
525 
526 
527 static void cmd_sdl ( void )
528 {
529  SDL_RendererInfo info;
530  SDL_Renderer *rendererp;
531  SDL_DisplayMode display;
532  const char *subsystem;
533  int a;
534  MPRINTF("Available SDL renderers:\n");
535  for (a = 0; a < SDL_GetNumRenderDrivers(); a++ ) {
536  int r = SDL_GetRenderDriverInfo(a, &info);
537  if (r)
538  MPRINTF(" (%d) *** CANNOT QUERY ***\n", a);
539  else
540  MPRINTF(" (%d) \"%s\"\n", a, info.name);
541  }
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)
557  );
558 #if defined(XEMU_ARCH_OSX)
559  subsystem = "MacOS";
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)
565  subsystem = "Linux";
566 #else
567  subsystem = "UNIX";
568 #endif
569  MPRINTF(XEP128_NAME " is running with SDL version %d.%d.%d on %s\n",
570  (int)sdlver_linked.major,
571  (int)sdlver_linked.minor,
572  (int)sdlver_linked.patch,
573  subsystem
574  );
575 }
576 
577 
578 
579 static void cmd_ports ( void )
580 {
581  int a;
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++) {
584  if (!(a & 15))
585  MPRINTF("\n%02X -", a);
586  MPRINTF(" %02X", ports[a]);
587  }
588  MPRINTF("\n");
589 }
590 
591 
592 
593 static void cmd_cd ( void )
594 {
595  int r_cd = 0;
596  char *arg = get_mon_arg(ARG_SPACE);
597  if (arg) {
598  char cwd_old[PATH_MAX + 1];
599  char *r_scwd = getcwd(cwd_old, PATH_MAX); // Save working directory
600  int r;
601  if (chdir(fileio_cwd)) // set old FILE: dir
602  r = chdir(DIRSEP_STR);
603  r_cd = chdir(arg); // do the CD - maybe relative - to the old one
604  if (!r_cd) {
605  if (getcwd(fileio_cwd, PATH_MAX)) { // store result directory as new FILE: dir
606  if (fileio_cwd[strlen(fileio_cwd) - 1] != DIRSEP_CHR)
607  strcat(fileio_cwd, DIRSEP_STR);
608  }
609  }
610  if (!r_scwd)
611  r = chdir(cwd_old); // restore current working directory
612  (void)r; // make GCC happy, we DO NOT need value of r, and some retvals, sorry!!
613  }
614  if (r_cd)
615  MPRINTF("*** Cannot change directory to %s\n", arg);
616  else if (!arg)
617  MPRINTF("%s\n", fileio_cwd);
618 }
619 
620 
621 
622 static void cmd_dir ( void )
623 {
624  struct dirent *entry;
625  DIR *dir;
626  if (get_mon_arg(ARG_ONE)) {
627  MPRINTF("*** DIR command does not have parameter\n");
628  return;
629  }
630  dir = opendir(fileio_cwd);
631  if (!dir) {
632  MPRINTF("*** Cannot open host OS directory: %s\n", fileio_cwd);
633  return;
634  }
635  MPRINTF("Directory of %s\n", fileio_cwd);
636  while ((entry = readdir(dir))) {
637  char fn[PATH_MAX + 1];
638  struct stat st;
639  if (entry->d_name[0] == '.')
640  continue;
641  if (CHECK_SNPRINTF(snprintf(fn, sizeof fn, "%s%s%s", fileio_cwd, DIRSEP_STR, entry->d_name), sizeof fn))
642  continue;
643  if (!stat(fn, &st)) {
644  char size_info[10];
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);
649  else
650  size_info[0] = 0;
651  if (size_info[0])
652  MPRINTF("%-12s %6s\n", entry->d_name, size_info);
653  }
654  }
655  closedir(dir);
656 }
657 
658 
659 
660 static void cmd_help ( void );
661 
662 static const struct commands_st commands[] = {
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 }
688 };
689 static const char help_for_all_desc[] = "\nFor help on all comamnds: (:XEP) HELP\n";
690 
691 
692 
693 static void cmd_help ( void ) {
694  const struct commands_st *cmds = commands;
695  char *arg = get_mon_arg(ARG_ONE);
696  if (arg) {
697  while (cmds->name) {
698  if ((!strcasecmp(arg, cmds->name) || !strcasecmp(arg, cmds->alias)) && cmds->help) {
699  MPRINTF("%s: [%s] %s%s",
700  cmds->name,
701  cmds->alias[0] ? cmds->alias : "-",
702  cmds->help,
703  help_for_all_desc
704  );
705  return;
706  }
707  cmds++;
708  }
709  MPRINTF("*** No help/command found '%s'%s", arg, help_for_all_desc);
710  } else {
711  MPRINTF("Helper ROM: %s %s %s\nBuilt on: %s\n%s\nGIT: %s\nCompiler: %s %s\n\nCommands:",
714  );
715  while (cmds->name) {
716  if (cmds->help)
717  MPRINTF(" %s%s%s%s", cmds->name,
718  cmds->alias[0] ? "[" : "",
719  cmds->alias,
720  cmds->alias[0] ? "]" : ""
721  );
722  cmds++;
723  }
724  MPRINTF("\n\nFor help on a command: (:XEP) HELP CMD\n");
725  }
726 }
727 
728 
729 
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 )
731 {
732  char *cmd_name;
733  const struct commands_st *cmds = commands;
734  /* initialize output parameters for the answer */
735  output_p = in_output_buffer;
736  *output_p = '\0';
737  output_limit = output_p + in_output_max_size;
738  output_nl = in_output_nl;
739  /* input pre-stuffs */
740  strcpy(input_buffer, in_input_buffer);
741  input_p = input_buffer;
742  /* OK, now it's time to do something ... */
743  cmd_name = get_mon_arg(ARG_ONE);
744  if (!cmd_name) {
745  if (in_source == 1)
746  MPRINTF("*** Use: XEP HELP\n");
747  return; // empty command line
748  }
749  while (cmds->name) {
750  if (!strcasecmp(cmds->name, cmd_name) || !strcasecmp(cmds->alias, cmd_name)) {
751  if (cmds->allowed & in_source)
752  return (void)(cmds->handler)();
753  else {
754  MPRINTF("*** Command cannot be used here: %s\n", cmd_name);
755  return;
756  }
757  }
758  cmds++;
759  }
760  MPRINTF("*** Unknown command: %s\n", cmd_name);
761 }
762 
763 
764 
765 /* this should be called by the emulator (main thread) regularly, to check console/monitor events queued by the console/monitor thread */
767 {
768  if (is_queued_command) {
769  char buffer[8192];
770  monitor_execute(queued_command, 2, buffer, sizeof buffer, NL);
771 #ifdef XEMU_ARCH_HTML
772  EM_ASM_INT({
773  Module.Xemu.getFromMonitor(Pointer_stringify($0));
774  }, buffer);
775 #else
776  printf("%s", buffer); // TODO, maybe we should ask for sync on stdout?
777 #endif
778  is_queued_command = 0;
779  }
780 }
781 
782 
783 /* for use by the console input thread */
784 int monitor_queue_used ( void )
785 {
786  return is_queued_command;
787 }
788 
789 
790 /* for use by the console input thread */
791 int monitor_queue_command ( char *buffer )
792 {
793  if (XEMU_UNLIKELY(is_queued_command))
794  return 1;
795  is_queued_command = 1;
796  strcpy(queued_command, buffer);
797  return 0;
798 }
799 
800 // EX console.c !!!!
801 
802 #ifdef NO_CONSOLE
803 //int console_is_open = 0;
804 void console_close_window ( void ) {
805 }
806 void console_close_window_on_exit ( void ) {
807 }
808 void console_open_window ( void ) {
809 }
810 void console_monitor_ready ( void ) {
811 }
812 #else
813 
814 
815 #ifdef XEMU_ARCH_WIN
816 //# include <windows.h>
817 //# include <stdio.h>
818 //# include <io.h>
819 //# include <fcntl.h>
820 #else
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?"
823 # endif
824 # include <readline/readline.h>
825 # include <readline/history.h>
826 #endif
827 
828 #define USE_MONITOR 1
829 
830 static volatile int monitor_running = 0;
831 static SDL_Thread *mont = NULL;
832 
833 
834 /* Monitor thread waits for console input and enqueues the request.
835  The thread is NOT executes the command itself! Even the answer
836  is printed by the main thread already!
837  Honestly, I was lazy, this may be also implemented in the main
838  main thread, with select() based scheme / async I/O on UNIX, but I have
839  no idea about Windows ... */
840 static int console_monitor_thread ( void *ptr )
841 {
842  printf("Welcome to " XEP128_NAME " monitor. Use \"help\" for help" NL);
843  while (monitor_running) {
844  char *p;
845 #ifdef XEMU_ARCH_WIN
846  char buffer[256];
847  printf(XEP128_NAME "> ");
848  p = fgets(buffer, sizeof buffer, stdin);
849 #else
850  p = readline(XEP128_NAME "> ");
851 #endif
852  if (p == NULL) {
853  SDL_Delay(10); // avoid flooding the CPU in case of I/O problem for fgets ...
854  } else {
855  // Queue the command!
856  while (monitor_queue_command(p) && monitor_running)
857  SDL_Delay(10); // avoid flooding the CPU in case of not processed-yet command in the "queue" buffer
858 #ifndef XEMU_ARCH_WIN
859  if (p[0])
860  add_history(p);
861  free(p);
862 #endif
863  // Wait for command completed
864  while (monitor_queue_used() && monitor_running)
865  SDL_Delay(10); // avoid flooding the CPU while waiting for command being processed and answered on the console
866  }
867  }
868  DEBUGPRINT("MONITOR: thread is about to exit" NL);
869  return 0;
870 }
871 
872 
873 int monitor_start ( void )
874 {
875  if (monitor_running || !USE_MONITOR)
876  return 0;
877  sysconsole_open(); // make sure we have system console so we can run the monitor on something ...
878  if (!sysconsole_is_open) {
879  ERROR_WINDOW("Cannot get system console to run monitor program on");
880  return 1; // could not open system console?
881  }
882  DEBUGPRINT("MONITOR: starting" NL);
883  monitor_running = 1;
884  mont = SDL_CreateThread(console_monitor_thread, XEP128_NAME " monitor", NULL);
885  if (mont == NULL)
886  monitor_running = 0;
887  return 0;
888 }
889 
890 
891 int monitor_check ( void )
892 {
893  return (mont != NULL);
894 }
895 
896 
897 int monitor_stop ( void )
898 {
899  int ret;
900  if (!monitor_running)
901  return 0;
902  DEBUGPRINT("MONITOR: stopping" NL);
903  monitor_running = 0;
904  if (mont != NULL) {
905  printf(NL NL "*** PRESS ENTER TO EXIT ***" NL);
906  // Though Info window here is overkill, I am still interested why it causes a segfault when I've tried ...
907  //INFO_WINDOW("Monitor runs on console. You must press ENTER there to continue");
908  SDL_WaitThread(mont, &ret);
909  mont = NULL;
910  DEBUGPRINT("MONITOR: thread joined, status code is %d" NL, ret);
911  }
912  return 1;
913 }
914 
915 #endif
z80_dasm.h
Z80_DE
#define Z80_DE
Definition: z80ex.h:85
Z80_AF
#define Z80_AF
Definition: z80ex.h:77
Z80_AF_
#define Z80_AF_
Definition: z80ex.h:93
sdext.h
ep_reset
void ep_reset(void)
Definition: cpu.c:621
xep_set_time_consts
void xep_set_time_consts(char *descbuffer)
Definition: emu_rom_interface.c:75
sysconsole_is_open
int sysconsole_is_open
Definition: emutools.c:109
_z80_cpu_context::nmos
int nmos
Definition: z80ex.h:175
commands_st
Definition: emu_monitor.c:50
CC_TYPE
#define CC_TYPE
Definition: emutools_basicdefs.h:104
primoemu.h
sdl_win
SDL_Window * sdl_win
Definition: screen.c:43
emutools.h
sysconsole_close
void sysconsole_close(const char *waitmsg)
Definition: emutools.c:1393
emu_monitor.h
Z80_SP
#define Z80_SP
Definition: z80ex.h:117
sdl_base_dir
char * sdl_base_dir
Definition: emutools.c:97
Z80_HL_
#define Z80_HL_
Definition: z80ex.h:105
USE_MONITOR
#define USE_MONITOR
Definition: emu_monitor.c:828
monitor_queue_used
int monitor_queue_used(void)
Definition: emu_monitor.c:784
XEP128_NAME
#define XEP128_NAME
Definition: enterprise128.h:37
monitor_stop
int monitor_stop(void)
Definition: emu_monitor.c:897
Z80_HL
#define Z80_HL
Definition: z80ex.h:89
set_ep_cpu
void set_ep_cpu(int type)
Definition: cpu.c:74
mouse_mode_description
int mouse_mode_description(int cfg, char *buffer)
Definition: input_devices.c:231
emu_rom_interface.h
INFO_WINDOW
#define INFO_WINDOW(...)
Definition: xep128.h:114
COPYRIGHT_YEARS
#define COPYRIGHT_YEARS
Definition: emutools_basicdefs.h:24
addr
int addr
Definition: dma65.c:81
monitor_process_queued
void monitor_process_queued(void)
Definition: emu_monitor.c:766
fn
const char * fn
Definition: roms.c:42
XEMU_BUILDINFO_GIT
const char XEMU_BUILDINFO_GIT[]
Definition: emutools_basicdefs.h:251
Z80_IY
#define Z80_IY
Definition: z80ex.h:113
OS_KIND
#define OS_KIND
CONFIG_Z180
#define CONFIG_Z180
Definition: xemu-target.h:3
sysconsole_open
void sysconsole_open(void)
Definition: emutools.c:1294
Z80EX_WORD
unsigned short Z80EX_WORD
Definition: z80ex.h:51
mem_desc
char * mem_desc
Definition: cpu.c:58
fileio.h
paused
int paused
Definition: enterprise128.c:53
Z80_IFF1
#define Z80_IFF1
Definition: z80ex.h:127
Uint8
uint8_t Uint8
Definition: fat32.c:51
exos_get_status_line
void exos_get_status_line(char *buffer)
Definition: emu_rom_interface.c:54
set_cpu_clock
int set_cpu_clock(int hz)
Definition: enterprise128.c:91
exos_version
Uint8 exos_version
Definition: emu_rom_interface.c:45
Z80_IFF2
#define Z80_IFF2
Definition: z80ex.h:128
XEMU_BUILDINFO_CC
const char XEMU_BUILDINFO_CC[]
Definition: emutools_basicdefs.h:251
CPU_Z180
#define CPU_Z180
Definition: cpu.h:26
DEBUGPRINT
#define DEBUGPRINT(...)
Definition: emutools_basicdefs.h:171
primo_rom_seg
int primo_rom_seg
Definition: primoemu.c:32
console_open_window
void console_open_window(void)
Definition: console.c:135
xep_set_default_device_name
void xep_set_default_device_name(const char *name)
Definition: emu_rom_interface.c:95
CPU_Z80
#define CPU_Z80
Definition: cpu.h:24
CONFIG_SDEXT_SUPPORT
#define CONFIG_SDEXT_SUPPORT
Definition: xemu-target.h:11
monitor_check
int monitor_check(void)
Definition: emu_monitor.c:891
dir
DIR * dir
Definition: cpmfs.c:46
sdlver_linked
SDL_version sdlver_linked
Definition: configuration.c:86
Z80EX_BYTE
unsigned char Z80EX_BYTE
Definition: z80ex.h:49
ERROR_WINDOW
#define ERROR_WINDOW(...)
Definition: xep128.h:116
SEGMENT_OF_Z80_ADDR
#define SEGMENT_OF_Z80_ADDR(n)
Definition: emu_monitor.c:159
sdlver_compiled
SDL_version sdlver_compiled
Definition: configuration.c:86
CPU_Z80C
#define CPU_Z80C
Definition: cpu.h:25
Z80_BC_
#define Z80_BC_
Definition: z80ex.h:97
nick_dump_lpt
char * nick_dump_lpt(const char *newline_seq)
Definition: nick.c:507
monitor_execute
void monitor_execute(char *in_input_buffer, int in_source, char *in_output_buffer, int in_output_max_size, const char *in_output_nl)
Definition: emu_monitor.c:730
Z80_F
#define Z80_F
Definition: z80ex.h:76
cpu.h
NL
#define NL
Definition: fat32.c:37
emutools_config.h
compress_sd_image.r
def r
Definition: compress_sd_image.py:76
z180.h
audio_init
void audio_init(int enable)
Definition: dave.c:153
memory
Uint8 memory[0x100000]
Definition: commodore_65.c:43
audio_start
void audio_start(void)
Definition: dave.c:123
_z80_cpu_context::prefix
Z80EX_BYTE prefix
Definition: z80ex.h:163
dave.h
XEMUEXIT
#define XEMUEXIT(n)
Definition: emutools_basicdefs.h:246
primo_emulator_execute
void primo_emulator_execute(void)
Definition: primoemu.c:211
MPRINTF
#define MPRINTF(...)
Definition: emu_monitor.c:81
Z80_IM
#define Z80_IM
Definition: z80ex.h:129
console_close_window
void console_close_window(void)
Definition: console.c:189
DIRSEP_STR
#define DIRSEP_STR
Definition: emutools_basicdefs.h:141
Z80_DE_
#define Z80_DE_
Definition: z80ex.h:101
Z80_BC
#define Z80_BC
Definition: z80ex.h:81
input_devices.h
XEMU_BUILDINFO_CDATE
const char XEMU_BUILDINFO_CDATE[]
Definition: emutools_basicdefs.h:251
Z80_IX
#define Z80_IX
Definition: z80ex.h:109
Z80_PC
#define Z80_PC
Definition: z80ex.h:121
CPU_CLOCK
#define CPU_CLOCK
Definition: tvc.h:30
commands_st::name
const char * name
Definition: emu_monitor.c:51
show_keys
int show_keys
Definition: input_devices.c:39
monitor_queue_command
int monitor_queue_command(char *buffer)
Definition: emu_monitor.c:791
OSD
#define OSD(...)
Definition: xep128.h:100
XEMU_BUILDINFO_ON
const char XEMU_BUILDINFO_ON[]
monitor_start
int monitor_start(void)
Definition: emu_monitor.c:873
Uint16
uint16_t Uint16
Definition: fat32.c:50
commands_st::handler
void(* handler)(void)
Definition: emu_monitor.c:55
z80ex_dasm
int z80ex_dasm(char *output, int output_size, unsigned flags, int *t_states, int *t_states2, z80ex_dasm_readbyte_cb readbyte_cb, Z80EX_WORD addr)
Definition: z80ex_dasm.c:42
enterprise128.h
z80ex
Z80EX_CONTEXT z80ex
Definition: primo.c:37
XEMU_BUILDINFO_AT
const char XEMU_BUILDINFO_AT[]
Definition: emutools_basicdefs.h:251
console_monitor_ready
void console_monitor_ready(void)
Definition: console.c:219
sdl_pref_dir
char * sdl_pref_dir
Definition: emutools.c:97
ARG_SPACE
#define ARG_SPACE
Definition: emu_monitor.c:88
ep_set_ram_config
int ep_set_ram_config(const char *spec)
Definition: cpu.c:131
commands_st::alias
const char * alias
Definition: emu_monitor.c:52
sdimg_path
char sdimg_path[PATH_MAX+1]
commands_st::help
const char * help
Definition: emu_monitor.c:54
XEMU_UNLIKELY
#define XEMU_UNLIKELY(__x__)
Definition: emutools_basicdefs.h:125
commands_st::allowed
const int allowed
Definition: emu_monitor.c:53
ARG_ONE
#define ARG_ONE
Definition: emu_monitor.c:87
console_close_window_on_exit
void console_close_window_on_exit(void)
Definition: console.c:206
exos_info
Uint8 exos_info[8]
Definition: emu_rom_interface.c:46
mouse_setup
int mouse_setup(int cfg)
Definition: input_devices.c:500
nick.h
buf
Uint8 buf[512]
Definition: fat32.c:155
st
struct stat st
Definition: cpmfs.c:43
fileio_cwd
char fileio_cwd[PATH_MAX+1]
Definition: fileio.c:44
DIRSEP_CHR
#define DIRSEP_CHR
Definition: emutools_basicdefs.h:142