RESTRICTION: The HP DS disk is not debugged. DO NOT enable this feature for normal operations. WARNING: Massive changes in the PDP-11 make all previous SAVEd file obsolete. Do not attempt to use a PDP-11 SAVE file from a prior release with V3.3! 1. New Features in 3.3 1.1 SCP - Added -p (powerup) qualifier to RESET - Changed SET <unit> ONLINE/OFFLINE to SET <unit> ENABLED/DISABLED - Moved SET DEBUG under SET CONSOLE hierarchy - Added optional parameter value to SHOW command - Added output file option to SHOW command 1.2 PDP-11 - Separated RH Massbus adapter from RP controller - Added TU tape support - Added model emulation framework - Added model details 1.3 VAX - Separated out CVAX-specific features from core instruction simulator - Implemented capability for CIS, octaword, compatibility mode instructions - Added instruction display and parse for compatibility mode - Changed SET CPU VIRTUAL=n to SHOW CPU VIRTUAL=n - Added =n optional parameter to SHOW CPU HISTORY 1.4 Unibus/Qbus simulators (PDP-11, VAX, PDP-10) - Simplified DMA API's - Modified DMA peripherals to use simplified API's 1.5 HP2100 (all changes from Dave Bryan) CPU - moved MP into its own device; added MP option jumpers - modified DMA to allow disabling - modified SET CPU 2100/2116 to truncate memory > 32K - added -F switch to SET CPU to force memory truncation - modified WRU to be REG_HRO - added BRK and DEL to save console settings DR - provided protected tracks and "Writing Enabled" status bit - added "parity error" status return on writes for 12606 - added track origin test for 12606 - added SCP test for 12606 - added "Sector Flag" status bit - added "Read Inhibit" status bit for 12606 - added TRACKPROT modifier LPS - added SET OFFLINE/ONLINE, POWEROFF/POWERON - added fast/realistic timing - added debug printouts LPT - added SET OFFLINE/ONLINE, POWEROFF/POWERON PTR - added paper tape loop mode, DIAG/READER modifiers to PTR - added PV_LEFT to PTR TRLLIM register CLK - modified CLK to permit disable 1.6 IBM 1401, IBM 1620, Interdata 16b, SDS 940, PDP-10 - Added instruction history 1.7 H316, PDP-15, PDP-8 - Added =n optional value to SHOW CPU HISTORY 2. Bugs Fixed in 3.3 2.1 SCP - Fixed comma-separated SET options (from Dave Bryan) - Fixed duplicate HELP displays with user-specified commands 2.2 PDP-10 - Replicated RP register state per drive - Fixed TU to set FCE on short record - Fixed TU to return bit<15> in drive type - Fixed TU format specification, 1:0 are don't cares - Fixed TU handling of TMK status - Fixed TU handling of DONE, ATA at end of operation - Implemented TU write check 2.3 PDP-11 - Replicated RP register state per drive - Fixed RQ, TQ to report correct controller type and stage 1 configuration flags on a Unibus system - Fixed HK CS2<output_ready> flag 2.4 VAX - Fixed parsing of indirect displacement modes in instruction input 2.5 HP2100 (all fixes from Dave Bryan) CPU - fixed S-register behavior on 2116 - fixed LIx/MIx behavior for DMA on 2116 and 2100 - fixed LIx/MIx behavior for empty I/O card slots DP - fixed enable/disable from either device - fixed ANY ERROR status for 12557A interface - fixed unattached drive status for 12557A interface - status cmd without prior STC DC now completes (12557A) - OTA/OTB CC on 13210A interface also does CLC CC - fixed RAR model - fixed seek check on 13210 if sector out of range DQ - fixed enable/disable from either device - shortened xtime from 5 to 3 (drive avg 156KW/second) - fixed not ready/any error status - fixed RAR model DR - fixed enable/disable from either device - fixed sector return in status word - fixed DMA last word write, incomplete sector fill value - fixed 12610 SFC operation - fixed current-sector determination IPL - fixed enable/disable from either device LPS - fixed status returns for error conditions - fixed handling of non-printing characters - fixed handling of characters after column 80 - improved timing model accuracy for RTE LPT - fixed status returns for error conditions - fixed TOF handling so form remains on line 0 SYS - fixed display of CCA/CCB/CCE instructions 2.5 PDP-15 FPP - fixed URFST to mask low 9b of fraction - fixed exception PC setting
942 lines
26 KiB
C
942 lines
26 KiB
C
/* s3_sys.c: IBM System/3 system interface
|
||
|
||
Copyright (c) 2001-2003, Charles E. Owen
|
||
|
||
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 name of Charles E. Owen shall not
|
||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||
in this Software without prior written authorization from Charles E. Owen.
|
||
*/
|
||
|
||
#include <ctype.h>
|
||
#include "s3_defs.h"
|
||
|
||
extern DEVICE cpu_dev;
|
||
extern DEVICE pkb_dev;
|
||
extern DEVICE cdr_dev;
|
||
extern DEVICE cdp_dev;
|
||
extern DEVICE stack_dev;
|
||
extern DEVICE lpt_dev;
|
||
extern DEVICE r1_dev;
|
||
extern DEVICE f1_dev;
|
||
extern DEVICE r2_dev;
|
||
extern DEVICE f2_dev;
|
||
extern UNIT cpu_unit;
|
||
extern REG cpu_reg[];
|
||
extern unsigned char M[];
|
||
extern int32 saved_PC, IAR[];
|
||
extern char ebcdic_to_ascii[256];
|
||
char *parse_addr(char *cptr, char *gbuf, int32 *addr, int32 *addrtype);
|
||
|
||
int32 printf_sym (FILE *of, char *strg, int32 addr, uint32 *val,
|
||
UNIT *uptr, int32 sw);
|
||
|
||
/* SCP data structures
|
||
|
||
sim_name simulator name string
|
||
sim_PC pointer to saved PC register descriptor
|
||
sim_emax number of words needed for examine
|
||
sim_devices array of pointers to simulated devices
|
||
sim_stop_messages array of pointers to stop messages
|
||
sim_load binary loader
|
||
*/
|
||
|
||
char sim_name[] = "System/3";
|
||
|
||
REG *sim_PC = &cpu_reg[0];
|
||
|
||
int32 sim_emax = 6;
|
||
|
||
DEVICE *sim_devices[] = { &cpu_dev,
|
||
&pkb_dev,
|
||
&cdr_dev,
|
||
&cdp_dev,
|
||
&stack_dev,
|
||
&lpt_dev,
|
||
&r1_dev,
|
||
&f1_dev,
|
||
&r2_dev,
|
||
&f2_dev,
|
||
NULL };
|
||
|
||
const char *sim_stop_messages[] = {
|
||
"Unknown error",
|
||
"Unknown I/O Instruction",
|
||
"HALT instruction",
|
||
"Breakpoint",
|
||
"Invalid Opcode",
|
||
"Invalid Qbyte",
|
||
"Invalid Address",
|
||
"Invalid Device Command",
|
||
"ATTN Card Reader"
|
||
};
|
||
|
||
/* This is the opcode master defintion table. Each possible opcode mnemonic
|
||
is defined here, with enough information to translate to and from
|
||
symbolic to binary machine code.
|
||
First field is the opcode's mnemonic
|
||
Second field is the hex of the right nybble of the binary opcode
|
||
Third field is the Q code for those with implicit Q codes
|
||
Fourth field is the symbolic format of the operands:
|
||
0 - (Q-byte),(R-byte)
|
||
1 - (Q-byte),(Address)
|
||
2 - (Address),(Address),(Qbyte)
|
||
3 - (Address),(Qbyte)
|
||
4 - (device),(modifier),(function) -- these 3 make up qbyte
|
||
5 - (device),(modifier),(function),(control)
|
||
6 - (device),(modifier),(function),(Address)
|
||
7 - (displacement) -- Q byte is implicit in opcode
|
||
8 - (address) -- Qbyte is implicit in opcode
|
||
9 - (Address),(Address) -- Qbyte is implicit in opcode
|
||
Fifth Field is the group number:
|
||
0 - Command Group (left op nybble is F)
|
||
1 - One Address Operations A (Left Nybble C, D, or E)
|
||
2 - Two Address Operations (Left Nybble 0,1,2,4,5,6,8,9, or A)
|
||
3 - One Address Operations B (left Nybble 3, 7, or B)
|
||
|
||
There is duplication in this table -- IBM defines different opcodes
|
||
that resolve to the same binary machine instruction -- e.g. JE and
|
||
JZ. On input this is no problem, on output, define the one you
|
||
want to appear first, the second will never appear on output.
|
||
*/
|
||
|
||
int32 nopcode = 75;
|
||
struct opdef opcode[75] = {
|
||
"HPL", 0x00,0,0,0, /* Halt Program Level */
|
||
"A", 0x06,0,1,3, /* Add to Register: A R,AADD */
|
||
"ST", 0x04,0,1,3, /* Store Register */
|
||
"L", 0x05,0,1,3, /* Load Register */
|
||
"LA", 0x02,0,1,1, /* Load Address */
|
||
"ZAZ", 0x04,0,2,2, /* Zero and Add Zoned */
|
||
"AZ", 0x06,0,2,2, /* Add Zoned Decimal */
|
||
"SZ", 0x07,0,2,2, /* Subtract Zoned Decimal */
|
||
"ALC", 0x0E,0,2,2, /* Add Logical: ALC BADD,AADD,LEN */
|
||
"SLC", 0x0F,0,2,2, /* Sub Logical: SLC BADD,AADD,LEN */
|
||
"MVC", 0x0C,0,2,2, /* Move Chars MVX BADD,AADD,LEN */
|
||
"ED", 0x0A,0,2,2, /* Edit: ED BADD,AADD,LEN */
|
||
"ITC", 0x0B,0,2,2, /* Insert Chars: ITC BADD,AADD,LEN */
|
||
"CLC", 0x0D,0,2,2, /* Compare Logical: CLC BADD,AADD,LEN */
|
||
"MVI", 0x0C,0,3,3, /* Move Immediate */
|
||
"SBN", 0x0A,0,3,3, /* Set Bits On */
|
||
"SBF", 0x0B,0,3,3, /* Set Bits Off */
|
||
"CLI", 0x0D,0,3,3, /* Compare Immediate */
|
||
"TBN", 0x08,0,3,3, /* Test Bits On */
|
||
"TBF", 0x09,0,3,3, /* Test Bits Off */
|
||
"APL", 0x01,0,4,0, /* Advance Program Level */
|
||
"SIO", 0x03,0,5,0, /* Start I/O */
|
||
"SNS", 0x00,0,6,3, /* Sense I/O */
|
||
"LIO", 0x01,0,6,3, /* Load I/O */
|
||
"TIO", 0x01,0,6,1, /* Test I/O */
|
||
"J", 0x02,0,7,0, /* Jump Unconditional */
|
||
"J", 0x02,0x87,7,0, /* Alternate J */
|
||
"JH", 0x02,132,7,0, /* Jump if High */
|
||
"JL", 0x02,130,7,0, /* Jump if Low */
|
||
"JE", 0x02,129,7,0, /* Jump if Equal */
|
||
"JNH", 0x02,4,7,0, /* Jump if Not High */
|
||
"JNL", 0x02,2,7,0, /* Jump if Not Low */
|
||
"JNE", 0x02,1,7,0, /* Jump if Not Equal */
|
||
"JOZ", 0x02,136,7,0, /* Jump if Overflow Zoned */
|
||
"JOL", 0x02,160,7,0, /* Jump if Overflow Logical */
|
||
"JNOZ", 0x02,8,7,0, /* Jump if No Overflow Zoned */
|
||
"JNOL", 0x02,32,7,0, /* Jump if No Overflow Logical */
|
||
"JT", 0x02,16,7,0, /* Jump if True */
|
||
"JF", 0x02,144,7,0, /* Jump if False */
|
||
"JP", 0x02,132,7,0, /* Jump if Plus */
|
||
"JM", 0x02,130,7,0, /* Jump if Minus */
|
||
"JZ", 0x02,129,7,0, /* Jump if Zero */
|
||
"JNP", 0x02,4,7,0, /* Jump if Not Plus */
|
||
"JNM", 0x02,2,7,0, /* Jump if Not Minus */
|
||
"JNZ", 0x02,1,7,0, /* Jump if Not Zero */
|
||
"NOPJ", 0x02,0x80,7,0, /* Never Jump - NOP */
|
||
"B", 0x00,0x00,8,1, /* Branch Unconditional */
|
||
"B", 0x00,0x87,8,1, /* Alternate B */
|
||
"BH", 0x00,0x84,8,1, /* Branch if High */
|
||
"BL", 0x00,0x82,8,1, /* Branch if Low */
|
||
"BE", 0x00,0x81,8,1, /* Branch if Equal */
|
||
"BNH", 0x00,0x04,8,1, /* Branch if Not High */
|
||
"BNL", 0x00,0x02,8,1, /* Branch if Not Low */
|
||
"BNE", 0x00,0x01,8,1, /* Branch if Not Equal */
|
||
"BOZ", 0x00,0x88,8,1, /* Branch if Overflow Zoned */
|
||
"BOL", 0x00,0xA0,8,1, /* Branch if Overflow Logical */
|
||
"BNOZ", 0x00,0x08,8,1, /* Branch if No Overflow Zoned */
|
||
"BNOL", 0x00,0x20,8,1, /* Branch if No Overflow Logical */
|
||
"BT", 0x00,0x10,8,1, /* Branch if True */
|
||
"BF", 0x00,0x90,8,1, /* Branch if False */
|
||
"BP", 0x00,0x84,8,1, /* Branch if Plus */
|
||
"BM", 0x00,0x82,8,1, /* Branch if Minus */
|
||
"BZ", 0x00,0x81,8,1, /* Branch if Zero */
|
||
"BNP", 0x00,0x04,8,1, /* Branch if Not Plus */
|
||
"BNM", 0x00,0x02,8,1, /* Branch if Not Minus */
|
||
"BNZ", 0x00,0x01,8,1, /* Branch if Not Zero */
|
||
"NOPB", 0x00,0x80,8,1, /* Never Branch - NOP */
|
||
"MZZ", 0x08,0,9,2, /* Move Zone to Zone */
|
||
"MNZ", 0x08,1,9,2, /* Move Numeric to Zone */
|
||
"MZN", 0x08,2,9,2, /* Move Zone to Numeric */
|
||
"MNN", 0x08,3,9,2, /* Move Numeric to Numeric */
|
||
"MVX", 0x08,0,2,2, /* Move Hex: MVX BADD,AADD,CODE */
|
||
"JC", 0x02,0,3,0, /* Jump on Specified Condition bits */
|
||
"BC", 0x00,0,3,1, /* Branch on Specified Condition */
|
||
"***", 0x00,0,0,0
|
||
};
|
||
|
||
int32 regcode[15] = { 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01,
|
||
0x80, 0xC0, 0xA0, 0x90, 0x88, 0x84, 0x82, 0x81 };
|
||
|
||
char regname[15][8] = { "(P2IAR)",
|
||
"(P1IAR)",
|
||
"(IAR)",
|
||
"(ARR)",
|
||
"(PSR)",
|
||
"(XR2)",
|
||
"(XR1)",
|
||
"(IAR0)",
|
||
"(IAR1)",
|
||
"(IAR2)",
|
||
"(IAR3)",
|
||
"(IAR4)",
|
||
"(IAR5)",
|
||
"(IAR6)",
|
||
"(IAR7)" };
|
||
|
||
/* This is the binary loader. The input file is considered to be
|
||
a string of literal bytes with no special format. The
|
||
load starts at the current value of the P1IAR.
|
||
*/
|
||
|
||
int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
|
||
{
|
||
int32 i, addr = 0, cnt = 0;
|
||
|
||
if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
|
||
addr = IAR[8];
|
||
while ((i = getc (fileref)) != EOF) {
|
||
M[addr] = i & 0xff;
|
||
addr++;
|
||
cnt++;
|
||
} /* end while */
|
||
printf ("%d Bytes loaded.\n", cnt);
|
||
return (SCPE_OK);
|
||
}
|
||
|
||
/* Symbolic output
|
||
|
||
Inputs:
|
||
*of = output stream
|
||
addr = current PC
|
||
*val = pointer to values
|
||
*uptr = pointer to unit
|
||
sw = switches
|
||
Outputs:
|
||
status = error code
|
||
*/
|
||
|
||
int32 fprint_sym (FILE *of, int32 addr, uint32 *val,
|
||
UNIT *uptr, int32 sw)
|
||
{
|
||
int32 r;
|
||
char strg[256];
|
||
|
||
strcpy(strg, "");
|
||
r = printf_sym(of, strg, addr, val, uptr, sw);
|
||
if (sw & SWMASK ('A'))
|
||
strcpy(strg, "");
|
||
else
|
||
fprintf(of, "%s", strg);
|
||
return (r);
|
||
}
|
||
|
||
int32 printf_sym (FILE *of, char *strg, int32 addr, uint32 *val,
|
||
UNIT *uptr, int32 sw)
|
||
{
|
||
int32 cflag, c1, c2, group, len1, len2, inst, aaddr, baddr;
|
||
int32 oplen, groupno, i, j, vpos, qbyte, da, m, n;
|
||
char bld[128], bldaddr[32], boperand[32], aoperand[32];
|
||
int32 blk[16], blt[16];
|
||
int32 blkadd;
|
||
|
||
cflag = (uptr == NULL) || (uptr == &cpu_unit);
|
||
c1 = val[0] & 0xff;
|
||
if (sw & SWMASK ('A')) {
|
||
for (i = 0; i < 16; i++) {
|
||
blkadd = addr + (i*16);
|
||
for (j = 0; j < 16; j++) {
|
||
blk[j] = M[blkadd+j] & 0xff;
|
||
c2 = ebcdic_to_ascii[blk[j]];
|
||
if (c2 < 040 || c2 > 0177 || blk[j] == 07) {
|
||
blt[j] = '.';
|
||
} else {
|
||
blt[j] = c2;
|
||
}
|
||
}
|
||
if (i == 0) {
|
||
fprintf(of, "%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X [%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c]\n ",
|
||
blk[0], blk[1], blk[2], blk[3], blk[4], blk[5], blk[6], blk[7],
|
||
blk[8], blk[9], blk[10], blk[11], blk[12], blk[13], blk[14], blk[15],
|
||
blt[0], blt[1], blt[2], blt[3], blt[4], blt[5], blt[6], blt[7],
|
||
blt[8], blt[9], blt[10], blt[11], blt[12], blt[13], blt[14], blt[15]);
|
||
} else {
|
||
fprintf(of, "%X\t%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X [%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c]\n ",
|
||
blkadd, blk[0], blk[1], blk[2], blk[3], blk[4], blk[5], blk[6], blk[7],
|
||
blk[8], blk[9], blk[10], blk[11], blk[12], blk[13], blk[14], blk[15],
|
||
blt[0], blt[1], blt[2], blt[3], blt[4], blt[5], blt[6], blt[7],
|
||
blt[8], blt[9], blt[10], blt[11], blt[12], blt[13], blt[14], blt[15]);
|
||
}
|
||
}
|
||
return SCPE_OK; }
|
||
if (sw & SWMASK ('C')) {
|
||
c2 = ebcdic_to_ascii[c1];
|
||
if (c2 < 040 || c2 > 0177) {
|
||
sprintf(strg, "<%02X>", c1 & 0xff);
|
||
} else {
|
||
sprintf (strg, "%c", c2 & 0xff);
|
||
}
|
||
return SCPE_OK; }
|
||
if (!(sw & SWMASK ('M'))) return SCPE_ARG;
|
||
|
||
inst = val[0] & 0x0f;
|
||
len1 = (val[0] >> 6) & 3;
|
||
len2 = (val[0] >> 4) & 3;
|
||
group = (val[0] >> 4) & 0x0f;
|
||
qbyte = val[1];
|
||
|
||
/* Get total length of instruction */
|
||
|
||
if (group == 0x0f) {
|
||
oplen = 3;
|
||
} else {
|
||
oplen = 2;
|
||
if (len1 == 0) oplen += 2;
|
||
if (len1 == 1 || len1 == 2) oplen++;
|
||
if (len2 == 0) oplen += 2;
|
||
if (len2 == 1 || len2 == 2) oplen++;
|
||
}
|
||
|
||
/* Find which group it belongs to */
|
||
|
||
switch (group) {
|
||
case 0x0f:
|
||
groupno = 0;
|
||
break;
|
||
case 0x0c:
|
||
case 0x0d:
|
||
case 0x0e:
|
||
groupno = 1;
|
||
break;
|
||
case 0x03:
|
||
case 0x07:
|
||
case 0x0b:
|
||
groupno = 3;
|
||
break;
|
||
default:
|
||
groupno = 2;
|
||
break;
|
||
}
|
||
|
||
/* find the table entry */
|
||
|
||
for (i = 0; i < nopcode; i++) {
|
||
if (opcode[i].form < 7) { /* Explicit Q */
|
||
if (opcode[i].group == groupno &&
|
||
opcode[i].opmask == inst) break;
|
||
} else { /* Implicit Q */
|
||
if (opcode[i].group == groupno &&
|
||
opcode[i].opmask == inst &&
|
||
opcode[i].q == qbyte) break;
|
||
}
|
||
}
|
||
|
||
/* print the opcode */
|
||
|
||
if (i >= nopcode) {
|
||
sprintf(strg, "%02X", val[0]);
|
||
oplen = 1;
|
||
} else {
|
||
sprintf(bld, "%s ", opcode[i].op);
|
||
|
||
/* Extract the addresses into aaddr and baddr */
|
||
|
||
strcpy(aoperand, "ERROR");
|
||
strcpy(boperand, "ERROR");
|
||
vpos = 2;
|
||
aaddr = baddr = 0;
|
||
switch (len1) {
|
||
case 0:
|
||
baddr = ((val[vpos] << 8) & 0xff00) | (val[vpos + 1] & 0x00ff);
|
||
sprintf(boperand, "%04X", baddr);
|
||
vpos = 4;
|
||
break;
|
||
case 1:
|
||
baddr = val[vpos] & 255;
|
||
sprintf(boperand, "(%02X,XR1)", baddr);
|
||
vpos = 3;
|
||
break;
|
||
case 2:
|
||
baddr = val[vpos] & 255;
|
||
sprintf(boperand, "(%02X,XR2)", baddr);
|
||
vpos = 3;
|
||
break;
|
||
default:
|
||
baddr = 0;
|
||
break;
|
||
}
|
||
switch (len2) {
|
||
case 0:
|
||
aaddr = ((val[vpos] << 8) & 0xff00) | (val[vpos + 1] & 0x00ff);
|
||
if (group == 0x0C || group == 0x0D || group == 0x0E)
|
||
sprintf(boperand, "%04X", aaddr);
|
||
else
|
||
sprintf(aoperand, "%04X", aaddr);
|
||
break;
|
||
case 1:
|
||
aaddr = val[vpos] & 255;
|
||
if (group == 0x0C || group == 0x0D || group == 0x0E)
|
||
sprintf(boperand, "(%02X,XR1)", aaddr);
|
||
else
|
||
sprintf(aoperand, "(%02X,XR1)", aaddr);
|
||
break;
|
||
case 2:
|
||
aaddr = val[vpos] & 255;
|
||
if (group == 0x0C || group == 0x0D || group == 0x0E)
|
||
sprintf(boperand, "(%02X,XR2)", aaddr);
|
||
else
|
||
sprintf(aoperand, "(%02X,XR2)", aaddr);
|
||
break;
|
||
default:
|
||
aaddr = 0;
|
||
break;
|
||
}
|
||
|
||
/* Display the operands in the correct format */
|
||
|
||
da = (qbyte >> 4) & 0x0f;
|
||
m = (qbyte >> 3) & 0x01;
|
||
n = (qbyte) & 0x07;
|
||
|
||
switch (opcode[i].form) {
|
||
case 0:
|
||
sprintf(bldaddr, "%02X,%02X", qbyte, val[2]);
|
||
break;
|
||
case 1:
|
||
if (inst == 2 || inst == 4 || inst == 5 || inst == 6) {
|
||
for (i = 0; i < 16; i++) {
|
||
if (regcode[i] == qbyte)
|
||
break;
|
||
}
|
||
if (i < 16) {
|
||
sprintf(bldaddr, "%s,%s", regname[i], boperand);
|
||
} else {
|
||
sprintf(bldaddr, "%02X,%s", qbyte, boperand);
|
||
}
|
||
} else {
|
||
sprintf(bldaddr, "%02X,%s", qbyte, boperand);
|
||
}
|
||
break;
|
||
case 2:
|
||
if (inst > 9 || inst == 4 || inst == 6 || inst == 7)
|
||
qbyte++; /* special +1 for length display */
|
||
sprintf(bldaddr, "%s,%s,%d", boperand, aoperand, qbyte);
|
||
break;
|
||
case 3:
|
||
if (strcmp(opcode[i].op, "JC") == 0) {
|
||
sprintf(bldaddr, "%04X,%02X", addr+oplen+val[2], qbyte);
|
||
} else {
|
||
sprintf(bldaddr, "%s,%02X", boperand, qbyte);
|
||
}
|
||
break;
|
||
case 4:
|
||
sprintf(bldaddr, "%d,%d,%d", da, m, n);
|
||
break;
|
||
case 5:
|
||
sprintf(bldaddr, "%d,%d,%d,%02X", da, m, n, val[2]);
|
||
break;
|
||
case 6:
|
||
sprintf(bldaddr, "%d,%d,%d,%s", da, m, n, boperand);
|
||
break;
|
||
case 7:
|
||
sprintf(bldaddr, "%04X", addr+oplen+val[2]);
|
||
break;
|
||
case 8:
|
||
sprintf(bldaddr, "%s", boperand);
|
||
break;
|
||
default:
|
||
sprintf(bldaddr, "%s,%s", boperand, aoperand);
|
||
break;
|
||
}
|
||
sprintf(strg, "%s%s", bld, bldaddr);
|
||
}
|
||
|
||
return -(oplen - 1);
|
||
}
|
||
|
||
/* 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
|
||
*/
|
||
|
||
int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw)
|
||
{
|
||
int32 cflag, i = 0, j, r, oplen, addtyp, saveaddr, vptr;
|
||
char gbuf[CBUFSIZE];
|
||
|
||
cflag = (uptr == NULL) || (uptr == &cpu_unit);
|
||
while (isspace (*cptr)) cptr++; /* absorb spaces */
|
||
if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
|
||
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
|
||
val[0] = (unsigned int) cptr[0];
|
||
return SCPE_OK; }
|
||
if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */
|
||
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
|
||
val[0] = ((unsigned int) cptr[0] << 8) + (unsigned int) cptr[1];
|
||
return SCPE_OK; }
|
||
|
||
/* An instruction: get opcode (all characters until null, comma, left paren,
|
||
or numeric (including spaces).
|
||
*/
|
||
|
||
while (1) {
|
||
if (*cptr == ',' || *cptr == '\0' || *cptr == '(' ||
|
||
isdigit(*cptr))
|
||
break;
|
||
gbuf[i] = toupper(*cptr);
|
||
cptr++;
|
||
i++;
|
||
}
|
||
|
||
/* kill trailing spaces if any */
|
||
gbuf[i] = '\0';
|
||
for (j = i - 1; gbuf[j] == ' '; j--) {
|
||
gbuf[j] = '\0';
|
||
}
|
||
|
||
/* find opcode in table */
|
||
for (j = 0; j < nopcode; j++) {
|
||
if (strcmp(gbuf, opcode[j].op) == 0)
|
||
break;
|
||
}
|
||
if (j >= nopcode) /* not found */
|
||
return SCPE_ARG;
|
||
|
||
oplen = 2; /* start with op & q */
|
||
|
||
val[0] = opcode[j].opmask; /* store opcode right nybble */
|
||
|
||
switch (opcode[j].form) { /* Get operands based on operand format */
|
||
case 0: /* Single Byte Operand */
|
||
if (*cptr == ',') cptr++;
|
||
cptr = get_glyph(cptr, gbuf, ','); /* Get Q Byte */
|
||
sscanf(gbuf, "%x", &r);
|
||
val[1] = r;
|
||
if (*cptr == ',') cptr++;
|
||
cptr = get_glyph(cptr, gbuf, 0); /* Get R Byte */
|
||
sscanf(gbuf, "%x", &r);
|
||
val[2] = r;
|
||
oplen = 3;
|
||
val[0] = 0xf0 | opcode[j].opmask;
|
||
break;
|
||
case 1:
|
||
if (*cptr == ',') cptr++;
|
||
cptr = get_glyph(cptr, gbuf, ',');
|
||
if (opcode[j].opmask == 2 ||
|
||
opcode[j].opmask == 4 ||
|
||
opcode[j].opmask == 5 ||
|
||
opcode[j].opmask == 6) {
|
||
if (isdigit(gbuf[0])) {
|
||
sscanf(gbuf, "%x", &r);
|
||
} else {
|
||
for (i = 0; i < 16; i++) {
|
||
if (strcmp(gbuf, regname[i]) == 0)
|
||
break;
|
||
}
|
||
if (i < 16) {
|
||
r = regcode[i];
|
||
} else {
|
||
return SCPE_ARG;
|
||
}
|
||
}
|
||
} else {
|
||
sscanf(gbuf, "%x", &r);
|
||
}
|
||
if (r > 255) return SCPE_ARG;
|
||
val[1] = r;
|
||
if (*cptr == ',') cptr++;
|
||
cptr = parse_addr(cptr, gbuf, &addr, &addtyp);
|
||
switch(addtyp) {
|
||
case 0:
|
||
val[2] = (addr >> 8) & 0x00ff;
|
||
val[3] = addr & 0xff;
|
||
oplen = 4;
|
||
if (opcode[j].group == 1)
|
||
val[0] = 0xC0 | opcode[j].opmask;
|
||
else
|
||
val[0] = 0x30 | opcode[j].opmask;
|
||
break;
|
||
case 1:
|
||
val[2] = addr & 0xff;
|
||
oplen = 3;
|
||
if (opcode[j].group == 1)
|
||
val[0] = 0xD0 | opcode[j].opmask;
|
||
else
|
||
val[0] = 0x70 | opcode[j].opmask;
|
||
break;
|
||
case 2:
|
||
val[2] = addr & 0xff;
|
||
oplen = 3;
|
||
if (opcode[j].group == 1)
|
||
val[0] = 0xE0 | opcode[j].opmask;
|
||
else
|
||
val[0] = 0xB0 | opcode[j].opmask;
|
||
break;
|
||
default:
|
||
return SCPE_ARG;
|
||
break;
|
||
}
|
||
break;
|
||
case 2:
|
||
oplen = 2;
|
||
cptr = parse_addr(cptr, gbuf, &addr, &addtyp);
|
||
switch(addtyp) {
|
||
case 0:
|
||
val[2] = (addr >> 8) & 0xff;
|
||
val[3] = addr & 0xff;
|
||
oplen += 2;
|
||
vptr = 4;
|
||
val[0] = 0x00 | opcode[j].opmask;
|
||
break;
|
||
case 1:
|
||
val[2] = addr & 0xff;
|
||
oplen += 1;
|
||
vptr = 3;
|
||
val[0] = 0x40 | opcode[j].opmask;
|
||
break;
|
||
case 2:
|
||
val[2] = addr & 0xff;
|
||
oplen += 1;
|
||
vptr = 3;
|
||
val[0] = 0x80 | opcode[j].opmask;
|
||
break;
|
||
default:
|
||
return SCPE_ARG;
|
||
break;
|
||
}
|
||
if (*cptr == ',') cptr++;
|
||
cptr = parse_addr(cptr, gbuf, &addr, &addtyp);
|
||
switch(addtyp) {
|
||
case 0:
|
||
val[vptr] = (addr >> 8) & 0xff;
|
||
val[vptr+1] = addr & 0xff;
|
||
oplen += 2;
|
||
break;
|
||
case 1:
|
||
val[vptr] = addr & 0xff;
|
||
oplen += 1;
|
||
val[0] = 0x10 | val[0];
|
||
break;
|
||
case 2:
|
||
val[vptr] = addr & 0xff;
|
||
oplen += 1;
|
||
val[0] = 0x20 | val[0];
|
||
break;
|
||
default:
|
||
return SCPE_ARG;
|
||
break;
|
||
}
|
||
if (*cptr == ',') cptr++;
|
||
cptr = get_glyph(cptr, gbuf, 0);
|
||
sscanf(gbuf, "%d", &r);
|
||
if (opcode[j].opmask > 9 ||
|
||
opcode[j].opmask == 4 ||
|
||
opcode[j].opmask == 6 ||
|
||
opcode[j].opmask == 7) r--; /* special: length -1 */
|
||
val[1] = r;
|
||
if (*cptr == ',') cptr++;
|
||
break;
|
||
case 3:
|
||
saveaddr = addr;
|
||
if (*cptr == ',') cptr++;
|
||
cptr = parse_addr(cptr, gbuf, &addr, &addtyp);
|
||
switch(addtyp) {
|
||
case 0:
|
||
if (opcode[j].group == 0) { /* Group 0 form 3 is JC with explicit Q */
|
||
if (*cptr == ',') cptr++;
|
||
cptr = get_glyph(cptr, gbuf, 0);
|
||
sscanf(gbuf, "%x", &r);
|
||
if ((addr - (saveaddr+3)) > 255 || (addr - (saveaddr+3)) < 1)
|
||
return SCPE_ARG;
|
||
val[2] = addr - (saveaddr+3);
|
||
val[1] = r;
|
||
val[0] = 0xf0 | opcode[j].opmask;
|
||
oplen = 3;
|
||
|
||
} else {
|
||
val[2] = (addr >> 8) & 0x00ff;
|
||
val[3] = addr & 0xff;
|
||
oplen = 4;
|
||
if (opcode[j].group == 1)
|
||
val[0] = 0xC0 | opcode[j].opmask;
|
||
else
|
||
val[0] = 0x30 | opcode[j].opmask;
|
||
}
|
||
break;
|
||
case 1:
|
||
val[2] = addr & 0xff;
|
||
oplen = 3;
|
||
if (opcode[j].group == 1)
|
||
val[0] = 0xD0 | opcode[j].opmask;
|
||
else
|
||
val[0] = 0x70 | opcode[j].opmask;
|
||
break;
|
||
case 2:
|
||
val[2] = addr & 0xff;
|
||
oplen = 3;
|
||
if (opcode[j].group == 1)
|
||
val[0] = 0xE0 | opcode[j].opmask;
|
||
else
|
||
val[0] = 0xB0 | opcode[j].opmask;
|
||
break;
|
||
default:
|
||
return SCPE_ARG;
|
||
break;
|
||
}
|
||
if (*cptr == ',') cptr++;
|
||
cptr = get_glyph(cptr, gbuf, 0);
|
||
sscanf(gbuf, "%x", &r);
|
||
if (r > 255) return SCPE_ARG;
|
||
val[1] = r;
|
||
break;
|
||
case 4:
|
||
if (*cptr == ',') cptr++;
|
||
cptr = get_glyph(cptr, gbuf, ',');
|
||
sscanf(gbuf, "%d", &r);
|
||
if (r > 15) return SCPE_ARG;
|
||
val[1] = (r << 4) & 0xf0;
|
||
val[0] = 0xf0 | opcode[j].opmask;
|
||
if (*cptr == ',') cptr++;
|
||
cptr = get_glyph(cptr, gbuf, ',');
|
||
sscanf(gbuf, "%d", &r);
|
||
if (r > 1) return SCPE_ARG;
|
||
val[1] |= (r << 3) & 0x08;
|
||
if (*cptr == ',') cptr++;
|
||
cptr = get_glyph(cptr, gbuf, 0);
|
||
sscanf(gbuf, "%d", &r);
|
||
if (r > 7) return SCPE_ARG;
|
||
val[1] |= r & 0x07;
|
||
val[2] = 0;
|
||
oplen = 3;
|
||
break;
|
||
case 5:
|
||
if (*cptr == ',') cptr++;
|
||
cptr = get_glyph(cptr, gbuf, ',');
|
||
sscanf(gbuf, "%d", &r);
|
||
if (r > 15) return SCPE_ARG;
|
||
val[1] = (r << 4) & 0xf0;
|
||
val[0] = 0xf0 | opcode[j].opmask;
|
||
if (*cptr == ',') cptr++;
|
||
cptr = get_glyph(cptr, gbuf, ',');
|
||
sscanf(gbuf, "%d", &r);
|
||
if (r > 1) return SCPE_ARG;
|
||
val[1] |= (r << 3) & 0x08;
|
||
if (*cptr == ',') cptr++;
|
||
cptr = get_glyph(cptr, gbuf, ',');
|
||
sscanf(gbuf, "%d", &r);
|
||
if (r > 7) return SCPE_ARG;
|
||
val[1] |= r & 0x07;
|
||
if (*cptr == ',') cptr++;
|
||
cptr = get_glyph(cptr, gbuf, 0);
|
||
sscanf(gbuf, "%x", &r);
|
||
if (r > 255) return SCPE_ARG;
|
||
val[2] = r;
|
||
oplen = 3;
|
||
break;
|
||
case 6:
|
||
if (*cptr == ',') cptr++;
|
||
cptr = get_glyph(cptr, gbuf, ',');
|
||
sscanf(gbuf, "%d", &r);
|
||
if (r > 15) return SCPE_ARG;
|
||
val[1] = (r << 4) & 0xf0;
|
||
if (*cptr == ',') cptr++;
|
||
cptr = get_glyph(cptr, gbuf, ',');
|
||
sscanf(gbuf, "%d", &r);
|
||
if (r > 1) return SCPE_ARG;
|
||
val[1] |= (r << 3) & 0x08;
|
||
if (*cptr == ',') cptr++;
|
||
cptr = get_glyph(cptr, gbuf, ',');
|
||
sscanf(gbuf, "%d", &r);
|
||
if (r > 7) return SCPE_ARG;
|
||
val[1] |= r & 0x07;
|
||
if (*cptr == ',') cptr++;
|
||
cptr = parse_addr(cptr, gbuf, &addr, &addtyp);
|
||
switch(addtyp) {
|
||
case 0:
|
||
val[2] = (addr >> 8) & 0x00ff;
|
||
val[3] = addr & 0xff;
|
||
oplen = 4;
|
||
if (opcode[j].group == 1)
|
||
val[0] = 0xC0 | opcode[j].opmask;
|
||
else
|
||
val[0] = 0x30 | opcode[j].opmask;
|
||
break;
|
||
case 1:
|
||
val[2] = addr & 0xff;
|
||
oplen = 3;
|
||
if (opcode[j].group == 1)
|
||
val[0] = 0xD0 | opcode[j].opmask;
|
||
else
|
||
val[0] = 0x70 | opcode[j].opmask;
|
||
break;
|
||
case 2:
|
||
val[2] = addr & 0xff;
|
||
oplen = 3;
|
||
if (opcode[j].group == 1)
|
||
val[0] = 0xE0 | opcode[j].opmask;
|
||
else
|
||
val[0] = 0xB0 | opcode[j].opmask;
|
||
break;
|
||
default:
|
||
return SCPE_ARG;
|
||
break;
|
||
}
|
||
break;
|
||
case 7:
|
||
if (*cptr == ',') cptr++;
|
||
cptr = get_glyph(cptr, gbuf, 0);
|
||
sscanf(gbuf, "%x", &r);
|
||
if ((r - (addr+3)) > 255 || (r - (addr+3)) < 1) return SCPE_ARG;
|
||
val[2] = r - (addr+3);
|
||
val[1] = opcode[j].q;
|
||
val[0] = 0xf0 | opcode[j].opmask;
|
||
oplen = 3;
|
||
break;
|
||
|
||
case 8:
|
||
if (*cptr == ',') cptr++;
|
||
cptr = parse_addr(cptr, gbuf, &addr, &addtyp);
|
||
switch(addtyp) {
|
||
case 0:
|
||
val[2] = (addr >> 8) & 0x00ff;
|
||
val[3] = addr & 0xff;
|
||
oplen = 4;
|
||
val[0] = 0xC0 | opcode[j].opmask;
|
||
break;
|
||
case 1:
|
||
val[2] = addr & 0xff;
|
||
oplen = 3;
|
||
val[0] = 0xD0 | opcode[j].opmask;
|
||
break;
|
||
case 2:
|
||
val[2] = addr & 0xff;
|
||
oplen = 3;
|
||
val[0] = 0xE0 | opcode[j].opmask;
|
||
break;
|
||
default:
|
||
return SCPE_ARG;
|
||
break;
|
||
}
|
||
val[1] = opcode[j].q;
|
||
break;
|
||
case 9:
|
||
oplen = 2;
|
||
val[0] = 0;
|
||
cptr = parse_addr(cptr, gbuf, &addr, &addtyp);
|
||
switch(addtyp) {
|
||
case 0:
|
||
val[2] = (addr >> 8) & 0xff;
|
||
val[3] = addr & 0xff;
|
||
oplen += 2;
|
||
vptr = 4;
|
||
val[0] = 0x00 | opcode[j].opmask;
|
||
break;
|
||
case 1:
|
||
val[2] = addr & 0xff;
|
||
oplen += 1;
|
||
vptr = 3;
|
||
val[0] = 0x40 | opcode[j].opmask;
|
||
break;
|
||
case 2:
|
||
val[2] = addr & 0xff;
|
||
oplen += 1;
|
||
vptr = 3;
|
||
val[0] = 0x80 | opcode[j].opmask;
|
||
break;
|
||
default:
|
||
return SCPE_ARG;
|
||
break;
|
||
}
|
||
if (*cptr == ',') cptr++;
|
||
cptr = parse_addr(cptr, gbuf, &addr, &addtyp);
|
||
switch(addtyp) {
|
||
case 0:
|
||
val[vptr] = (addr >> 8) & 0xff;
|
||
val[vptr+1] = addr & 0xff;
|
||
oplen += 2;
|
||
break;
|
||
case 1:
|
||
val[vptr] = addr & 0xff;
|
||
oplen += 1;
|
||
val[0] = 0x10 | val[0];
|
||
break;
|
||
case 2:
|
||
val[vptr] = addr & 0xff;
|
||
oplen += 1;
|
||
val[0] = 0x20 | val[0];
|
||
break;
|
||
default:
|
||
return SCPE_ARG;
|
||
break;
|
||
}
|
||
val[1] = opcode[j].q;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
|
||
return (-(oplen-1));
|
||
}
|
||
|
||
char *parse_addr(char *cptr, char *gbuf, int32 *addr, int32 *addrtype)
|
||
{
|
||
int32 nybble = 0;
|
||
char temp[32];
|
||
|
||
cptr = get_glyph(cptr, gbuf, ',');
|
||
if (gbuf[0] == '(') { /* XR relative */
|
||
strcpy(temp, gbuf+1);
|
||
sscanf(temp, "%x", addr);
|
||
if (*cptr == ',') cptr++;
|
||
cptr = get_glyph(cptr, gbuf, ',');
|
||
nybble = -1;
|
||
if (strcmp(gbuf, "XR1)") == 0)
|
||
nybble = 1;
|
||
if (strcmp(gbuf, "XR2)") == 0)
|
||
nybble = 2;
|
||
} else { /* Direct */
|
||
sscanf(gbuf, "%x", addr);
|
||
nybble = 0;
|
||
}
|
||
*addrtype = nybble;
|
||
return cptr;
|
||
}
|
||
|