964 lines
32 KiB
C
964 lines
32 KiB
C
/* i701_cpu.c: IBM 701 CPU simulator
|
||
|
||
Copyright (c) 2005-2016, Richard Cornwell
|
||
|
||
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
|
||
RICHARD CORNWELL 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.
|
||
|
||
cpu 701 central processor
|
||
|
||
The IBM 701 also know as "Defense Calculator" was introduced by IBM
|
||
on April 7, 1953. This computer was start of IBM 700 and 7000 line.
|
||
Memory was 2048 36 bit words. Each instruction could be signed plus
|
||
or minus, plus would access memory as 18 bit words, minus as 36 bit
|
||
words. There was a expansion option to add another 2048 words of
|
||
memory, but I can't find documentation on how it worked. Memory cycle
|
||
time was 12 microseconds. The 701 was withdrawn from the market
|
||
October 1, 1954 replaced by 704 and 702. A total of 19 machines were
|
||
installed.
|
||
|
||
The system state for the IBM 701 is:
|
||
|
||
AC<S,P,Q,1:35> AC register
|
||
MQ<S,1:35> MQ register
|
||
IC<0:15> program counter
|
||
SSW<0:5> sense switches
|
||
SLT<0:3> sense lights
|
||
ACOVF AC overflow
|
||
DVC divide check
|
||
IOC I/O check
|
||
|
||
The 701 had one instruction format: memory reference,
|
||
|
||
00000 000011111111
|
||
S 12345 678901234567
|
||
+-+-----+------------+
|
||
| |opcod| address | memory reference
|
||
+-+-----+------------+
|
||
|
||
This routine is the instruction decode routine for the 701.
|
||
It is called from the simulator control program to execute
|
||
instructions in simulated memory, starting at the simulated PC.
|
||
It runs until a stop condition occurs.
|
||
|
||
General notes:
|
||
|
||
1. Reasons to stop. The simulator can be stopped by:
|
||
|
||
HALT instruction
|
||
illegal instruction
|
||
illegal I/O operation for device
|
||
illegal I/O operation for channel
|
||
breakpoint encountered
|
||
nested XEC's exceeding limit
|
||
divide check
|
||
I/O error in I/O simulator
|
||
|
||
3. Arithmetic. The 701 uses signed magnitude arithmetic for
|
||
integer and floating point calculations, and 2's complement
|
||
arithmetic for indexing calculations.
|
||
|
||
4. Adding I/O devices. These modules must be modified:
|
||
|
||
i7090_defs.h add device definitions
|
||
i7090_chan.c add channel subsystem
|
||
i701_sys.c add sim_devices table entry
|
||
*/
|
||
|
||
#include "i7090_defs.h"
|
||
|
||
#define HIST_XCT 1 /* instruction */
|
||
#define HIST_INT 2 /* interrupt cycle */
|
||
#define HIST_TRP 3 /* trap cycle */
|
||
#define HIST_MIN 64
|
||
#define HIST_MAX 65536
|
||
#define HIST_NOEA 0x40000000
|
||
#define HIST_PC 0x10000
|
||
|
||
struct InstHistory
|
||
{
|
||
t_int64 ac;
|
||
t_int64 mq;
|
||
t_int64 op;
|
||
t_int64 sr;
|
||
uint32 ic;
|
||
uint16 ea;
|
||
};
|
||
|
||
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_show_hist(FILE * st, UNIT * uptr, int32 val,
|
||
CONST void *desc);
|
||
t_stat cpu_set_hist(UNIT * uptr, int32 val, CONST char *cptr,
|
||
void *desc);
|
||
t_stat cpu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag,
|
||
const char *cptr);
|
||
const char *cpu_description (DEVICE *dptr);
|
||
|
||
|
||
t_uint64 M[MAXMEMSIZE] = { 0 }; /* memory */
|
||
t_uint64 AC, MQ; /* registers */
|
||
uint16 IC; /* program counter */
|
||
uint8 SL; /* Sense lights */
|
||
uint8 SW = 0; /* Sense switch */
|
||
uint8 dcheck; /* Divide check */
|
||
uint8 acoflag; /* AC Overflow */
|
||
uint8 ihold = 0; /* Hold interrupts */
|
||
uint16 iotraps; /* IO trap flags */
|
||
t_uint64 ioflags; /* Trap enable flags */
|
||
uint8 iocheck;
|
||
uint8 iowait; /* Waiting on io */
|
||
uint8 dualcore; /* Set to true if dual core in
|
||
use */
|
||
uint16 dev_pulse[NUM_CHAN]; /* SPRA device pulses */
|
||
int cycle_time = 120; /* Cycle time of 12us */
|
||
|
||
/* History information */
|
||
int32 hst_p = 0; /* History pointer */
|
||
int32 hst_lnt = 0; /* History length */
|
||
struct InstHistory *hst = NULL; /* History stack */
|
||
extern uint32 drum_addr;
|
||
uint32 hsdrm_addr;
|
||
extern UNIT chan_unit[];
|
||
|
||
#undef AMASK /* Change definition of AMASK here */
|
||
#define AMASK 00000000007777L
|
||
|
||
/* CPU data structures
|
||
|
||
cpu_dev CPU device descriptor
|
||
cpu_unit CPU unit descriptor
|
||
cpu_reg CPU register list
|
||
cpu_mod CPU modifiers list
|
||
*/
|
||
|
||
UNIT cpu_unit =
|
||
{ UDATA(NULL, UNIT_BINK, MAXMEMSIZE / 2) };
|
||
|
||
REG cpu_reg[] = {
|
||
{ORDATAD(IC, IC, 15, "Instruction counter"), REG_FIT},
|
||
{ORDATAD(AC, AC, 38, "Accumulator"), REG_FIT},
|
||
{ORDATAD(MQ, MQ, 36, "Multiplier quotent"), REG_FIT},
|
||
{ORDATAD(SL, SL, 4, "Lights"), REG_FIT},
|
||
{ORDATAD(SW, SW, 6, "Switch register"), REG_FIT},
|
||
{FLDATAD(SW1, SW, 0, "Switch 0"), REG_FIT},
|
||
{FLDATAD(SW2, SW, 1, "Switch 1"), REG_FIT},
|
||
{FLDATAD(SW3, SW, 2, "Switch 2"), REG_FIT},
|
||
{FLDATAD(SW4, SW, 3, "Switch 3"), REG_FIT},
|
||
{FLDATAD(SW5, SW, 4, "Switch 4"), REG_FIT},
|
||
{FLDATAD(SW6, SW, 5, "Switch 5"), REG_FIT},
|
||
{ORDATAD(ACOVF, acoflag, 1, "Overflow flag"), REG_FIT},
|
||
{ORDATAD(IOC, iocheck, 1, "I/O Check flag"), REG_FIT},
|
||
{ORDATAD(DVC, dcheck, 1, "Divide Check"), REG_FIT},
|
||
{NULL}
|
||
};
|
||
|
||
MTAB cpu_mod[] = {
|
||
{MTAB_XTD | MTAB_VDV | MTAB_NMO | MTAB_SHP, 0, "HISTORY", "HISTORY",
|
||
&cpu_set_hist, &cpu_show_hist},
|
||
{0}
|
||
};
|
||
|
||
DEVICE cpu_dev = {
|
||
"CPU", &cpu_unit, cpu_reg, cpu_mod,
|
||
1, 8, 15, 1, 8, 36,
|
||
&cpu_ex, &cpu_dep, &cpu_reset, NULL, NULL, NULL,
|
||
NULL, 0, 0, NULL,
|
||
NULL, NULL, &cpu_help, NULL, NULL, &cpu_description
|
||
};
|
||
|
||
/* Simulate instructions */
|
||
t_stat
|
||
sim_instr(void)
|
||
{
|
||
t_stat reason;
|
||
t_uint64 temp = 0;
|
||
t_uint64 ibr;
|
||
t_uint64 SR;
|
||
uint16 opcode;
|
||
uint16 MA;
|
||
uint8 f;
|
||
int shiftcnt;
|
||
int stopnext = 0;
|
||
int instr_count = 0; /* Number of instructions to execute */
|
||
|
||
if (sim_step != 0) {
|
||
instr_count = sim_step;
|
||
sim_cancel_step();
|
||
}
|
||
|
||
reason = 0;
|
||
|
||
iowait = 0;
|
||
while (reason == 0) { /* loop until halted */
|
||
|
||
/* If doing fast I/O don't sit in idle loop */
|
||
if (iowait == 0 && stopnext)
|
||
return SCPE_STEP;
|
||
|
||
if (sim_interval <= 0) { /* event queue? */
|
||
reason = sim_process_event();
|
||
if (reason != SCPE_OK) {
|
||
if (reason == SCPE_STEP && iowait)
|
||
stopnext = 1;
|
||
else
|
||
break; /* process */
|
||
}
|
||
}
|
||
|
||
if (iowait == 0 && sim_brk_summ && sim_brk_test(IC, SWMASK('E'))) {
|
||
reason = STOP_IBKPT;
|
||
break;
|
||
}
|
||
|
||
/* Split out current instruction */
|
||
if (iowait) {
|
||
/* If we are awaiting I/O complete, don't fetch. */
|
||
sim_interval -= 6;
|
||
iowait = 0;
|
||
} else {
|
||
MA = IC >> 1;
|
||
sim_interval -= 24; /* count down */
|
||
SR = ReadP(MA);
|
||
temp = SR;
|
||
if ((IC & 1) == 0)
|
||
temp >>= 18;
|
||
if (hst_lnt) { /* history enabled? */
|
||
hst_p = (hst_p + 1); /* next entry */
|
||
if (hst_p >= hst_lnt)
|
||
hst_p = 0;
|
||
hst[hst_p].ic = IC | HIST_PC;
|
||
hst[hst_p].ea = 0;
|
||
hst[hst_p].op = temp & RMASK;
|
||
hst[hst_p].ac = AC;
|
||
hst[hst_p].mq = MQ;
|
||
hst[hst_p].sr = 0;
|
||
}
|
||
IC = (IC + 1) & AMASK;
|
||
}
|
||
ihold = 0;
|
||
opcode = ((uint16)(temp >> 12L)) & 077;
|
||
MA = (uint16)(temp & AMASK);
|
||
ibr = SR = ReadP(MA>>1);
|
||
if ((opcode & 040) == 0) {
|
||
if (MA & 1)
|
||
SR <<= 18;
|
||
SR &= LMASK;
|
||
}
|
||
if (hst_lnt) { /* history enabled? */
|
||
hst[hst_p].sr = SR;
|
||
hst[hst_p].ea = MA;
|
||
}
|
||
|
||
switch (opcode & 037) {
|
||
case 19: /* RND */
|
||
if (MQ & ONEBIT)
|
||
AC++;
|
||
break;
|
||
case 30: /* SENSE */
|
||
switch (MA) {
|
||
case 64: /* SLN */
|
||
SL = 0;
|
||
break;
|
||
case 65: /* */
|
||
SL |= 1;
|
||
break;
|
||
case 66:
|
||
SL |= 2;
|
||
break;
|
||
case 67:
|
||
SL |= 4;
|
||
break;
|
||
case 68:
|
||
SL |= 8;
|
||
break;
|
||
case 69:
|
||
if ((SW & 1) == 0)
|
||
IC++;
|
||
break;
|
||
case 70:
|
||
if ((SW & 2) == 0)
|
||
IC++;
|
||
break;
|
||
case 71:
|
||
if ((SW & 4) == 0)
|
||
IC++;
|
||
break;
|
||
case 72:
|
||
if ((SW & 8) == 0)
|
||
IC++;
|
||
break;
|
||
case 73:
|
||
if ((SW & 16) == 0)
|
||
IC++;
|
||
break;
|
||
case 74:
|
||
if ((SW & 32) == 0)
|
||
IC++;
|
||
break;
|
||
case 1024:
|
||
case 1025:
|
||
MA -= 1024;
|
||
dev_pulse[0] |= 1 << MA;
|
||
break;
|
||
case 522:
|
||
if (dev_pulse[0] & PRINT_I)
|
||
IC++;
|
||
dev_pulse[0] &= ~PRINT_I;
|
||
break;
|
||
case 512:
|
||
case 513:
|
||
case 514:
|
||
case 515:
|
||
case 516:
|
||
case 517:
|
||
case 518:
|
||
case 519:
|
||
case 520:
|
||
case 521:
|
||
MA = (MA - 512) + 5;
|
||
dev_pulse[0] |= 1 << MA;
|
||
break;
|
||
}
|
||
break;
|
||
case 0: /* STOP */
|
||
/* Stop at HTR instruction if trapped */
|
||
IC--;
|
||
halt:
|
||
reason = STOP_HALT;
|
||
/* Clear off any pending events before we halt */
|
||
do {
|
||
|
||
f = chan_active(0);
|
||
chan_proc();
|
||
for (shiftcnt = 1; shiftcnt < NUM_CHAN; shiftcnt++) {
|
||
f |= chan_active(shiftcnt);
|
||
}
|
||
sim_interval = 0;
|
||
(void)sim_process_event();
|
||
} while (f);
|
||
if (reason != 0)
|
||
IC = MA;
|
||
break;
|
||
case 8: /* NO OP */
|
||
break;
|
||
case 1: /* TR */
|
||
IC = MA;
|
||
break;
|
||
case 4: /* TR 0 */
|
||
f = (AC & AMMASK) == 0;
|
||
branch:
|
||
if (f) {
|
||
IC = MA;
|
||
}
|
||
break;
|
||
case 2: /* TR OV */
|
||
f = acoflag;
|
||
acoflag = 0;
|
||
goto branch;
|
||
case 3: /* TR + */
|
||
f = ((AC & AMSIGN) == 0);
|
||
goto branch;
|
||
case 10: /* R ADD */
|
||
AC = ((SR & MSIGN) << 2) | (SR & PMASK);
|
||
sim_interval -= 6;
|
||
break;
|
||
case 6: /* R SUB */
|
||
AC = (((SR & MSIGN) ^ MSIGN) << 2) | (SR & PMASK);
|
||
sim_interval -= 6;
|
||
break;
|
||
case 15: /* LOAD MQ */
|
||
MQ = SR;
|
||
sim_interval -= 6;
|
||
break;
|
||
case 14: /* STORE MQ */
|
||
SR = MQ;
|
||
goto store;
|
||
case 12: /* STORE */
|
||
SR = AC & PMASK;
|
||
if (AC & AMSIGN)
|
||
SR |= MSIGN;
|
||
store:
|
||
if ((opcode & 040) == 0) {
|
||
SR &= LMASK;
|
||
if (MA & 1) {
|
||
ibr &= LMASK;
|
||
SR >>= 18;
|
||
} else {
|
||
ibr &= RMASK;
|
||
}
|
||
SR |= ibr;
|
||
}
|
||
WriteP(MA>>1, SR);
|
||
if (hst_lnt) { /* history enabled? */
|
||
hst[hst_p].sr = SR;
|
||
}
|
||
sim_interval -= 6;
|
||
break;
|
||
/* Logic operations */
|
||
case 13: /* EXTR or STORE A */
|
||
if ((opcode & 040) == 0) {
|
||
SR &= ~(AMASK << 18);
|
||
SR |= AC & (AMASK << 18);
|
||
} else {
|
||
t_uint64 t = AC & PMASK;
|
||
if (AC & AMSIGN)
|
||
t |= MSIGN;
|
||
SR &= t;
|
||
}
|
||
goto store;
|
||
case 7: /* SUB AB */
|
||
SR |= MSIGN;
|
||
goto iadd;
|
||
case 11: /* ADD AB */
|
||
SR &= PMASK;
|
||
goto iadd;
|
||
case 5: /* SUB */
|
||
SR ^= MSIGN;
|
||
/* Fall through */
|
||
case 9: /* ADD */
|
||
iadd:
|
||
f = 0;
|
||
/* Make AC Positive */
|
||
if (AC & AMSIGN) {
|
||
f = 2;
|
||
AC &= AMMASK;
|
||
}
|
||
if (AC & APSIGN)
|
||
f |= 8;
|
||
/* Check signes of SR & AC */
|
||
if (((SR & MSIGN) && ((f & 2) == 0)) ||
|
||
(((SR & MSIGN) == 0) && ((f & 2) != 0))) {
|
||
AC ^= AMMASK; /* One's compliment */
|
||
f |= 1;
|
||
}
|
||
AC = AC + (SR & PMASK);
|
||
/* Check carry from Q */
|
||
if (f & 1) { /* Check if signs were not same */
|
||
if (AC & AMSIGN) {
|
||
f ^= 2;
|
||
AC++;
|
||
if (((AC & APSIGN) != 0) != ((f & 8) != 0))
|
||
acoflag = 1;
|
||
} else {
|
||
AC ^= AMMASK; /* One's compliment */
|
||
}
|
||
} else {
|
||
if (((AC & APSIGN) != 0) != ((f & 8) != 0))
|
||
acoflag = 1;
|
||
}
|
||
/* Restore sign to AC */
|
||
AC &= AMMASK;
|
||
if (f & 2)
|
||
AC |= AMSIGN;
|
||
sim_interval -= 6;
|
||
break;
|
||
case 16: /* MPY */
|
||
case 17: /* MPY R */
|
||
shiftcnt = 043;
|
||
sim_interval -= 34 * 6;
|
||
f = 0;
|
||
/* Save sign */
|
||
if (MQ & MSIGN)
|
||
f |= 1;
|
||
if (SR & MSIGN)
|
||
f |= 2;
|
||
SR &= PMASK;
|
||
MQ &= PMASK;
|
||
AC = 0; /* Clear AC */
|
||
if (SR == 0) {
|
||
MQ = 0;
|
||
} else {
|
||
while (shiftcnt-- > 0) {
|
||
if (MQ & 1)
|
||
AC += SR;
|
||
MQ >>= 1;
|
||
if (AC & 1)
|
||
MQ |= ONEBIT;
|
||
AC >>= 1;
|
||
}
|
||
}
|
||
if ((opcode & 037) == 17 && MQ & ONEBIT)
|
||
AC++;
|
||
if (f & 2)
|
||
f ^= 1;
|
||
if (f & 1) {
|
||
MQ |= MSIGN;
|
||
AC |= AMSIGN;
|
||
}
|
||
break;
|
||
case 18: /* DIV */
|
||
shiftcnt = 043;
|
||
sim_interval -= 34 * 6;
|
||
/* Save sign */
|
||
if (SR & MSIGN) {
|
||
SR &= PMASK;
|
||
f = 1;
|
||
} else
|
||
f = 0;
|
||
|
||
if (AC & AMSIGN)
|
||
f |= 2;
|
||
|
||
/* Check if SR less then AC */
|
||
if (((SR - (AC & AMMASK)) & AMSIGN) ||
|
||
(SR == (AC & AMMASK))) {
|
||
dcheck = 1;
|
||
MQ &= PMASK;
|
||
if (f == 1 || f == 2)
|
||
MQ |= MSIGN;
|
||
goto halt;
|
||
}
|
||
/* Clear signs */
|
||
MQ &= PMASK;
|
||
AC &= AMMASK;
|
||
/* Do divide operation */
|
||
do {
|
||
AC <<= 1;
|
||
AC &= AMMASK;
|
||
MQ <<= 1;
|
||
if (MQ & MSIGN) {
|
||
MQ ^= MSIGN;
|
||
AC |= 1;
|
||
}
|
||
if (SR <= AC) {
|
||
AC -= SR;
|
||
MQ |= 1;
|
||
}
|
||
} while (--shiftcnt != 0);
|
||
switch (f) {
|
||
case 0:
|
||
break;
|
||
case 3:
|
||
AC |= AMSIGN;
|
||
break;
|
||
case 2:
|
||
AC |= AMSIGN;
|
||
/* FALL THRU */
|
||
case 1:
|
||
MQ |= MSIGN;
|
||
break;
|
||
}
|
||
break;
|
||
|
||
/* Shift */
|
||
case 20: /* L LEFT */
|
||
shiftcnt = MA & 0377;
|
||
sim_interval -= (shiftcnt >> 6) * 6;
|
||
/* Save sign */
|
||
if (MQ & MSIGN)
|
||
f = 1;
|
||
else
|
||
f = 0;
|
||
/* Clear it for now */
|
||
AC &= AQMASK;
|
||
while (shiftcnt-- > 0) {
|
||
MQ <<= 1;
|
||
AC <<= 1;
|
||
if (MQ & MSIGN)
|
||
AC |= 1;
|
||
if (AC & APSIGN)
|
||
acoflag = 1;
|
||
}
|
||
/* Restore sign when done */
|
||
AC &= AMMASK;
|
||
MQ &= PMASK;
|
||
if (f) {
|
||
AC |= AMSIGN;
|
||
MQ |= MSIGN;
|
||
}
|
||
break;
|
||
case 21: /* L RIGHT */
|
||
shiftcnt = MA & 0377;
|
||
sim_interval -= (shiftcnt >> 6) * 6;
|
||
/* Save sign */
|
||
if (AC & AMSIGN)
|
||
f = 1;
|
||
else
|
||
f = 0;
|
||
/* Clear it for now */
|
||
AC &= AMMASK;
|
||
MQ &= PMASK;
|
||
while (shiftcnt-- > 0) {
|
||
if (AC & 1)
|
||
MQ |= MSIGN;;
|
||
MQ >>= 1;
|
||
AC >>= 1;
|
||
}
|
||
/* Restore sign when done */
|
||
AC &= AMMASK;
|
||
if (f) {
|
||
AC |= AMSIGN;
|
||
MQ |= MSIGN;
|
||
}
|
||
break;
|
||
case 22: /* A LEFT */
|
||
shiftcnt = MA & 0377;
|
||
sim_interval -= (shiftcnt >> 6) * 6;
|
||
/* Save sign */
|
||
if (AC & AMSIGN)
|
||
f = 1;
|
||
else
|
||
f = 0;
|
||
/* Clear it for now */
|
||
AC &= AQMASK;
|
||
while (shiftcnt-- > 0) {
|
||
AC <<= 1;
|
||
if (AC & APSIGN)
|
||
acoflag = 1;
|
||
}
|
||
/* Restore sign and overflow when done */
|
||
AC &= AMMASK;
|
||
if (f)
|
||
AC |= AMSIGN;
|
||
break;
|
||
case 23: /* A RIGHT */
|
||
shiftcnt = MA & 0377;
|
||
sim_interval -= (shiftcnt >> 6) * 6;
|
||
/* Save sign */
|
||
if (AC & AMSIGN)
|
||
f = 1;
|
||
else
|
||
f = 0;
|
||
/* Clear it for now */
|
||
AC &= AMMASK;
|
||
AC >>= shiftcnt;
|
||
/* Restore sign when done */
|
||
if (f)
|
||
AC |= AMSIGN;
|
||
break;
|
||
|
||
/* 704 Input output Instructions */
|
||
case 29: /* SET DR */
|
||
if (chan_test(0, DEV_SEL)) {
|
||
drum_addr = (uint32)MA;
|
||
chan_clear(0, DEV_FULL); /* Incase something got
|
||
read while waiting */
|
||
} else
|
||
iocheck = 1;
|
||
break;
|
||
case 31: /* COPY */
|
||
/* If no channel, set Iocheck and treat as nop */
|
||
if (chan_unit[0].flags & UNIT_DIS) {
|
||
iocheck = 1;
|
||
break;
|
||
}
|
||
|
||
/* If device disconnecting, just wait */
|
||
if (chan_test(0, DEV_DISCO)) {
|
||
iowait = 1;
|
||
break;
|
||
}
|
||
|
||
/* Instruct is NOP first time */
|
||
/* Incomplete last word leaves result in MQ */
|
||
if (chan_select(0)) {
|
||
extern uint8 bcnt[NUM_CHAN];
|
||
chan_set(0, STA_ACTIVE);
|
||
switch (chan_flags[0] & (DEV_WRITE | DEV_FULL)) {
|
||
case DEV_WRITE | DEV_FULL:
|
||
case 0:
|
||
/* On EOR skip 1, on EOF skip two */
|
||
if (chan_test(0, CHS_EOF|CHS_EOT|DEV_REOR))
|
||
chan_set(0, DEV_DISCO);
|
||
iowait = 1;
|
||
break;
|
||
case DEV_WRITE:
|
||
MQ = assembly[0] = SR;
|
||
bcnt[0] = 6;
|
||
chan_set(0, DEV_FULL);
|
||
break;
|
||
case DEV_FULL:
|
||
SR = MQ;
|
||
WriteP(MA, MQ);
|
||
bcnt[0] = 6;
|
||
chan_clear(0, DEV_FULL);
|
||
break;
|
||
}
|
||
} else {
|
||
if (chan_stat(0, CHS_EOF|CHS_EOT)) {
|
||
IC++;
|
||
/* On EOR skip two */
|
||
} else if (chan_stat(0, DEV_REOR)) {
|
||
IC += 2;
|
||
/* Advance 1 on Error and set iocheck */
|
||
} else if (chan_stat(0, CHS_ERR)) {
|
||
iocheck = 1;
|
||
IC++;
|
||
}
|
||
chan_clear(0, STA_ACTIVE|DEV_REOR|CHS_ERR);
|
||
break;
|
||
}
|
||
break;
|
||
|
||
/* Input/Output Instuctions */
|
||
case 24: /* Read select */
|
||
opcode = IO_RDS;
|
||
MQ = 0;
|
||
goto iostart;
|
||
case 26: /* Write select */
|
||
opcode = IO_WRS;
|
||
goto iostart;
|
||
case 27: /* Write EOF */
|
||
opcode = IO_WEF;
|
||
goto iostart;
|
||
case 25: /* Read Backwards */
|
||
opcode = IO_RDB;
|
||
MQ = 0;
|
||
goto iostart;
|
||
case 28: /* Rewind */
|
||
opcode = IO_REW;
|
||
iostart:
|
||
switch (chan_cmd(MA, opcode)) {
|
||
case SCPE_BUSY:
|
||
iowait = 1; /* Channel is active, hold */
|
||
case SCPE_OK:
|
||
ihold = 1; /* Hold interupts for one */
|
||
break;
|
||
case SCPE_IOERR:
|
||
iocheck = 1;
|
||
break;
|
||
case SCPE_NODEV:
|
||
reason = STOP_IOCHECK;
|
||
break;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
reason = STOP_UUO;
|
||
break;
|
||
}
|
||
|
||
chan_proc(); /* process any pending channel events */
|
||
if (instr_count != 0 && --instr_count == 0)
|
||
return SCPE_STEP;
|
||
} /* end while */
|
||
|
||
/* Simulation halted */
|
||
|
||
return reason;
|
||
}
|
||
|
||
|
||
/* Reset routine */
|
||
|
||
t_stat
|
||
cpu_reset(DEVICE * dptr)
|
||
{
|
||
extern void sys_init(void);
|
||
|
||
sys_init();
|
||
AC = 0;
|
||
MQ = 0;
|
||
dualcore = 0;
|
||
iotraps = 0;
|
||
ioflags = 0;
|
||
dcheck = acoflag = iocheck = 0;
|
||
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 * 2))
|
||
return SCPE_NXM;
|
||
if (vptr == NULL)
|
||
return SCPE_OK;
|
||
|
||
*vptr = M[(addr & 07777) >> 1];
|
||
if ((addr & 0400000) == 0) {
|
||
if ( addr & 1)
|
||
*vptr <<= 18;
|
||
else
|
||
*vptr &= LMASK;
|
||
}
|
||
*vptr &= 0777777777777L;
|
||
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Memory deposit */
|
||
|
||
t_stat
|
||
cpu_dep(t_value val, t_addr addr, UNIT * uptr, int32 sw)
|
||
{
|
||
t_addr a = (addr >> 1) & 03777;
|
||
|
||
if (addr >= (MEMSIZE * 2))
|
||
return SCPE_NXM;
|
||
if ((addr & 0400000) == 0) {
|
||
if (addr & 1) {
|
||
M[a] &= LMASK;
|
||
M[a] |= (val >> 18) & RMASK;
|
||
} else {
|
||
M[a] &= RMASK;
|
||
M[a] |= val & LMASK;
|
||
}
|
||
} else
|
||
M[a] = val & 0777777777777L;
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Handle execute history */
|
||
|
||
/* 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].ic = 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 = (struct InstHistory *)calloc(sizeof(struct InstHistory), lnt);
|
||
|
||
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 k, di, lnt;
|
||
char *cptr = (char *) desc;
|
||
t_stat r;
|
||
t_value sim_eval;
|
||
struct 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, "IC AC MQ EA SR\n\n");
|
||
for (k = 0; k < lnt; k++) { /* print specified */
|
||
h = &hst[(++di) % hst_lnt]; /* entry pointer */
|
||
if (h->ic & HIST_PC) { /* instruction? */
|
||
fprintf(st, "%06lo ", h->ic & AMASK);
|
||
switch (h->ac & (AMSIGN | AQSIGN | APSIGN)) {
|
||
case AMSIGN | AQSIGN | APSIGN:
|
||
fprintf(st, "-QP");
|
||
break;
|
||
case AMSIGN | AQSIGN:
|
||
fprintf(st, " -Q");
|
||
break;
|
||
case AMSIGN | APSIGN:
|
||
fprintf(st, " -P");
|
||
break;
|
||
case AMSIGN:
|
||
fprintf(st, " -");
|
||
break;
|
||
case AQSIGN | APSIGN:
|
||
fprintf(st, " QP");
|
||
break;
|
||
case AQSIGN:
|
||
fprintf(st, " Q");
|
||
break;
|
||
case APSIGN:
|
||
fprintf(st, " P");
|
||
break;
|
||
case 0:
|
||
fprintf(st, " ");
|
||
break;
|
||
}
|
||
fprint_val(st, h->ac & PMASK, 8, 35, PV_RZRO);
|
||
fputc(' ', st);
|
||
if (h->mq & MSIGN)
|
||
fputc('-', st);
|
||
else
|
||
fputc(' ', st);
|
||
fprint_val(st, h->mq & PMASK, 8, 35, PV_RZRO);
|
||
fputc(' ', st);
|
||
fprint_val(st, h->ea, 8, 12, PV_RZRO);
|
||
fputc(' ', st);
|
||
if (h->sr & MSIGN)
|
||
fputc('-', st);
|
||
else
|
||
fputc(' ', st);
|
||
fprint_val(st, h->sr & PMASK, 8, 35, PV_RZRO);
|
||
fputc(' ', st);
|
||
sim_eval = h->op;
|
||
if (
|
||
(fprint_sym
|
||
(st, h->ic & AMASK, &sim_eval, &cpu_unit,
|
||
SWMASK('M'))) > 0) fprintf(st, "(undefined) %012llo",
|
||
h->op);
|
||
fputc('\n', st); /* end line */
|
||
} /* end else instruction */
|
||
} /* end for */
|
||
return SCPE_OK;
|
||
}
|
||
|
||
const char *
|
||
cpu_description (DEVICE *dptr)
|
||
{
|
||
return "IBM 701 CPU";
|
||
}
|
||
|
||
t_stat
|
||
cpu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
|
||
{
|
||
fprintf (st, "The CPU behaves as a IBM 701\n");
|
||
fprintf (st, "These switches are recognized when examining or depositing in CPU memory:\n\n");
|
||
fprintf (st, " -c examine/deposit characters, 6 per word\n");
|
||
fprintf (st, " -l examine/deposit half words\n");
|
||
fprintf (st, " -m examine/deposit IBM 701 instructions\n\n");
|
||
fprintf (st, "The CPU can maintain a history of the most recently executed instructions.\n");
|
||
fprintf (st, "This is controlled by the SET CPU HISTORY and SHOW CPU HISTORY commands:\n\n");
|
||
fprintf (st, " sim> SET CPU HISTORY clear history buffer\n");
|
||
fprintf (st, " sim> SET CPU HISTORY=0 disable history\n");
|
||
fprintf (st, " sim> SET CPU HISTORY=n{:file} enable history, length = n\n");
|
||
fprintf (st, " sim> SHOW CPU HISTORY print CPU history\n");
|
||
fprint_set_help(st, dptr);
|
||
fprint_show_help(st, dptr);
|
||
|
||
return SCPE_OK;
|
||
}
|
||
|