diff --git a/frontpanel/FrontPanelTest.c b/frontpanel/FrontPanelTest.c index 9afa4140..52090418 100644 --- a/frontpanel/FrontPanelTest.c +++ b/frontpanel/FrontPanelTest.c @@ -56,7 +56,7 @@ const char *sim_config = "VAX-PANEL.ini"; /* Registers visible on the Front Panel */ -unsigned int PC, SP, FP, AP, R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11; +unsigned int PC, SP, FP, AP, R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, atPC; int update_display = 1; @@ -76,7 +76,7 @@ if (!update_display) return; update_display = 0; buf1[sizeof(buf1)-1] = buf2[sizeof(buf2)-1] = buf3[sizeof(buf3)-1] = 0; -sprintf (buf1, "%s PC: %08X SP: %08X AP: %08X FP: %08X\r\n", states[sim_panel_get_state (panel)], PC, SP, AP, FP); +sprintf (buf1, "%s PC: %08X SP: %08X AP: %08X FP: %08X @PC: %08X\r\n", states[sim_panel_get_state (panel)], PC, SP, AP, FP, atPC); sprintf (buf2, "R0:%08X R1:%08X R2:%08X R3:%08X R4:%08X R5:%08X\r\n", R0, R1, R2, R3, R4, R5); sprintf (buf3, "R6:%08X R7:%08X R8:%08X R9:%08X R10:%08X R11:%08X\r\n", R6, R7, R8, R9, R10, R11); #if defined(_WIN32) @@ -198,6 +198,10 @@ if (sim_panel_add_register (panel, "PC", NULL, sizeof(PC), &PC)) { printf ("Error adding register 'PC': %s\n", sim_panel_get_error()); goto Done; } +if (sim_panel_add_register_indirect (panel, "PC", NULL, sizeof(atPC), &atPC)) { + printf ("Error adding register indirect 'PC': %s\n", sim_panel_get_error()); + goto Done; + } if (sim_panel_add_register (panel, "SP", NULL, sizeof(SP), &SP)) { printf ("Error adding register 'SP': %s\n", sim_panel_get_error()); goto Done; @@ -262,6 +266,41 @@ if (sim_panel_get_registers (panel, NULL)) { printf ("Error getting register data: %s\n", sim_panel_get_error()); goto Done; } +if (1) { + long deadbeef = 0xdeadbeef, beefdead = 0xbeefdead, addr200 = 0x00000200, beefdata; + + if (sim_panel_set_register_value (panel, "R0", "DEADBEEF")) { + printf ("Error setting R0 to DEADBEEF: %s\n", sim_panel_get_error()); + goto Done; + } + if (sim_panel_gen_deposit (panel, "R1", sizeof(deadbeef), &deadbeef)) { + printf ("Error setting R1 to DEADBEEF: %s\n", sim_panel_get_error()); + goto Done; + } + if (sim_panel_mem_deposit (panel, sizeof(addr200), &addr200, sizeof(deadbeef), &deadbeef)) { + printf ("Error setting 00000200 to DEADBEEF: %s\n", sim_panel_get_error()); + goto Done; + } + beefdata = 0; + if (sim_panel_gen_examine (panel, "200", sizeof(beefdata), &beefdata)) { + printf ("Error getting contents of memory location 200: %s\n", sim_panel_get_error()); + goto Done; + } + beefdata = 0; + if (sim_panel_mem_examine (panel, sizeof (addr200), &addr200, sizeof (beefdata), &beefdata)) { + printf ("Error getting contents of memory location 200: %s\n", sim_panel_get_error()); + goto Done; + } + beefdata = 0; + if (!sim_panel_gen_examine (panel, "20000000", sizeof(beefdata), &beefdata)) { + printf ("Unexpected success getting contents of memory location 20000000: %s\n", sim_panel_get_error()); + goto Done; + } + } +if (sim_panel_get_registers (panel, NULL)) { + printf ("Error getting register data: %s\n", sim_panel_get_error()); + goto Done; + } if (sim_panel_set_display_callback (panel, &DisplayCallback, NULL, 5)) { printf ("Error setting automatic display callback: %s\n", sim_panel_get_error()); goto Done; diff --git a/sim_frontpanel.c b/sim_frontpanel.c index 6c4086fe..c521b286 100644 --- a/sim_frontpanel.c +++ b/sim_frontpanel.c @@ -24,6 +24,7 @@ in this Software without prior written authorization from Mark Pizzolato. 05-Feb-15 MP Initial implementation + 01-Apr-15 MP Added register indirect, mem_examine and mem_deposit This module provides interface between a front panel application and a simh simulator. Facilities provide ways to gather information from and to @@ -111,6 +112,7 @@ typedef struct { char *device_name; void *addr; size_t size; + int indirect; } REG; struct PANEL { @@ -148,6 +150,7 @@ struct PANEL { int callbacks_per_second; int debug; char *simulator_version; + int radix; FILE *Debug; #if defined(_WIN32) HANDLE hProcess; @@ -160,6 +163,7 @@ static const char *sim_prompt = "sim> "; static const char *register_get_prefix = "show time"; static const char *register_get_echo = "# REGISTERS-DONE"; static const char *register_dev_echo = "# REGISTERS-FOR-DEVICE:"; +static const char *register_ind_echo = "# REGISTER-INDIRECT:"; static const char *command_done_echo = "# COMMAND-DONE"; static int little_endian; static void *_panel_reader(void *arg); @@ -347,8 +351,11 @@ char *dev; pthread_mutex_lock (&panel->io_lock); buf_needed = 2 + strlen (register_get_prefix); /* SHOW TIME */ -for (i=0; ireg_count; i++) +for (i=0; ireg_count; i++) { buf_needed += 9 + strlen (panel->regs[i].name) + (panel->regs[i].device_name ? strlen (panel->regs[i].device_name) : 0); + if (panel->regs[i].indirect) + buf_needed += 12 + strlen (register_ind_echo) + strlen (panel->regs[i].name); + } buf_needed += 10 + strlen (register_get_echo); /* # REGISTERS-DONE */ if (buf_needed > *buf_size) { free (*buf); @@ -367,6 +374,8 @@ dev = ""; for (i=j=0; ireg_count; i++) { char *reg_dev = panel->regs[i].device_name ? panel->regs[i].device_name : ""; + if (panel->regs[i].indirect) + continue; if (strcmp (dev, reg_dev)) {/* devices are different */ char *tbuf; @@ -393,8 +402,18 @@ for (i=j=0; ireg_count; i++) { ++j; buf_data += strlen (*buf + buf_data); } -strcpy (*buf + buf_data, "\r"); -buf_data += strlen (*buf + buf_data); +if (buf_data && ((*buf)[buf_data-1] != '\r')) { + strcpy (*buf + buf_data, "\r"); + buf_data += strlen (*buf + buf_data); + } +for (i=j=0; ireg_count; i++) { + char *reg_dev = panel->regs[i].device_name ? panel->regs[i].device_name : ""; + + if (!panel->regs[i].indirect) + continue; + sprintf (*buf + buf_data, "%s%s\rE -H %s %s,$\r", register_ind_echo, panel->regs[i].name, reg_dev, panel->regs[i].name); + buf_data += strlen (*buf + buf_data); + } strcpy (*buf + buf_data, register_get_echo); buf_data += strlen (*buf + buf_data); strcpy (*buf + buf_data, "\r"); @@ -618,7 +637,7 @@ if (p->sock == INVALID_SOCKET) { if (stat (sim_path, &statb) < 0) sim_panel_set_error ("Can't stat simulator '%s': %s", sim_path, strerror(errno)); else - sim_panel_set_error ("Can't connect to simulator Remote Console on port %s", p->hostport); + sim_panel_set_error ("Can't connect to the %s simulator Remote Console on port %s, the simulator process may not have started or the simulator binary can't be found", sim_path, p->hostport); } goto Error_Return; } @@ -669,6 +688,20 @@ else { goto Error_Return; } } + if (1) { + char *radix = NULL; + + if (_panel_sendf (p, 1, &radix, "SHOW %s RADIX\r", p->device_name ? p->device_name : "")) { + free (radix); + goto Error_Return; + } + sscanf (radix, "Radix=%d", &p->radix); + free (radix); + if ((p->radix != 16) && (p->radix != 8)) { + sim_panel_set_error ("Unsupported Radix: %d%s%s.", p->radix, p->device_name ? " on device " : "", p->device_name ? p->device_name : ""); + goto Error_Return; + } + } } _panel_register_panel (p); return p; @@ -813,12 +846,13 @@ if (!panel) return panel->State; } -int -sim_panel_add_register (PANEL *panel, - const char *name, - const char *device_name, - size_t size, - void *addr) +static int +_panel_add_register (PANEL *panel, + const char *name, + const char *device_name, + size_t size, + void *addr, + int indirect) { REG *regs, *reg; char *response = NULL; @@ -844,6 +878,7 @@ if (reg->name == NULL) { return -1; } strcpy (reg->name, name); +reg->indirect = indirect; for (i=0; iname); i++) { if (islower (reg->name[i])) reg->name[i] = toupper (reg->name[i]); @@ -877,7 +912,7 @@ for (i=0; ireg_count; i++) { } sprintf (t1, "%s %s", regs[i].device_name ? regs[i].device_name : "", regs[i].name); sprintf (t2, "%s %s", reg->device_name ? reg->device_name : "", reg->name); - if (!strcmp (t1, t2)) { + if ((!strcmp (t1, t2)) && (reg->indirect == regs[i].indirect)) { sim_panel_set_error ("Duplicate Register Declaration"); free (t1); free (t2); @@ -919,6 +954,26 @@ if (_panel_register_query_string (panel, &panel->reg_query, &panel->reg_query_si return 0; } +int +sim_panel_add_register (PANEL *panel, + const char *name, + const char *device_name, + size_t size, + void *addr) +{ +return _panel_add_register (panel, name, device_name, size, addr, 0); +} + +int +sim_panel_add_register_indirect (PANEL *panel, + const char *name, + const char *device_name, + size_t size, + void *addr) +{ +return _panel_add_register (panel, name, device_name, size, addr, 1); +} + int sim_panel_get_registers (PANEL *panel, unsigned long long *simulation_time) { @@ -1067,6 +1122,201 @@ panel->State = Run; return 0; } +/** + + sim_panel_gen_examine + + name_or_addr the name the simulator knows this register by + size the size (in local storage) of the buffer which will + receive the data returned when examining the simulator + value a pointer to the buffer which will be loaded with the + data returned when examining the simulator + */ + +int +sim_panel_gen_examine (PANEL *panel, + const char *name_or_addr, + size_t size, + void *value) +{ +char *response = NULL, *c; +unsigned long long data = 0; + +if (!panel || (panel->State == Error)) { + sim_panel_set_error ("Invalid Panel"); + return -1; + } +if (panel->State == Run) { + sim_panel_set_error ("Not Halted"); + return -1; + } +if (_panel_sendf (panel, 1, &response, "EXAMINE -H %s", name_or_addr)) { + free (response); + return -1; + } +c = strchr (response, ':'); +if (!c) { + sim_panel_set_error (response); + free (response); + return -1; + } +data = strtoull (c + 1, NULL, 16); +if (little_endian) + memcpy (value, &data, size); +else + memcpy (value, ((char *)&data) + sizeof(data)-size, size); +free (response); +return 0; +} + +/** + + sim_panel_gen_deposit + + name_or_addr the name the simulator knows this register by + size the size (in local storage) of the buffer which + contains the data to be deposited into the simulator + value a pointer to the buffer which contains the data to + be deposited into the simulator + */ + +int +sim_panel_gen_deposit (PANEL *panel, + const char *name_or_addr, + size_t size, + const void *value) +{ +unsigned long long data = 0; + +if (!panel || (panel->State == Error)) { + sim_panel_set_error ("Invalid Panel"); + return -1; + } +if (panel->State == Run) { + sim_panel_set_error ("Not Halted"); + return -1; + } +if (little_endian) + memcpy (&data, value, size); +else + memcpy (((char *)&data) + sizeof(data)-size, value, size); +if (_panel_sendf (panel, 1, NULL, "DEPOSIT -H %s %llx", name_or_addr, data)) + return -1; +return 0; +} + +/** + + sim_panel_mem_examine + + addr_size the size (in local storage) of the buffer which + contains the memory address of the data to be examined + in the simulator + addr a pointer to the buffer containing the memory address + of the data to be examined in the simulator + value_size the size (in local storage) of the buffer which will + receive the data returned when examining the simulator + value a pointer to the buffer which will be loaded with the + data returned when examining the simulator + */ + +int +sim_panel_mem_examine (PANEL *panel, + size_t addr_size, + const void *addr, + size_t value_size, + void *value) +{ +char *response = NULL, *c; +unsigned long long data = 0, address = 0; + +if (!panel || (panel->State == Error)) { + sim_panel_set_error ("Invalid Panel"); + return -1; + } +if (panel->State == Run) { + sim_panel_set_error ("Not Halted"); + return -1; + } +if (little_endian) + memcpy (&address, addr, addr_size); +else + memcpy (((char *)&address) + sizeof(address)-addr_size, addr, addr_size); +if (_panel_sendf (panel, 1, &response, (panel->radix == 16) ? "EXAMINE -H %llx" : "EXAMINE -H %llo", address)) { + free (response); + return -1; + } +c = strchr (response, ':'); +if (!c) { + sim_panel_set_error (response); + free (response); + return -1; + } +data = strtoull (c + 1, NULL, 16); +if (little_endian) + memcpy (value, &data, value_size); +else + memcpy (value, ((char *)&data) + sizeof(data)-value_size, value_size); +free (response); +return 0; +} + +/** + + sim_panel_mem_deposit + + addr_size the size (in local storage) of the buffer which + contains the memory address of the data to be deposited + into the simulator + addr a pointer to the buffer containing the memory address + of the data to be deposited into the simulator + value_size the size (in local storage) of the buffer which will + contains the data to be deposited into the simulator + value a pointer to the buffer which contains the data to be + deposited into the simulator + */ + + int +sim_panel_mem_deposit (PANEL *panel, + size_t addr_size, + const void *addr, + size_t value_size, + const void *value) +{ +unsigned long long data = 0, address = 0; + +if (!panel || (panel->State == Error)) { + sim_panel_set_error ("Invalid Panel"); + return -1; + } +if (panel->State == Run) { + sim_panel_set_error ("Not Halted"); + return -1; + } +if (little_endian) { + memcpy (&data, value, value_size); + memcpy (&address, addr, addr_size); + } +else { + memcpy (((char *)&data) + sizeof(data)-value_size, value, value_size); + memcpy (((char *)&address) + sizeof(address)-addr_size, addr, addr_size); + } +if (_panel_sendf (panel, 1, NULL, (panel->radix == 16) ? "DEPOSIT -H %llx %llx" : "DEPOSIT -H %llo %llx", address, data)) + return -1; +return 0; +} + +/** + sim_panel_set_register_value + + name the name of a simulator register or a memory address + which is to receive a new value + value the new value in character string form. The string + must be in the native/natural radix that the simulator + uses when referencing that register + + */ + int sim_panel_set_register_value (PANEL *panel, const char *name, @@ -1076,8 +1326,8 @@ if (!panel || (panel->State == Error)) { sim_panel_set_error ("Invalid Panel"); return -1; } -if (panel->callback) { - sim_panel_set_error ("Callback provides register data"); +if (panel->State == Run) { + sim_panel_set_error ("Not Halted"); return -1; } if (_panel_sendf (panel, 1, NULL, "DEPOSIT %s %s", name, value)) @@ -1089,6 +1339,7 @@ static void * _panel_reader(void *arg) { PANEL *p = (PANEL*)arg; +REG *r = NULL; int sched_policy; struct sched_param sched_priority; char buf[4096]; @@ -1159,6 +1410,37 @@ while ((p->sock != INVALID_SOCKET) && ++s; continue; } + if (!strncmp (s + strlen (sim_prompt), register_ind_echo, strlen (register_ind_echo) - 1)) { + e = s + strlen (sim_prompt) + strlen (register_ind_echo); + r = NULL; + for (i=0; ireg_count; i++) { + if (p->regs[i].indirect && (!strcmp(p->regs[i].name, e))) { + r = &p->regs[i]; + break; + } + } + s = eol; + while (isspace(0xFF & (*s))) + ++s; + if (r) + continue; + } + if (r) { + if (strcmp (s, r->name)) { + unsigned long long data; + + data = strtoull (e, NULL, 16); + if (little_endian) + memcpy (p->regs[i].addr, &data, p->regs[i].size); + else + memcpy (p->regs[i].addr, ((char *)&data) + sizeof(data)-p->regs[i].size, p->regs[i].size); + r = NULL; + } + s = eol; + while (isspace(0xFF & (*s))) + ++s; + continue; + } for (i=0; ireg_count; i++) { if (!strcmp(p->regs[i].name, s)) { unsigned long long data; @@ -1385,6 +1667,8 @@ while (1) { /* format passed string, arg if (buf != stackbuf) free (buf); bufsize = bufsize * 2; + if (bufsize < len + 2) + bufsize = len + 2; buf = (char *) _panel_malloc (bufsize); if (buf == NULL) return -1; diff --git a/sim_frontpanel.h b/sim_frontpanel.h index 50fd08af..0f8d5641 100644 --- a/sim_frontpanel.h +++ b/sim_frontpanel.h @@ -24,6 +24,7 @@ in this Software without prior written authorization from Mark Pizzolato. 15-Jan-15 MP Initial implementation + 01-Apr-15 MP Added register indirect, mem_examine and mem_deposit This module defines interface between a front panel application and a simh simulator. Facilities provide ways to gather information from and to @@ -125,6 +126,8 @@ sim_panel_destroy (PANEL *panel); access to are described by the application by calling: sim_panel_add_register +and + sim_panel_add_register_indirect name the name the simulator knows this register by device_name the device this register is part of. Defaults to @@ -143,6 +146,12 @@ sim_panel_add_register (PANEL *panel, size_t size, void *addr); +int +sim_panel_add_register_indirect (PANEL *panel, + const char *name, + const char *device_name, + size_t size, + void *addr); /** A panel application has a choice of two different methods of getting @@ -204,11 +213,103 @@ sim_panel_exec_run (PANEL *panel); int sim_panel_exec_step (PANEL *panel); +/** + + When a front panel application needs to change or access + memory or a register one of the following routines should + be called: + + sim_panel_gen_examine - Examine register or memory + sim_panel_gen_deposit - Deposit to register or memory + sim_panel_mem_examine - Examine memory location + sim_panel_mem_deposit - Deposit to memory location + sim_panel_set_register_value - + + */ + + +/** + + sim_panel_gen_examine + + name_or_addr the name the simulator knows this register by + size the size (in local storage) of the buffer which will + receive the data returned when examining the simulator + value a pointer to the buffer which will be loaded with the + data returned when examining the simulator + */ + +int +sim_panel_gen_examine (PANEL *panel, + const char *name_or_addr, + size_t size, + void *value); +/** + + sim_panel_gen_deposit + + name_or_addr the name the simulator knows this register by + size the size (in local storage) of the buffer which + contains the data to be deposited into the simulator + value a pointer to the buffer which contains the data to + be deposited into the simulator + */ + +int +sim_panel_gen_deposit (PANEL *panel, + const char *name_or_addr, + size_t size, + const void *value); + +/** + + sim_panel_mem_examine + + addr_size the size (in local storage) of the buffer which + contains the memory address of the data to be examined + in the simulator + addr a pointer to the buffer containing the memory address + of the data to be examined in the simulator + value_size the size (in local storage) of the buffer which will + receive the data returned when examining the simulator + value a pointer to the buffer which will be loaded with the + data returned when examining the simulator + */ + +int +sim_panel_mem_examine (PANEL *panel, + size_t addr_size, + const void *addr, + size_t value_size, + void *value); + +/** + + sim_panel_mem_deposit + + addr_size the size (in local storage) of the buffer which + contains the memory address of the data to be deposited + into the simulator + addr a pointer to the buffer containing the memory address + of the data to be deposited into the simulator + value_size the size (in local storage) of the buffer which will + contains the data to be deposited into the simulator + value a pointer to the buffer which contains the data to be + deposited into the simulator + */ + +int +sim_panel_mem_deposit (PANEL *panel, + size_t addr_size, + const void *addr, + size_t value_size, + const void *value); + /** sim_panel_set_register_value - name the name of a simulator register which is to receive - a new value + name the name of a simulator register or a memory address + which is to receive a new value value the new value in character string form. The string must be in the native/natural radix that the simulator uses when referencing that register