/* pdq3_sys.c: PDQ3 simulator interface Work derived from Copyright (c) 2004-2012, Robert M. Supnik Copyright (c) 2013 Holger Veit Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the names of Robert M Supnik and Holger Veit shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik and Holger Veit. 2013xxxx hv initial version (written up to the leval to test against bootloader) 20130907 hv added VIEWSEG command 20130925 hv added CALL and NAME command 20130927 hv wrong disassembly of LDC instr 20141003 hv compiler suggested warnings (vc++2013, gcc) */ #include "pdq3_defs.h" #include t_stat parse_sym_m (char *cptr, t_value *val, int32 sw); void pdq3_vm_init (void); static t_stat pdq3_cmd_exstack(int32 arg, char *buf); static t_stat pdq3_cmd_exmscw(int32 arg, char *buf); static t_stat pdq3_cmd_extib(int32 arg, char *buf); static t_stat pdq3_cmd_exseg(int32 arg, char *buf); static t_stat pdq3_cmd_calltree(int32 arg, char *buf); static t_stat pdq3_cmd_namealias(int32 arg, char *buf); extern DEVICE cpu_dev; extern UNIT cpu_unit; extern DEVICE tty_dev; extern DEVICE fdc_dev; extern DEVICE tim_dev; extern REG cpu_reg[]; extern uint16 M[]; extern uint16 reg_pc; /* SCP data structures and interface routines sim_name simulator name string sim_PC pointer to saved PC register descriptor sim_emax maximum number of words for examine/deposit sim_devices array of pointers to simulated devices sim_stop_messages array of pointers to stop messages sim_load binary loader */ char sim_name[] = "PDQ3"; REG *sim_PC = &cpu_reg[0]; /* note this is the artifical register PCX */ int32 sim_emax = 6; DEVICE *sim_devices[] = { &cpu_dev, &con_dev, &fdc_dev, &tim_dev, NULL }; const char *sim_stop_messages[] = { "---", "PC Breakpoint", "MEM Breakpoint", "Invalid Opcode", "Invalid MEM Access", "Invalid I/O Access", "Not yet implemented", "BPT instruction", "DEBUG PRE exec stop", "DEBUG POST exec stop", "HALT on Pascal Exception", }; CTAB pdq3_cmds[] = { { "VSTACK", &pdq3_cmd_exstack, 0, "Display last N elements of stack. Top is where SP points to" }, { "VMSCW", &pdq3_cmd_exmscw, 0, "Display current MSCW" }, { "VTIB", &pdq3_cmd_extib, 0, "Display current TIB" }, { "VSEG", &pdq3_cmd_exseg, 0, "Display a segment table entry" }, { "VCALL", &pdq3_cmd_calltree, 0, "Display the call tree" }, { "NAME", &pdq3_cmd_namealias, 0, "Define a name" }, { NULL, NULL, 0, NULL } }; void (*sim_vm_init)(void) = &pdq3_vm_init; /* Loader proper */ t_stat sim_load (FILE *fi, char *cptr, char *fnam, int flag) { int rombase; int c1, c2, i; if (flag == 1) /* don't dump */ return SCPE_ARG; /* this assumes a HDT style ROM, where the first 2 bytes refer to the * actual word start of the ROM, e.g. with PDQ-3 the HDT ROM has 0xf401 * as the first word, so it will load at word address 0xf400, and 0xfc68 * will be preset to 0xf401 */ c1 = fgetc(fi); c2 = fgetc(fi); rombase = c1 + c2 * 256; rom_write(rombase & 0xfffe, rombase); reg_fc68 = rombase; i = 0; while (!feof(fi) && i<0x1ff) { c1 = fgetc(fi); c2 = fgetc(fi); rom_write(rombase+i, (uint16)(c1 + c2*256)); i++; } reg_romsize = i; /* preset the cpu_serial number from ROM, may be overwritten manually for special purposes */ rom_read(rombase+i-1, ®_cpuserial); return SCPE_OK; } /* Note: this simh handles ABSOLUTE word addresses and segmented byte addresses. * A word address addresses a single cell in memory (up to 65536 cells). * A byte address only occurs in IPC context, it is relative to the content of * the reg_segb register. * Convention: * $xxxx = word address * xxxx:yyyy = byte address yyyy relative to segment xxxx * #yyyy = byte address relative to current reg_segb * The t_addr type must be 32 bit, the upper half contains the segment, the lower * half contains the offset. If the upper half is NIL, it is a word address */ /* Use scp.c provided fprintf function */ #define fprintf Fprintf #define fputs(_s,f) Fprintf(f,"%s",_s) #define fputc(_c,f) Fprintf(f,"%c",_c) void pdq3_fprint_addr (FILE *st, DEVICE *dptr, t_addr addr) { if (ADDR_ISWORD(addr)) fprintf(st,"$"); else if (ADDR_SEG(addr) == reg_segb) fprintf(st,"#"); else { fprint_val (st, ADDR_SEG(addr), dptr->dradix, dptr->dwidth, PV_LEFT); fprintf(st,":"); } fprint_val (st, ADDR_OFF(addr), dptr->dradix, dptr->dwidth, PV_LEFT); return; } t_addr pdq3_parse_addr (DEVICE *dptr, char *cptr, char **tptr) { t_addr seg, off; if (cptr[0] == '#') { off = strtotv(cptr+1, tptr, dptr->aradix); return MAKE_BADDR(reg_segb,off); } else if (cptr[0] == '$') { off = strtotv(cptr+1, tptr, dptr->aradix); return MAKE_WADDR(off); } else { char gbuf[CBUFSIZE]; get_glyph (cptr, gbuf, 0); if (!strncmp(gbuf,"SEGB",4)) { seg = reg_segb; *tptr = cptr+4; } else seg = strtotv(cptr, tptr, dptr->aradix); if (*tptr[0] == ':') { cptr = *tptr + 1; off = strtotv(cptr, tptr, dptr->aradix); return MAKE_BADDR(seg,off); } else return MAKE_WADDR(seg); } } void pdq3_vm_init (void) { sim_vm_fprint_addr = &pdq3_fprint_addr; sim_vm_parse_addr = &pdq3_parse_addr; sim_vm_cmd = pdq3_cmds; return; } static t_stat pdq3_cmd_exstack(int32 arg, char *buf) { t_stat rc; uint16 data; int i; int n = buf[0] ? atol(buf) : 0; if (n < 0) n = 0; sim_printf("SP: $%04x LOW: $%04x UPR: $%04x\n", reg_sp, reg_splow, reg_spupr); for (i=n; i>=0; i--) { if ((rc=Read(reg_sp+i, 0, &data, 0)) != SCPE_OK) continue; if (i==0) sim_printf(" TOS: "); else sim_printf(" %3d: ",i); sim_printf("%04x ($%04x)\n", data, reg_sp+i); } return SCPE_OK; } static t_stat pdq3_cmd_exmscw(int32 arg, char *buf) { char* next; return dbg_dump_mscw(stdout, buf[0] ? pdq3_parse_addr(&cpu_dev, buf, &next) : reg_mp); } static t_stat pdq3_cmd_extib(int32 arg, char *buf) { char* next; return dbg_dump_tib(stdout, buf[0] ? pdq3_parse_addr(&cpu_dev, buf, &next) : reg_ctp); } static t_stat pdq3_cmd_exseg(int32 arg, char *buf) { t_stat rc; uint16 nsegs; uint16 segnum, segptr; char* next; FILE* fd = stdout; /* XXX */ if (reg_ssv < 0x2030 || reg_ssv > 0xf000) { fprintf(fd, "Cannot list segments in bootloader: incomplete tables\n"); return SCPE_NXM; } if ((rc=Read(reg_ssv, -1, &nsegs, 0)) != SCPE_OK) return rc; if (buf[0]) { segnum = pdq3_parse_addr(&cpu_dev, buf, &next); fprintf(fd, "Segment $%02x\n", segnum); if (segnum > nsegs) { fprintf(fd, "Too high: maxsegs=$%02x\n",nsegs); return SCPE_ARG; } if ((rc=Read(reg_ssv, segnum, &segptr, 0)) != SCPE_OK) return rc; rc = dbg_dump_seg(fd, segptr); } else rc = dbg_dump_segtbl(fd); return rc; } static t_stat pdq3_cmd_calltree(int32 arg, char *buf) { return dbg_calltree(stdout); } static t_stat pdq3_cmd_namealias(int32 arg, char *buf) { char* name, *alias; if (buf[0]==0) return dbg_listalias(stdout); name = strtok(buf, " \t"); alias = strtok(NULL, " \t\n"); return dbg_enteralias(name,alias); } /************************************************************************************** * PDQ utility functions *************************************************************************************/ OPTABLE optable[] = { /*00*/ { "SLDC0", OP_NULL }, { "SLDC1", OP_NULL }, /*02*/ { "SLDC2", OP_NULL }, { "SLDC3", OP_NULL }, /*04*/ { "SLDC4", OP_NULL }, { "SLDC5", OP_NULL }, /*06*/ { "SLDC6", OP_NULL }, { "SLDC7", OP_NULL }, /*08*/ { "SLDC8", OP_NULL }, { "SLDC9", OP_NULL }, /*0a*/ { "SLDC10", OP_NULL }, { "SLDC11", OP_NULL }, /*0c*/ { "SLDC12", OP_NULL }, { "SLDC13", OP_NULL }, /*0e*/ { "SLDC14", OP_NULL }, { "SLDC15", OP_NULL }, /*10*/ { "SLDC16", OP_NULL }, { "SLDC17", OP_NULL }, /*12*/ { "SLDC18", OP_NULL }, { "SLDC19", OP_NULL }, /*14*/ { "SLDC20", OP_NULL }, { "SLDC21", OP_NULL }, /*16*/ { "SLDC22", OP_NULL }, { "SLDC23", OP_NULL }, /*18*/ { "SLDC24", OP_NULL }, { "SLDC25", OP_NULL }, /*1a*/ { "SLDC26", OP_NULL }, { "SLDC27", OP_NULL }, /*1c*/ { "SLDC28", OP_NULL }, { "SLDC29", OP_NULL }, /*1e*/ { "SLDC30", OP_NULL }, { "SLDC31", OP_NULL }, /*20*/ { "SLDL1", OP_NULL }, { "SLDL2", OP_NULL }, /*22*/ { "SLDL3", OP_NULL }, { "SLDL4", OP_NULL }, /*24*/ { "SLDL5", OP_NULL }, { "SLDL6", OP_NULL }, /*26*/ { "SLDL7", OP_NULL }, { "SLDL8", OP_NULL }, /*28*/ { "SLDL9", OP_NULL }, { "SLDL10", OP_NULL }, /*2a*/ { "SLDL11", OP_NULL }, { "SLDL12", OP_NULL }, /*2c*/ { "SLDL13", OP_NULL }, { "SLDL14", OP_NULL }, /*2e*/ { "SLDL15", OP_NULL }, { "SLDL16", OP_NULL }, /*30*/ { "SLDO1", OP_NULL }, { "SLDO2", OP_NULL }, /*32*/ { "SLDO3", OP_NULL }, { "SLDO4", OP_NULL }, /*34*/ { "SLDO5", OP_NULL }, { "SLDO6", OP_NULL }, /*36*/ { "SLDO7", OP_NULL }, { "SLDO8", OP_NULL }, /*38*/ { "SLDO9", OP_NULL }, { "SLDO10", OP_NULL }, /*3a*/ { "SLDO11", OP_NULL }, { "SLDO12", OP_NULL }, /*3c*/ { "SLDO13", OP_NULL }, { "SLDO14", OP_NULL }, /*3e*/ { "SLDO15", OP_NULL }, { "SLDO16", OP_NULL }, /*40*/ { "", OP_ERROR }, { "", OP_ERROR }, /*42*/ { "", OP_ERROR }, { "", OP_ERROR }, /*44*/ { "", OP_ERROR }, { "", OP_ERROR }, /*46*/ { "", OP_ERROR }, { "", OP_ERROR }, /*48*/ { "", OP_ERROR }, { "", OP_ERROR }, /*4a*/ { "", OP_ERROR }, { "", OP_ERROR }, /*4c*/ { "", OP_ERROR }, { "", OP_ERROR }, /*4e*/ { "", OP_ERROR }, { "", OP_ERROR }, /*50*/ { "", OP_ERROR }, { "", OP_ERROR }, /*52*/ { "", OP_ERROR }, { "", OP_ERROR }, /*54*/ { "", OP_ERROR }, { "", OP_ERROR }, /*56*/ { "", OP_ERROR }, { "", OP_ERROR }, /*58*/ { "", OP_ERROR }, { "", OP_ERROR }, /*5a*/ { "", OP_ERROR }, { "", OP_ERROR }, /*5c*/ { "", OP_ERROR }, { "", OP_ERROR }, /*5e*/ { "", OP_ERROR }, { "", OP_ERROR }, /*60*/ { "", OP_ERROR }, { "", OP_ERROR }, /*62*/ { "", OP_ERROR }, { "", OP_ERROR }, /*64*/ { "", OP_ERROR }, { "", OP_ERROR }, /*66*/ { "", OP_ERROR }, { "", OP_ERROR }, /*68*/ { "", OP_ERROR }, { "", OP_ERROR }, /*6a*/ { "", OP_ERROR }, { "", OP_ERROR }, /*6c*/ { "", OP_ERROR }, { "", OP_ERROR }, /*6e*/ { "", OP_ERROR }, { "", OP_ERROR }, /*70*/ { "", OP_ERROR }, { "", OP_ERROR }, /*72*/ { "", OP_ERROR }, { "", OP_ERROR }, /*74*/ { "", OP_ERROR }, { "", OP_ERROR }, /*76*/ { "", OP_ERROR }, { "", OP_ERROR }, /*78*/ { "SIND0", OP_NULL }, { "SIND1", OP_NULL }, /*7a*/ { "SIND2", OP_NULL }, { "SIND3", OP_NULL }, /*7c*/ { "SIND4", OP_NULL }, { "SIND5", OP_NULL }, /*7e*/ { "SIND6", OP_NULL }, { "SIND7", OP_NULL }, /*80*/ { "LDCB", OP_UB }, { "LDCI", OP_W }, /*82*/ { "LCA", OP_AB }, { "LDC", OP_BUB }, /*84*/ { "LLA", OP_B }, { "LDO", OP_B }, /*86*/ { "LAO", OP_B }, { "LDL", OP_B }, /*88*/ { "LDA", OP_DBB }, { "LOD", OP_DBB }, /*8a*/ { "UJP", OP_SB }, { "UJPL", OP_SW }, /*8c*/ { "MPI", OP_NULL }, { "DVI", OP_NULL }, /*8e*/ { "STM", OP_UB }, { "MODI", OP_NULL }, /*90*/ { "CPL", OP_UB }, { "CPG", OP_UB }, /*92*/ { "CPI", OP_DBUB }, { "CXL", OP_UBUB }, /*94*/ { "CXG", OP_UBUB }, { "CXI", OP_UBDBUB }, /*96*/ { "RPU", OP_B }, { "CPF", OP_NULL }, /*98*/ { "LDCN", OP_NULL }, { "LSL", OP_DB }, /*9a*/ { "LDE", OP_UBB }, { "LAE", OP_UBB }, /*9c*/ { "NOP", OP_NULL }, { "LPR", OP_NULL }, /*9e*/ { "BPT", OP_NULL }, { "BNOT", OP_NULL }, /*a0*/ { "LOR", OP_NULL }, { "LAND", OP_NULL }, /*a2*/ { "ADI", OP_NULL }, { "SBI", OP_NULL }, /*a4*/ { "STL", OP_B }, { "SRO", OP_B }, /*a6*/ { "STR", OP_DBB }, { "LDB", OP_NULL }, /*a8*/ { "LHO", OP_NULL }, { "LVO", OP_NULL }, /*aa*/ { "", OP_ERROR }, { "", OP_ERROR }, /*ac*/ { "", OP_ERROR }, { "", OP_ERROR }, /*ae*/ { "", OP_ERROR }, { "", OP_ERROR }, /*b0*/ { "EQUI", OP_NULL }, { "NEQI", OP_NULL }, /*b2*/ { "LEQI", OP_NULL }, { "GEQI", OP_NULL }, /*b4*/ { "LEUSW", OP_NULL }, { "GEUSW", OP_NULL }, /*b6*/ { "EQUPWR", OP_NULL }, { "LEQPWR", OP_NULL }, /*b8*/ { "GEQPWR", OP_NULL }, { "EQUBYT", OP_B }, /*ba*/ { "LEQBYT", OP_B }, { "GEQBYT", OP_B }, /*bc*/ { "SRS", OP_NULL }, { "SWAP", OP_NULL }, /*be*/ { "TNC", OP_NULL }, { "RND", OP_NULL }, /*c0*/ { "ADR", OP_NULL }, { "SBR", OP_NULL }, /*c2*/ { "MPR", OP_NULL }, { "DVR", OP_NULL }, /*c4*/ { "STO", OP_NULL }, { "MOV", OP_B }, /*c6*/ { "DUP2", OP_NULL }, { "ADJ", OP_UB }, /*c8*/ { "STB", OP_NULL }, { "LDP", OP_NULL }, /*ca*/ { "STP", OP_NULL }, { "CHK", OP_NULL }, /*cc*/ { "FLT", OP_NULL }, { "EQUREAL",OP_NULL }, /*ce*/ { "LEQREAL",OP_NULL }, { "GEQREAL",OP_NULL }, /*d0*/ { "LDM", OP_UB }, { "SPR", OP_NULL }, /*d2*/ { "EFJ", OP_SB }, { "NFJ", OP_SB }, /*d4*/ { "FJP", OP_SB }, { "FJPL", OP_SW }, /*d6*/ { "XJP", OP_B }, { "IXA", OP_B }, /*d8*/ { "IXP", OP_UBUB }, { "STE", OP_UBB }, /*da*/ { "INN", OP_NULL }, { "UNI", OP_NULL }, /*dc*/ { "INT", OP_NULL }, { "DIF", OP_NULL }, /*de*/ { "SIGNAL", OP_NULL }, { "WAIT", OP_NULL }, /*e0*/ { "ABI", OP_NULL }, { "NGI", OP_NULL }, /*e2*/ { "DUP1", OP_NULL }, { "ABR", OP_NULL }, /*e4*/ { "NGR", OP_NULL }, { "LNOT", OP_NULL }, /*e6*/ { "IND", OP_B }, { "INC", OP_B }, }; static uint16 UB(t_value arg) { return arg & 0xff; } static uint16 DB(t_value arg) { return UB(arg); } static int16 W(t_value arg1, t_value arg2) { uint16 wl = arg1 & 0xff; uint16 wh = arg2 & 0xff; return wl | ((wh << 8) & 0xff00); } static int16 SW(t_value arg1, t_value arg2) { return W(arg1,arg2); } static int16 SB(t_value arg) { int16 w = arg & 0xff; if (w & 0x80) w |= 0xff00; return w; } static uint16 B(t_value arg1, t_value arg2, int* sz) { uint16 wh = arg1 & 0xff; uint16 wl; if (wh & 0x80) { wl = arg2 & 0xff; wl |= ((wh & 0x7f) << 8); *sz = 2; return wl; } else { *sz = 1; return wh; } } t_stat print_hd(FILE *of, t_value val, t_bool hexdec, t_bool isbyte) { uint16 data = isbyte ? (val & 0xff) : (val & 0xffff); if (hexdec) fprintf(of,"%0xh",data); else fprintf(of,"%d",data); return SCPE_OK; } t_stat fprint_sym_m (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) { uint16 op, arg1, arg2, arg3; int16 sarg; t_stat size = 0; int optype, sz; t_bool hexdec = (sw & SWMASK('H')) ? TRUE : FALSE; addr = ADDR_OFF(addr); op = val[0]; if (op > 0xe7) return SCPE_ARG; optype = optable[op].flags; if (optype > OP_ERROR) { fprintf(of,"%-8s", optable[op].name); switch (optype) { case OP_NULL: break; case OP_UB: size = 1; arg1 = UB(val[1]); print_hd(of, arg1, hexdec, FALSE); break; case OP_W: size = 2; sarg = W(val[1],val[2]); print_hd(of, sarg, hexdec, FALSE); break; case OP_AB: arg1 = B(val[1],val[2], &sz); size = sz; fprintf(of,"#%x", arg1*2); break; case OP_B: arg1 = B(val[1],val[2], &sz); size = sz; print_hd(of, arg1, hexdec, FALSE); break; case OP_DBB: arg1 = DB(val[1]); arg2 = B(val[2],val[3], &sz); size = sz+1; print_hd(of, arg1, hexdec, TRUE); fputc(',',of); print_hd(of, arg2, hexdec, FALSE); break; case OP_UBB: arg1 = UB(val[1]); arg2 = B(val[2],val[3], &sz); size = sz+1; print_hd(of, arg1, hexdec, TRUE); fputc(',',of); print_hd(of, arg2, hexdec, FALSE); break; case OP_BUB: arg1 = B(val[1],val[2], &sz); size = sz+1; arg2 = UB(val[sz+1]); print_hd(of, arg1, hexdec, FALSE); fputc(',',of); print_hd(of, arg2, hexdec, TRUE); break; case OP_SB: size = 1; sarg = SB(val[1]); fprintf(of,"#%x", addr+sarg+2); break; case OP_SW: size = 2; sarg = SW(val[1],val[2]); fprintf(of,"#%x", addr+sarg+3); break; case OP_DBUB: size = 2; arg1 = DB(val[1]); arg2 = UB(val[2]); print_hd(of, arg1, hexdec, TRUE); fputc(',',of); print_hd(of, arg2, hexdec, TRUE); break; case OP_UBUB: size = 2; arg1 = UB(val[1]); arg2 = UB(val[2]); print_hd(of, arg1, hexdec, TRUE); fputc(',',of); print_hd(of, arg2, hexdec, TRUE); break; case OP_UBDBUB: size = 3; arg1 = UB(val[1]); arg2 = DB(val[2]); arg3 = UB(val[3]); print_hd(of, arg1, hexdec, TRUE); fputc(',',of); print_hd(of, arg2, hexdec, TRUE); fputc(',',of); print_hd(of, arg3, hexdec, TRUE); break; case OP_DB: size = 1; arg1 = DB(val[1]); print_hd(of, arg1, hexdec, TRUE); break; } return -size; } else { fprintf(of,"%-8s","DB"); print_hd(of, op, hexdec, TRUE); return SCPE_OK; } } /* Symbolic decode Inputs: *of = output stream addr = current PC *val = pointer to data *uptr = pointer to unit sw = switches Outputs: return = status code */ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) { t_addr off; T_FLCVT t; int ch; if (sw & SWMASK('M') && !ADDR_ISWORD(addr)) { return fprint_sym_m(of, addr, val, uptr, sw); } if (sw & SWMASK('B')) { /* as BYTE */ if (ADDR_ISWORD(addr)) { fprint_val(of, (val[0]>>8) & 0xff, cpu_dev.dradix, 8, PV_RZRO); fprintf(of, ","); fprint_val(of, val[0] & 0xff, cpu_dev.dradix, 8, PV_RZRO); } else fprint_val(of, val[0], cpu_dev.dradix, 8, PV_RZRO); return SCPE_OK; } if (sw & SWMASK('C')) { /* as CHAR */ if (ADDR_ISWORD(addr)) { ch = val[0] & 0xff; fprintf(of, isprint(ch) ? "%c," : "%02x,", ch); ch = val[0]>>8; fprintf(of, isprint(ch) ? "%c" : "%02x", ch); } else { ch = val[0] & 0xff; fprintf(of, isprint(ch) ? "%c" : "%02x", ch); } return SCPE_OK; } if (sw & SWMASK('W')) { /* as WORD */ if (ADDR_ISWORD(addr)) { fprint_val(of, val[0], cpu_dev.dradix, 16, PV_RZRO); off = ADDR_OFF(addr); if (off > (t_addr)(reg_bp+MSCW_SZ-1)) fprintf(of," (GLOBAL+%d)", off - reg_bp - MSCW_SZ + 1); else if (off >= reg_mp && off <= (t_addr)(reg_mp+OFFB_MSSEG)) fprintf(of," (MP+%d)", off - reg_mp); else if (off > (t_addr)(reg_mp+MSCW_SZ-1)) fprintf(of," (LOCAL+%d)", off - reg_mp - MSCW_SZ + 1); else if (off >= reg_sp && off < reg_spupr) fprintf(of," (SP+%d)", off - reg_sp); } else { fprint_val(of, val[0], cpu_dev.dradix, 8, PV_RZRO); fprint_val(of, val[1], cpu_dev.dradix, 8, PV_RZRO); } return SCPE_OK; } if (sw & SWMASK('F')) { /* as FLOAT */ t.i[0] = val[1]; t.i[1] = val[0]; fprintf(of, "%12.6e", t.f); return -1; } if (sw & SWMASK('S')) { /* as semaphore */ fprintf(of, "SEM(count=%d, waitq=$%04x)", val[0], val[1]); return -1; } if (sw & SWMASK('M')) { /* as MSCW */ dbg_dump_mscw(of, val[0]); return SCPE_OK; } if (sw & SWMASK('T')) { /* as TIB */ dbg_dump_tib(of, addr); return SCPE_OK; } return SCPE_ARG; } /* Symbolic input Inputs: *cptr = pointer to input string addr = current PC *uptr = pointer to unit *val = pointer to output values sw = switches Outputs: status = error status */ t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) { return SCPE_ARG; }