/* 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 <ctype.h> | |
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, CONST char *buf); | |
static t_stat pdq3_cmd_exmscw(int32 arg, CONST char *buf); | |
static t_stat pdq3_cmd_extib(int32 arg, CONST char *buf); | |
static t_stat pdq3_cmd_exseg(int32 arg, CONST char *buf); | |
static t_stat pdq3_cmd_calltree(int32 arg, CONST char *buf); | |
static t_stat pdq3_cmd_namealias(int32 arg, CONST 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 } | |
}; | |
WEAK void (*sim_vm_init)(void) = &pdq3_vm_init; | |
/* Loader proper */ | |
t_stat sim_load (FILE *fi, CONST char *cptr, CONST 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 | |
*/ | |
if ((c1 = fgetc(fi))==EOF) return SCPE_EOF; | |
if ((c2 = fgetc(fi))==EOF) return SCPE_EOF; | |
rombase = c1 + c2 * 256; | |
if (rombase > (MAXMEMSIZE-512)) return SCPE_ARG; | |
rom_write(rombase & 0xfffe, rombase); | |
reg_fc68 = rombase; | |
i = 0; | |
while (!feof(fi) && i<0x1ff) { | |
if ((c1 = fgetc(fi))==EOF) return SCPE_EOF; | |
if ((c2 = fgetc(fi))==EOF) return SCPE_EOF; | |
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 | |
*/ | |
void pdq3_sprint_addr (char *buf, DEVICE *dptr, t_addr addr) | |
{ | |
*buf = '\0'; | |
if (ADDR_ISWORD(addr)) | |
sprintf(buf,"$"); | |
else if (ADDR_SEG(addr) == reg_segb) | |
sprintf(&buf[strlen(buf)],"#"); | |
else { | |
sprint_val (&buf[strlen(buf)], ADDR_SEG(addr), dptr->dradix, dptr->dwidth, PV_LEFT); | |
sprintf(&buf[strlen(buf)],":"); | |
} | |
sprint_val (&buf[strlen(buf)], ADDR_OFF(addr), dptr->dradix, dptr->dwidth, PV_LEFT); | |
return; | |
} | |
void pdq3_fprint_addr (FILE *st, DEVICE *dptr, t_addr addr) | |
{ | |
char buf[65]; | |
pdq3_sprint_addr (buf, dptr, addr); | |
fprintf(st,"%s", buf); | |
} | |
t_addr pdq3_parse_addr (DEVICE *dptr, CONST char *cptr, CONST 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_sprint_addr = &pdq3_sprint_addr; | |
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, CONST 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, CONST char *buf) | |
{ | |
CONST 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, CONST char *buf) | |
{ | |
CONST 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, CONST char *buf) | |
{ | |
t_stat rc; | |
uint16 nsegs; | |
uint16 segnum, segptr; | |
CONST 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, CONST char *buf) { | |
return dbg_calltree(stdout); | |
} | |
static t_stat pdq3_cmd_namealias(int32 arg, CONST char *buf) { | |
char* name, *alias, gbuf[2*CBUFSIZE]; | |
if (buf[0]==0) | |
return dbg_listalias(stdout); | |
gbuf[sizeof(gbuf)-1] = '\0'; | |
strncpy (gbuf, buf, sizeof(gbuf)-1); | |
name = strtok(gbuf, " \t"); | |
alias = strtok(NULL, " \t\n"); | |
return name == NULL || alias == NULL ? SCPE_ARG : 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 (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) | |
{ | |
return SCPE_ARG; | |
} |