blob: 869b5b3122b9b2a25cf29264c5712cc036baad9c [file] [log] [blame] [raw]
/*************************************************************************
* *
* $Id: tx0_cpu.c 2066 2009-02-27 15:57:22Z hharte $ *
* *
* Copyright (c) 2009-2017 Howard M. Harte. *
* Based on pdp1_cpu.c, Copyright (c) 1993-2007, Robert M. Supnik *
* *
* 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 HOWARD M. HARTE 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 Howard M. Harte shall *
* not be used in advertising or otherwise to promote the sale, use or *
* other dealings in this Software without prior written authorization *
* of Howard M. Harte. *
* *
* Module Description: *
* TX-0 Central Processor *
* *
* Environment: *
* User mode only *
* *
* References: *
* See: www.bitsavers.org/pdf/mit/tx-0/ for documentation. *
* See: www.bitsavers.org/bits/MIT/tx-0/ for software. *
*************************************************************************/
/*
The original Lincoln Labs TX-0 had only two bits of opcode and no index
register. The machine was moved to room 26-248 at MIT in July 1958 and
after about a year and a half the opcode field was extended to four bits
and an index register was added.
(ref. Computer Museum Report Vol 8, Spring 1984)
--------------------------------------------------------------
Original TX-0 Registers and Instruction Set
from "A Functional Description of the TX-0 Computer" Oct, 1958
--------------------------------------------------------------
The register state for the TX-0 is:
MBR[0:17] Memory Buffer Register (18 bits)
AC[0:17] Accumulator (18 bits)
MAR[0:15] Memory Address Register (16 bits)
PC[0:15] Program Counter (16 bits)
IR[0:1] Instruction Register (2 bits)
LR[0:17] Live Register (18 bits)
TBR[0:17] Toggle Switch Buffer Register (18 toggle switches)
TAC[0:17] Toggle Switch Accumulator (18 toggle switches)
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| op | address |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
This routine is the instruction decode routine for the TX-0.
It is called from the simulator control program to execute
instructions in simulated memory, starting at the simulated PC.
It runs until 'reason' is set non-zero.
General notes:
1. Instruction Set: The TX-0 had (at least) two different instruction sets.
The original instruction set from 1956 had two bits for the opcode (IR)
while the later 1961 instruction set used five bits for this purpose.
This simulator is designed to simulate both of these modes. The micro
orders were also changed along with the new instruction set. The main
part of the instruction fetch/decode logic is the same for both
instruction sets. Memory address range is adjusted depending on the mode.
IR[2:4] are forced to 0 in the 1956 mode. The Micro Orders are vastly
different, so the main loop decodes and executes the 1961 micro-orders,
while the sim_opr_orig() function decodes and executes the 1956 micro-orders.
2. Reasons to stop. The simulator can be stopped by:
HALT instruction
breakpoint encountered
I/O error in I/O simulator
3. Arithmetic. The TX-0 is a 1's complement system. In 1's
complement arithmetic, a negative number is represented by the
complement (XOR 0777777) of its absolute value. Addition of 1's
complement numbers requires propagating the carry out of the high
order bit back to the low order bit.
4. Adding I/O devices. Three modules must be modified:
tx0_cpu.c add dispatch code
tx0_sys.c add sim_devices table entry
5. Bugs, limitations, and known issues:
o There is a bug in the 1961 instruction set simulation, which causes the
mouse maze program's searching algorithm to fail.
o The CRY micro-order is not implemented.
o The instruction timing (ie, sim_interval) is not accurate, so implementing a
timing-critical I/O device like the Magtape would require this to be added first.
o PCQ and History do not work.
o Symbolic input does not work.
o Probably lots of other bugs, as Tic-Tac-Toe and Mouse Maze are the only tapes
that I've tested to mostly work. It's difficult to tell what tapes on
bitsavers.org are designed for the 1956 instruction set vs. the later one.
OP Description
-- -----------
00 sto x Replace the contents of register x with the contents of the AC
Let the AC remain the same.
01 add x Add the word in register x to the contents of the AC and leave
the sum in the AC
10 trn x If the sign digit of the accumulator (AC bit 0) is negative (i.e., a one)
take the next instruction from register x and continue from there.
If the sign is positive (i.e., a zero ignore this instruction and proceed
to the next instruction
11 opr x Execute one of the operate class commands indicated by the number x
Around 1961, the TX-0 was modified to include additional instructions, and the addressable
memory range was lowered to 8K words. The IR was increased from two bits to five bits.
In addtion, many of the operate-class micro-orders changed.
OPERATE CLASS MICRO-ORDERS FOR 1961 INSTRUCTION SET
---------------------------------------------------
Cycle.tp
cla --1 --- --- --- --- --- 0.8 Clear AC
amb --- 1-- --- --- --- --- 0.7 Transfer AC contents to MBR
cyr --- --- --- 110 --- --- 1.6 Cycle AC contents right one binary position (AC 17 -> AC 0)
shr --- --- --- 100 --- --- 1.6 Shift AC contents right one binary position (AC 0 unchanged)
mbl --- --- --- 01x --- --- 1.4 Transfer MBR contents to LR
xmb --- --- --- 0x1 --- --- 1.2 Transfer XR contents to MBR
com --- --- --- --- 1-- --- 1.2 Compliment AC
pad --- --- --- --- -1- --- 1.5 Parital add MBR to AC (for each MBR one, complement the correp AC bit)
cry --- --- --- --- --1 --- 1.7 A carry digit is a one if in the next least sigmificant digit,
either ac=0 and mbr=1 or ac=1 and carry digit=1. The carry digits
so determined are partial added to the AC by cry. pad and cry used
together give a full one's complement addition of C(MBR) to C(AC)
anb --- --- --- --- --- 111 1.2-2 And LR and MBR
orb --- --- --- --- --- 101 1.3 Or LR into MBR
lmb --- --- --- --- --- 01x 1.4 Tranfer LR contents to MBR
mbx --- --- --- --- --- 0x1 1.8 Transfer MBR contents to XR
*/
#include "tx0_defs.h"
#define OPR_CLA 0100000 /* 0.8 */
#define OPR_AMB 0040000 /* 0.7 */
#define OPR_SHF_MASK 0000700 /* 1.6 */
#define OPR_CYR 0000600
#define OPR_SHR 0000400
#define OPR_MBL_MASK 0000600 /* 1.4 */
#define OPR_MBL 0000200
#define OPR_XMB_MASK 0000500 /* 1.2 */
#define OPR_XMB 0000100
#define OPR_COM 0000040 /* 1.2 */
#define OPR_PAD 0000020 /* 1.5 */
#define OPR_CRY 0000010 /* 1.7 */
#define OPR_LOG_MASK 0000007 /* Logical operation mask */
#define OPR_ANB 0000007 /* 1.2-2 */
#define OPR_ORB 0000005 /* 1.3 */
#define OPR_LMB_MASK 0000006 /* 1.4 */
#define OPR_LMB 0000002
#define OPR_MBX_MASK 0000005 /* 1.8 */
#define OPR_MBX 0000001
/*
IN OUT GROUP
------------
nop --- -00 000 --- --- --- NOP
tac --- -00 001 --- --- --- 1.1
tbr --- -00 010 --- --- --- 1.2
pen --- -00 011 --- --- --- 1.1
sel --- -00 100 --- --- ---
spare--- -00 101 --- --- ---
rpf --- -00 110 --- --- --- 1.2
spf --- -00 111 --- --- --- 1.6
exN --- -01 nnn --- --- --- IOS
cpy --- -10 000 --- --- --- IOS
r1l --- -10 001 --- --- --- IOS
dis --- -10 010 --- --- --- IOS
r3l --- -10 011 --- --- --- IOS
prt --- -10 100 --- --- --- IOS
spare--- -10 101 --- --- ---
p6h --- -10 110 --- --- --- IOS
p7h --- -10 111 --- --- --- IOS
hlt --- -11 000 --- --- --- 1.8
cll --- -11 001 --- --- --- 0.6
clr --- -11 010 --- --- --- 0.6
*/
#define IOS_MASK 0037000
#define IOS_EX_MASK 0030000
#define IOS_NOP 0000000
#define IOS_TAC 0001000
#define IOS_TBR 0002000
#define IOS_PEN 0003000
#define IOS_SEL 0004000
#define IOS_RPF 0006000
#define IOS_SPF 0007000
#define IOS_CPY 0020000
#define IOS_R1L 0021000
#define IOS_DIS 0022000
#define IOS_R3L 0023000
#define IOS_PRT 0024000
#define IOS_P6H 0026000
#define IOS_P7H 0027000
#define IOS_HLT 0030000
#define IOS_CLL 0031000
#define IOS_CLR 0032000
#define PCQ_SIZE 64 /* must be 2**n */
#define PCQ_MASK (PCQ_SIZE - 1)
#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC
#define UNIT_V_MSIZE (UNIT_V_UF + 4) /* dummy mask */
#define UNIT_V_EXT (UNIT_V_UF + 2)
#define UNIT_EXT_INST (1 << UNIT_V_EXT)
#define UNIT_MSIZE (1 << UNIT_V_MSIZE)
#define HIST_PC 0x40000000
#define HIST_V_SHF 18
#define HIST_MIN 64
#define HIST_MAX 65536
#define TRACE_PRINT(level, args) if(cpu_dev.dctrl & level) { \
printf args; \
}
typedef struct {
uint32 pc;
uint32 ir;
uint32 ovac;
uint32 pfio;
uint32 ea;
uint32 opnd;
} InstHistory;
int32 M[MAXMEMSIZE] = { 0 }; /* memory */
int32 AC = 0; /* AC */
int32 IR = 0; /* IR */
int32 PC = 0; /* PC */
int32 MAR = 0; /* MAR */
int32 XR = 0; /* XR (index register) */
int32 MBR = 0; /* MBR */
int32 LR = 0; /* LR (Live Register) */
int32 OV = 0; /* overflow */
int32 TBR = 0; /* sense switches */
int32 PF = 0; /* program flags */
int32 TAC = 0; /* Toggle Switch Accumulator */
int32 iosta = 0; /* status reg */
int32 ios = 0; /* I/O Stop */
int32 ch = 0; /* Chime Alarm */
int32 LPEN = 0; /* Light Pen / Light Gun flops */
int32 mode_tst = 1; /* Test Mode Flip-flop */
int32 mode_rdin = 1; /* Read-In Mode Flip-flop */
uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */
int32 pcq_p = 0; /* PC queue ptr */
REG *pcq_r = NULL; /* PC queue reg ptr */
int32 hst_p = 0; /* history pointer */
int32 hst_lnt = 0; /* history length */
InstHistory *hst = NULL; /* inst history */
int32 fpc_MA; /* shadow ma for FPC access */
int32 fpc_OP; /* shadow op for FPC access */
int32 addr_mask = YMASK;
t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_reset (DEVICE *dptr);
t_stat cpu_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat cpu_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
int32 cpu_get_mode (void);
t_stat cpu_set_hist (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat cpu_set_ext (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat cpu_set_noext (UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat Read (void);
t_stat Write (void);
extern int32 petr (int32 inst, int32 dev, int32 dat);
extern int32 ptp (int32 inst, int32 dev, int32 dat);
extern int32 tti (int32 inst, int32 dev, int32 dat);
extern int32 tto (int32 inst, int32 dev, int32 dat);
extern int32 lpt (int32 inst, int32 dev, int32 dat);
extern int32 dt (int32 inst, int32 dev, int32 dat);
extern int32 drm (int32 inst, int32 dev, int32 dat);
#ifdef USE_DISPLAY
extern int32 dpy (int32 ac);
#endif
/* CPU data structures
cpu_dev CPU device descriptor
cpu_unit CPU unit
cpu_reg CPU register list
cpu_mod CPU modifier list
*/
UNIT cpu_unit = { UDATA (NULL, UNIT_FIX | UNIT_BINK | UNIT_EXT_INST | UNIT_MODE_READIN, MAXMEMSIZE) };
REG cpu_reg[] = {
{ ORDATAD (PC, PC, ASIZE, "program counter") },
{ ORDATAD (AC, AC, 18, "accumulator") },
{ ORDATAD (IR, IR, 5, "instruction register (5 bits in Extented Mode, 2 bits in standard mode)") },
{ ORDATAD (MAR, MAR, 16, "memory address register") },
{ ORDATAD (XR, XR, 14, "index register (Extended Mode only)") },
{ ORDATAD (MBR, MBR, 18, "memory buffer register") },
{ ORDATAD (LR, LR, 18, "live register") },
{ ORDATAD (TAC, TAC, 18, "toggle switch accumulator") },
{ ORDATAD (TBR, TBR, 18, "toggle switch buffer register") },
{ ORDATA (PF, PF, 18) },
{ BRDATA (PCQ, pcq, 8, ASIZE, PCQ_SIZE), REG_RO+REG_CIRC },
{ ORDATA (PCQP, pcq_p, 6), REG_HRO },
{ FLDATAD (IOS, ios, 0, "in out stop") }, /* In Out Stop */
{ FLDATAD (CH, ch, 0, "chime alarm") }, /* Chime Alarm */
{ ORDATAD (LP, LPEN, 2, "light pen") }, /* Light Pen */
{ FLDATA (R, mode_rdin, 0), REG_HRO }, /* Mode "R" (Read In) Flip-Flop */
{ FLDATA (T, mode_tst, 0), REG_HRO }, /* Mode "T" (Test) Flip-Flop */
{ NULL }
};
MTAB cpu_mod[] = {
{ UNIT_EXT_INST, 0, "standard CPU", "TX0STD", &cpu_set_noext },
{ UNIT_EXT_INST, UNIT_EXT_INST, "Extended Instruction Set", "TX0EXT", &cpu_set_ext },
{ UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size },
{ UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size },
{ UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size },
{ UNIT_MODE, 0, "NORMAL", "NORMAL", &cpu_set_mode },
{ UNIT_MODE, UNIT_MODE_TEST, "TEST", "TEST", &cpu_set_mode },
{ UNIT_MODE, UNIT_MODE_READIN, "READIN", "READIN", &cpu_set_mode },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY",
&cpu_set_hist, &cpu_show_hist },
{ 0 }
};
/* Debug flags */
#define ERROR_MSG (1 << 0)
#define TRACE_MSG (1 << 1)
#define STO_MSG (1 << 2)
#define ADD_MSG (1 << 3)
#define TRN_MSG (1 << 4)
#define ORD_MSG (1 << 5)
#define IOS_MSG (1 << 6)
#define READIN_MSG (1 << 7)
#define VERBOSE_MSG (1 << 8)
#define COUNTERS_MSG (1 << 9)
/* Debug Flags */
static DEBTAB cpu_dt[] = {
{ "ERROR", ERROR_MSG },
{ "TRACE", TRACE_MSG },
{ "STO", STO_MSG },
{ "ADD", ADD_MSG },
{ "TRN", TRN_MSG },
{ "ORD", ORD_MSG },
{ "IOS", IOS_MSG },
{ "READIN", READIN_MSG },
{ "VERBOSE",VERBOSE_MSG },
{ "COUNTERS",COUNTERS_MSG },
{ NULL, 0 }
};
DEVICE cpu_dev = {
"CPU", &cpu_unit, cpu_reg, cpu_mod,
1, 8, ASIZE, 1, 8, 18,
&cpu_ex, &cpu_dep, &cpu_reset,
NULL, NULL, NULL,
NULL, DEV_DEBUG, ERROR_MSG,
cpu_dt, NULL
};
int32 compute_index (int32 y, int32 XR)
{
int32 sum;
y &= YMASK; /* force 13-bit (0 sign) */
XR &= 037777; /* force 14-bit */
sum = y + XR;
if (sum > 037777) { /* Carry from bit 4 into bit 17. */
sum += 1;
}
sum &= YMASK; /* truncate to 13-bit */
return (sum);
}
/* CPU Instruction usage counters */
typedef struct {
/* Store group */
int32 sto, stx, sxa, ado, slr, slx, stz;
/* Add group */
int32 add, adx, ldx, aux, llr, llx, lda, lax;
/* TRN Group */
int32 trn, tze, tsx, tix, tra, trx, tlv;
/* OPR Group */
int32 cla, amb, cyr, shr, mbl, xmb, com, pad, cry, anb, orb, lmb, mbx;
} INST_CTRS;
INST_CTRS inst_ctr;
void tx0_dump_regs(const char *desc)
{
TRACE_PRINT(TRACE_MSG, ("%s: AC=%06o, MAR=%05o, MBR=%06o, LR=%06o, XR=%05o\n", desc, AC, MAR, MBR, LR, XR));
/* Check regs sanity */
if (AC > DMASK) {
sim_printf("Error: AC > DMASK\n");
}
if (MBR > DMASK) {
sim_printf("Error: MBR > DMASK\n");
}
if (LR > DMASK) {
sim_printf("Error: LR > DMASK\n");
}
if (!MEM_ADDR_OK(MAR)) {
sim_printf("Error: MAR > %06o\n", MEMSIZE);
}
}
t_stat sim_opr_orig(int32 op);
t_stat sim_instr (void)
{
int32 IR, op, inst_class, y;
int32 tempLR; /* LR temporary storage in case both LMB and MBL are set (swap LR<->MBR) */
t_stat reason;
/* Clear Instruction counters */
inst_ctr.sto = inst_ctr.stx = inst_ctr.sxa = inst_ctr.ado = inst_ctr.slr = inst_ctr.slx = inst_ctr.stz = 0;
inst_ctr.add = inst_ctr.adx = inst_ctr.ldx = inst_ctr.aux = inst_ctr.llr = inst_ctr.llx = inst_ctr.lda = inst_ctr.lax = 0;
inst_ctr.trn = inst_ctr.tze = inst_ctr.tsx = inst_ctr.tix = inst_ctr.tra = inst_ctr.trx = inst_ctr.tlv = 0;
inst_ctr.cla = inst_ctr.amb = inst_ctr.cyr = inst_ctr.shr = inst_ctr.mbl = inst_ctr.xmb = inst_ctr.com = inst_ctr.pad = inst_ctr.cry = inst_ctr.anb = inst_ctr.orb = inst_ctr.lmb = inst_ctr.mbx = 0;
#define INCR_ADDR(x) ((x+1) & (MEMSIZE-1))
/* Main instruction fetch/decode loop: check events */
reason = 0;
while (reason == 0) { /* loop until halted */
if (sim_interval <= 0) { /* check clock queue */
reason = sim_process_event ();
if (reason != SCPE_OK)
break;
}
if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */
reason = STOP_IBKPT; /* stop simulation */
break;
}
if (ios) {
TRACE_PRINT(ERROR_MSG, ("I/O Stop - Waiting...\n"));
continue;
}
/* Handle Instruction Execution in TEST and READIN modes */
if (mode_tst) { /* Test Mode / Readin mode */
if (mode_rdin) { /* Readin Mode */
reason = SCPE_OK; /* Default is to continue reading, and transfer control when done. */
AC = petr(3,0,0); /* Read three chars from tape into AC */
MAR = AC & AMASK; /* Set memory address */
IR = AC >> 16;
if (!MEM_ADDR_OK(MAR)) {
TRACE_PRINT(ERROR_MSG, ("READIN: Tape address out of range.\n"));
reason = SCPE_FMT;
}
switch (IR) {
case 00: /* Storage (sto x) */
case 03: /* Storage (opr x) */
MBR = petr(3,0,0); /* Read three characters from tape. */
TRACE_PRINT(READIN_MSG, ("READIN: sto @%06o = %06o\n", MAR, MBR));
Write();
break;
case 02: /* Transfer Control (trn x) Start Execution */
PC = MAR;
reason = SCPE_OK; /* let SIMH start execution. */
TRACE_PRINT(READIN_MSG, ("READIN: trn %06o (Start Execution)\n", PC));
reason = cpu_set_mode(&cpu_unit, 0, NULL, NULL);
break;
case 01: /* Transfer (add x) - Halt */
PC = MAR;
reason = SCPE_STOP; /* let SIMH halt. */
TRACE_PRINT(READIN_MSG, ("READIN: add %06o (Halt)\n", PC));
reason = cpu_set_mode(&cpu_unit, 0, NULL, NULL);
break;
default:
reason = SCPE_IERR;
break;
}
} else if (mode_tst) { /* Test mode not implemented yet. */
TRACE_PRINT(ERROR_MSG, ("TEST Mode not implemented.\n"));
reason = SCPE_STOP;
} else {
TRACE_PRINT(ERROR_MSG, ("Invalid CPU mode.\n"));
reason = SCPE_IERR;
}
continue; /* Proceed with next instruction */
}
/* Fetch, decode instruction in NORMAL mode */
MAR = PC;
if (Read ()) break; /* fetch inst */
IR = (MBR >> 13); /* save in IR */
inst_class = IR >> 3;
op = MBR & AMASK;
y = MBR & YMASK;
sim_interval = sim_interval - 1;
if ((cpu_unit.flags & UNIT_EXT_INST) == 0) { /* Original instruction set */
IR &= 030;
MAR = MBR & AMASK; /* 16-bit address field */
} else {
MAR = MBR & YMASK; /* 13-bit address field */
}
if (hst_lnt) { /* history enabled? */
hst_p = (hst_p + 1); /* next entry */
if (hst_p >= hst_lnt) hst_p = 0;
hst[hst_p].pc = MAR | HIST_PC; /* save state */
hst[hst_p].ir = IR;
hst[hst_p].ovac = (OV << HIST_V_SHF) | AC;
}
PC = INCR_ADDR (PC); /* increment PC */
#ifdef USE_FPC
fpc_OP = op; /* shadow opcode for FPC */
#endif
tx0_dump_regs("START");
switch (inst_class) { /* decode IR<0:1> */
/* Logical, load, store instructions */
case 00: /* sto x */
switch (IR & 07) {
case 0: /* sto */
MBR = AC;
Write();
inst_ctr.sto++;
break;
case 1: /* stx */
MBR = AC;
MAR = compute_index(y, XR);
Write();
inst_ctr.stx++;
break;
case 2: /* sxa */
{
int32 temp = M[MAR];
temp &= 0760000;
temp |= (XR & YMASK);
MBR = temp;
Write();
}
inst_ctr.sxa++;
break;
case 3: /* ado */
{
int32 temp = M[MAR];
temp += 1; /* add 1 */
if (temp > DMASK) { /* Overflow, */
temp += 1; /* propagate carry from bit 0 to bit 17. */
}
temp &= DMASK;
MBR = temp;
AC = temp;
Write();
}
inst_ctr.ado++;
break;
case 4: /* slr */
MBR = LR;
Write();
inst_ctr.slr++;
break;
case 5: /* slx */
MAR = compute_index(y, XR);
MBR = LR;
Write();
inst_ctr.slx++;
break;
case 6: /* stz */
MBR = 0;
Write();
inst_ctr.stz++;
break;
case 7: /* no-op */
break;
}
break;
case 01: /* add x */
switch (IR & 07) {
case 0: /* add */
Read();
AC = AC + MBR;
if (AC > DMASK) {
AC += 1;
}
AC &= DMASK;
inst_ctr.add++;
break;
case 1: /* adx */
MAR = compute_index(y, XR);
Read();
AC = AC + MBR;
if (AC > DMASK) {
AC += 1;
}
AC &= DMASK;
inst_ctr.adx++;
break;
case 2: /* ldx */
Read();
XR = MBR & YMASK; /* load XR[5:17] from C(y[5:17]) */
XR |= ((MBR & SIGN) >> 4); /* Load XR[4] from C(y[0]) */
inst_ctr.ldx++;
break;
case 3: /* aux (Augment Index) */
{
uint32 newY = (y & 0017777) | ((y & SIGN) >> 4);
TRACE_PRINT(ADD_MSG, ("[%06o] AUX: y=%05o, XR=%05o = ", PC-1, newY, XR));
XR = XR + newY;
TRACE_PRINT(ADD_MSG, ("%05o\n", XR));
inst_ctr.aux++;
break;
}
case 4: /* llr (Load Live Register) */
Read();
LR = MBR;
inst_ctr.llr++;
break;
case 5: /* llx (Load Live Register, Indexed) */
MAR = compute_index(y, XR);
Read();
LR = MBR;
inst_ctr.llx++;
break;
case 6: /* lda (Load Accumulator) */
Read();
AC = MBR;
inst_ctr.lda++;
break;
case 7: /* lax (Load Accumulator, Indexed) */
MAR = compute_index(y, XR);
Read();
AC = MBR;
inst_ctr.lax++;
break;
}
break;
case 02: /* trn x */
switch (IR & 07) {
case 0: /* trn (Transfer on Negative AC) */
if (AC & SIGN) {
TRACE_PRINT(TRN_MSG, ("[%06o] TRN: Transfer taken: PC=%06o\n", PC-1, y));
PC = MAR;
}
inst_ctr.trn++;
break;
case 1: /* tze (Transfer on +/- Zero) */
if ((AC == 0777777) || (AC == 0000000)) {
TRACE_PRINT(TRN_MSG, ("[%06o] TZE: Transfer taken: PC=%06o\n", PC-1, y));
PC = y;
}
inst_ctr.tze++;
break;
case 2: /* tsx (Transfer and set Index) */
XR = PC & 0017777; /* XR[4] = 0; */
TRACE_PRINT(TRN_MSG, ("[%06o] TSX: PC=%06o, XR=%05o\n", PC-1, y, XR));
PC = y;
inst_ctr.tsx++;
break;
case 3: /* tix (Transfer and Index) */
TRACE_PRINT(TRN_MSG, ("[%06o] TIX: XR=%05o\n", PC-1, XR));
if ((XR == 037777) || (XR == 000000)) { /* +/- 0, take next instruction */
TRACE_PRINT(TRN_MSG, ("+/- 0, transfer not taken.\n"));
} else { /* Not +/- 0 */
if (XR & 0020000) { /* XR[4] == 1 */
TRACE_PRINT(TRN_MSG, ("XR is negative, transfer taken,"));
XR ++;
} else { /* XR[4] = 0 */
TRACE_PRINT(TRN_MSG, ("XR is positive, transfer taken,"));
XR --;
}
PC = y;
XR &= 037777;
TRACE_PRINT(TRN_MSG, (" PC=%06o, XR=%05o\n", PC, XR));
}
inst_ctr.tix++;
break;
case 4: /* tra (Unconditional Transfer) */
TRACE_PRINT(TRN_MSG, ("[%06o] TRA: Transfer taken: PC=%06o\n", PC-1, y));
PC = y;
inst_ctr.tra++;
break;
case 5: /* trx */
{
int32 newPC;
newPC = compute_index(y, XR);
TRACE_PRINT(TRN_MSG, ("[%06o] TRA: Transfer taken: PC=%06o\n", PC-1, newPC));
PC = newPC;
}
inst_ctr.trx++;
break;
case 6: /* tlv (Transfer on External Level) */
TRACE_PRINT(ERROR_MSG, ("[%06o] TODO: Implement TLV\n", PC-1));
inst_ctr.tlv++;
break;
case 7: /* no-op */
break;
}
break;
case 03: /* opr x */
if ((cpu_unit.flags & UNIT_EXT_INST) == 0) { /* Original instruction set */
reason = sim_opr_orig(op);
break;
}
/* I can't find this mentioned in the TX-0 Documentation, but for the
* lro and xro instructions, this must be needed.
*/
MBR = 0;
/* Cycle 0 */
if (op & OPR_AMB) { /* 0.7 */
inst_ctr.amb++;
MBR = AC;
TRACE_PRINT(ORD_MSG, ("[%06o]: AMB: MBR=%06o\n", PC-1, MBR));
}
if (op & OPR_CLA) { /* 0.8 */
inst_ctr.cla++;
AC = 0;
TRACE_PRINT(ORD_MSG, ("[%06o]: CLA: AC=%06o\n", PC-1, AC));
}
/* IOS - In / Out Stop */
/* Check TTI for character. If so, put in LR and set LR bit 0. */
if (iosta & IOS_TTI) {
int32 rbuf;
rbuf = tti(0,0,0);
TRACE_PRINT(IOS_MSG, ("TTI: character received=%03o\n", rbuf &077));
LR &= 0266666; /* Clear bits 0,2,5,8,...,17 */
LR |= SIGN; /* Set bit 0, character available. */
LR |= ((rbuf & 001) >> 0) << 15;/* bit 2 */
LR |= ((rbuf & 002) >> 1) << 12;/* bit 5 */
LR |= ((rbuf & 004) >> 2) << 9; /* bit 8 */
LR |= ((rbuf & 010) >> 3) << 6; /* bit 11 */
LR |= ((rbuf & 020) >> 4) << 3; /* bit 14 */
LR |= ((rbuf & 040) >> 5) << 0; /* bit 17 */
}
switch(op & IOS_MASK) {
case IOS_NOP:
break;
case IOS_TAC:
TRACE_PRINT(IOS_MSG, ("[%06o] TAC %06o\n", PC-1, TAC));
AC |= TAC;
break;
case IOS_TBR:
TRACE_PRINT(IOS_MSG, ("[%06o] TBR %06o\n", PC-1, TBR));
MBR |= TBR;
break;
case IOS_PEN:
TRACE_PRINT(IOS_MSG, ("[%06o] Light Pen %01o\n", PC-1, LPEN));
AC &= AMASK;
AC |= (LPEN & 1) << 17;
AC |= (LPEN & 2) << 16;
AC &= DMASK;
break;
case IOS_SEL:
{ /* These are used for Magtape control.
Magtape is compatible with IBM 709. Maybe the SIMH 7090 magtape can be leveraged. */
int32 CLRA = (op & 0100000);
int32 BINDEC = (op & 020);
int32 device = op & 03;
int32 tape_ord = (op >> 2) & 03;
const char *tape_cmd[] = {"Backspace Tape", "Read/Select Tape", "Rewind Tape", "Write/Select Tape" };
TRACE_PRINT(ERROR_MSG, ("[%06o] TODO: SEL (magtape)\n", PC-1));
sim_printf("Device %d: CLRA=%d, BINDEC=%d: %s\n", device, CLRA, BINDEC, tape_cmd[tape_ord]);
}
break;
case IOS_RPF: /* These are used for Magtape control. */
TRACE_PRINT(IOS_MSG, ("[%06o] RPF %06o\n", PC-1, PF));
MBR |= PF;
break;
case IOS_SPF: /* These are used for Magtape control. */
TRACE_PRINT(IOS_MSG, ("[%06o] SPF %06o\n", PC-1, MBR));
PF = MBR;
break;
case IOS_CPY: /* These are used for Magtape control. */
TRACE_PRINT(ERROR_MSG, ("[%06o] TODO: CPY\n", PC-1));
break;
case IOS_R1L:
AC &= 0333333; /* Clear bits 0,3,6,9,12,15 */
AC |= petr(1, 0, 0); /* Read one line from PETR */
break;
case IOS_DIS:
#ifdef USE_DISPLAY
LPEN = dpy (AC); /* Display point on the CRT */
#endif /* USE_DISPLAY */
break;
case IOS_R3L:
AC = petr(3, 0, 0); /* Read three lines from PETR */
break;
case IOS_PRT:
{
uint32 tmpAC = 0;
tmpAC |= ((AC & 0000001) >> 0) << 0; /* bit 17 */
tmpAC |= ((AC & 0000010) >> 3) << 1; /* bit 14 */
tmpAC |= ((AC & 0000100) >> 6) << 2; /* bit 11 */
tmpAC |= ((AC & 0001000) >> 9) << 3; /* bit 8 */
tmpAC |= ((AC & 0010000) >> 12) << 4; /* bit 5 */
tmpAC |= ((AC & 0100000) >> 15) << 5; /* bit 2 */
tto (0, 0, tmpAC & 077); /* Print one character on TTO */
}
break;
case IOS_P6H:
case IOS_P7H:
{
uint32 tmpAC = 0;
tmpAC |= ((AC & 0000001) >> 0) << 0; /* bit 17 */
tmpAC |= ((AC & 0000010) >> 3) << 1; /* bit 14 */
tmpAC |= ((AC & 0000100) >> 6) << 2; /* bit 11 */
tmpAC |= ((AC & 0001000) >> 9) << 3; /* bit 8 */
tmpAC |= ((AC & 0010000) >> 12) << 4; /* bit 5 */
tmpAC |= ((AC & 0100000) >> 15) << 5; /* bit 2 */
tmpAC &= 0077;
if ((op & IOS_MASK) == IOS_P7H) {
tmpAC |= 0100; /* Punch 7th hole. */
TRACE_PRINT(ERROR_MSG, ("[%06o] Punch 7 holes\n", PC-1));
} else {
TRACE_PRINT(ERROR_MSG, ("[%06o] Punch 6 holes\n", PC-1));
}
ptp (0, 0, tmpAC); /* Punch character on PTP */
}
break;
case IOS_HLT:
TRACE_PRINT(IOS_MSG, ("[%06o] HALT Instruction\n", PC-1));
reason = STOP_HALT;
break;
case IOS_CLL:
AC &= 0000777;
break;
case IOS_CLR:
AC &= 0777000;
break;
default: /* Could be ex0-ex7, handle them here. */
if ((op & IOS_EX_MASK) == 0010000) {
TRACE_PRINT(ERROR_MSG, ("[%06o] TODO: EX%o\n", PC-1, (op >> 9) & 07));
}
break;
}
/* Cycle 1 */
if (op & OPR_COM) { /* 1.2 */
AC = ~AC;
AC &= DMASK;
TRACE_PRINT(ORD_MSG, ("[%06o]: COM: AC=%06o\n", PC-1, AC));
inst_ctr.com++;
}
if ((op & OPR_XMB_MASK) == OPR_XMB) { /* 1.2 XR[5:17] -> MBR[5:17], XR[4] -> MBR[0:4] */
int32 bit14 = (XR >> 13) & 1;
MBR = XR & YMASK; /* XR[5:17] -> MBR[5:17] */
MBR |= (bit14 << 17); /* XR[4] -> MBR[0] */
MBR |= (bit14 << 16); /* XR[4] -> MBR[1] */
MBR |= (bit14 << 15); /* XR[4] -> MBR[2] */
MBR |= (bit14 << 14); /* XR[4] -> MBR[3] */
MBR |= (bit14 << 13); /* XR[4] -> MBR[4] */
TRACE_PRINT(ORD_MSG, ("[%06o]: XMB: XR=%05o, MBR=%06o\n", PC-1, XR, MBR));
inst_ctr.xmb++;
}
if ((op & OPR_LOG_MASK) == OPR_ANB) { /* 1.2-2 */
MBR &= LR;
TRACE_PRINT(ORD_MSG, ("[%06o]: ANB: MBR=%06o\n", PC-1, MBR));
inst_ctr.anb++;
}
if ((op & OPR_LOG_MASK) == OPR_ORB) { /* 1.3 */
MBR |= LR;
TRACE_PRINT(ORD_MSG, ("[%06o]: ORB: MBR=%06o\n", PC-1, MBR));
inst_ctr.orb++;
}
tempLR = LR; /* LR temporary storage in case both LMB and MBL are set (swap LR<->MBR) */
if ((op & OPR_MBL_MASK) == OPR_MBL) { /* 1.4 */
LR = MBR;
TRACE_PRINT(ORD_MSG, ("[%06o]: MBL: LR=%06o, prev LR=%06o\n", PC-1, LR, tempLR));
inst_ctr.mbl++;
}
if ((op & OPR_LMB_MASK) == OPR_LMB) { /* 1.4 */
MBR = tempLR;
TRACE_PRINT(ORD_MSG, ("[%06o]: LMB: LR=%06o, MBR=%06o\n", PC-1, LR, MBR));
inst_ctr.lmb++;
}
if (op & OPR_PAD) { /* 1.5 Partial Add (XOR): AC = MBR ^ AC */
if (op & OPR_CRY) { /* 1.7 */
TRACE_PRINT(ORD_MSG, ("[%06o] PAD+CRY: AC=%06o, MBR=%06o = ", PC-1, AC, MBR));
AC = AC + MBR;
if (AC > DMASK) {
AC += 1;
}
AC &= DMASK;
TRACE_PRINT(ORD_MSG, ("%06o\n", AC));
} else {
TRACE_PRINT(ORD_MSG, ("[%06o] PAD: AC=%06o, MBR=%06o\n", PC-1, AC, MBR));
AC = AC ^ MBR;
AC &= DMASK;
TRACE_PRINT(ORD_MSG, ("[%06o] PAD: Check: AC=%06o\n", PC-1, AC));
}
inst_ctr.pad++;
}
if ((op & OPR_SHF_MASK) == OPR_CYR) { /* 1.6 */
int32 bit17;
bit17 = (AC & 1) << 17;
AC >>= 1;
AC |= bit17;
TRACE_PRINT(ORD_MSG, ("[%06o]: CYR: AC=%06o\n", PC-1, AC));
inst_ctr.cyr++;
}
if ((op & OPR_SHF_MASK) == OPR_SHR) { /* 1.6 Shift AC Right, preserve bit 0. */
int32 bit0;
bit0 = AC & 0400000;
AC = AC >> 1;
AC |= bit0;
TRACE_PRINT(ORD_MSG, ("[%06o]: SHR: AC=%06o\n", PC-1, AC));
inst_ctr.shr++;
}
if (op & OPR_CRY) { /* 1.7 */
if (op & OPR_PAD) {
} else {
TRACE_PRINT(ERROR_MSG, ("[%06o] CRY: TODO: AC=%06o\n", PC-1, AC));
inst_ctr.cry++;
}
}
if ((op & OPR_MBX_MASK) == OPR_MBX) { /* 1.8 MBR[5:17] -> XR[5:17], MBR[0] -> XR[4] */
int32 tempXR;
tempXR = MBR & YMASK;
tempXR |= (((MBR >> 17) & 1) << 13);
XR = tempXR;
TRACE_PRINT(ORD_MSG, ("[%06o]: MBX: MBR=%06o, XR=%06o\n", PC-1, MBR, XR));
inst_ctr.mbx++;
}
}
tx0_dump_regs("END");
#ifdef USE_FPC
fpc_MA = MAR; /* shadow MAR for FPC */
#endif
} /* end while */
pcq_r->qptr = pcq_p; /* update pc q ptr */
TRACE_PRINT(COUNTERS_MSG, ("Instruction Counters\nSTO=%d, STX=%d, SXA=%d, ADO=%d, SLR=%d, SLX=%d, STZ=%d\n",
inst_ctr.sto, inst_ctr.stx, inst_ctr.sxa, inst_ctr.ado, inst_ctr.slr, inst_ctr.slx, inst_ctr.stz));
TRACE_PRINT(COUNTERS_MSG, ("ADD=%d, ADX=%d, LDX=%d, AUX=%d, LLR=%d, LLX=%d, LDA=%d, LAX=%d\n",
inst_ctr.add, inst_ctr.adx, inst_ctr.ldx, inst_ctr.aux, inst_ctr.llr, inst_ctr.llx, inst_ctr.lda, inst_ctr.lax));
TRACE_PRINT(COUNTERS_MSG, ("TRN=%d, TZE=%d, TSX=%d, TIX=%d, TRA=%d, TRX=%d, TLV=%d\n",
inst_ctr.trn, inst_ctr.tze, inst_ctr.tsx, inst_ctr.tix, inst_ctr.tra, inst_ctr.trx, inst_ctr.tlv));
TRACE_PRINT(COUNTERS_MSG, ("CLA=%d, AMB=%d, CYR=%d, SHR=%d, MBL=%d, XMB=%d, COM=%d, PAD=%d, CRY=%d, ANB=%d, ORB=%d, LMB=%d, MBX=%d\n",
inst_ctr.cla, inst_ctr.amb, inst_ctr.cyr, inst_ctr.shr, inst_ctr.mbl, inst_ctr.xmb, inst_ctr.com, inst_ctr.pad, inst_ctr.cry, inst_ctr.anb, inst_ctr.orb, inst_ctr.lmb, inst_ctr.mbx));
return reason;
}
/* Read and write memory */
t_stat Read (void)
{
MAR &= (MEMSIZE - 1);
MBR = M[MAR];
MBR &= DMASK;
return SCPE_OK;
}
t_stat Write (void)
{
MAR &= (MEMSIZE - 1);
MBR &= DMASK;
M[MAR] = MBR;
return SCPE_OK;
}
/* Reset routine */
t_stat cpu_reset (DEVICE *dptr)
{
ios = 0;
PF = 0;
MAR = 0;
MBR = 0;
pcq_r = find_reg ("PCQ", NULL, dptr);
if (pcq_r) {
pcq_r->qptr = 0;
} else {
return SCPE_IERR;
}
sim_brk_types = sim_brk_dflt = SWMASK ('E');
return SCPE_OK;
}
/* Memory examine */
t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
{
if (addr >= MEMSIZE) return SCPE_NXM;
if (vptr != NULL) *vptr = M[addr] & DMASK;
return SCPE_OK;
}
/* Memory deposit */
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
{
if (addr >= MEMSIZE) return SCPE_NXM;
M[addr] = val & DMASK;
return SCPE_OK;
}
/* Change memory size */
t_stat cpu_set_size (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
int32 mc = 0;
uint32 i;
if ((val <= 0) || (val > (int32)MAXMEMSIZE) || ((val & 07777) != 0))
return SCPE_ARG;
for (i = val; i < MEMSIZE; i++) mc = mc | M[i];
if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
return SCPE_OK;
MEMSIZE = val;
for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;
return SCPE_OK;
}
/* Change CPU Mode (Normal, Test, Readin) */
t_stat cpu_set_mode (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
if (val == UNIT_MODE_TEST) {
mode_tst = 1;
mode_rdin = 0;
} else if (val == UNIT_MODE_READIN) {
mode_tst = 1;
mode_rdin = 1;
} else { /* Normal Mode */
mode_tst = 0;
mode_rdin = 0;
}
return SCPE_OK;
}
/* Set TX-0 with Extended Instruction Set */
t_stat cpu_set_ext (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
sim_printf("Set CPU Extended Mode\n");
return SCPE_OK;
}
t_stat cpu_set_noext (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
sim_printf("Set CPU Non-Extended Mode\n");
return SCPE_OK;
}
int32 cpu_get_mode (void)
{
return (cpu_unit.flags & UNIT_EXT_INST);
}
/* Set history */
t_stat cpu_set_hist (UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
int32 i, lnt;
t_stat r;
if (cptr == NULL) {
for (i = 0; i < hst_lnt; i++) hst[i].pc = 0;
hst_p = 0;
return SCPE_OK;
}
lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r);
if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG;
hst_p = 0;
if (hst_lnt) {
free (hst);
hst_lnt = 0;
hst = NULL;
}
if (lnt) {
hst = (InstHistory *) calloc (lnt, sizeof (InstHistory));
if (hst == NULL) return SCPE_MEM;
hst_lnt = lnt;
}
return SCPE_OK;
}
/* Show history */
t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
int32 ov, pf, op, k, di, lnt;
const char *cptr = (const char *) desc;
t_stat r;
InstHistory *h;
if (hst_lnt == 0) return SCPE_NOFNC; /* enabled? */
if (cptr) {
lnt = (int32) get_uint (cptr, 10, hst_lnt, &r);
if ((r != SCPE_OK) || (lnt == 0)) return SCPE_ARG;
}
else lnt = hst_lnt;
di = hst_p - lnt; /* work forward */
if (di < 0) di = di + hst_lnt;
fprintf (st, "PC OV AC IO PF EA IR\n\n");
for (k = 0; k < lnt; k++) { /* print specified */
h = &hst[(++di) % hst_lnt]; /* entry pointer */
if (h->pc & HIST_PC) { /* instruction? */
ov = (h->ovac >> HIST_V_SHF) & 1; /* overflow */
pf = 0;
op = ((h->ir >> 13) & 037); /* get opcode */
fprintf (st, "%06o %o %06o %06o %03o ",
h->pc & AMASK, ov, h->ovac & DMASK, h->pfio & DMASK, pf);
if ((op < 032) && (op != 007)) /* mem ref instr */
fprintf (st, "%06o ", h->ea);
else fprintf (st, " ");
sim_eval[0] = h->ir;
if ((fprint_sym (st, h->pc & AMASK, sim_eval, &cpu_unit, SWMASK ('M'))) > 0)
fprintf (st, "(undefined) %06o", h->ir);
else if (op < 030) /* mem ref instr */
fprintf (st, " [%06o]", h->opnd);
fputc ('\n', st); /* end line */
} /* end else instruction */
} /* end for */
return SCPE_OK;
}
/* set "test switches"; from display code */
void
cpu_set_switches(unsigned long bits)
{
/* just what we want; smaller CPUs might want to shift down? */
TAC = bits;
}
unsigned long
cpu_get_switches(void)
{
return TAC;
}
t_stat sim_load(FILE *fileref, CONST char *cptr, CONST char *fnam, int flag) {
uint32 word;
t_addr j, lo, hi, sz, sz_words;
CONST char *result;
if (flag) { /* Dump to file. */
result = get_range(NULL, cptr, &lo, &hi, 8, 0xFFFF, 0);
if (result == NULL) return SCPE_ARG;
for (j = lo; j <= hi; j++) {
if (sim_fwrite(&j, 4, 1, fileref) == 0) return SCPE_IOERR;
if (sim_fwrite(&M[j], 4, 1, fileref) == 0) return SCPE_IOERR;
}
} else {
lo = strtotv(cptr, &result, 8) & 0xFFFF;
sz = sim_fsize(fileref);
sz_words = sz / 4;
for (j = lo; j < sz_words; j++) {
sim_fread(&word, 4, 1, fileref);
M[j] = word;
}
}
sim_printf("%d words %s [%06o - %06o].\n", j - lo, flag ? "dumped" : "loaded", lo, j-1);
return SCPE_OK;
}
/*
Original Operate-class instruction micro orders for the 1956 TX-0 Instruction Set
Operate Fields
--------------
--1 --- --- --- --- --- CLL 0.8
--- 1-- --- --- --- --- CLR 0.8
--- -10 --- --- --- --- IOS 0.8
--- -11 --- --- --- --- HLT 1.8
--- --- 111 --- --- --- P7H 0.8
--- --- 110 --- --- --- P6H 0.8
--- --- 100 --- --- --- PNT 0.8
--- --- 001 --- --- --- R1C 0.8
--- --- 011 --- --- --- R3C 0.8
--- --- 010 --- --- --- DIS 0.8
--- --- --- 10- --- --- SHR 1.4
--- --- --- 11- --- --- CYR 1.4
--- --- --- 01- --- --- MLR 1.3
--- --- --- --1 --- 0-- PEN 1.1
--- --- --- --0 --- 1-- TAC 1.1
--- --- --- --- 1-- --- COM 1.2
--- --- --- --- -1- --- PAD 1.4
--- --- --- --- --1 --- CRY 1.7
--- --- --- --- --- -01 AMB 1.2 AC -> MBR
--- --- --- --- --- -11 TBR 1.2 TBR -> MBR
--- --- --- --- --- -10 LMB 1.3 LR -> MBR
*/
#define OOPR_CLL 0100000
#define OOPR_CLR 0040000
#define OOPR_IOS 0020000
#define OOPR_HLT 0030000
#define OOPR_IOS_MASK 0007000
#define OOPR_P7H 0007000
#define OOPR_P6H 0006000
#define OOPR_PNT 0004000
#define OOPR_R3C 0003000
#define OOPR_DIS 0002000
#define OOPR_R1C 0001000
#define OOPR_SHF_MASK 0000600
#define OOPR_SHR 0000400
#define OOPR_CYR 0000600
#define OOPR_MLR 0000200
#define OOPR_PEN_MASK 0000104
#define OOPR_PEN 0000100
#define OOPR_TAC_MASK 0000104
#define OOPR_TAC 0000004
#define OOPR_COM 0000040
#define OOPR_PAD 0000020
#define OOPR_CRY 0000010
#define OOPR_AMB_MASK 0000007
#define OOPR_AMB 0000001
#define OOPR_TBR 0000003
#define OOPR_LMB 0000002
t_stat sim_opr_orig(int32 op)
{
t_stat reason = SCPE_OK;
if (op & OOPR_CLL) { /* cll 0.8 Clear the left nine digital positions of the AC */
AC &= 0000777;
TRACE_PRINT(ORD_MSG, ("[%06o]: CLL\n", PC-1));
}
if (op & OOPR_CLR) { /* clr 0.8 Clear the right nine digital positions of the AC */
AC &= 0777000;
TRACE_PRINT(ORD_MSG, ("[%06o]: CLR\n", PC-1));
}
/* IOS - In / Out Stop */
/* Check TTI for character. If so, put in LR and set LR bit 0. */
if (iosta & IOS_TTI) {
int32 rbuf;
rbuf = tti(0,0,0);
TRACE_PRINT(IOS_MSG, ("TTI: character received='%c'\n", rbuf &077));
sim_printf("TTI: character received='%c'\n", rbuf &077);
LR &= 0266666; /* Clear bits 0,2,5,8,...,17 */
LR |= SIGN; /* Set bit 0, character available. */
LR |= ((rbuf & 001) >> 0) << 15;/* bit 2 */
LR |= ((rbuf & 002) >> 1) << 12;/* bit 5 */
LR |= ((rbuf & 004) >> 2) << 9; /* bit 8 */
LR |= ((rbuf & 010) >> 3) << 6; /* bit 11 */
LR |= ((rbuf & 020) >> 4) << 3; /* bit 14 */
LR |= ((rbuf & 040) >> 5) << 0; /* bit 17 */
}
if ((op & OOPR_HLT) == OOPR_IOS) { /* I/O 0.8 IOS */
TRACE_PRINT(IOS_MSG, ("[%06o] I/O Operation\n", PC-1));
switch (op & OOPR_IOS_MASK) {
case OOPR_P7H:
case OOPR_P6H:
{
uint32 tmpAC = 0;
tmpAC |= ((AC & 0000001) >> 0) << 0; /* bit 17 */
tmpAC |= ((AC & 0000010) >> 3) << 1; /* bit 14 */
tmpAC |= ((AC & 0000100) >> 6) << 2; /* bit 11 */
tmpAC |= ((AC & 0001000) >> 9) << 3; /* bit 8 */
tmpAC |= ((AC & 0010000) >> 12) << 4; /* bit 5 */
tmpAC |= ((AC & 0100000) >> 15) << 5; /* bit 2 */
tmpAC &= 0077;
if ((op & OOPR_IOS_MASK) == OOPR_P7H) {
tmpAC |= 0100; /* Punch 7th hole. */
TRACE_PRINT(ERROR_MSG, ("[%06o] Punch 7 holes\n", PC-1));
} else {
TRACE_PRINT(ERROR_MSG, ("[%06o] Punch 6 holes\n", PC-1));
}
ptp (0, 0, tmpAC); /* Punch one character on TTO */
}
break;
case OOPR_PNT:
{
uint32 tmpAC = 0;
tmpAC |= ((AC & 0000001) >> 0) << 0; /* bit 17 */
tmpAC |= ((AC & 0000010) >> 3) << 1; /* bit 14 */
tmpAC |= ((AC & 0000100) >> 6) << 2; /* bit 11 */
tmpAC |= ((AC & 0001000) >> 9) << 3; /* bit 8 */
tmpAC |= ((AC & 0010000) >> 12) << 4; /* bit 5 */
tmpAC |= ((AC & 0100000) >> 15) << 5; /* bit 2 */
tto (0, 0, tmpAC & 077); /* Print one character on TTO */
}
break;
case OOPR_R3C:
AC = petr(3, 0, 0);
break;
case OOPR_R1C:
AC &= 0333333; /* Clear bits 0,3,6,9,12,15 */
AC |= petr(1, 0, 0);
break;
case OOPR_DIS:
#ifdef USE_DISPLAY
LPEN = dpy (AC); /* Display point on the CRT */
#endif /* USE_DISPLAY */
break;
}
}
/* 1.1 TAC and PEN */
if ((op & OOPR_PEN_MASK) == OOPR_PEN) { /* pen 1.1 Read the light pen flip flops 1 and 2 into AC0 and AC1 */
TRACE_PRINT(IOS_MSG, ("[%06o] Light Pen %01o\n", PC-1, LPEN));
AC &= AMASK;
AC |= (LPEN & 1) << 17;
AC |= (LPEN & 2) << 16;
AC &= DMASK;
}
if ((op & OOPR_TAC_MASK) == OOPR_TAC) { /* tac 1.1 Insert a one in each digital position of the AC whereever there is a one in the corresponding digital position of the TAC */
TRACE_PRINT(IOS_MSG, ("[%06o] TAC %06o\n", PC-1, TAC));
AC |= TAC;
}
/* 1.2: COM, AMB, TBR */
if (op & OOPR_COM) { /* com 1.2 Complement every digit in the accumulator */
AC = ~AC;
inst_ctr.com++;
}
switch (op & OOPR_AMB_MASK) {
case OOPR_AMB:
inst_ctr.amb++;
MBR = AC;
break;
case OOPR_TBR:
TRACE_PRINT(IOS_MSG, ("[%06o] TBR %06o\n", PC-1, TBR));
MBR |= TBR;
break;
case OOPR_LMB:
MBR = LR;
inst_ctr.lmb++;
break;
}
/* 1.3, 1.4: can these happen together? */
switch (op & OOPR_SHF_MASK) {
case OOPR_MLR:
LR = MBR;
inst_ctr.mbl++;
break;
case OOPR_SHR: /* Shift AC Right, preserve bit 0. */
{
int32 bit0;
bit0 = AC & 0400000;
AC = AC >> 1;
AC |= bit0;
inst_ctr.shr++;
break;
}
case OOPR_CYR: /* cyr 1.4 Cycle the AC right one digital position (AC17 -> AC0) */
{
int32 bit17;
bit17 = (AC & 1) << 17;
AC >>= 1;
AC |= bit17;
inst_ctr.cyr++;
}
break;
}
if (op & OOPR_PAD) { /* 1.5 Partial Add (XOR): AC = MBR ^ AC */
if (op & OOPR_CRY) { /* 1.7 */
TRACE_PRINT(ORD_MSG, ("[%06o] PAD+CRY: AC=%06o, MBR=%06o = ", PC-1, AC, MBR));
AC = AC + MBR;
if (AC & 01000000) {
AC += 1;
}
AC &= DMASK;
TRACE_PRINT(ORD_MSG, ("%06o\n", AC));
inst_ctr.cry++;
} else {
TRACE_PRINT(ORD_MSG, ("[%06o] PAD: AC=%06o, MBR=%06o\n", PC-1, AC, MBR));
AC = AC ^ MBR;
AC &= DMASK;
TRACE_PRINT(ORD_MSG, ("[%06o] PAD: Check: AC=%06o\n", PC-1, AC));
}
inst_ctr.pad++;
}
if (op & OOPR_CRY) { /* 1.7 */
if (op & OOPR_PAD) {
} else {
TRACE_PRINT(ERROR_MSG, ("[%06o] CRY: TODO: AC=%06o\n", PC-1, AC));
inst_ctr.cry++;
}
}
if ((op & OOPR_HLT) == OOPR_HLT) { /* hlt 1.8 Halt the computer */
TRACE_PRINT(IOS_MSG, ("[%06o] HALT Instruction\n", PC-1));
reason = STOP_HALT;
}
return reason;
}