Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
uart_monitor.c
Go to the documentation of this file.
1 /* A work-in-progess MEGA65 (Commodore-65 clone origins) emulator
2  Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
3  Copyright (C)2016-2021 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 #include "xemu/emutools.h"
20 #include "mega65.h"
21 #include "uart_monitor.h"
22 
23 
24 #if !defined(HAS_UARTMON_SUPPORT)
25 // Windows is not supported currently, as it does not have POSIX-standard socket interface (?).
26 // Also, it's pointless for emscripten, for sure.
27 #warning "Platform does not support UMON"
28 #else
29 
31 
32 //#include <sys/types.h>
33 //#include <sys/stat.h>
34 //#include <fcntl.h>
35 //#include <errno.h>
36 #include <string.h>
37 //#include <limits.h>
38 
39 #ifndef XEMU_ARCH_WIN
40 #include <unistd.h>
41 #include <sys/un.h>
42 //#include <sys/socket.h>
43 //#include <netinet/in.h>
44 //#include <netdb.h>
45 #endif
46 
47 int umon_write_size;
48 int umon_send_ok;
49 char umon_write_buffer[UMON_WRITE_BUFFER_SIZE];
50 
51 #define UNCONNECTED XS_INVALID_SOCKET
52 
53 #ifdef XEMU_ARCH_WIN
54 # define PRINTF_SOCK "%I64d"
55 #else
56 # define PRINTF_SOCK "%d"
57 #endif
58 
59 
60 static xemusock_socket_t sock_server = UNCONNECTED;
61 static xemusock_socklen_t sock_len;
62 static xemusock_socket_t sock_client = UNCONNECTED;
63 
64 static int umon_write_pos, umon_read_pos;
65 static int umon_echo;
66 static char umon_read_buffer [0x1000];
67 
68 
69 // WARNING: This source is pretty ugly, ie not so much check of overflow of the output (write) buffer.
70 
71 
72 static char *parse_hex_arg ( char *p, int *val, int min, int max )
73 {
74  while (*p == 32)
75  p++;
76  *val = -1;
77  if (!*p) {
78  umon_printf(UMON_SYNTAX_ERROR "unexpected end of command (no parameter)");
79  return NULL;
80  }
81  int r = 0;
82  for (;;) {
83  if (*p >= 'a' && *p <= 'f')
84  r = (r << 4) | (*p - 'a' + 10);
85  else if (*p >= 'A' && *p <= 'F')
86  r = (r << 4) | (*p - 'A' + 10);
87  else if (*p >= '0' && *p <= '9')
88  r = (r << 4) | (*p - '0');
89  else if (*p == 32 || *p == 0)
90  break;
91  else {
92  umon_printf(UMON_SYNTAX_ERROR "invalid data as hex digit '%c'", *p);
93  return NULL;
94  }
95  p++;
96  }
97  *val = r;
98  if (r < min || r > max) {
99  umon_printf(UMON_SYNTAX_ERROR "command parameter's value is outside of the allowed range for this command %X (%X...%X)", r, min, max);
100  return NULL;
101  }
102  return p;
103 }
104 
105 
106 
107 static int check_end_of_command ( char *p, int error_out )
108 {
109  while (*p == 32)
110  p++;
111  if (*p) {
112  if (error_out)
113  umon_printf(UMON_SYNTAX_ERROR "unexpected command parameter");
114  return 0;
115  }
116  return 1;
117 }
118 
119 
120 static void setmem28 ( char *param, int addr )
121 {
122  char *orig_param = param;
123  int cnt = 0;
124  // get param count
125  while (param && !check_end_of_command(param, 0)) {
126  int val;
127  param = parse_hex_arg(param, &val, 0, 0xFF);
128  cnt++;
129  }
130  param = orig_param;
131  for (int idx = 0; idx < cnt; idx++) {
132  int val;
133  param = parse_hex_arg(param, &val, 0, 0xFF);
134  m65mon_setmem28(addr & 0xFFFFFFF, 1, (Uint8*)&val);
135  addr++;
136  }
137 }
138 
139 
140 static void execute_command ( char *cmd )
141 {
142  int bank;
143  int par1;
144  char *p = cmd;
145  while (*p)
146  if (p == cmd && (*cmd == 32 || *cmd == '\t' || *cmd == 8))
147  cmd = ++p;
148  else if (*p == '\t')
149  *(p++) = 32;
150  else if (*p == 8)
151  memmove(p - 1, p + 1, strlen(p + 1) + 1);
152  else if ((unsigned char)*p > 127 || (unsigned char)*p < 32) {
153  umon_printf(UMON_SYNTAX_ERROR "invalid character in the command (ASCII=%d)", *p);
154  return;
155  } else
156  p++;
157  p--;
158  while (p >= cmd && *p <= 32)
159  *(p--) = 0;
160  DEBUG("UARTMON: command got \"%s\" (%d bytes)." NL, cmd, (int)strlen(cmd));
161  switch (*(cmd++)) {
162  case 'h':
163  case 'H':
164  case '?':
165  if (check_end_of_command(cmd, 1))
166  umon_printf("Xemu/MEGA65 Serial Monitor\r\nWarning: not 100%% compatible with UART monitor of a *real* MEGA65 ...");
167  break;
168  case 'r':
169  case 'R':
170  if (check_end_of_command(cmd, 1))
172  break;
173  case 'm':
174  cmd = parse_hex_arg(cmd, &par1, 0, 0xFFFFFFF);
175  bank = par1 >> 16;
176  if (cmd && check_end_of_command(cmd, 1))
177  {
178  if (bank == 0x777)
179  m65mon_dumpmem16(par1);
180  else
181  m65mon_dumpmem28(par1);
182  }
183  break;
184  case 'M':
185  cmd = parse_hex_arg(cmd, &par1, 0, 0xFFFFFFF);
186  bank = par1 >> 16;
187  if (cmd && check_end_of_command(cmd, 1))
188  {
189  for (int k = 0; k < 32; k++)
190  {
191  if (bank == 0x777)
192  m65mon_dumpmem16(par1);
193  else
194  m65mon_dumpmem28(par1);
195  par1 += 16;
196  umon_printf("\n");
197  }
198  }
199  break;
200  case 's':
201  cmd = parse_hex_arg(cmd, &par1, 0, 0xFFFFFFF);
202  setmem28(cmd, par1);
203  break;
204  case 't':
205  if (!*cmd)
206  m65mon_do_trace();
207  else if (*cmd == 'c') {
208  if (check_end_of_command(cmd, 1))
210  } else {
211  cmd = parse_hex_arg(cmd, &par1, 0, 1);
212  if (cmd && check_end_of_command(cmd, 1))
213  m65mon_set_trace(par1);
214  }
215  break;
216  case 'b':
217  cmd = parse_hex_arg(cmd, &par1, 0, 0xFFFF);
218  if (cmd && check_end_of_command(cmd, 1))
219  m65mon_breakpoint(par1);
220  break;
221 #ifdef TRACE_NEXT_SUPPORT
222  case 'N':
223  m65mon_next_command();
224  break;
225 #endif
226  case 0:
227  m65mon_empty_command(); // emulator can use this, if it wants
228  break;
229  default:
230  umon_printf(UMON_SYNTAX_ERROR "unknown (or not implemented) command '%c'", cmd[-1]);
231  break;
232  }
233 }
234 
235 
236 
237 /* ------------------------- SOCKET HANDLING, etc ------------------------- */
238 
239 
240 int uartmon_is_active ( void )
241 {
242  return sock_server != UNCONNECTED;
243 }
244 
245 
246 int uartmon_init ( const char *fn )
247 {
248  static char fn_stored[PATH_MAX] = "";
249  int xerr;
250  xemusock_socket_t sock;
251  if (*fn_stored) {
252  ERROR_WINDOW("UARTMON: already activated on %s", fn_stored);
253  return 1;
254  }
255  sock_server = UNCONNECTED;
256  sock_client = UNCONNECTED;
257  if (!fn || !*fn) {
258  DEBUGPRINT("UARTMON: disabled, no name is specified to bind to." NL);
259  return 0;
260  }
261  const char *init_status = xemusock_init();
262  if (init_status) {
263  ERROR_WINDOW("Cannot initialize network, uart_mon won't be availbale\n%s", init_status);
264  return 1;
265  }
266  if (fn[0] == ':') {
267  int port = atoi(fn + 1);
268  if (port < 1024 || port > 65535) {
269  ERROR_WINDOW("uartmon: invalid port specification %d (1024-65535 is allowed) from string %s", port, fn);
270  return 1;
271  }
272  struct sockaddr_in sock_st;
273  sock_len = sizeof(struct sockaddr_in);
274  //sock = socket(AF_INET, SOCK_STREAM, 0);
275  sock = xemusock_create_for_inet(XEMUSOCK_TCP, XEMUSOCK_BLOCKING, &xerr);
276  if (sock == XS_INVALID_SOCKET) {
277  ERROR_WINDOW("Cannot create TCP socket: %s", xemusock_strerror(xerr));
278  return 1;
279  }
280  if (xemusock_setsockopt_reuseaddr(sock, &xerr)) {
281  ERROR_WINDOW("UARTMON: setsockopt for SO_REUSEADDR failed with %s", xemusock_strerror(xerr));
282  }
283  //sock_st.sin_family = AF_INET;
284  //sock_st.sin_addr.s_addr = htonl(INADDR_ANY);
285  //sock_st.sin_port = htons(port);
286  xemusock_fill_servaddr_for_inet_ip_native(&sock_st, 0, port);
287  if (xemusock_bind(sock, (struct sockaddr*)&sock_st, sock_len, &xerr)) {
288  ERROR_WINDOW("Cannot bind TCP socket %d, UART monitor cannot be used: %s", port, xemusock_strerror(xerr));
289  xemusock_close(sock, NULL);
290  return 1;
291  }
292  } else {
293 #if !defined(XEMU_ARCH_UNIX)
294  ERROR_WINDOW("On non-UNIX systems, you must use TCP/IP sockets, so uartmon parameter must be in form of :n (n=port number to bind to)\nUARTMON is not available because of bad syntax.");
295  return 1;
296 #else
297  // This is UNIX specific code (UNIX named socket) thus it's OK not use Xemu socket API calls here.
298  // Note: on longer term, we want to drop this, and allow only TCP sockets to be more unified and simple.
299  struct sockaddr_un sock_st;
300  sock_len = sizeof(struct sockaddr_un);
301  sock = socket(AF_UNIX, SOCK_STREAM, 0);
302  if (sock < 0) {
303  ERROR_WINDOW("Cannot create named socket %s, UART monitor cannot be used: %s", fn, strerror(errno));
304  return 1;
305  }
306  sock_st.sun_family = AF_UNIX;
307  strcpy(sock_st.sun_path, fn);
308  unlink(sock_st.sun_path);
309  if (bind(sock, (struct sockaddr*)&sock_st, sock_len)) {
310  ERROR_WINDOW("Cannot bind named socket %s, UART monitor cannot be used: %s", fn, strerror(errno));
311  xemusock_close(sock, NULL);
312  return 1;
313  }
314 #endif
315  }
316  if (xemusock_listen(sock, 5, &xerr)) {
317  ERROR_WINDOW("Cannot listen socket %s, UART monitor cannot be used: %s", fn, xemusock_strerror(xerr));
318  xemusock_close(sock, NULL);
319  return 1;
320  }
321  if (xemusock_set_nonblocking(sock, XEMUSOCK_NONBLOCKING, &xerr)) {
322  ERROR_WINDOW("Cannot set socket %s into non-blocking mode, UART monitor cannot be used: %s", fn, xemusock_strerror(xerr));
323  xemusock_close(sock, NULL);
324  return 1;
325  }
326  DEBUG("UARTMON: monitor is listening on socket %s" NL, fn);
327  sock_client = UNCONNECTED; // no client connection yet
328  sock_server = sock; // now set the server socket visible outside of this function too
329  umon_echo = 1;
330  umon_send_ok = 1;
331  strcpy(fn_stored, fn);
332  return 0;
333 }
334 
335 
336 void uartmon_close ( void )
337 {
338  if (sock_server != UNCONNECTED) {
339  xemusock_close(sock_server, NULL);
340  sock_server = UNCONNECTED;
341  }
342  if (sock_client != UNCONNECTED) {
343  xemusock_close(sock_client, NULL);
344  sock_client = UNCONNECTED;
345  }
346 }
347 
348 
349 void uartmon_finish_command ( void )
350 {
351  umon_send_ok = 1;
352  if (umon_write_buffer[umon_write_size - 1] != '\n') {
353  // if generated message wasn't closed with CRLF (well, only LF is checked), we do so here
354  umon_write_buffer[umon_write_size++] = '\r';
355  umon_write_buffer[umon_write_size++] = '\n';
356  }
357  // umon_trigger_end_of_answer = 1;
358  umon_write_buffer[umon_write_size++] = '.'; // add the 'dot prompt'! (m65dbg seems to check LF + dot for end of the answer)
359  umon_read_pos = 0;
360  umon_echo = 1;
361 }
362 
363 
364 // Non-blocky I/O for UART monitor emulation.
365 // Note: you need to call it "quite often" or it will be terrible slow ...
366 // From emulator main update, aka etc 25Hz rate should be Okey ...
367 void uartmon_update ( void )
368 {
369  int xerr, ret;
370  // If there is no server socket, we can't do anything!
371  if (sock_server == UNCONNECTED)
372  return;
373  // Try to accept new connection, if not yet have one (we handle only *ONE* connection!!!!)
374  if (sock_client == UNCONNECTED) {
375  //struct sockaddr_un sock_st;
376  xemusock_socklen_t len = sock_len;
377  union {
378 #ifdef XEMU_ARCH_UNIX
379  struct sockaddr_un un;
380 #endif
381  struct sockaddr_in in;
382  } sock_st;
383  xemusock_socket_t ret_sock = xemusock_accept(sock_server, (struct sockaddr *)&sock_st, &len, &xerr);
384  if (ret_sock != XS_INVALID_SOCKET || (ret_sock == XS_INVALID_SOCKET && !xemusock_should_repeat_from_error(xerr)))
385  DEBUG("UARTMON: accept()=" PRINTF_SOCK " error=%s" NL,
386  ret_sock,
387  ret_sock != XS_INVALID_SOCKET ? "OK" : xemusock_strerror(xerr)
388  );
389  if (ret_sock != XS_INVALID_SOCKET) {
390  if (xemusock_set_nonblocking(ret_sock, 1, &xerr)) {
391  DEBUGPRINT("UARTMON: error, cannot make socket non-blocking %s", xemusock_strerror(xerr));
392  xemusock_close(ret_sock, NULL);
393  return;
394  } else {
395  sock_client = ret_sock; // "publish" new client socket
396  // Reset reading/writing information
397  umon_write_size = 0;
398  umon_read_pos = 0;
399  DEBUGPRINT("UARTMON: new connection established on socket " PRINTF_SOCK NL, sock_client);
400  }
401  }
402  }
403  // If no established connection, return
404  if (sock_client == UNCONNECTED)
405  return;
406  // If there is data to write, try to write
407  if (umon_write_size) {
408  if (!umon_send_ok)
409  return;
410  ret = xemusock_send(sock_client, umon_write_buffer + umon_write_pos, umon_write_size, &xerr);
411  if (ret != XS_SOCKET_ERROR || (ret == XS_SOCKET_ERROR && !xemusock_should_repeat_from_error(xerr)))
412  DEBUG("UARTMON: write(" PRINTF_SOCK ",buffer+%d,%d)=%d (%s)" NL,
413  sock_client, umon_write_pos, umon_write_size,
414  ret, ret == XS_SOCKET_ERROR ? xemusock_strerror(xerr) : "OK"
415  );
416  if (ret == 0) { // client socket closed
417  xemusock_close(sock_client, NULL);
418  sock_client = UNCONNECTED;
419  DEBUGPRINT("UARTMON: connection closed by peer while writing" NL);
420  return;
421  }
422  if (ret > 0) {
423  //debug_buffer_slice(umon_write_buffer + umon_write_pos, ret);
424  umon_write_pos += ret;
425  umon_write_size -= ret;
426  if (umon_write_size < 0)
427  FATAL("FATAL: negative umon_write_size!");
428  }
429  if (umon_write_size)
430  return; // if we still have bytes to write, return and leave the work for the next update
431  }
432  umon_write_pos = 0;
433  // Try to read data
434  ret = xemusock_recv(sock_client, umon_read_buffer + umon_read_pos, sizeof(umon_read_buffer) - umon_read_pos - 1, &xerr);
435  if (ret != XS_SOCKET_ERROR || (ret == XS_SOCKET_ERROR && !xemusock_should_repeat_from_error(xerr)))
436  DEBUG("UARTMON: read(" PRINTF_SOCK ",buffer+%d,%d)=%d (%s)" NL,
437  sock_client, umon_read_pos, (int)sizeof(umon_read_buffer) - umon_read_pos - 1,
438  ret, ret == XS_SOCKET_ERROR ? xemusock_strerror(xerr) : "OK"
439  );
440  if (ret == 0) { // client socket closed
441  xemusock_close(sock_client, NULL);
442  sock_client = UNCONNECTED;
443  DEBUGPRINT("UARTMON: connection closed by peer while reading" NL);
444  return;
445  }
446  if (ret > 0) {
447  /* ECHO: provide echo for the client */
448  if (umon_echo) {
449  char*p = umon_read_buffer + umon_read_pos;
450  int n = ret;
451  while (n--)
452  if (*p != 13 && *p != 10) {
453  umon_write_buffer[umon_write_size++] = *(p++);
454  } else {
455  umon_echo = 0; // setting to zero avoids more input to echo, and also signs a complete command
456  *p = 0; // terminate string in read buffer
457  break;
458  }
459  }
460  /* ECHO: end */
461  umon_read_pos += ret;
462  umon_read_buffer[umon_read_pos] = 0;
463  //debug_buffer(umon_read_buffer);
464  if (!umon_echo || sizeof(umon_read_buffer) - umon_read_pos - 1 == 0) {
465  umon_read_buffer[sizeof(umon_read_buffer) - 1] = 0; // just in case of a "mega long command" with filled rx buffer ...
466  umon_write_buffer[umon_write_size++] = '\r';
467  umon_write_buffer[umon_write_size++] = '\n';
468  umon_send_ok = 1; // by default, command is finished after the execute_command()
469  execute_command(umon_read_buffer); // Execute our command!
470  // command may delay (like with trace) the finish of the command with
471  // setting umon_send_ok to zero. In this case, some need to call
472  // uartmon_finish_command() some time otherwise the monitor connection
473  // will just hang!
474  if (umon_send_ok)
475  uartmon_finish_command();
476  }
477  }
478 }
479 
480 #endif
m65mon_do_trace_c
void m65mon_do_trace_c(void)
emutools.h
m65mon_dumpmem16
void m65mon_dumpmem16(Uint16 addr)
m65mon_show_regs
void m65mon_show_regs(void)
m65mon_breakpoint
void m65mon_breakpoint(int brk)
addr
int addr
Definition: dma65.c:81
fn
const char * fn
Definition: roms.c:42
m65mon_setmem28
void m65mon_setmem28(int addr, int cnt, Uint8 *vals)
mega65.h
Uint8
uint8_t Uint8
Definition: fat32.c:51
DEBUGPRINT
#define DEBUGPRINT(...)
Definition: emutools_basicdefs.h:171
m65mon_set_trace
void m65mon_set_trace(int m)
emutools_socketapi.h
m65mon_empty_command
void m65mon_empty_command(void)
ERROR_WINDOW
#define ERROR_WINDOW(...)
Definition: xep128.h:116
uart_monitor.h
NL
#define NL
Definition: fat32.c:37
compress_sd_image.r
def r
Definition: compress_sd_image.py:76
m65mon_dumpmem28
void m65mon_dumpmem28(int addr)
m65mon_do_trace
void m65mon_do_trace(void)
DEBUG
#define DEBUG(...)
Definition: emutools_basicdefs.h:167
FATAL
#define FATAL(...)
Definition: xep128.h:117