SEL32: Update Ping and ICMP support code to use correct packet size. SEL32: Update SetupNet script to support latest Fedora release. SEL32: Improve disk write speed. SEL32: Add .tap file reassignent support in sel32_mt.c.
1885 lines
94 KiB
C
1885 lines
94 KiB
C
/* sel32_sys.c: SEL-32 Gould Concept/32 (orignal SEL-32) Simulator system interface.
|
|
|
|
Copyright (c) 2018-2023, James C. Bevier
|
|
Portions provided by Richard Cornwell, Geert Rolf and other SIMH contributers
|
|
|
|
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
|
|
JAMES C. BEVIER 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.
|
|
*/
|
|
|
|
/* Concept 32 PSD Mode Trap/Interrupt Priorities */
|
|
/* Relative|Logical |Int Vect|TCW |IOCD|Description */
|
|
/* Priority|Priority|Location|Addr|Addr */
|
|
/* - 080 Power Fail Safe Trap */
|
|
/* - 084 Power On Trap */
|
|
/* - 088 Memory Parity Trap */
|
|
/* - 08C Nonpresent Memory Trap */
|
|
/* - 090 Undefined Instruction Trap */
|
|
/* - 094 Privilege Violation Trap */
|
|
/* - 098 Supervisor Call Trap (SVC) */
|
|
/* - 09C Machine Check Trap */
|
|
/* - 0A0 System Check Trap */
|
|
/* - 0A4 Map Fault Trap */
|
|
/* - 0A8 CALM or Undefined IPU Instruction Trap */
|
|
/* - 0AC Signal CPU or Signal IPU Trap */
|
|
/* - 0B0 Address Specification Trap */
|
|
/* - 0B4 Console Attention Trap */
|
|
/* - 0B8 Privlege Mode Halt Trap */
|
|
/* - 0BC Arithmetic Exception Trap */
|
|
/* - 0C0 Cache Error Trap (V9 Only) */
|
|
/* - 0C4 Demand Page Fault Trap (V6&V9 Only) */
|
|
/* */
|
|
/* 0 00 100 External/software Interrupt 0 */
|
|
/* 1 01 104 External/software Interrupt 1 */
|
|
/* 2 02 108 External/software Interrupt 2 */
|
|
/* 3 03 10C External/software Interrupt 3 */
|
|
/* 4 04 110 704 700 I/O Channel 0 interrupt */
|
|
/* 5 05 114 70C 708 I/O Channel 1 interrupt */
|
|
/* 6 06 118 714 710 I/O Channel 2 interrupt */
|
|
/* 7 07 11C 71C 718 I/O Channel 3 interrupt */
|
|
/* 8 08 120 724 720 I/O Channel 4 interrupt */
|
|
/* 9 09 124 72C 728 I/O Channel 5 interrupt */
|
|
/* A 0A 128 734 730 I/O Channel 6 interrupt */
|
|
/* B 0B 12C 73C 738 I/O Channel 7 interrupt */
|
|
/* C 0C 130 744 740 I/O Channel 8 interrupt */
|
|
/* D 0D 134 74C 748 I/O Channel 9 interrupt */
|
|
/* E 0E 138 754 750 I/O Channel A interrupt */
|
|
/* F 0F 13C 75C 758 I/O Channel B interrupt */
|
|
/* 10 10 140 764 760 I/O Channel C interrupt */
|
|
/* 11 11 144 76C 768 I/O Channel D interrupt */
|
|
/* 12 12 148 774 770 I/O Channel E interrupt */
|
|
/* 13 13 14c 77C 778 I/O Channel F interrupt */
|
|
/* 14 14 150 External/Software Interrupt */
|
|
/* 15 15 154 External/Software Interrupt */
|
|
/* 16 16 158 External/Software Interrupt */
|
|
/* 17 17 15C External/Software Interrupt */
|
|
/* 18 18 160 Real-Time Clock Interrupt */
|
|
/* 19 19 164 External/Software Interrupt */
|
|
/* 1A 1A 1A8 External/Software Interrupt */
|
|
/* 1B 1B 1AC External/Software Interrupt */
|
|
/* 1C 1C 1B0 External/Software Interrupt */
|
|
/* THRU THRU THRU THRU */
|
|
/* 6C 6C 2B0 External/Software Interrupt */
|
|
/* 6D 6D 2B4 External/Software Interrupt */
|
|
/* 6E 6E 2B8 External/Software Interrupt */
|
|
/* 6F 6F 2BC Interval Timer Interrupt */
|
|
|
|
/* IVL ------------> ICB Trap/Interrupt Vector Location points to Interrupt Context Block */
|
|
/* Wd 0 - Old PSD Word 1 points to return location */
|
|
/* Wd 1 - Old PSD Word 2 */
|
|
/* Wd 2 - New PSD Word 1 points to first instruction of service routine */
|
|
/* Wd 3 - New PSD Word 2 */
|
|
/* Wd 4 - CPU Status word at time of interrupt/trap */
|
|
/* Wd 5 - N/U For Traps/Interrupts */
|
|
|
|
/* IVL ------------> ICB XIO Interrupt Vector Location */
|
|
/* Wd 0 - Old PSD Word 1 points to return location */
|
|
/* Wd 1 - Old PSD Word 2 */
|
|
/* Wd 2 - New PSD Word 1 points to first instruction of service routine */
|
|
/* Wd 3 - New PSD Word 2 */
|
|
/* Wd 4 - Input/Output Command List Address (IOCL) for the Class F I/O CHannel */
|
|
/* Wd 5 - 24 bit real address of the channel status word */
|
|
|
|
/*-----------------------------------------------------------------------------------------------*/
|
|
|
|
/* Map image descriptor 32/77 */
|
|
/* |--------------------------------------| */
|
|
/* |0|1|2|3 4 5 6|7 8 9 10 11 12 13 14 15| */
|
|
/* |N|V|P| n/u | 9 bit map block entry | */
|
|
/* |U| | | | 32kb/block | */
|
|
/* | | 32 8kb maps per task | */
|
|
/* | | 1 mb address space | */
|
|
/* |--------------------------------------| */
|
|
|
|
/* Map image descriptor 32/27 */
|
|
/* |--------------------------------------| */
|
|
/* |0|1|2|3|4|5 6 7 8 9 10 11 12 13 14 15| */
|
|
/* |V|P|P|P|P| 11 bit map block entry | */
|
|
/* | |1|2|3|4| 8kb/block | */
|
|
/* | | 256 8kb maps per task | */
|
|
/* | | 2 mb address space | */
|
|
/* |--------------------------------------| */
|
|
|
|
/* Map image descriptor 32/67, 32/87, 32/97 */
|
|
/* |--------------------------------------| */
|
|
/* |0|1|2|3|4|5 6 7 8 9 10 11 12 13 14 15| */
|
|
/* |V|P|P|P|P| 11 bit map block entry | */
|
|
/* | |1|2|3|4| 2kb/block | */
|
|
/* | | 2048 8kb maps per task | */
|
|
/* | | 16 mb address space | */
|
|
/* |--------------------------------------| */
|
|
/* BIT 0 = 0 Invalid map block (page) entry */
|
|
/* = 1 Valid map block (page) entry */
|
|
/* 1 = 0 000-7ff of 8kb page is not write protected */
|
|
/* = 1 000-7ff of 8kb page is write protected */
|
|
/* 2 = 0 800-fff of 8kb page is not write protected */
|
|
/* = 1 800-fff of 8kb page is write protected */
|
|
/* 3 = 0 1000-17ff of 8kb page is not write protected */
|
|
/* = 1 1000-17ff of 8kb page is write protected */
|
|
/* 4 = 0 1800-1fff of 8kb page is not write protected */
|
|
/* = 1 1800-1fff of 8kb page is write protected */
|
|
/* 5-15 = 11 most significant bits of the 24 bit real address for page */
|
|
|
|
/* Map image descriptor V6 & V9 */
|
|
/* |--------------------------------------| */
|
|
/* |0|1|2|3|4|5 6 7 8 9 10 11 12 13 14 15| */
|
|
/* |V|P|P|M|M| 11 bit map block entry | */
|
|
/* | |1|2|M|A| 2kb/map | */
|
|
/* | | 2048 8kb maps per task | */
|
|
/* | | 16 mb address space | */
|
|
/* |--------------------------------------| */
|
|
/* BIT 0 = 0 Invalid map block (page) entry */
|
|
/* = 1 Valid map block (page) entry */
|
|
/* */
|
|
/* PSD 1 BIT 0 - Map Bit 1 - Map Bit 2 - Access state */
|
|
/* Priv Bits with ECO for Access Protection change */
|
|
/* 0 0 0 No access allowed to page */
|
|
/* 0 0 1 No access allowed to page */
|
|
/* 0 1 0 Read/Write/Execute access */
|
|
/* 0 1 1 Read/Execute access only */
|
|
/*O/S*/
|
|
/* 1 0 0 Read/Write/Execute access */
|
|
/* 1 0 1 Read/Execute access only */
|
|
/* 1 1 0 Read/Write/Execute access */
|
|
/* 1 1 1 Read/Execute access only */
|
|
/* Priv Bits without ECO for Access Protection change */
|
|
/* 0 0 0 No access allowed to page */
|
|
/* 0 0 1 Read/Execute access only */
|
|
/* 0 1 0 Read//Execute access only */
|
|
/* 0 1 1 Read/Write/Execute access */
|
|
/*O/S*/
|
|
/* 1 0 0 Read/Write/Execute only */
|
|
/* 1 0 1 Read/Execute access only */
|
|
/* 1 1 0 Read/Write/Execute access */
|
|
/* 1 1 1 Read/Write/Execute access */
|
|
/* */
|
|
/* BIT 3 = 0 (MM) A first write (modify) to the map block (page) has not occurred */
|
|
/* = 1 (MM) A first write (modify) to the map block (page) has occurred */
|
|
/* BIT 4 = 0 (MA) A first read or write (access) to the map block (page) has not occurred */
|
|
/* = 1 (MA) A first read or write (access) to the map block (page) has occurred */
|
|
/* 5-15 = 11 most significant bits of the 24 bit real address for page */
|
|
|
|
/* Note */
|
|
/* If a map is valid, a MAP (page) hit occurs and logical to physical translation occures */
|
|
/* If the map is not valid, a demand MAP (page) fault occures and the faulting page is provided */
|
|
/* P1 and P2 are used with Bit 0 of PSD to define the access rights */
|
|
/* A privilege violation trap occurres if access it denied */
|
|
/* Bits 5-15 contain the 11 most-significant bits of the physical address */
|
|
/* MSD 0 page limit is used to verify access to O/S pages */
|
|
/* CPIXPL page limit is used to verify access to user pages and page faults */
|
|
/* CPIX CPIX of user MPL offset */
|
|
/* Access to pages outside the limit registers results in a map fault */
|
|
|
|
/*-----------------------------------------------------------------------------------------------*/
|
|
|
|
#include "sel32_defs.h"
|
|
#include <ctype.h>
|
|
|
|
extern REG cpu_reg[];
|
|
extern uint32 SPAD[];
|
|
extern uint32 PSD[];
|
|
char *dump_mem(uint32 mp, int cnt);
|
|
char *dump_buf(uint8 *mp, int32 off, int cnt);
|
|
|
|
/* SCP data structures and interface routines
|
|
|
|
The interface between the simulator control package (SCP) and the
|
|
simulator consists of the following routines and data structures
|
|
|
|
sim_name simulator name string
|
|
sim_devices[] array of pointers to simulated devices
|
|
sim_PC pointer to saved PC register descriptor
|
|
sim_interval simulator interval to next event (in sel32_cpu.c)
|
|
sim_stop_messages[] array of pointers to stop messages
|
|
sim_instr() instruction execution routine (in sel32_cpu.c)
|
|
sim_load() binary loader routine
|
|
sim_emax maximum number of words for examine
|
|
|
|
In addition, the simulator must supply routines to print and parse
|
|
architecture specific formats
|
|
|
|
fprint_sym print symbolic output
|
|
fparse_sym parse symbolic input
|
|
*/
|
|
|
|
char sim_name[] = "SEL-32"; /* our simulator name */
|
|
REG *sim_PC = &cpu_reg[0];
|
|
|
|
int32 sim_emax = 4; /* maximum number of instructions/words to examine */
|
|
|
|
DEVICE *sim_devices[] = {
|
|
&cpu_dev,
|
|
#ifdef USE_IPU_THREAD
|
|
&ipu_dev,
|
|
#endif
|
|
#ifdef NUM_DEVS_IOP
|
|
&iop_dev, /* IOP channel controller */
|
|
#endif
|
|
#ifdef NUM_DEVS_MFP
|
|
&mfp_dev, /* MFP channel controller */
|
|
#endif
|
|
#ifdef NUM_DEVS_RTOM
|
|
&rtc_dev,
|
|
&itm_dev,
|
|
#endif
|
|
#ifdef NUM_DEVS_CON
|
|
&con_dev,
|
|
#endif
|
|
#ifdef NUM_DEVS_CDR
|
|
&cdr_dev,
|
|
#endif
|
|
#ifdef NUM_DEVS_CDP
|
|
&cdp_dev,
|
|
#endif
|
|
#ifdef NUM_DEVS_LPR
|
|
&lpr_dev,
|
|
#endif
|
|
#ifdef NUM_DEVS_MT
|
|
&mta_dev,
|
|
#if NUM_DEVS_MT > 1
|
|
&mtb_dev,
|
|
#endif
|
|
#endif
|
|
#ifdef NUM_DEVS_DISK
|
|
&dda_dev,
|
|
#if NUM_DEVS_DISK > 1
|
|
&ddb_dev,
|
|
#endif
|
|
#endif
|
|
#ifdef NUM_DEVS_SCFI
|
|
&sda_dev,
|
|
#if NUM_DEVS_SCFI > 1
|
|
&sdb_dev,
|
|
#endif
|
|
#endif
|
|
#ifdef NUM_DEVS_HSDP
|
|
&dpa_dev,
|
|
#if NUM_DEVS_HSDP > 1
|
|
&dpb_dev,
|
|
#endif
|
|
#endif
|
|
#ifdef NUM_DEVS_SCSI
|
|
&sba_dev,
|
|
#if NUM_DEVS_SCSI > 1
|
|
&sbb_dev,
|
|
#endif
|
|
#endif
|
|
#ifdef NUM_DEVS_ETHER
|
|
&ec_dev,
|
|
#endif
|
|
#ifdef NUM_DEVS_COM
|
|
&coml_dev,
|
|
&com_dev,
|
|
#endif
|
|
NULL };
|
|
|
|
/* Simulator debug controls */
|
|
DEBTAB dev_debug[] = {
|
|
{"CMD", DEBUG_CMD, "Show command execution to devices"},
|
|
{"DATA", DEBUG_DATA, "Show data transfers"},
|
|
{"DETAIL", DEBUG_DETAIL, "Show details about device"},
|
|
{"EXP", DEBUG_EXP, "Show exception information"},
|
|
{"INST", DEBUG_INST, "Show instruction execution"},
|
|
{"XIO", DEBUG_XIO, "Show XIO I/O instructions"},
|
|
{"IRQ", DEBUG_IRQ, "Show interrupt requests"},
|
|
{"TRAP", DEBUG_TRAP, "Show trap requests"},
|
|
{0, 0}
|
|
};
|
|
|
|
const char *sim_stop_messages[SCPE_BASE] = {
|
|
"Unknown error",
|
|
"IO device not ready",
|
|
"HALT instruction",
|
|
"Breakpoint",
|
|
"IPU Reset request",
|
|
"Invalid instruction",
|
|
"Invalid I/O operation",
|
|
"Waiting for CPU to run",
|
|
"I/O Check opcode",
|
|
"Memory management trap during trap",
|
|
};
|
|
|
|
#define PRINTABLE(x) ((x < 32) || (x > 126)) ? '.' : x
|
|
|
|
static char line[257];
|
|
/* function to dump SEL32 memory up to 16 bytes with side by side ascii values */
|
|
char *dump_mem(uint32 mp, int cnt)
|
|
{
|
|
char buff[257];
|
|
uint32 ma = mp; /* save memory address */
|
|
char *cp = &line[0]; /* output buffer */
|
|
int cc=0, ch, bp=0, bl=cnt;
|
|
|
|
if (cnt > 16)
|
|
bl = 16; /* stop at 16 chars */
|
|
|
|
while (bp < bl) {
|
|
if (!bp) {
|
|
cc = sprintf(cp, " %06x : ", ma); /* output location address */
|
|
cp += cc; /* next print location */
|
|
}
|
|
ch = RMB(ma) & 0xff; /* get a char from memory */
|
|
ma++; /* next loc */
|
|
cc += sprintf(cp, "%02x", ch); /* print out current char */
|
|
cp += 2; /* next print location */
|
|
buff[bp++] = PRINTABLE(ch); /* get printable version of char */
|
|
if (!(bp % 4)) { /* word boundry yet? */
|
|
cc += sprintf(cp, " "); /* space between words */
|
|
cp += 1; /* next print location */
|
|
}
|
|
}
|
|
|
|
while (bp < 16) {
|
|
cc += sprintf(cp, " "); /* print out one space */
|
|
cp += 1; /* next print location */
|
|
buff[bp++] = 0x20; /* blank char buffer */
|
|
if (!(bp % 4)) {
|
|
cc += sprintf(cp, " "); /* space between words */
|
|
cp += 1; /* next print location */
|
|
}
|
|
}
|
|
buff[bp] = 0; /* terminate line */
|
|
cc += sprintf(cp, "|%s|\n", buff); /* print out ascii text */
|
|
return (line); /* return pointer to caller */
|
|
}
|
|
|
|
/* function to dump caller buffer upto 16 bytes with side by side ascii values */
|
|
/* off is offset in buffer to start */
|
|
char *dump_buf(uint8 *mp, int32 off, int cnt)
|
|
{
|
|
char buff[257];
|
|
uint32 ma = off; /* save memory address */
|
|
char *cp = &line[0]; /* output buffer */
|
|
int cc=0, ch, bp=0, bl=cnt;
|
|
|
|
if (cnt > 16)
|
|
bl = 16; /* stop at 16 chars */
|
|
|
|
while (bp < bl) {
|
|
if (!bp) {
|
|
cc = sprintf(cp, " %06x : ", ma); /* output location offset */
|
|
cp += cc; /* next print location */
|
|
}
|
|
ch = mp[ma++] & 0xff; /* get a char from memory */
|
|
cc += sprintf(cp, "%02x", ch); /* print out current char */
|
|
cp += 2; /* next print location */
|
|
buff[bp++] = PRINTABLE(ch); /* get printable version of char */
|
|
if (!(bp % 4)) { /* word boundry yet? */
|
|
cc += sprintf(cp, " "); /* space between words */
|
|
cp += 1; /* next print location */
|
|
}
|
|
}
|
|
|
|
while (bp < 16) {
|
|
cc += sprintf(cp, " "); /* print out one space */
|
|
cp += 1; /* next print location */
|
|
buff[bp++] = 0x20; /* blank char buffer */
|
|
if (!(bp % 4)) {
|
|
cc += sprintf(cp, " "); /* space between words */
|
|
cp += 1; /* next print location */
|
|
}
|
|
}
|
|
buff[bp] = 0; /* terminate line */
|
|
cc += sprintf(cp, "|%s|\n", buff); /* print out ascii text */
|
|
return (line); /* return pointer to caller */
|
|
}
|
|
|
|
/*
|
|
* get_word - function to load a 32 bit word from the input file
|
|
* return 1 - OK
|
|
* return 0 - error or eof
|
|
*/
|
|
int get_word(FILE *fileref, uint32 *word)
|
|
{
|
|
unsigned char cbuf[4];
|
|
|
|
/* read in the 4 chars */
|
|
if (sim_fread(cbuf, 1, 4, fileref) != 4)
|
|
return 1; /* read error or eof */
|
|
/* byte swap while reading data */
|
|
*word = ((cbuf[0]) << 24) | ((cbuf[1]) << 16) |
|
|
((cbuf[2]) << 8) | ((cbuf[3]));
|
|
return 0; /* all OK */
|
|
}
|
|
|
|
#ifdef NO_TAP_FOR_NOW
|
|
/*
|
|
* get_halfword - function to load a 16 bit halfword from the input file
|
|
* return 1 - OK
|
|
* return 0 - error or eof
|
|
*/
|
|
int get_halfword(FILE *fileref, uint16 *word)
|
|
{
|
|
unsigned char cbuf[2];
|
|
|
|
/* read in the 2 chars */
|
|
if (sim_fread(cbuf, 1, 2, fileref) != 2)
|
|
return 1; /* read error or eof */
|
|
/* byte swap while reading data */
|
|
*word = ((uint16)(cbuf[0]) << 8) | ((uint16)(cbuf[1]));
|
|
return 0; /* all OK */
|
|
}
|
|
#endif
|
|
|
|
/* load a binary file into memory starting at loc 0 */
|
|
/* return SCPE_OK on load complete */
|
|
t_stat load_mem (FILE *fileref)
|
|
{
|
|
uint32 data;
|
|
uint32 ma = 0; /* start at mem add 0 */
|
|
|
|
/* read the file until the end */
|
|
for ( ;; ) {
|
|
if (get_word(fileref, &data)) /* get 32 bits of data */
|
|
return SCPE_OK; /* load is complete, return */
|
|
M[ma++] = data; /* put data in memory */
|
|
}
|
|
return SCPE_OK; /* never here */
|
|
}
|
|
|
|
#ifdef NO_TAP_FOR_NOW
|
|
/* load tap formated tape into memory */
|
|
/* return SCPE_OK on load complete */
|
|
t_stat load_tap (FILE *fileref)
|
|
{
|
|
uint32 bdata, edata;
|
|
uint16 hdata;
|
|
uint32 ma = 0; /* start loading at loc 0 */
|
|
int32 wc;
|
|
|
|
for ( ;; ) { /* loop until EOF read */
|
|
/* look for record byte count or zero for EOF */
|
|
if (get_word(fileref, &bdata)) /* read 4 bytes of data */
|
|
return SCPE_FMT; /* must be error, exit */
|
|
wc = (int32)(bdata); /* byte count in tape record */
|
|
wc = (wc + 1)/2; /* change byte count into hw count */
|
|
if (wc == 0)
|
|
return SCPE_OK; /* eof found, return */
|
|
/* copy data to memory in 16 bit halfwords */
|
|
while (wc-- != 0) {
|
|
if (get_halfword(fileref, &hdata)) /* get 16 bits of data */
|
|
return SCPE_FMT; /* must be error, exit */
|
|
((uint16*)M)[ma++] = hdata; /* put the hw into memory */
|
|
}
|
|
/* look only for record byte count */
|
|
if (get_word(fileref, &edata)) /* read 4 bytes of data */
|
|
return SCPE_FMT; /* must be error, exit */
|
|
/* the before and after byte count must be equal */
|
|
if (bdata != edata)
|
|
return SCPE_FMT; /* must be error, exit */
|
|
}
|
|
return SCPE_OK; /* never here */
|
|
}
|
|
#endif
|
|
|
|
/* ICL formats */
|
|
/***********************************************
|
|
*
|
|
* *DEVXX=FCILCASA (,N)
|
|
*
|
|
* *DEV defines a controller definition entry
|
|
* XX hex address that will be used by I/O instructions to address controller
|
|
* = required delimiter for following 8 hex characters
|
|
* F flag used for I/O emulation by CPU, not used but must be zero.
|
|
* C defines the class of controller:
|
|
* 0 = Line Printer
|
|
* 1 = Card Reader
|
|
* 2 = Teletype
|
|
* 3 = Interval Timer
|
|
* 4 = Panel
|
|
* 5-D Unassigned
|
|
* E = All Others
|
|
* F = Extended I/O
|
|
* IL Controller interrupt priority level of Service Interrupt (0x14 - 0x23)
|
|
* CA Controller address defined by hardware switches on controller
|
|
* SA Lowest controller device subaddress. Usually zero when only 1 device configured
|
|
* The subaddress field (SA) must reflect the following for TLC controller:
|
|
* 00 = Card Reader
|
|
* 01 = Teletype
|
|
* 02 = Line Printer
|
|
* () denotes optional parameter
|
|
* ,NN 2 digit hexx number of devices configured on the controller`
|
|
*
|
|
***********************************************
|
|
*
|
|
* *INTXX=RS
|
|
* *INT defines interrupt definition entry
|
|
* XX Hex interrupt priority level to be defined
|
|
* = required delimiter for following 2 hex characters
|
|
* R Hex RTOM board number to which the interrupt XX is assigned
|
|
* S 1's complement of the hex subaddress of the RTOM board
|
|
* assigned to the interrupt XX
|
|
*
|
|
* RTOM physical controller address 0x79 is RTOM board number 1, RTOM
|
|
* address 0x7A is board number 2, etc.
|
|
* Real-Time Clock is connected tp subaddress 6 on RTOM board
|
|
* Interval Timer is connected to subaddress 4 on RTOM board
|
|
* RTOM physical address must be 0x79 or above to be able to
|
|
* support up to seven RTOM boards for maximum configuration
|
|
* of 112 interrupt levels (7 x 16).
|
|
*
|
|
***********************************************
|
|
*
|
|
* *END Defines the last record of the Initial Configuration Load file.
|
|
*
|
|
***********************************************
|
|
*/
|
|
|
|
/* Example device entry
|
|
* *DEV04=0E140100,04
|
|
* The controller is "E" class
|
|
* CPU command device address will be 0x04
|
|
* The priority of the Service Interrupt is 0x14
|
|
* The first device has suaddress of 00 and there are 4 devices defined
|
|
* There will be four devices defined in SPAD. The I/O commands (CD and TD)
|
|
* will address the devices as 0x04, 0x05, 0x06, and 0x07.
|
|
* The physical address of the controller is 0x10.
|
|
* Assigning SI address of 0x14 means:
|
|
* The transfer Interrupt location for priority 0x14 is 0x100.
|
|
* The Service Interrupt vector location for priority 0x14 is 0x140.
|
|
* The emulation IOCD will be stored at loation 0x700.
|
|
* The interrupt control instructions (DI, DI, RI, AI, DAI) will control
|
|
* the interrupt of the controller by addressing priority 0x14.
|
|
*
|
|
* Example interrupt entry (RTOM)
|
|
* *INT28=16
|
|
* The interrupt control instructions (DI, EI, RI, AI, DAI) will control
|
|
* the interrupt on the RTOM by addressing priority 0x28.
|
|
* The RTOM board is 1
|
|
* The subaddress on the board is 0x06 (jumpered locic subaddress is 9)
|
|
*/
|
|
|
|
/*
|
|
* Example ICL file
|
|
* *DEV04=0E150400,02 Cartridge disc with two platters
|
|
* *DEV08=0E160800,04 Moving head disc
|
|
* *DEV10=0E181000,04 9-Track magnetic tape
|
|
* *DEV20=0E1A2000,10 GPMC with 16 terminals
|
|
* *DEV60=0E1E6000,08 ADS
|
|
* *DEV78=01207800 Primary card reader
|
|
* *DEV7A=00217802 Primary line printer
|
|
* *DEV7E=02237801 Primary Teletype
|
|
* *INT00=1F Power fail/Auto restart
|
|
* *INT01=1E System Overide
|
|
* *INT12=1D Memory parity
|
|
* *INT13=1C Console Interrupt
|
|
* *INT24=1B Nonpresent memory
|
|
* *INT25=1A Undefined instruction trap
|
|
* *INT26=19 Privlege violation
|
|
* *INT27=18 Call Monitor
|
|
* *INT28=16 Real-time clock
|
|
* *INT29=17 Arithmetic exception
|
|
* *INT2A=15 External interrupt
|
|
* *INT2B=14 External interrupt
|
|
* *INT2C=13 External interrupt
|
|
* *INT2D=12 External interrupt
|
|
* *END
|
|
*/
|
|
|
|
/* process two hex input characters into a number
|
|
* pt - input char pointer
|
|
* val - word oiunter when number will be saved
|
|
* return SCPE_OK for OK
|
|
* or SCPE_ARG for arg error (bad number)
|
|
*/
|
|
t_value get_2hex(char *pt, uint32 *val)
|
|
{
|
|
int32 hexval;
|
|
uint32 c1 = sim_toupper((uint32)pt[0]); /* first hex char */
|
|
uint32 c2 = sim_toupper((uint32)pt[1]); /* next hex char */
|
|
|
|
if (isdigit(c1)) /* digit */
|
|
hexval = c1 - (uint32)'0'; /* get value */
|
|
else
|
|
if (isxdigit(c1)) /* hex digit */
|
|
hexval = c1 - (uint32)'A' + 10; /* get hex value */
|
|
else
|
|
return SCPE_ARG; /* oops, error */
|
|
hexval <<= 4; /* move to upper nibble */
|
|
if (isdigit(c2)) /* digit */
|
|
hexval += c2 - (uint32)'0'; /* get value */
|
|
else
|
|
if (isxdigit(c2)) /* hex digit */
|
|
hexval += c2 - (uint32)'A' + 10; /* get hex value */
|
|
else
|
|
return SCPE_ARG; /* oops, error */
|
|
*val = hexval; /* return value to caller */
|
|
return SCPE_OK; /* all OK */
|
|
}
|
|
|
|
/* load an ICL file and configure SPAD interupt and device entries */
|
|
/* SPAD keyword will not be set and will be set when MPX or UTX is loaded */
|
|
/* return SCPE_OK on load complete */
|
|
t_stat load_icl(FILE *fileref)
|
|
{
|
|
char *cp; /* work pointer in buf[] */
|
|
uint32 sa; /* spad address */
|
|
uint32 dev; /* device entry */
|
|
uint32 intr; /* interrupt entry */
|
|
uint32 data; /* entry data */
|
|
uint32 cls; /* device class */
|
|
uint32 ivl; /* Interrupt Vector Location */
|
|
uint32 i; /* just a tmp */
|
|
char buf[120]; /* input buffer */
|
|
|
|
/* read file input records until the end */
|
|
while (fgets(&buf[0], 120, fileref) != 0) {
|
|
/* skip any white spaces */
|
|
for (cp = &buf[0]; *cp == ' ' || *cp == '\t'; cp++);
|
|
if (*cp++ != '*')
|
|
continue; /* if line does not start with *, ignore */
|
|
if (sim_strncasecmp(cp, "END", 3) == 0) {
|
|
return SCPE_OK; /* we are done */
|
|
}
|
|
else
|
|
if (sim_strncasecmp(cp, "DEV", 3) == 0) {
|
|
/* process device entry */
|
|
/*
|
|
|----+----+----+----+----+----+----+----|
|
|
|Flgs|CLS |0|Int Lev|0|Phy Adr|Sub Addr |
|
|
|----+----+----+----+----+----+----+----|
|
|
*/
|
|
for (cp += 3; *cp == ' ' || *cp == '\t'; cp++); /* skip white spaces */
|
|
if (get_2hex(cp, &dev) != SCPE_OK) /* get the device address */
|
|
return SCPE_ARG; /* unknown input, argument error */
|
|
if (dev > 0x7f) /* devices are 0-7f (0-127) */
|
|
return SCPE_ARG; /* argument error */
|
|
sa = dev + 0x00; /* device entry spad address is dev# + 0x00 */
|
|
cp += 2; /* skip the 2 processed chars */
|
|
if (*cp++ != '=') /* must have = sign */
|
|
return SCPE_ARG; /* unknown input, argument error */
|
|
if (get_2hex(cp, &cls) != SCPE_OK) /* get unused '0" and class */
|
|
return SCPE_ARG; /* unknown input, argument error */
|
|
cp += 2; /* skip the 2 processed chars */
|
|
if (get_2hex(cp, &intr) != SCPE_OK) /* get the interrupt level value */
|
|
return SCPE_ARG; /* unknown input, argument error */
|
|
if (intr > 0x6f) /* ints are 0-6f (0-111) */
|
|
return SCPE_ARG; /* argument error */
|
|
/* put class and 1's intr in place */
|
|
dev = ((~intr & 0x7f) << 16) | ((cls & 0x0f) << 24);
|
|
cp += 2; /* skip the 2 processed chars */
|
|
if (get_2hex(cp, &data) != SCPE_OK) /* get the selbus physical address */
|
|
return SCPE_ARG; /* unknown input, argument error */
|
|
if (data > 0x7f) /* address is 0-7f (0-127) */
|
|
return SCPE_ARG; /* argument error */
|
|
dev |= (data & 0x7f) << 8; /* insert the physical address */
|
|
cp += 2; /* skip the 2 processed chars */
|
|
if (get_2hex(cp, &data) != SCPE_OK) /* get the starting sub address 0-ff (255) */
|
|
return SCPE_ARG; /* unknown input, argument error */
|
|
if (data > 0x7f) /* sub address is 0-ff (0-256) */
|
|
return SCPE_ARG; /* argument error */
|
|
if ((cls & 0xf) != 0xf) /* sub addr must be zero for class F */
|
|
dev |= (data & 0xff); /* insert the starting sub address for non f class */
|
|
SPAD[sa] = dev; /* put the first device entry into the spad */
|
|
/* see if there is an optional device count for class 'E' I/O */
|
|
if ((cls & 0xf) == 0xe) {
|
|
cp += 2; /* skip the 2 processed chars */
|
|
if (*cp++ == ',') { /* must have comma if optional parameters */
|
|
/* check for optional sub addr cnt */
|
|
if (get_2hex(cp, &data) != SCPE_OK) /* get the count */
|
|
return SCPE_ARG; /* unknown input, argument error */
|
|
if (data > 0x10) /* sub address is max of 16 */
|
|
return SCPE_ARG; /* argument error */
|
|
for (i=0; i<data-1; i++) { /* 1st is already stored, redice cnt by 1 */
|
|
/* each of the devices will share the same interrupt */
|
|
SPAD[++sa] = ++dev; /* put next device entry in spad for the controller */
|
|
} /* done with 'E' class device with multiple devices */
|
|
}
|
|
} /* done with device entry */
|
|
/* now create an interrupt entry for the controller */
|
|
/*
|
|
|----+----+----+----+----+----+----+----|
|
|
| Flags |0|Int Lev| Int IVL |
|
|
|----+----+----+----+----+----+----+----|
|
|
*/
|
|
/* TODO call function here to create 32/7x IVL location for interrupt */
|
|
/* if (CPU_MODEL < MODEL_27) get_IVL(intr, &ivl); */
|
|
sa = intr + 0x80; /* interrupt entry spad address is int# + 0x80 */
|
|
ivl = (intr << 2) + 0x100; /* default IVL base is 0x100 for Concept machines */
|
|
intr = (intr << 16) | ivl; /* combine int level and ivl */
|
|
SPAD[sa] = intr; /* put the device interrupt entry into the spad */
|
|
}
|
|
else
|
|
if (sim_strncasecmp(cp, "INT", 3) == 0) {
|
|
/* process interrupt entry */
|
|
/*
|
|
|----+----+----+----+----+----+----+----|
|
|
| Flags |1RRR|SSSS| Int IVL |
|
|
|----+----+----+----+----+----+----+----|
|
|
*/
|
|
for (cp += 3; *cp == ' ' || *cp == '\t'; cp++); /* skip white spaces */
|
|
if (get_2hex(cp, &intr) != SCPE_OK) /* get the interrupt level value */
|
|
return SCPE_ARG; /* unknown input, argument error */
|
|
if (intr > 0x6f) /* ints are 0-6f (0-111) */
|
|
return SCPE_ARG; /* argument error */
|
|
sa = intr + 0x80; /* interrupt entry spad address is int# + 0x80 */
|
|
/* TODO call function here to create 32/7x IVL location for interrupt */
|
|
/* if (CPU_MODEL < MODEL_27) get_IVL(intr, &ivl); */
|
|
ivl = (intr << 2) + 0x100; /* default IVL base is 0x100 for Concept machines */
|
|
cp += 2; /* skip the 2 processed chars */
|
|
if (*cp++ != '=') /* must have = sign */
|
|
return SCPE_ARG; /* unknown input, argument error */
|
|
if (get_2hex(cp, &data) != SCPE_OK)
|
|
return SCPE_ARG; /* unknown input, argument error */
|
|
/* first digit is 3 ls bits of RTOM addr 0x79 is 001 */
|
|
intr = 0x00800000 | ((data & 0x70) << 16); /* put the RTOM 3 LSBs into entry */
|
|
/* second digit is subaddress on RTOM board for interrupt connection, ~6 = 9 */
|
|
intr |= (data & 0xf) << 16; /* put in 1's comp of RTOM subaddress */
|
|
/* add in the correct IVL for 32/7x or concelt machines */
|
|
intr |= ivl; /* set the IVL location */
|
|
SPAD[sa] = intr; /* put the interrupt entry into the spad */
|
|
}
|
|
else
|
|
return SCPE_ARG; /* unknown input, argument error */
|
|
}
|
|
return SCPE_OK; /* file done */
|
|
}
|
|
|
|
|
|
/* Load a file image into memory. */
|
|
/* file.mem files are binary files created with the makecode utility */
|
|
#ifdef NO_TAP_FOR_NOW
|
|
/* file.tap files are TAP formatted binary files created from tape images */
|
|
#endif
|
|
/* data is raw binary memory data and is loaded starting at loc 0 */
|
|
|
|
#define FMT_NONE 0
|
|
#define FMT_MEM 1
|
|
#ifdef NO_TAP_FOR_NOW
|
|
#define FMT_TAP 2
|
|
#endif
|
|
#define FMT_ICL 3
|
|
t_stat sim_load (FILE *fileref, CONST char *cptr, CONST char *fnam, int flag)
|
|
{
|
|
int32 fmt;
|
|
|
|
fmt = FMT_NONE; /* no format */
|
|
/* match the extension to .mem for this file */
|
|
if (match_ext(fnam, "MEM"))
|
|
fmt = FMT_MEM; /* we have binary format */
|
|
else
|
|
#ifdef NO_TAP_FOR_NOW
|
|
if (match_ext(fnam, "TAP"))
|
|
fmt = FMT_TAP; /* we have tap tape format */
|
|
else
|
|
#endif
|
|
/* match the extension to .icl for this file */
|
|
if (match_ext(fnam, "ICL"))
|
|
fmt = FMT_ICL; /* we have initial configuration load (ICL) format */
|
|
else
|
|
return SCPE_FMT; /* format error */
|
|
|
|
switch (fmt) {
|
|
|
|
case FMT_MEM: /* binary memory image */
|
|
return load_mem(fileref);
|
|
|
|
#ifdef NO_TAP_FOR_NOW
|
|
case FMT_TAP: /* tape file image */
|
|
return load_tap(fileref);
|
|
#endif
|
|
|
|
case FMT_ICL: /* icl file image */
|
|
return load_icl(fileref);
|
|
|
|
#ifdef NO_TAP_FOR_NOW
|
|
case FMT_NONE: /* nothing */
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
return SCPE_FMT; /* format error */
|
|
}
|
|
|
|
/* Symbol tables */
|
|
|
|
/*
|
|
* The SEL 32 supports the following instruction formats.
|
|
*
|
|
* TYPE Format Normal Base Mode
|
|
* A ADR d,[*]o,x d,o[(b)],x FC = extra
|
|
* B BRA [*]o,x o[(b)],x
|
|
* C IMM d,o d,o
|
|
* D BIT d,[*]o d,o[(b)]
|
|
* E ADR [*]o,x o[(b)],x FC = extra
|
|
* HALFWORD
|
|
* F REG s,d s,d Half Word
|
|
* G RG1 s s
|
|
* H HLF
|
|
* I SHF d,v d,v
|
|
* K RBT d,b d,b
|
|
* L EXR s s
|
|
* M IOP n,b n,b
|
|
* N SVC n,b n,b
|
|
*/
|
|
|
|
#define TYPE_A 0
|
|
#define TYPE_B 1
|
|
#define TYPE_C 2
|
|
#define TYPE_D 3
|
|
#define TYPE_E 4
|
|
#define TYPE_F 5
|
|
#define TYPE_G 6
|
|
#define TYPE_H 7
|
|
#define TYPE_I 8
|
|
#define TYPE_K 9
|
|
#define TYPE_L 10
|
|
#define TYPE_M 11
|
|
#define TYPE_N 12
|
|
#define H 0x10 /* halfword instruction */
|
|
/* all instruction unless specified as base/nobase only will be either */
|
|
#define B 0x20 /* base register mode only */
|
|
#define N 0x40 /* non base register mode only */
|
|
#define X 0x80 /* 32/55 or 32/75 only */
|
|
|
|
typedef struct _opcode {
|
|
uint16 opbase;
|
|
uint16 mask;
|
|
uint8 type;
|
|
const char *name;
|
|
} t_opcode;
|
|
|
|
t_opcode optab[] = {
|
|
{ 0x0000, 0xFFFF, H|TYPE_H, "HALT", }, /* Halt # * */
|
|
{ 0x0001, 0xFFFF, H|TYPE_H, "WAIT", }, /* Wait # * */
|
|
{ 0x0002, 0xFFFF, H|TYPE_H, "NOP", }, /* Nop # */
|
|
{ 0x0003, 0xFC0F, H|TYPE_G, "LCS", }, /* Load Control Switches */
|
|
{ 0x0004, 0xFC0F, H|TYPE_G, "ES", }, /* Extend Sign # */
|
|
{ 0x0005, 0xFC0F, H|TYPE_G, "RND", }, /* Round Register # */
|
|
{ 0x0006, 0xFFFF, H|TYPE_H, "BEI", }, /* Block External Interrupts # */
|
|
{ 0x0007, 0xFFFF, H|TYPE_H, "UEI", }, /* Unblock External Interrupts # */
|
|
{ 0x0008, 0xFFFF, H|TYPE_H, "EAE", }, /* Enable Arithmetic Exception Trap # */
|
|
{ 0x0009, 0xFC0F, H|TYPE_G, "RDSTS", }, /* Read CPU Status Word * */
|
|
{ 0x000A, 0xFFFF, H|TYPE_H, "SIPU", }, /* Signal IPU # */
|
|
{ 0x000B, 0xFC0F, H|TYPE_F, "RWCS", }, /* Read Writable Control Store # */
|
|
{ 0x000C, 0xFC0F, H|TYPE_F, "WWCS", }, /* Write Writable Control Store # */
|
|
{ 0x000D, 0xFFFF, N|H|TYPE_H, "SEA", }, /* Set Extended Addressing # NBR Only */
|
|
{ 0x000E, 0xFFFF, H|TYPE_H, "DAE", }, /* Disable Arithmetic Exception Trap # */
|
|
{ 0x000F, 0xFFFF, N|H|TYPE_H, "CEA", }, /* Clear Extended Addressing # NBR Only */
|
|
{ 0x0400, 0xFC0F, H|TYPE_F, "ANR", }, /* And Register # */
|
|
{ 0x0407, 0xFC0F, H|TYPE_G, "SMC", }, /* Shared Memory Control # */
|
|
{ 0x040A, 0xFC0F, H|TYPE_G, "CMC", }, /* Cache Memory Control # */
|
|
{ 0x040B, 0xFC0F, H|TYPE_G, "RPSWT", }, /* Read Processor Status Word Two # */
|
|
{ 0x0800, 0xFC0F, H|TYPE_F, "ORR", }, /* Or Register # */
|
|
{ 0x0808, 0xFC0F, H|TYPE_F, "ORRM", }, /* Or Register Masked # */
|
|
{ 0x0C00, 0xFC0F, H|TYPE_F, "EOR", }, /* Exclusive Or Register # */
|
|
{ 0x0C08, 0xFC0F, H|TYPE_F, "EORM", }, /* Exclusive Or Register Masked # */
|
|
{ 0x1000, 0xFC0F, H|TYPE_F, "CAR", }, /* Compare Arithmetic Register # */
|
|
{ 0x1008, 0xFC0F, B|H|TYPE_F, "SACZ", }, /* Shift and Count Zeros # BR */
|
|
{ 0x1400, 0xFC0F, H|TYPE_F, "CMR", }, /* Compare masked with register */
|
|
{ 0x1800, 0xFC0C, H|TYPE_K, "SBR", }, /* Set Bit in Register # */
|
|
{ 0x1804, 0xFC0C, B|H|TYPE_K, "ZBR", }, /* Zero Bit In register # BR */
|
|
{ 0x1808, 0xFC0C, B|H|TYPE_K, "ABR", }, /* Add Bit In Register # BR */
|
|
{ 0x180C, 0xFC0C, B|H|TYPE_K, "TBR", }, /* Test Bit in Register # BR */
|
|
{ 0x1C00, 0xFC0C, N|H|TYPE_K, "ZBR", }, /* Zero Bit in Register # NBR */ /* CON SRABR */
|
|
{ 0x1C00, 0xFC60, B|H|TYPE_I, "SRABR", }, /* Shift Right Arithmetic # BR */ /* CON ZBM */
|
|
{ 0x1C20, 0xFC60, B|H|TYPE_I, "SRLBR", }, /* Shift Right Logical # BR */
|
|
{ 0x1C40, 0xFC60, B|H|TYPE_I, "SLABR", }, /* Shift Left Arithmetic # BR */
|
|
{ 0x1C60, 0xFC60, B|H|TYPE_I, "SLLBR", }, /* Shift Left Logical # BR */
|
|
{ 0x2000, 0xFC0C, N|H|TYPE_K, "ABR", }, /* Add Bit in Register # NBR */ /* CON SRADBR */
|
|
{ 0x2000, 0xFC60, B|H|TYPE_I, "SRADBR", }, /* Shift Right Arithmetic Double # BR */ /* CON ABR */
|
|
{ 0x2020, 0xFC60, B|H|TYPE_I, "SRLDBR", }, /* Shift Left Logical Double # BR */
|
|
{ 0x2040, 0xFC60, B|H|TYPE_I, "SLADBR", }, /* Shift Right Arithmetic Double # BR */
|
|
{ 0x2060, 0xFC60, B|H|TYPE_I, "SLLDBR", }, /* Shift Left Logical Double # BR */
|
|
{ 0x2400, 0xFC0C, N|H|TYPE_K, "TBR", }, /* Test Bit in Register # NBR */ /* CON SRCBR */
|
|
{ 0x2400, 0xFC60, B|H|TYPE_I, "SRCBR", }, /* Shift Right Circular # BR */ /* CON TBR */
|
|
{ 0x2440, 0xFC60, B|H|TYPE_F, "SLCBR", }, /* Shift Left Circular # BR */
|
|
{ 0x2800, 0xFC0F, H|TYPE_G, "TRSW", }, /* Transfer GPR to PSD */
|
|
{ 0x2802, 0xFC0F, B|H|TYPE_F, "XCBR", }, /* Exchange Base Registers # BR Only */
|
|
{ 0x2804, 0xFC0F, B|H|TYPE_G, "TCCR", }, /* Transfer CC to GPR # BR Only */
|
|
{ 0x2805, 0xFC0F, B|H|TYPE_G, "TRCC", }, /* Transfer GPR to CC # BR */
|
|
{ 0x2808, 0xFF8F, B|H|TYPE_F, "BSUB", }, /* Branch Subroutine # BR Only */
|
|
{ 0x2808, 0xFC0F, B|H|TYPE_F, "CALL", }, /* Procedure Call # BR Only */
|
|
{ 0x280C, 0xFC0F, B|H|TYPE_G, "TPCBR", }, /* Transfer Program Counter to Base # BR Only */
|
|
{ 0x280E, 0xFC7F, B|H|TYPE_G, "RETURN", }, /* Procedure Return # BR Only */
|
|
{ 0x2C00, 0xFC0F, H|TYPE_F, "TRR", }, /* Transfer Register to Register # */
|
|
{ 0x2C01, 0xFC0F, B|H|TYPE_F, "TRBR", }, /* Transfer GPR to BR # */
|
|
{ 0x2C02, 0xFC0F, B|H|TYPE_F, "TBRR", }, /* Transfer BR to GPR # BR Only */
|
|
{ 0x2C03, 0xFC0F, H|TYPE_F, "TRC", }, /* Transfer Register Complement # */
|
|
{ 0x2C04, 0xFC0F, H|TYPE_F, "TRN", }, /* Transfer Register Negative # */
|
|
{ 0x2C05, 0xFC0F, H|TYPE_F, "XCR", }, /* Exchange Registers # */
|
|
{ 0x2C07, 0xFC0F, H|TYPE_G, "LMAP", }, /* Load MAP * */
|
|
{ 0x2C08, 0xFC0F, H|TYPE_F, "TRRM", }, /* Transfer Register to Register Masked # */
|
|
{ 0x2C09, 0xFC0F, H|TYPE_G, "SETCPU", }, /* Set CPU Mode # * */
|
|
{ 0x2C0A, 0xFC0F, H|TYPE_F, "TMAPR", }, /* Transfer MAP to Register # * */
|
|
{ 0x2C0B, 0xFC0F, H|TYPE_F, "TRCM", }, /* Transfer Register Complement Masked # */
|
|
{ 0x2C0C, 0xFC0F, H|TYPE_F, "TRNM", }, /* Transfer Register Negative Masked # */
|
|
{ 0x2C0D, 0xFC0F, H|TYPE_F, "XCRM", }, /* Exchange Registers Masked # */
|
|
{ 0x2C0E, 0xFC0F, H|TYPE_F, "TRSC", }, /* Transfer Register to Scratchpad # * */
|
|
{ 0x2C0F, 0xFC0F, H|TYPE_F, "TSCR", }, /* Transfer Scratchpad to Register # * */
|
|
{ 0x3000, 0xFC0F, X|H|TYPE_F, "CALM", }, /* Call Monitor 32/55 # */
|
|
{ 0x3400, 0xFC00, N|TYPE_D, "LA", }, /* Load Address NBR Note! FW instruction */
|
|
{ 0x3800, 0xFC0F, H|TYPE_F, "ADR", }, /* Add Register to Register # */
|
|
{ 0x3801, 0xFC0F, H|TYPE_F, "ADRFW", }, /* Add Floating Point to Register # */
|
|
{ 0x3802, 0xFC0F, B|H|TYPE_F, "MPR", }, /* Multiply Register BR # */
|
|
{ 0x3803, 0xFC0F, H|TYPE_F, "SURFW", }, /* Subtract Floating Point Register # */
|
|
{ 0x3804, 0xFC0F, H|TYPE_F, "DVRFW", }, /* Divide Floating Point Register # */
|
|
{ 0x3805, 0xFC0F, H|TYPE_F, "FIXW", }, /* Fix Floating Point Register # */
|
|
{ 0x3806, 0xFC0F, H|TYPE_F, "MPRFW", }, /* Multiply Floating Point Register # */
|
|
{ 0x3807, 0xFC0F, H|TYPE_F, "FLTW", }, /* Float Floating Point Register # */
|
|
{ 0x3808, 0xFC0F, H|TYPE_F, "ADRM", }, /* Add Register to Register Masked # */
|
|
{ 0x3809, 0xFC0F, H|TYPE_F, "ADRFD", }, /* Add Floating Point Register to Register # */
|
|
{ 0x380A, 0xFC0F, B|H|TYPE_F, "DVR", }, /* Divide Register by Registier BR # */
|
|
{ 0x380B, 0xFC0F, H|TYPE_F, "SURFD", }, /* Subtract Floating Point Double # */
|
|
{ 0x380C, 0xFC0F, H|TYPE_F, "DVRFD", }, /* Divide Floating Point Double # */
|
|
{ 0x380D, 0xFC0F, H|TYPE_F, "FIXD", }, /* Fix Double Register # */
|
|
{ 0x380E, 0xFC0F, H|TYPE_F, "MPRFD", }, /* Multiply Double Register # */
|
|
{ 0x380F, 0xFC0F, H|TYPE_F, "FLTD", }, /* Float Double # */
|
|
{ 0x3C00, 0xFC0F, H|TYPE_F, "SUR", }, /* Subtract Register to Register # */
|
|
{ 0x3C08, 0xFC0F, H|TYPE_F, "SURM", }, /* Subtract Register to Register Masked # */
|
|
{ 0x4000, 0xFC0F, N|H|TYPE_F, "MPR", }, /* Multiply Register to Register # NBR */
|
|
{ 0x4400, 0xFC0F, N|H|TYPE_F, "DVR", }, /* Divide Register to Register # NBR */
|
|
{ 0x5000, 0xFC08, B|TYPE_D, "LABRM", }, /* Load Address BR Mode */
|
|
{ 0x5400, 0xFC08, B|TYPE_A, "STWBR", }, /* Store Base Register BR Only */
|
|
{ 0x5800, 0xFC08, B|TYPE_A, "SUABR", }, /* Subtract Base Register BR Only */
|
|
{ 0x5808, 0xFC08, B|TYPE_D, "LABR", }, /* Load Address Base Register BR Only */
|
|
{ 0x5C00, 0xFC08, B|TYPE_A, "LWBR", }, /* Load Base Register BR Only */
|
|
{ 0x5C08, 0xFF88, B|TYPE_B, "BSUBM", }, /* Branch Subroutine Memory BR Only */
|
|
{ 0x5C08, 0xFC08, B|TYPE_B, "CALLM", }, /* Call Memory BR Only */
|
|
{ 0x6000, 0xFC0F, N|H|TYPE_F, "NOR", }, /* Normalize # NBR Only */
|
|
{ 0x6400, 0xFC0F, N|H|TYPE_F, "NORD", }, /* Normalize Double # NBR Only */
|
|
{ 0x6800, 0xFC0F, N|H|TYPE_F, "SCZ", }, /* Shift and Count Zeros # */
|
|
{ 0x6C00, 0xFC40, N|H|TYPE_I, "SRA", }, /* Shift Right Arithmetic # NBR */
|
|
{ 0x6C40, 0xFC40, N|H|TYPE_I, "SLA", }, /* Shift Left Arithmetic # NBR */
|
|
{ 0x7000, 0xFC40, N|H|TYPE_I, "SRL", }, /* Shift Right Logical # NBR */
|
|
{ 0x7040, 0xFC40, N|H|TYPE_I, "SLL", }, /* Shift Left Logical # NBR */
|
|
{ 0x7400, 0xFC40, N|H|TYPE_I, "SRC", }, /* Shift Right Circular # NBR */
|
|
{ 0x7440, 0xFC40, N|H|TYPE_I, "SLC", }, /* Shift Left Circular # NBR */
|
|
{ 0x7800, 0xFC40, N|H|TYPE_I, "SRAD", }, /* Shift Right Arithmetic Double # NBR */
|
|
{ 0x7840, 0xFC40, N|H|TYPE_I, "SLAD", }, /* Shift Left Arithmetic Double # NBR */
|
|
{ 0x7C00, 0xFC40, N|H|TYPE_I, "SRLD", }, /* Shift Right Logical Double # NBR */
|
|
{ 0x7C40, 0xFC40, N|H|TYPE_I, "SLLD", }, /* Shift Left Logical Double # NBR */
|
|
{ 0x8000, 0xFC08, TYPE_A, "LEAR", }, /* Load Effective Address Real * */
|
|
{ 0x8400, 0xFC00, TYPE_A, "ANM", }, /* And Memory B,H,W,D */
|
|
{ 0x8800, 0xFC00, TYPE_A, "ORM", }, /* Or Memory B,H,W,D */
|
|
{ 0x8C00, 0xFC00, TYPE_A, "EOM", }, /* Exclusive Or Memory */
|
|
{ 0x9000, 0xFC00, TYPE_A, "CAM", }, /* Compare Arithmetic with Memory */
|
|
{ 0x9400, 0xFC00, TYPE_A, "CMM", }, /* Compare Masked with Memory */
|
|
{ 0x9800, 0xFC00, TYPE_D, "SBM", }, /* Set Bit in Memory */
|
|
{ 0x9C00, 0xFC00, TYPE_D, "ZBM", }, /* Zero Bit in Memory */
|
|
{ 0xA000, 0xFC00, TYPE_D, "ABM", }, /* Add Bit in Memory */
|
|
{ 0xA400, 0xFC00, TYPE_D, "TBM", }, /* Test Bit in Memory */
|
|
{ 0xA800, 0xFC00, TYPE_B, "EXM", }, /* Execute Memory */
|
|
{ 0xAC00, 0xFC00, TYPE_A, "L", }, /* Load B,H,W,D */
|
|
{ 0xB000, 0xFC00, TYPE_A, "LM", }, /* Load Masked B,H,W,D */
|
|
{ 0xB400, 0xFC00, TYPE_A, "LN", }, /* Load Negative B,H,W,D */
|
|
{ 0xB800, 0xFC00, TYPE_A, "ADM", }, /* Add Memory B,H,W,D */
|
|
{ 0xBC00, 0xFC00, TYPE_A, "SUM", }, /* Subtract Memory B,H,W,D */
|
|
{ 0xC000, 0xFC00, TYPE_A, "MPM", }, /* Multiply Memory B,H,W,D */
|
|
{ 0xC400, 0xFC00, TYPE_A, "DVM", }, /* Divide Memory B,H,W,D */
|
|
{ 0xC800, 0xFC0F, TYPE_C, "LI", }, /* Load Immediate */
|
|
{ 0xC801, 0xFC0F, TYPE_C, "ADI", }, /* Add Immediate */
|
|
{ 0xC802, 0xFC0F, TYPE_C, "SUI", }, /* Subtract Immediate */
|
|
{ 0xC803, 0xFC0F, TYPE_C, "MPI", }, /* Multiply Immediate */
|
|
{ 0xC804, 0xFC0F, TYPE_C, "DVI", }, /* Divide Immediate */
|
|
{ 0xC805, 0xFC0F, TYPE_C, "CI", }, /* Compare Immediate */
|
|
{ 0xC806, 0xFC0F, TYPE_N, "SVC", }, /* Supervisor Call */
|
|
{ 0xC807, 0xFC0F, TYPE_G, "EXR", }, /* Execute Register/ Right */
|
|
{ 0xC808, 0xFC0F, X|TYPE_A, "SEM", }, /* Store External Map 32/7X * */
|
|
{ 0xC809, 0xFC0F, X|TYPE_A, "LEM", }, /* Load External Map 32/7X * */
|
|
{ 0xC80A, 0xFC0F, X|TYPE_A, "CEMA", }, /* Convert External Map 32/7X * */
|
|
{ 0xCC00, 0xFC08, TYPE_A, "LF", }, /* Load File */
|
|
{ 0xCC08, 0xFC08, TYPE_A, "LFBR", }, /* Load Base File */
|
|
{ 0xD000, 0xFC00, N|TYPE_A, "LEA", }, /* Load Effective Address # NBR */
|
|
{ 0xD400, 0xFC00, TYPE_A, "ST", }, /* Store B,H,W,D */
|
|
{ 0xD800, 0xFC00, TYPE_A, "STM", }, /* Store Masked B,H,W,D */
|
|
{ 0xDC00, 0xFC08, TYPE_A, "STF", }, /* Store File */
|
|
{ 0xDC08, 0xFC08, TYPE_A, "STFBR", }, /* Store Base File */
|
|
{ 0xE000, 0xFC08, TYPE_A, "SUF", }, /* Subtract Floating Memory D,W */
|
|
{ 0xE008, 0xFC08, TYPE_A, "ADF", }, /* Add Floating Memory D,W */
|
|
{ 0xE400, 0xFC08, TYPE_A, "DVF", }, /* Divide Floating Memory D,W */
|
|
{ 0xE408, 0xFC08, TYPE_A, "MPF", }, /* Multiply Floating Memory D,W */
|
|
{ 0xE800, 0xFC00, TYPE_A, "ARM", }, /* Add Register to Memory B,H,W,D */
|
|
{ 0xEC00, 0xFF80, TYPE_B, "BU", }, /* Branch Unconditional */
|
|
{ 0xEC00, 0xFF80, TYPE_A, "BCT", }, /* Branch Condition True */
|
|
{ 0xEC80, 0xFF80, TYPE_B, "BS", }, /* Branch Condition True CC1 = 1 */
|
|
{ 0xED00, 0xFF80, TYPE_B, "BGT", }, /* Branch Condition True CC2 = 1 */
|
|
{ 0xED80, 0xFF80, TYPE_B, "BLT", }, /* Branch Condition True CC3 = 1 */
|
|
{ 0xEE00, 0xFF80, TYPE_B, "BEQ", }, /* Branch Condition True CC4 = 1 */
|
|
{ 0xEE80, 0xFF80, TYPE_B, "BGE", }, /* Branch Condition True CC2|CC4 = 1 */
|
|
{ 0xEF00, 0xFF80, TYPE_B, "BLE", }, /* Branch Condition True CC3|CC4 = 1 */
|
|
{ 0xEF80, 0xFF80, TYPE_B, "BANY", }, /* Branch Condition True CC1|CC2|CC3|CC4 */
|
|
{ 0xF000, 0XFF80, TYPE_B, "BFT", }, /* Branch Function True */
|
|
{ 0xF000, 0xFF80, TYPE_A, "BCF", }, /* Branch Condition False */
|
|
{ 0xF080, 0xFF80, TYPE_B, "BNS", }, /* Branch Condition False CC1 = 0 */
|
|
{ 0xF100, 0xFF80, TYPE_B, "BNP", }, /* Branch Condition False CC2 = 0 */
|
|
{ 0xF180, 0xFF80, TYPE_B, "BNN", }, /* Branch Condition False CC3 = 0 */
|
|
{ 0xF200, 0xFF80, TYPE_B, "BNE", }, /* Branch Condition False CC4 = 0 */
|
|
{ 0xF280, 0xFF80, TYPE_B, "BCF 5,", }, /* Branch Condition False CC2|CC4 = 0 */
|
|
{ 0xF300, 0xFF80, TYPE_B, "BCF 6,", }, /* Branch Condition False CC3|CC4 = 0 */
|
|
{ 0xF380, 0xFF80, TYPE_B, "BAZ", }, /* Branch Condition False CC1|CC2|CC3|CC4=0*/
|
|
{ 0xF400, 0xFC70, TYPE_D, "BIB", }, /* Branch after Incrementing Byte */
|
|
{ 0xF420, 0xFC70, TYPE_D, "BIH", }, /* Branch after Incrementing Half */
|
|
{ 0xF440, 0xFC70, TYPE_D, "BIW", }, /* Branch after Incrementing Word */
|
|
{ 0xF460, 0xFC70, TYPE_D, "BID", }, /* Branch after Incrementing Double */
|
|
{ 0xF800, 0xFF80, TYPE_E, "ZM", }, /* Zero Memory B,H,W,D */
|
|
{ 0xF880, 0xFF80, TYPE_B, "BL", }, /* Branch and Link */
|
|
{ 0xF900, 0xFCC0, X|TYPE_B, "BRI", }, /* Branch and Reset Interrupt 32/55 * */
|
|
{ 0xF980, 0xFF80, TYPE_B, "LPSD", }, /* Load Program Status Double * */
|
|
{ 0xFA08, 0xFC00, TYPE_B, "JWCS", }, /* Jump to Writable Control Store * */
|
|
{ 0xFA80, 0xFF80, TYPE_B, "LPSDCM", }, /* LPSD and Change Map * */
|
|
{ 0xFB00, 0xFCC0, X|TYPE_A, "TRP", }, /* Transfer Register to Protect Register 32/7X */
|
|
{ 0xFB80, 0xFCC0, X|TYPE_A, "TPR", }, /* Transfer Protect Register to Register 32/7X */
|
|
{ 0xFC00, 0xFC07, TYPE_L, "EI", }, /* Enable Interrupt */
|
|
{ 0xFC01, 0xFC07, TYPE_L, "DI", }, /* Disable Interrupt */
|
|
{ 0xFC02, 0xFC07, TYPE_L, "RI", }, /* Request Interrupt */
|
|
{ 0xFC03, 0xFC07, TYPE_L, "AI", }, /* Activate Interrupt */
|
|
{ 0xFC04, 0xFC07, TYPE_L, "DAI", }, /* Deactivate Interrupt */
|
|
{ 0xFC05, 0xFC07, TYPE_M, "TD", }, /* Test Device */
|
|
{ 0xFC06, 0xFC07, TYPE_M, "CD", }, /* Command Device */
|
|
{ 0xFC17, 0xFC7F, TYPE_C, "SIO", }, /* Start I/O */
|
|
{ 0xFC1F, 0xFC7F, TYPE_C, "TIO", }, /* Test I/O */
|
|
{ 0xFC27, 0xFC7F, TYPE_C, "STPIO", }, /* Stop I/O */
|
|
{ 0xFC2F, 0xFC7F, TYPE_C, "RSCHNL", }, /* Reset Channel */
|
|
{ 0xFC37, 0xFC7F, TYPE_C, "HIO", }, /* Halt I/O */
|
|
{ 0xFC3F, 0xFC7F, TYPE_C, "GRIO", }, /* Grab Controller */
|
|
{ 0xFC47, 0xFC7F, TYPE_C, "RSCTL", }, /* Reset Controller */
|
|
{ 0xFC4F, 0xFC7F, TYPE_C, "ECWCS", }, /* Enable Channel WCS Load */
|
|
{ 0xFC5F, 0xFC7F, TYPE_C, "WCWCS", }, /* Write Channel WCS */
|
|
{ 0xFC67, 0xFC7F, TYPE_C, "ECI", }, /* Enable Channel Interrupt */
|
|
{ 0xFC6F, 0xFC7F, TYPE_C, "DCI", }, /* Disable Channel Interrupt */
|
|
{ 0xFC77, 0xFC7F, TYPE_C, "ACI", }, /* Activate Channel Interrupt */
|
|
{ 0xFC7F, 0xFC7F, TYPE_C, "DACI", }, /* Deactivate Channel Interrupt */
|
|
};
|
|
|
|
/* Instruction decode printing routine
|
|
Inputs:
|
|
*of = output stream
|
|
val = 16/32 bit instruction to print left justified
|
|
sw = mode switches, 'M'=base mode, 'N'=nonbase mode
|
|
*/
|
|
const char *fc_type = "WHDHBBBB"; /* F & C bit values */
|
|
|
|
int fprint_inst(FILE *of, uint32 val, int32 sw)
|
|
{
|
|
uint16 inst = (val >> 16) & 0xFFFF;
|
|
int i;
|
|
int mode = 0; /* assume non base mode instructions */
|
|
t_opcode *tab;
|
|
|
|
if ((PSD[0] & 0x02000000) || (sw & SWMASK('M'))) /* bit 6 is base mode */
|
|
mode = 1;
|
|
/* loop through the instruction table for an opcode match and get the type */
|
|
for (tab = optab; tab->name != NULL; tab++) {
|
|
if (tab->opbase == (inst & tab->mask)) {
|
|
if (mode && (tab->type & (X | N)))
|
|
continue; /* non basemode instruction in base mode, skip */
|
|
if (!mode && (tab->type & B))
|
|
continue; /* basemode instruction in nonbase mode, skip */
|
|
|
|
/* TODO? Maybe want to make sure MODEL is 32/7X for X type instructions */
|
|
|
|
/* match found */
|
|
fputs(tab->name, of); /* output the base opcode */
|
|
|
|
/* process the other fields of the instruction */
|
|
switch(tab->type & 0xF) {
|
|
/* memory reference instruction */
|
|
case TYPE_A: /* r,[*]o[,x] or r,o[(b)][,x] */
|
|
/* zero memory instruction */
|
|
case TYPE_E: /* [*]o[,x] or o[(b)][,x] */
|
|
/* append B, H, W, D to base instruction using F & C bits */
|
|
i = (val & 3) | ((inst >> 1) & 04);
|
|
if (((inst&0xfc00) == 0xe000) ||
|
|
((inst&0xfc00) == 0xe400))
|
|
i &= ~4; /* remove f bit from fpt instr */
|
|
if (((inst&0xfc00) != 0xdc00) &&
|
|
((inst&0xfc00) != 0xd000) &&
|
|
((inst&0xfc00) != 0x5400) &&
|
|
((inst&0xfc00) != 0x5800) &&
|
|
((inst&0xfc00) != 0x5c00) &&
|
|
((inst&0xfc00) != 0xcc00) &&
|
|
((inst&0xfc00) != 0x8000))
|
|
fputc(fc_type[i], of);
|
|
/* Fall through */
|
|
|
|
/* BIx instructions or bit in memory reference instructions */
|
|
case TYPE_D: /* r,[*]o[,x] or r,o[(b)],[,x] */
|
|
if ((tab->type & 0xF) != TYPE_E) {
|
|
fputc(' ', of);
|
|
// fputc('R', of);
|
|
/* output the reg or bit number */
|
|
fputc('0'+((inst>>7) & 07), of);
|
|
fputc(',', of);
|
|
}
|
|
/* Fall through */
|
|
|
|
/* branch instruction */
|
|
case TYPE_B: /* [*]o[,x] or o[(b)],[,x] */
|
|
if (((tab->type & 0xf) != TYPE_A) && ((tab->type & 0xf) != TYPE_D))
|
|
fputc(' ', of);
|
|
if (mode) {
|
|
/* base reg mode */
|
|
fprint_val(of, val&0xffff, 16, 16, PV_LEFT); /* output 16 bit offset */
|
|
if (inst & 07) {
|
|
fputc('(', of);
|
|
// fputc('B', of);
|
|
fputc(('0'+(inst & 07)), of); /* output the base reg number */
|
|
fputc(')', of);
|
|
}
|
|
if (inst & 0x70) {
|
|
fputc(',', of);
|
|
// fputc('R', of);
|
|
fputc(('0'+((inst >> 4) & 07)), of); /* output the index reg number */
|
|
}
|
|
} else {
|
|
/* nonbase reg mode */
|
|
if (inst & 0x10)
|
|
fputc('*', of); /* show indirection */
|
|
fprint_val(of, val&0x7ffff, 16, 19, PV_LEFT); /* 19 bit offset */
|
|
if (inst & 0x60) {
|
|
fputc(',', of); /* register coming */
|
|
// fputc('R', of);
|
|
if (tab->type != TYPE_D)
|
|
fputc('0'+((inst & 0x60) >> 5), of); /* output the index reg number */
|
|
else {
|
|
if ((inst & 0xfc00) != 0xf400)
|
|
fputc('0'+((inst & 0x60) >> 5), of); /* output the index reg number */
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
/* immediate or XIO instructions */
|
|
case TYPE_C: /* r,v */
|
|
fputc(' ', of);
|
|
// fputc('R', of);
|
|
fputc('0'+((inst>>7) & 07), of); /* index reg number */
|
|
fputc(',', of);
|
|
fprint_val(of, val&0xffff, 16, 16, PV_LEFT); /* 16 bit imm val or chan/suba */
|
|
break;
|
|
|
|
/* reg - reg instructions */
|
|
case TYPE_F: /* rs,rd */
|
|
fputc(' ', of);
|
|
// fputc('R', of);
|
|
fputc('0'+((inst>>4) & 07), of); /* src reg */
|
|
fputc(',', of);
|
|
// fputc('R', of);
|
|
fputc('0'+((inst>>7) & 07), of); /* dest reg */
|
|
break;
|
|
|
|
/* single reg instructions */
|
|
case TYPE_G: /* op r */
|
|
fputc(' ', of);
|
|
// fputc('R', of);
|
|
fputc('0'+((inst>>7) & 07), of); /* output src/dest reg num */
|
|
break;
|
|
|
|
/* just output the instruction */
|
|
case TYPE_H: /* empty */
|
|
break;
|
|
|
|
/* reg and bit shift cnt */
|
|
case TYPE_I: /* r,b */
|
|
fputc(' ', of);
|
|
// fputc('R', of);
|
|
fputc('0'+((inst>>7) & 07), of); /* reg number */
|
|
fputc(',', of);
|
|
fprint_val(of, inst&0x1f, 10, 5, PV_LEFT); /* 5 bit shift count */
|
|
break;
|
|
|
|
/* register bit operations */
|
|
case TYPE_K: /* r,rb */
|
|
fputc(' ', of);
|
|
// fputc('R', of);
|
|
fputc('0'+((inst>>4) & 07), of); /* register number */
|
|
fputc(',', of);
|
|
i = ((inst & 3) << 3) | ((inst >> 7) & 07);
|
|
fprint_val(of, i, 10, 5, PV_LEFT); /* reg bit number to operate on */
|
|
break;
|
|
|
|
/* interrupt control instructions */
|
|
case TYPE_L: /* i */
|
|
fputc(' ', of);
|
|
fprint_val(of, (inst>>3)&0x7f, 16, 7, PV_RZRO); /* output 7 bit priority level value */
|
|
break;
|
|
|
|
/* CD/TD Class E I/O instructions */
|
|
case TYPE_M: /* i,v */
|
|
fputc(' ', of);
|
|
fprint_val(of, (inst>>3)&0x7f, 16, 7, PV_RZRO); /* output 7 bit device address */
|
|
fputc(',', of);
|
|
fprint_val(of, (val&0xffff), 16, 16, PV_RZRO); /* output 16 bit command code */
|
|
break;
|
|
|
|
/* SVC instructions */
|
|
case TYPE_N: /* i,v */
|
|
fputc(' ', of);
|
|
fprint_val(of, (val>>12)&0xf, 16, 4, PV_RZRO); /* output 4 bit svc number */
|
|
fputc(',', of);
|
|
fprint_val(of, (val & 0xFFF), 16, 12, PV_LEFT); /* output 12 bit command code */
|
|
break;
|
|
|
|
default:
|
|
/* FIXME - return error code here? */
|
|
// /* fputs(" unknown type", of); /* output error message */
|
|
// return SCPE_ARG; /* unknown type */
|
|
break;
|
|
}
|
|
/* return the size of the instruction */
|
|
return (tab->type & H) ? 2 : 4;
|
|
}
|
|
}
|
|
/* FIXME - should we just return error here? or dump as hex data? */
|
|
/* we get here if opcode not found, print data value */
|
|
if (mode)
|
|
fputs(" Binvld ", of); /* output basemode error message */
|
|
else
|
|
fputs(" Ninvld ", of); /* output non-basmode error message */
|
|
fprint_val(of, val, 16, 32, PV_RZRO); /* output unknown 32 bit instruction code */
|
|
return 4; /* show as full word size */
|
|
}
|
|
|
|
/* Symbolic decode
|
|
|
|
Inputs:
|
|
*of = output stream
|
|
addr = current PC
|
|
*val = pointer to values
|
|
*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)
|
|
{
|
|
int i;
|
|
int l = 4; /* default to full words */
|
|
int rdx = 16; /* default radex is hex */
|
|
uint32 num;
|
|
|
|
if (sw & SIM_SW_STOP) { /* special processing for step */
|
|
if (PSD[0] & 0x02000000) { /* bit 6 is base mode */
|
|
sw |= SWMASK('M'); /* display basemode */
|
|
sw &= ~SWMASK('N'); /* no non-based display */
|
|
} else {
|
|
sw |= SWMASK('N'); /* display non-basemode */
|
|
sw &= ~SWMASK('M'); /* no basemode display */
|
|
}
|
|
}
|
|
if (addr & 0x02)
|
|
l = 2;
|
|
/* determine base for number output */
|
|
if (sw & SWMASK ('D'))
|
|
rdx = 10; /* decimal */
|
|
else
|
|
if (sw & SWMASK ('O'))
|
|
rdx = 8; /* octal */
|
|
else
|
|
if (sw & SWMASK ('H'))
|
|
rdx = 16; /* hex */
|
|
|
|
if (sw & SWMASK ('M')) { /* machine base mode? */
|
|
sw &= ~ SWMASK('B'); /* Can't do B and M at same time */
|
|
sw &= ~ SWMASK('C'); /* Can't do C and M at same time */
|
|
if (addr & 0x02)
|
|
l = 2;
|
|
else
|
|
l = 4;
|
|
} else
|
|
if (sw & SWMASK('F')) {
|
|
l = 4; /* words are 4 bytes */
|
|
} else
|
|
if (sw & SWMASK('W')) {
|
|
l = 2; /* halfwords are 2 bytes */
|
|
} else
|
|
if (sw & SWMASK('B')) {
|
|
l = 1; /* bytes */
|
|
}
|
|
|
|
if (sw & SWMASK ('C')) {
|
|
fputc('\'', of); /* opening apostorphe */
|
|
for (i = 0; i < l; i++) {
|
|
int ch = val[i] & 0xff; /* get the char */
|
|
if (ch >= 0x20 && ch <= 0x7f) /* see if printable */
|
|
fprintf(of, "%c", ch); /* output the ascii char */
|
|
else
|
|
fputc('_', of); /* use underscore for unprintable char */
|
|
}
|
|
fputc('\'', of); /* closing apostorphe */
|
|
} else
|
|
/* go print the symbolic instruction for base or nonbase mode */
|
|
if (sw & (SWMASK('M') | SWMASK('N'))) {
|
|
num = 0;
|
|
for (i = 0; i < l && i < 4; i++) {
|
|
num |= (uint32)val[i] << ((l-i-1) * 8); /* collect 8-32 bit data value to print */
|
|
}
|
|
if (addr & 0x02)
|
|
num <<= 16; /* use rt hw */
|
|
l = fprint_inst(of, num, sw); /* go print the instruction */
|
|
if (((addr & 2) == 0) && (l == 2)) { /* did we execute a left halfword instruction */
|
|
fprintf(of, "; ");
|
|
l = fprint_inst(of, num<<16, sw); /* go print right halfword instruction */
|
|
l = 4; /* next word address */
|
|
}
|
|
} else {
|
|
/* print the numeric value of the memory data */
|
|
num = 0;
|
|
for (i = 0; i < l && i < 4; i++)
|
|
num |= (uint32)val[i] << ((l-i-1) * 8); /* collect 8-32 bit data value to print */
|
|
fprint_val(of, num, rdx, l*8, PV_RZRO); /* print it in requested radix */
|
|
}
|
|
return -(l-1); /* will be negative if we did anything */
|
|
}
|
|
|
|
/*
|
|
* Collect offset in radix.
|
|
*/
|
|
t_stat get_off (CONST char *cptr, CONST char **tptr, uint32 radix, t_value *val, char *m)
|
|
{
|
|
t_stat r = SCPE_OK; /* assume OK return */
|
|
|
|
*m = 0; /* left parend found flag if set */
|
|
*val = (uint32)strtotv(cptr, tptr, radix); /* convert to value */
|
|
if (cptr == *tptr)
|
|
r = SCPE_ARG; /* no argument found error */
|
|
else {
|
|
cptr = *tptr; /* where to start looking */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip any spaces */
|
|
if (*cptr++ == '(') {
|
|
*m = 1; /* show we found a left parend */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip any spaces */
|
|
}
|
|
*tptr = cptr; /* return next char pointer */
|
|
}
|
|
return r; /* return status */
|
|
}
|
|
|
|
/*
|
|
* Collect immediate in radix.
|
|
*/
|
|
t_stat get_imm (CONST char *cptr, CONST char **tptr, uint32 radix, t_value *val)
|
|
{
|
|
t_stat r;
|
|
|
|
r = SCPE_OK;
|
|
*val = (uint32)strtotv (cptr, tptr, radix);
|
|
if ((cptr == *tptr) || (*val > 0xffff))
|
|
r = SCPE_ARG;
|
|
else {
|
|
cptr = *tptr;
|
|
while (sim_isspace (*cptr)) cptr++;
|
|
*tptr = cptr;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
/* 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)
|
|
{
|
|
int i;
|
|
int x;
|
|
int l = 4; /* default to full words */
|
|
int rdx = 16; /* default radex is hex */
|
|
char mod = 0;
|
|
t_opcode *tab;
|
|
t_stat r;
|
|
uint32 num;
|
|
uint32 max[5] = {0, 0xff, 0xffff, 0, 0xffffffff};
|
|
CONST char *tptr;
|
|
char gbuf[CBUFSIZE];
|
|
|
|
/* determine base for numbers */
|
|
if (sw & SWMASK ('D'))
|
|
rdx = 10; /* decimal */
|
|
else
|
|
if (sw & SWMASK ('O'))
|
|
rdx = 8; /* octal */
|
|
else
|
|
if (sw & SWMASK ('H'))
|
|
rdx = 16; /* hex */
|
|
|
|
/* set instruction size */
|
|
if (sw & SWMASK('F')) {
|
|
l = 4;
|
|
} else
|
|
if (sw & SWMASK('W')) {
|
|
l = 2;
|
|
}
|
|
|
|
/* process a character string */
|
|
if (sw & SWMASK ('C')) {
|
|
cptr = get_glyph_quoted(cptr, gbuf, 0); /* Get string */
|
|
for (i = 0; gbuf[i] != 0; i++) {
|
|
val[i] = gbuf[i]; /* copy in the string */
|
|
}
|
|
return -(i - 1);
|
|
}
|
|
|
|
/* see if we are processing a nonbase instruction */
|
|
if (sw & SWMASK ('N')) {
|
|
/* process nonbased instruction */
|
|
cptr = get_glyph(cptr, gbuf, 0); /* Get uppercase opcode */
|
|
l = strlen(gbuf); /* opcode length */
|
|
/* try to find the opcode in the table */
|
|
for (tab = optab; tab->name != NULL; tab++) {
|
|
i = tab->type & 0xf; /* get the instruction type */
|
|
/* check for memory reference instruction */
|
|
if (i == TYPE_A || i == TYPE_E) {
|
|
/* test for base opcode name without B, H, W, D applied */
|
|
if (sim_strncasecmp(tab->name, gbuf, l - 1) == 0)
|
|
break; /* found */
|
|
} else
|
|
/* test the full opcode name */
|
|
if (sim_strcasecmp(tab->name, gbuf) == 0)
|
|
break; /* found */
|
|
}
|
|
if (tab->name == NULL) /* see if anything found */
|
|
return SCPE_ARG; /* no, return invalid argument error */
|
|
num = tab->opbase<<16; /* get the base opcode value */
|
|
|
|
/* process each instruction type */
|
|
switch(i) {
|
|
/* mem ref instruction */
|
|
case TYPE_A: /* c r,[*]o[,x] */
|
|
/* zero memory instruction */
|
|
case TYPE_E: /* c [*]o[,x] */
|
|
switch(gbuf[l]) {
|
|
case 'B': num |= 0x80000; break; /* byte, set F bit */
|
|
case 'H': num |= 0x00001; break; /* halfword */
|
|
case 'W': num |= 0x00000; break; /* word */
|
|
case 'D': num |= 0x00002; break; /* doubleword */
|
|
default:
|
|
return SCPE_ARG; /* base op suffix error */
|
|
}
|
|
/* Fall through */
|
|
|
|
/* BIx instructions or memory reference */
|
|
case TYPE_D: /* r,[*]o[,x] */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip leading blanks */
|
|
if (i != TYPE_E) {
|
|
/* get reg number except for zero memory instruction */
|
|
if (*cptr >= '0' || *cptr <= '7') { /* reg# is 0-7 */
|
|
x = *cptr++ - '0'; /* get the reg# */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip any blanks */
|
|
if (*cptr++ != ',') /* check for required comma */
|
|
return SCPE_ARG; /* anything else is an argument error */
|
|
num |= x << 23; /* position reg number in instruction */
|
|
} else
|
|
return SCPE_ARG; /* invalid reg number is an argument error */
|
|
}
|
|
/* Fall through */
|
|
|
|
/* branch instruction */
|
|
case TYPE_B: /* [*]o[,x] */
|
|
if (*cptr == '*') { /* test for indirection */
|
|
num |= 0x100000; /* set indirect flag */
|
|
cptr++; /* skip past the '*' */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip blanks */
|
|
}
|
|
if ((r = get_off(cptr, &tptr, 16, val, &mod))) /* get operand address */
|
|
return r; /* argument error if a problem */
|
|
cptr = tptr; /* set pointer to returned next char pointer */
|
|
if (*val > 0x7FFFF) /* 19 bit address max */
|
|
return SCPE_ARG; /* argument error */
|
|
num |= *val; /* or our address into instruction */
|
|
if (mod) {
|
|
return SCPE_ARG; /* if a '(' found, that is an arg error */
|
|
}
|
|
if (*cptr++ == ',') { /* test for optional index reg number */
|
|
if (*cptr >= '0' || *cptr <= '7') { /* reg# is 0-7 */
|
|
x = *cptr++ - '0'; /* get reg number */
|
|
num |= x << 20; /* position and put into instruction */
|
|
} else
|
|
return SCPE_ARG; /* reg# not 0-7, so arg error */
|
|
}
|
|
break;
|
|
|
|
/* immediate or XIO instruction */
|
|
case TYPE_C: /* r,v */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip spaces */
|
|
if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */
|
|
x = *cptr++ - '0'; /* get reg# */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip spaces */
|
|
if (*cptr++ != ',') /* next char need to be a comma */
|
|
return SCPE_ARG; /* it's not, so arg error */
|
|
num |= x << 23; /* position and put into instruction */
|
|
} else
|
|
return SCPE_ARG; /* invalid reg#, so arg error */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip any blanks */
|
|
if ((r = get_imm(cptr, &tptr, rdx, val))) /* get 16 bit immediate value */
|
|
return r; /* return error from conversion */
|
|
num |= *val; /* or in the 16 bit value */
|
|
break;
|
|
|
|
/* reg-reg instructions */
|
|
case TYPE_F: /* r,r */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip blanks */
|
|
if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */
|
|
x = *cptr++ - '0'; /* calc reg# */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip spaces */
|
|
if (*cptr++ != ',') /* test for required ',' */
|
|
return SCPE_ARG; /* it's not there, so error */
|
|
num |= x << 23; /* insert first reg# into instruction */
|
|
} else
|
|
return SCPE_ARG; /* reg# invalid, so arg error */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip more spaces */
|
|
if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */
|
|
x = *cptr++ - '0'; /* calc reg# */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip any spaces */
|
|
num |= x << 20; /* insert 2nd reg# into instruction */
|
|
} else
|
|
return SCPE_ARG; /* reg# invalid, so arg error */
|
|
break;
|
|
|
|
/* single reg instructions */
|
|
case TYPE_G: /* r */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip blanks */
|
|
if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */
|
|
x = *cptr++ - '0'; /* calc reg# */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip spaces */
|
|
num |= x << 23; /* insert first reg# into instruction */
|
|
} else
|
|
return SCPE_ARG; /* reg# invalid, so arg error */
|
|
break;
|
|
|
|
/* opcode only instructions */
|
|
case TYPE_H: /* empty */
|
|
break;
|
|
|
|
/* reg and bit shift instructions */
|
|
case TYPE_I: /* r,b */
|
|
while (sim_isspace (*cptr))
|
|
cptr++; /* skip blanks */
|
|
if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */
|
|
x = *cptr++ - '0'; /* calc reg# */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip spaces */
|
|
if (*cptr++ != ',') /* test for required ',' */
|
|
return SCPE_ARG; /* it's not there, so error */
|
|
num |= (x << 23); /* insert first reg# into instruction */
|
|
} else
|
|
return SCPE_ARG; /* reg# invalid, so arg error */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip any blanks */
|
|
if ((r = get_imm(cptr, &tptr, 10, val))) /* get 5 bit shift value */
|
|
return r; /* return error from conversion */
|
|
if (*val > 0x1f) /* 5 bit max count */
|
|
return SCPE_ARG; /* invalid shift count */
|
|
num |= (*val << 16); /* or in the 5 bit value */
|
|
break;
|
|
|
|
/* register bit operations */
|
|
case TYPE_K: /* r,rb */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip blanks */
|
|
if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */
|
|
x = *cptr++ - '0'; /* calc reg# */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip spaces */
|
|
if (*cptr++ != ',') /* test for required ',' */
|
|
return SCPE_ARG; /* it's not there, so error */
|
|
num |= (x << 20); /* insert reg# into instruction */
|
|
} else
|
|
return SCPE_ARG; /* reg# invalid, so arg error */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip any blanks */
|
|
if ((r = get_imm(cptr, &tptr, 10, val))) /* get 5 bit bit number */
|
|
return r; /* return error from conversion */
|
|
if (*val > 0x1f) /* 5 bit max count */
|
|
return SCPE_ARG; /* invalid bit count */
|
|
x = *val / 8; /* get 2 bit byte number */
|
|
num |= (x & 3) << 16; /* insert 2 bit byte code into instruction */
|
|
x = *val % 8; /* get bit in byte value */
|
|
num |= (x & 7) << 23; /* or in the bit value */
|
|
break;
|
|
|
|
/* interrupt control instructions */
|
|
case TYPE_L: /* i */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip any blanks */
|
|
if ((r = get_imm(cptr, &tptr, rdx, val))) /* get 7 bit bit number */
|
|
return r; /* return error from conversion */
|
|
if (*val > 0x7f) /* 7 bit max count */
|
|
return SCPE_ARG; /* invalid value */
|
|
num |= (*val & 0x7f) << 19; /* or in the interrupt level */
|
|
break;
|
|
|
|
/* CD/TD Class E I/O instructions */
|
|
case TYPE_M: /* d,v */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip any blanks */
|
|
if ((r = get_imm(cptr, &tptr, rdx, val))) /* get 7 bit bit number */
|
|
return r; /* return error from conversion */
|
|
if (*val > 0x7f) /* 7 bit max count */
|
|
return SCPE_ARG; /* invalid value */
|
|
num |= (*val & 0x7f) << 19; /* or in the device address */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip any blanks */
|
|
if ((r = get_imm(cptr, &tptr, rdx, val))) /* get 16 bit command code */
|
|
return r; /* return error from conversion */
|
|
num |= *val; /* or in the 16 bit value */
|
|
break;
|
|
}
|
|
return (tab->type & H) ? 2 : 4; /* done with nonbased instructions */
|
|
}
|
|
|
|
/* see if we are processing a base mode instruction */
|
|
if (sw & SWMASK ('M')) { /* base mode? */
|
|
/* process base mode instruction */
|
|
cptr = get_glyph(cptr, gbuf, 0); /* Get uppercase opcode */
|
|
l = strlen(gbuf); /* save the num of char in opcode */
|
|
/* loop through the instruction table for an opcode match and get the type */
|
|
for (tab = optab; tab->name != NULL; tab++) {
|
|
i = tab->type & 0xf; /* get the type */
|
|
/* check for memory reference instruction */
|
|
if (i == TYPE_A || i == TYPE_E) {
|
|
/* test for base opcode name without B, H, W, D applied */
|
|
if (sim_strncasecmp(tab->name, gbuf, l - 1) == 0)
|
|
break; /* found */
|
|
} else
|
|
/* test the full opcode name */
|
|
if (sim_strcasecmp(tab->name, gbuf) == 0)
|
|
break; /* found */
|
|
}
|
|
if (tab->name == NULL) /* see if anything found */
|
|
return SCPE_ARG; /* no, return invalid argument error */
|
|
num = tab->opbase<<16; /* get the base opcode value */
|
|
|
|
/* process each instruction type */
|
|
switch(i) {
|
|
/* mem ref instruction */
|
|
case TYPE_A: /* c r,o[(b)][,x] */
|
|
/* zero memory instruction */
|
|
case TYPE_E: /* c o[(b)][,x] */
|
|
switch(gbuf[l]) {
|
|
case 'B': num |= 0x80000; break; /* byte, set F bit */
|
|
case 'H': num |= 0x00001; break; /* halfword */
|
|
case 'W': num |= 0x00000; break; /* word */
|
|
case 'D': num |= 0x00002; break; /* doubleword */
|
|
default:
|
|
return SCPE_ARG; /* base op suffix error */
|
|
}
|
|
/* Fall through */
|
|
|
|
/* BIx instructions or memory reference */
|
|
case TYPE_D: /* r,o[(b)],[,x] */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip leading blanks */
|
|
if (i != TYPE_E) {
|
|
/* get reg number except for zero memory instruction */
|
|
if (*cptr >= '0' || *cptr <= '7') { /* reg# is 0-7 */
|
|
x = *cptr++ - '0'; /* get the reg# */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip any blanks */
|
|
if (*cptr++ != ',') /* check for required comma */
|
|
return SCPE_ARG; /* anything else is an argument error */
|
|
num |= x << 23; /* position reg number in instruction */
|
|
} else
|
|
return SCPE_ARG; /* invalid reg number is an argument error */
|
|
}
|
|
/* Fall through */
|
|
|
|
/* branch instruction */
|
|
case TYPE_B: /* o[(b)],[,x] */
|
|
if ((r = get_off(cptr, &tptr, 16, val, &mod))) /* get offset */
|
|
return r; /* argument error if a problem */
|
|
cptr = tptr; /* set pointer to returned next char pointer */
|
|
if (*val > 0xFFFF) /* 16 bit offset max */
|
|
return SCPE_ARG; /* argument error */
|
|
num |= *val; /* or offset into instruction */
|
|
if (mod) { /* see if '(' found in input */
|
|
if (*cptr >= '0' || *cptr <= '7') { /* base reg# 0-7 */
|
|
x = *cptr++ - '0'; /* get reg number */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip any spaces */
|
|
if (*cptr++ != ')') /* test for closing right parend */
|
|
return SCPE_ARG; /* arg error if not found */
|
|
num |= x << 16; /* put base reg number into instruction */
|
|
} else
|
|
return SCPE_ARG; /* no '(' found, so arg error */
|
|
}
|
|
if (*cptr++ == ',') { /* test for optional index reg number */
|
|
if (*cptr >= '0' || *cptr <= '7') { /* reg# is 0-7 */
|
|
x = *cptr++ - '0'; /* get reg number */
|
|
num |= x << 20; /* position and put into instruction */
|
|
} else
|
|
return SCPE_ARG; /* reg# not 0-7, so arg error */
|
|
}
|
|
break;
|
|
|
|
/* immediate or XIO instruction */
|
|
case TYPE_C: /* r,v */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip spaces */
|
|
if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */
|
|
x = *cptr++ - '0'; /* get reg# */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip spaces */
|
|
if (*cptr++ != ',') /* next char need to be a comma */
|
|
return SCPE_ARG; /* it's not, so arg error */
|
|
num |= x << 23; /* position and put into instruction */
|
|
} else
|
|
return SCPE_ARG; /* invalid reg#, so arg error */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip any blanks */
|
|
if ((r = get_imm(cptr, &tptr, rdx, val))) /* get 16 bit immediate value */
|
|
return r; /* return error from conversion */
|
|
num |= *val; /* or in the 16 bit value */
|
|
break;
|
|
|
|
/* reg-reg instructions */
|
|
case TYPE_F: /* r,r */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip blanks */
|
|
if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */
|
|
x = *cptr++ - '0'; /* calc reg# */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip spaces */
|
|
if (*cptr++ != ',') /* test for required ',' */
|
|
return SCPE_ARG; /* it's not there, so error */
|
|
num |= x << 23; /* insert first reg# into instruction */
|
|
} else
|
|
return SCPE_ARG; /* reg# invalid, so arg error */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip more spaces */
|
|
if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */
|
|
x = *cptr++ - '0'; /* calc reg# */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip any spaces */
|
|
num |= x << 20; /* insert 2nd reg# into instruction */
|
|
} else
|
|
return SCPE_ARG; /* reg# invalid, so arg error */
|
|
break;
|
|
|
|
/* single reg instructions */
|
|
case TYPE_G: /* r */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip blanks */
|
|
if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */
|
|
x = *cptr++ - '0'; /* calc reg# */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip spaces */
|
|
num |= x << 23; /* insert first reg# into instruction */
|
|
} else
|
|
return SCPE_ARG; /* reg# invalid, so arg error */
|
|
break;
|
|
|
|
/* opcode only instructions */
|
|
case TYPE_H: /* empty */
|
|
break;
|
|
|
|
/* reg and bit shift instructions */
|
|
case TYPE_I: /* r,b */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip blanks */
|
|
if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */
|
|
x = *cptr++ - '0'; /* calc reg# */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip spaces */
|
|
if (*cptr++ != ',') /* test for required ',' */
|
|
return SCPE_ARG; /* it's not there, so error */
|
|
num |= (x << 23); /* insert first reg# into instruction */
|
|
} else
|
|
return SCPE_ARG; /* reg# invalid, so arg error */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip any blanks */
|
|
if ((r = get_imm(cptr, &tptr, 10, val))) /* get 5 bit shift value */
|
|
return r; /* return error from conversion */
|
|
if (*val > 0x1f) /* 5 bit max count */
|
|
return SCPE_ARG; /* invalid shift count */
|
|
num |= (*val << 16); /* or in the 5 bit value */
|
|
break;
|
|
|
|
/* register bit operations */
|
|
case TYPE_K: /* r,rb */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip blanks */
|
|
if (*cptr >= '0' || *cptr <= '7') { /* test for valid reg# */
|
|
x = *cptr++ - '0'; /* calc reg# */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip spaces */
|
|
if (*cptr++ != ',') /* test for required ',' */
|
|
return SCPE_ARG; /* it's not there, so error */
|
|
num |= (x << 20); /* insert reg# into instruction */
|
|
} else
|
|
return SCPE_ARG; /* reg# invalid, so arg error */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip any blanks */
|
|
if ((r = get_imm(cptr, &tptr, 10, val))) /* get 5 bit bit number */
|
|
return r; /* return error from conversion */
|
|
if (*val > 0x1f) /* 5 bit max count */
|
|
return SCPE_ARG; /* invalid bit count */
|
|
x = *val / 8; /* get 2 bit byte number */
|
|
num |= (x & 3) << 16; /* insert 2 bit byte code into instruction */
|
|
x = *val % 8; /* get bit in byte value */
|
|
num |= (x & 7) << 23; /* or in the bit value */
|
|
break;
|
|
|
|
/* interrupt control instructions */
|
|
case TYPE_L: /* i */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip any blanks */
|
|
if ((r = get_imm(cptr, &tptr, rdx, val))) /* get 7 bit bit number */
|
|
return r; /* return error from conversion */
|
|
if (*val > 0x7f) /* 7 bit max count */
|
|
return SCPE_ARG; /* invalid value */
|
|
num |= (*val & 0x7f) << 19; /* or in the interrupt level */
|
|
break;
|
|
|
|
/* CD/TD Class E I/O instructions */
|
|
case TYPE_M: /* d,v */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip any blanks */
|
|
if ((r = get_imm(cptr, &tptr, rdx, val))) /* get 7 bit bit number */
|
|
return r; /* return error from conversion */
|
|
if (*val > 0x7f) /* 7 bit max count */
|
|
return SCPE_ARG; /* invalid value */
|
|
num |= (*val & 0x7f) << 19; /* or in the device address */
|
|
while (sim_isspace(*cptr))
|
|
cptr++; /* skip any blanks */
|
|
if ((r = get_imm(cptr, &tptr, rdx, val))) /* get 16 bit command code */
|
|
return r; /* return error from conversion */
|
|
num |= *val; /* or in the 16 bit value */
|
|
break;
|
|
}
|
|
return (tab->type & H) ? 2 : 4; /* done with base mode insrructions */
|
|
}
|
|
|
|
/* get here for any other switch value */
|
|
/* this code will get a value based on length specified in switches */
|
|
num = get_uint(cptr, rdx, max[l], &r); /* get the unsigned value */
|
|
for (i = 0; i < l && i < 4; i++)
|
|
val[i] = (num >> ((l - (1 + i)) * 8)) & 0xff; /* get 1-4 bytes of data */
|
|
return -(l-1);
|
|
}
|
|
|