blob: 7d7f802d6242af48a4a1d6cc31614f276819ffd5 [file] [log] [blame] [raw]
/* i7080_cpu.c: IBM 7080 CPU simulator
Copyright (c) 2006-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 705 central processor
The system state for the IBM 705 is:
IC<0:15> program counter
SW<0:6> sense switches
AC<0:6>[0:512] AC
The 705 has one instruction format.
Char
1 2 3 4 5
opc addh add add addl
This routine is the instruction decode routine for the 705.
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
breakpoint encountered
divide check
I/O error in I/O simulator
2. Arithmetic. The 705 uses decimal arithmetic.
4. Adding I/O devices. These modules must be modified:
i705_defs.h add device definitions
i705_sys.c add sim_devices table entry
*/
#include "i7080_defs.h"
#include "sim_card.h"
#include <math.h>
#define UNIT_V_MSIZE (UNIT_V_UF + 0)
#define UNIT_MSIZE (017 << UNIT_V_MSIZE)
#define UNIT_V_CPUMODEL (UNIT_V_UF + 4)
#define UNIT_MODEL (0x3 << UNIT_V_CPUMODEL)
#define CPU_MODEL ((cpu_unit.flags >> UNIT_V_CPUMODEL) & 0x3)
#define MODEL(x) (x << UNIT_V_CPUMODEL)
#define MEMAMOUNT(x) (x << UNIT_V_MSIZE)
#define UNIT_EMU (UNIT_V_CPUMODEL + 2)
#define EMULATE3 (1 << UNIT_EMU)
#define EMULATE2 (2 << UNIT_EMU)
#define UNIT_V_NONSTOP (UNIT_EMU + 2)
#define NONSTOP (1 << UNIT_V_NONSTOP)
#define CPU_702 0x0
#define CPU_705 0x1
#define CPU_7053 0x2
#define CPU_7080 0x3
#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 0x80000
struct InstHistory
{
uint32 ic;
uint32 ea;
uint32 inst;
uint8 reg;
uint8 op;
uint16 flags;
uint8 store[256];
};
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);
uint32 read_addr(uint8 *reg, uint8 *zone);
void write_addr(uint32 addr, uint8 reg, uint8 zone);
uint32 load_addr(int loc);
void store_addr(uint32 addr, int loc);
void store_cpu(uint32 addr, int full);
void load_cpu(uint32 addr, int full);
uint16 get_acstart(uint8 reg);
t_stat do_addsub(int mode, int reg, int smt, uint16 fmsk);
t_stat do_mult(int reg, uint16 fmsk);
t_stat do_divide(int reg, uint16 fmsk);
t_stat do_compare(int reg, int tluop);
void mem_init(void);
uint16 bstarts[16] = {
/* 1 2 3 4 5 6 7 */
0, 512, 528, 544, 560, 576, 592, 608,
624, 640, 656, 672, 688, 704, 720, 736,
};
uint8 bcd_bin[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0,
1, 2, 3, 4, 5};
uint8 bin_bcd[21] = { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
uint32 dig2[11] = { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90,0 };
uint32 dig3[11] = { 0, 100, 200, 300, 400, 500, 600, 700, 800, 900,0 };
uint32 dig4[11] = { 0, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000,0};
uint32 dig_zone[16] = {0, 10000, 20000, 30000,
80000, 90000, 100000, 110000,
40000, 50000, 60000, 70000,
120000, 130000, 140000, 150000
};
uint8 zone_dig[16] = {0x0, 0x4, 0x8, 0xc,
0x2, 0x6, 0xa, 0xe,
0x1, 0x5, 0x9, 0xd,
0x3, 0x7, 0xb, 0xf
};
/* Flip BA bits of low order zone for LDA */
uint8 lda_flip[16] = {0x0, 0x1, 0x2, 0x3,
0x8, 0x9, 0xa, 0xb,
0x4, 0x5, 0x6, 0x7,
0xc, 0xd, 0xe, 0xf
};
/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */
uint8 comp_bcd[16] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 9, 6, 5, 4, 3, 2 };
#define I 0x80
uint8 digit_addone[16] = {
0,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10,0x01,0x0b,0x0c,0x0d,0x0e,
0x0f};
uint8 cmp_order[0100] = {
077, 42, 43, 44, 45, 46, 47, 48, 49, 50, 41, 10, 11, 077, 077, 077,
0, 7, 33, 34, 35, 36, 37, 38, 39, 40, 32, 8, 9, 077, 077, 077,
4, 23, 24, 25, 26, 27, 28, 29, 30, 31, 22, 5, 6, 077, 077, 077,
1, 13, 14, 15, 16, 17, 18, 19, 20, 21, 12, 2, 3, 077, 077, 077
};
/* Flags */
#define ASIGN 0x0001 /* ACC Minus */
#define BSIGN 0x0002 /* ASU Minus */
#define AZERO 0x0004 /* ACC A Zero */
#define BZERO 0x0008 /* ASU Zero */
#define INSTFLAG 0x0010 /* Instruction error */
#define MCHCHK 0x0020 /* Machine check */
#define IOCHK 0x0040 /* I/O Check */
#define RECCHK 0x0080 /* Record check */
#define ACOFLAG 0x0100 /* AC Overflow flag */
#define SGNFLAG 0x0200 /* Sign mismatch */
#define ANYFLAG 0x0400 /* Anyflag set */
#define EIGHTMODE 0x0800 /* 7080 mode */
#define HIGHFLAG 0x1000 /* High comparison */
#define LOWFLAG 0x2000 /* Low comparison */
#define CMPFLAG 0x3000 /* Comparison flags */
/* If stop_flags is set to 1 (Automatic Mode) the sim stops if the flag is
set. If the stop_flags is set to 0 (Program mode) the sim continues */
#define SIGN (ASIGN|BSIGN)
#define ZERO (AZERO|BZERO)
#define IRQFLAGS (INSTFLAG|MCHCHK|IOCHK|RECCHK|ACOFLAG|SGNFLAG)
uint8 M[MAXMEMSIZE] = { 0 }; /* memory */
uint32 EMEMSIZE; /* Physical memory size */
uint8 AC[6*256]; /* store registers */
uint16 flags; /* Flags */
uint16 spc; /* Reg start point */
uint16 spcb; /* Reg start point b */
uint32 IC; /* program counter */
uint8 SL; /* Sense lights */
uint32 MA; /* Memory address */
uint32 MAC; /* Memory address */
uint32 MAC2; /* Second memory address */
uint8 SW = 0; /* Sense switch */
uint8 indflag; /* Indirect flag */
uint8 intmode; /* Interupt mode */
uint8 intprog; /* Interupt program */
uint16 stop_flags = 0; /* Stop on error */
uint16 selreg; /* Last select address */
uint16 selreg2; /* RWW select address */
int chwait; /* Channel wait register */
uint8 ioflags[5000/8] = {0}; /* IO Error flags */
uint16 irqflags; /* IRQ Flags */
uint8 lpr_chan9[NUM_CHAN]; /* Line printer Channel 9 flag */
uint8 bkcmp = 0; /* Backwords compare */
uint8 cpu_type; /* Current CPU type */
int cycle_time = 45; /* Cycle time is 4.5us */
/* History information */
int32 hst_p = 0; /* History pointer */
int32 hst_lnt = 0; /* History length */
struct InstHistory *hst = NULL; /* History stack */
extern uint32 drum_addr;
extern UNIT chan_unit[];
void (*sim_vm_init) (void) = &mem_init;
/* 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, MODEL(CPU_7053) | MEMAMOUNT(3) | NONSTOP, MAXMEMSIZE) };
REG cpu_reg[] = {
{DRDATAD(IC, IC, 32, "Instruction register")},
{"A", &AC, 8, 8, 0, 256, "A Register", NULL, REG_VMIO|REG_CIRC, 0, },
{"ASU1", &AC[256], 8, 8, 256, 16, "ASU1 Register", NULL, REG_VMIO|REG_CIRC, 0},
{"ASU2", &AC[256], 8, 8, 256, 16, "ASU2 Register", NULL, REG_VMIO|REG_CIRC, 0},
{"ASU3", &AC[256], 8, 8, 256, 16, "ASU3 Register", NULL, REG_VMIO|REG_CIRC, 0},
{"ASU4", &AC[256], 8, 8, 256, 16, "ASU4 Register", NULL, REG_VMIO|REG_CIRC, 0},
{"ASU5", &AC[256], 8, 8, 256, 16, "ASU5 Register", NULL, REG_VMIO|REG_CIRC, 0},
{"ASU6", &AC[256], 8, 8, 256, 16, "ASU6 Register", NULL, REG_VMIO|REG_CIRC, 0},
{"ASU7", &AC[256], 8, 8, 256, 16, "ASU7 Register", NULL, REG_VMIO|REG_CIRC, 0},
{"ASU8", &AC[256], 8, 8, 256, 16, "ASU8 Register", NULL, REG_VMIO|REG_CIRC, 0},
{"ASU9", &AC[256], 8, 8, 256, 16, "ASU9 Register", NULL, REG_VMIO|REG_CIRC, 0},
{"ASU10", &AC[256], 8, 8, 256, 16, "ASU10 Register", NULL, REG_VMIO|REG_CIRC, 0},
{"ASU11", &AC[256], 8, 8, 256, 16, "ASU11 Register", NULL, REG_VMIO|REG_CIRC, 0},
{"ASU12", &AC[256], 8, 8, 256, 16, "ASU12 Register", NULL, REG_VMIO|REG_CIRC, 0},
{"ASU13", &AC[256], 8, 8, 256, 16, "ASU13 Register", NULL, REG_VMIO|REG_CIRC, 0},
{"ASU14", &AC[256], 8, 8, 256, 16, "ASU14 Register", NULL, REG_VMIO|REG_CIRC, 0},
{"ASU15", &AC[256], 8, 8, 256, 32, "ASU15 Register", NULL, REG_VMIO|REG_CIRC, 0},
{BRDATA(SW, &SW, 2, 6, 1), REG_FIT},
{FLDATA(SW911, SW, 0), REG_FIT},
{FLDATA(SW912, SW, 1), REG_FIT},
{FLDATA(SW913, SW, 2), REG_FIT},
{FLDATA(SW914, SW, 3), REG_FIT},
{FLDATA(SW915, SW, 4), REG_FIT},
{FLDATA(SW916, SW, 5), REG_FIT},
{GRDATA(STOP, stop_flags, 2, 6, 4), REG_FIT},
{FLDATA(STOP0, stop_flags, 4), REG_FIT},
{FLDATA(STOP1, stop_flags, 5), REG_FIT},
{FLDATA(STOP2, stop_flags, 6), REG_FIT},
{FLDATA(STOP3, stop_flags, 7), REG_FIT},
{FLDATA(STOP4, stop_flags, 8), REG_FIT},
{FLDATA(STOP5, stop_flags, 9), REG_FIT},
{NULL}
};
MTAB cpu_mod[] = {
{UNIT_MODEL, MODEL(CPU_702), "702", "702", NULL, NULL, NULL},
{UNIT_MODEL, MODEL(CPU_705), "705", "705", NULL, NULL, NULL},
{UNIT_MODEL, MODEL(CPU_7053), "7053", "7053", NULL, NULL, NULL},
{UNIT_MODEL, MODEL(CPU_7080), "7080", "7080", NULL, NULL, NULL},
{UNIT_MSIZE, MEMAMOUNT(0), "10K", "10K", &cpu_set_size},
{UNIT_MSIZE, MEMAMOUNT(1), "20K", "20K", &cpu_set_size},
{UNIT_MSIZE, MEMAMOUNT(3), "40K", "40K", &cpu_set_size},
{UNIT_MSIZE, MEMAMOUNT(7), "80K", "80K", &cpu_set_size},
{UNIT_MSIZE, MEMAMOUNT(11), "120K", "120K", &cpu_set_size},
{UNIT_MSIZE, MEMAMOUNT(15), "160K", "160K", &cpu_set_size},
{EMULATE2, 0, NULL, "NOEMU40K", NULL, NULL, NULL},
{EMULATE2, EMULATE2, "EMU40K", "EMU40K", NULL, NULL, NULL},
{EMULATE3, 0, "EMU705", "EMU705", NULL, NULL, NULL},
{EMULATE3, EMULATE3, "EMU7053", "EMU7053", NULL, NULL, NULL},
{NONSTOP, 0, "PROGRAM", "PROGRAM", NULL, NULL, NULL},
{NONSTOP, NONSTOP, "NONSTOP", "NONSTOP", NULL, NULL, NULL},
{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, 10, 18, 1, 8, 8,
&cpu_ex, &cpu_dep, &cpu_reset, NULL, NULL, NULL,
NULL, DEV_DEBUG, 0, dev_debug,
NULL, NULL, &cpu_help, NULL, NULL, &cpu_description
};
/* Quick ways to wrap addresses */
uint16 next_addr[6 * 256]; /* Next storage location */
uint16 prev_addr[6 * 256]; /* Previous storage location */
uint16 next_half[6 * 256]; /* Forward half loop locations */
/*#define ReadP(addr) M[(addr) % EMEMSIZE] */
#define WriteP(addr, data) M[(addr) % EMEMSIZE] = data
#define Next(reg) if (reg == 0) reg = EMEMSIZE; reg--
#define Prev5(reg) reg += 5; if (reg > EMEMSIZE) reg -= EMEMSIZE
#define Prev10(reg) reg += 10; if (reg > EMEMSIZE) reg -= EMEMSIZE
#define Prev(reg) reg++; if (reg == EMEMSIZE) reg = 0
/* Read 1 character from memory, checking for reducancy error. */
uint8 ReadP(uint32 addr, uint16 flag) {
uint8 value;
value = M[(addr) % EMEMSIZE];
if (value & 0100) {
if (flag == 0)
return value;
flags |= flag|ANYFLAG;
} else if (value == 0) {
flags |= flag|ANYFLAG;
}
return value & 077;
}
/* Read 5 characters from memory starting at addr */
uint32 Read5(uint32 addr, uint16 flag) {
uint32 value;
value = ReadP(addr-4, flag) << (4 * 6);
value |= ReadP(addr-3, flag) << (3 * 6);
value |= ReadP(addr-2, flag) << (2 * 6);
value |= ReadP(addr-1, flag) << (1 * 6);
value |= ReadP(addr, flag);
return value;
}
/* Write 5 characters from memory starting at addr */
void Write5(uint32 addr, uint32 value) {
WriteP(addr-4, 077 & (value >> (4 * 6)));
WriteP(addr-3, 077 & (value >> (3 * 6)));
WriteP(addr-2, 077 & (value >> (2 * 6)));
WriteP(addr-1, 077 & (value >> (1 * 6)));
WriteP(addr , 077 & (value));
}
t_stat
sim_instr(void)
{
t_stat reason;
int opcode;
uint8 reg;
uint16 fmsk;
uint8 zone;
uint8 sign;
uint8 zero;
uint8 at;
uint8 carry;
uint8 t;
uint8 cr1, cr2;
int temp;
uint32 addr;
uint8 iowait = 0;
int instr_count = 0; /* Number of instructions to execute */
if (sim_step != 0) {
instr_count = sim_step;
sim_cancel_step();
}
cpu_type = CPU_MODEL;
/* Adjust max memory and flags based on emulation mode */
EMEMSIZE = MEMSIZE;
switch (cpu_type) {
case CPU_7080:
if ((flags & EIGHTMODE) == 0) {
cpu_type = (cpu_unit.flags & EMULATE3)?CPU_7053:CPU_705;
EMEMSIZE = MEMSIZE;
if (cpu_unit.flags & EMULATE2 && EMEMSIZE > 40000)
EMEMSIZE = 40000;
if (cpu_type == CPU_705 && (cpu_unit.flags & EMULATE2) == 0
&& EMEMSIZE > 20000)
EMEMSIZE = 20000;
if (EMEMSIZE > 80000)
EMEMSIZE = 80000;
}
break;
case CPU_7053:
if (EMEMSIZE > 80000)
EMEMSIZE = 80000;
if (cpu_unit.flags & EMULATE2 && EMEMSIZE > 40000)
EMEMSIZE = 40000;
break;
case CPU_705:
if (cpu_unit.flags & EMULATE2 && EMEMSIZE > 40000)
EMEMSIZE = 40000;
else if (EMEMSIZE > 20000)
EMEMSIZE = 20000;
break;
case CPU_702:
EMEMSIZE = 10000;
break;
}
reason = 0;
while (reason == 0) { /* loop until halted */
chan_proc();
if (chwait != 0) {
if (chan_active(chwait - 1)) {
sim_interval = 0;
} else {
chwait = 0;
}
}
stop_cpu:
if (sim_interval <= 0) { /* event queue? */
reason = sim_process_event();
if (reason != SCPE_OK)
break; /* process */
}
if (sim_brk_summ && sim_brk_test(IC, SWMASK('E'))) {
reason = STOP_IBKPT;
break;
}
/* Make sure instruction is on 4 or 9 boundary */
if (((IC + 1) % 5) != 0) {
flags |= INSTFLAG|ANYFLAG;
}
/* Check stop conditions */
if ((cpu_unit.flags & NONSTOP) && (intprog == 0) && intmode != 0 &&
selreg2 == 0 && (IRQFLAGS & flags)) {
/* Process as interrupt */
Next(IC); /* Back up to start of instruction */
Next(IC);
Next(IC);
Next(IC);
Next(IC);
store_cpu(0x3E0, 1);
load_cpu(0x2A0, 0);
intprog = 1;
spc = 0x200;
} else if (((cpu_unit.flags & NONSTOP) == 0 || intprog == 0) &&
(stop_flags & flags)) {
/* Issue sim halt */
if (stop_flags & flags & INSTFLAG) {
reason = STOP_UUO;
flags &= ~ (INSTFLAG|ANYFLAG);
break;
}
if (stop_flags & flags & MCHCHK) {
reason = STOP_MMTRP;
flags &= ~(MCHCHK|ANYFLAG);
break;
}
if (stop_flags & flags & IOCHK) {
reason = STOP_IOCHECK;
flags &= ~(IOCHK|ANYFLAG);
break;
}
if (stop_flags & flags & RECCHK) {
reason = STOP_RECCHK;
flags &= ~(RECCHK|ANYFLAG);
break;
}
if (stop_flags & flags & ACOFLAG) {
reason = STOP_ACOFL;
flags &= ~(ACOFLAG|ANYFLAG);
break;
}
if (stop_flags & flags & SGNFLAG) {
reason = STOP_SIGN;
flags &= ~(SGNFLAG|ANYFLAG);
break;
}
} else if (cpu_unit.flags & NONSTOP && intprog && (IRQFLAGS & flags)) {
/* Issue sim halt */
if (flags & INSTFLAG) {
reason = STOP_UUO;
flags &= ~ (INSTFLAG|ANYFLAG);
break;
}
if (flags & MCHCHK) {
reason = STOP_MMTRP;
flags &= ~(MCHCHK|ANYFLAG);
break;
}
if (flags & IOCHK) {
reason = STOP_IOCHECK;
flags &= ~(IOCHK|ANYFLAG);
break;
}
if (flags & RECCHK) {
reason = STOP_RECCHK;
flags &= ~(RECCHK|ANYFLAG);
break;
}
if (flags & ACOFLAG) {
reason = STOP_ACOFL;
flags &= ~(ACOFLAG|ANYFLAG);
break;
}
if (flags & SGNFLAG) {
reason = STOP_SIGN;
flags &= ~(SGNFLAG|ANYFLAG);
break;
}
}
/* If we are waiting on I/O, don't fetch */
if (!chwait) {
if (!iowait) {
if (indflag == 0 && bkcmp == 0 && intprog == 0 &&
intmode != 0 && irqflags != 0) {
/* Process as interrupt */
store_cpu(0x3E0, 1);
addr = 0x200;
temp = 2; /* Start channel 20 */
while((temp & irqflags) == 0) {
temp <<= 1;
addr += 32;
if (temp == 0x20) /* Channel 40 */
addr = 0x400;
}
sim_debug(DEBUG_TRAP, &cpu_dev, "Trap on channel %x\n", addr);
irqflags &= ~temp;
load_cpu(addr, 0);
intprog = 1;
spc = 0x200;
sim_debug(DEBUG_TRAP, &cpu_dev, "Trap to addr %d\n", IC);
}
/* Make sure IC is on correct boundry */
if ((IC % 5) != 4) {
flags |= INSTFLAG|ANYFLAG;
sim_interval--;
goto stop_cpu;
}
/* Split out current instruction */
MA = IC;
MAC = read_addr(&reg, &zone);
opcode = ReadP(MA, INSTFLAG); /* Finaly read opcode */
MA = MAC;
IC += 5;
switch (CPU_MODEL) {
case CPU_7080:
temp = 160000;
if ((flags & EIGHTMODE) == 0) {
temp = 80000;
if (cpu_unit.flags & EMULATE2)
temp = 40000;
else if (cpu_type == CPU_705)
temp = 20000;
}
break;
case CPU_7053:
temp = 80000;
if (cpu_unit.flags & EMULATE2)
temp = 40000;
break;
case CPU_705:
temp = 20000;
if (cpu_unit.flags & EMULATE2)
temp = 40000;
break;
case CPU_702:
temp = 10000;
break;
}
while (IC >= (uint32)temp)
IC -= temp;
/* Resolve full address and register based on cpu mode */
switch (cpu_type) {
case CPU_705: /* 705 */
case CPU_702: /* 702 */
break;
case CPU_7080: /* 7080 */
if (indflag) {
indflag = 0;
if ((MA % 5) != 4) {
flags |= INSTFLAG|ANYFLAG;
goto stop_cpu;
}
MAC = read_addr(&t, &zone);
MA = MAC;
}
break;
case CPU_7053: /* 705-iii */
if (zone & 04) { /* Check indirect */
if ((MA % 5) != 4) {
flags |= INSTFLAG|ANYFLAG;
goto stop_cpu;
}
MAC = read_addr(&t, &zone);
MA = MAC;
}
break;
}
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 - 5) | HIST_PC;
hst[hst_p].op = opcode;
hst[hst_p].ea = MAC;
hst[hst_p].reg = reg;
hst[hst_p].inst = Read5(IC-5, 0);
#if 0
addr = get_acstart(reg);
for (t = 0; t < 32; t++) {
hst[hst_p].store[t] = AC[addr];
addr = next_addr[addr];
if (hst[hst_p].store[t] == 0)
break;
}
#endif
}
}
fmsk = (reg)?(BSIGN|BZERO):(ASIGN|AZERO);
iowait = 0;
sim_interval -= 5; /* count down */
switch (opcode) {
case OP_TR: /* TR */
if ((MAC % 5) != 4) {
flags |= INSTFLAG|ANYFLAG;
break;
}
/* 7080, reg = 1, TSL */
if (cpu_type >= CPU_7053 && reg == 1) {
/* MAC2 <- IC+5 */
MA = MAC2+4;
write_addr(IC, 0, 0);
sim_interval -= 4; /* count down */
}
IC = MAC;
break;
case OP_HLT: /* STOP */
if ((cpu_unit.flags & NONSTOP) && (intprog == 0)
&& intmode != 0) {
/* Process as interrupt */
store_cpu(0x3E0, 1);
load_cpu(0x2A0, 0);
intprog = 1;
spc = 0x200;
} else
reason = STOP_HALT;
break;
case OP_TRH: /* TR HI */
if ((MAC % 5) != 4) {
flags |= INSTFLAG|ANYFLAG;
break;
}
if (flags & HIGHFLAG) {
IC = MAC;
}
break;
case OP_TRE: /* TR EQ */
if ((MAC % 5) != 4) {
flags |= INSTFLAG|ANYFLAG;
break;
}
if ((flags & CMPFLAG) == 0) {
IC = MAC;
}
break;
case OP_TRP: /* TR + */
if ((MAC % 5) != 4) {
flags |= INSTFLAG|ANYFLAG;
break;
}
if ((flags & SIGN & fmsk) == 0) {
IC = MAC;
}
break;
case OP_TRZ: /* TR 0 */
if ((MAC % 5) != 4) {
flags |= INSTFLAG|ANYFLAG;
break;
}
if (flags & ZERO & fmsk) {
IC = MAC;
}
break;
case OP_TRS: /* TR SIG */
if ((MAC % 5) != 4) {
flags |= INSTFLAG|ANYFLAG;
break;
}
temp = selreg & 0xff;
t = 0;
if (cpu_type >= CPU_7053 && reg != 0) {
switch (reg) {
case 1: /* TRR */
switch (chan_cmd(selreg, IO_TRS << 8, 0)) {
case SCPE_OK:
t = 1;
break;
case SCPE_BUSY:
case SCPE_NODEV:
case SCPE_IOERR:
break;
}
break;
case 2: /* TTC */
temp = chan_mapdev(selreg);
if (temp > 0 && chan_test(temp, CHS_ERR))
t = 1;
break;
case 3: /* TSA */
temp = chan_mapdev(selreg);
addr = (selreg & 0xf) +((selreg >> 8) & 0xff0);
if (temp > 0 && chan_active(temp)) {
chwait = temp + 1;
IC -= 5;
} else if (temp > 0 && chan_test(temp, CHS_ERR))
t = 1;
else if (ioflags[selreg/8] & 1<<(selreg & 07))
t = 1;
else if (ioflags[addr/8] & 1<<(addr & 07))
t = 1;
break;
case 10:/* TIC */ /* Instruction error */
case 11:/* TMC */ /* Machine check */
case 12:/* TRC */ /* I/O Check */
case 13:/* TEC */ /* Record check */
case 14:/* TOC */ /* AC Overflow flag */
case 15:/* TSC */ /* Sign mismatch */
temp = 1 << (reg - 6);
if (flags & temp)
t = 1;
flags &= ~temp;
break;
default:
break;
}
} else {
switch((selreg >> 8) & 0xff) {
case 20: /* Tape DS */
case 21:
case 22:
case 23:
if (ioflags[selreg/8] & 1<<(selreg & 07))
t = 1;
/* Handle tapes at either location */
temp = (selreg & 0xf) +((selreg >> 8) & 0xff0);
if (ioflags[temp/8] & 1<<(temp & 07))
t = 1;
break;
case 2: /* Tape EOF */
if (ioflags[selreg/8] & 1<<(selreg & 07))
t = 1;
/* Handle tapes at either location */
temp = (selreg & 0xf) +((selreg << 8) & 0xff0);
if (temp < 2400) {
if (ioflags[temp/8] & 1<<(temp & 07))
t = 1;
}
break;
case 1: /* Card Reader */
if (ioflags[selreg/8] & 1<<(selreg & 07))
t = 1;
break;
case 9: /* Special signals */
switch(temp) {
case 0: /* Instruction error */
case 1: /* Machine check */
case 2: /* I/O Check */
case 3: /* Record check */
case 4: /* AC Overflow flag */
case 5: /* Sign mismatch */
temp = 1 << (temp + 4);
if (flags & temp)
t = 1;
flags &= ~temp;
break;
case 0x11: case 0x12: case 0x13: case 0x14:
case 0x15: case 0x16: case 0x17: case 0x18:
case 0x19:
if(SW & (1 << ((temp & 0xf) - 1)))
t = 1;
break;
}
break;
case 4: /* Printer */
/* Check channel 12 end of page */
/* Devices never signals */
case 3: /* Card punch */
case 5: /* Typewriter */
/* Invalid digits */
case 0: /* Nothing */
case 6: /* ???? */
case 7: /* ???? */
case 8: /* ???? */
default: /* Drum */
break;
}
}
if (t) {
IC = MAC;
}
break;
case OP_TRA: /* TRA */
t = 0;
if ((MAC % 5) != 4) {
flags |= INSTFLAG|ANYFLAG;
break;
}
switch (cpu_type) {
case CPU_7080: /* 7080 */
case CPU_7053: /* 705-iii */
if (reg > 0 && reg < 7) {
/* Test sense switch */
if (SW & (1<<(reg - 1)))
t = 1;
break;
} else if (reg == 7) {
/* Transfer if Non-stop */
if (cpu_unit.flags & NONSTOP)
t = 1;
break;
} else if (reg > 7) {
/* Nop */
break;
}
case CPU_705: /* 705 */
case CPU_702: /* 702 */
if (flags & ANYFLAG)
t = 1;
flags &= ~ANYFLAG;
break;
}
if (t) {
IC = MAC;
}
break;
case OP_TZB: /* TZB */
/* transfer bit zero addr = MAC2 */
if (CPU_MODEL < CPU_7053) {
flags |= INSTFLAG|ANYFLAG;
break;
}
if ((MAC % 5) != 4) {
flags |= INSTFLAG|ANYFLAG;
break;
}
t = ReadP(MAC2, MCHCHK);
/* Undocumented, but diags seem to indicate this */
/* if (t == CHR_RM) t = 0; */
switch(reg) {
case 7: /* C */
/* Develop parity */
t = sim_parity_table[t & 077];
t ^= M[MAC % EMEMSIZE] & 0100; /* C654 */
if (t == 0)
IC = MA;
break;
case 1: /* 1 */
case 2: /* 2 */
case 3: /* 4 */
case 4: /* 8 */
case 5: /* A */
case 6: /* B */
if ((t & (1<<(reg-1))) == 0)
IC = MA;
break;
case 0:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
break;
}
sim_interval --; /* count down */
break;
case OP_NOP: /* NOP */
break;
case OP_CMP: /* CMP */
do_compare(reg, 0);
break;
case OP_UNL: /* UNL */
addr = get_acstart(reg);
cr2 = AC[addr];
while(cr2 != 0) {
WriteP(MA, cr2);
Next(MA);
addr = next_addr[addr];
cr2 = AC[addr];
sim_interval--; /* count down */
}
break;
case OP_LOD: /* LOD */
addr = get_acstart(reg);
flags |= ZERO & fmsk;
/* Clear sign */
flags &= ~(SIGN & fmsk);
while(AC[addr] != 0) {
cr1 = ReadP(MA, MCHCHK);
AC[addr] = cr1;
if ((cr1 & 0xf) != 10)
flags &= ~(ZERO & fmsk);
Next(MA);
addr = next_addr[addr];
sim_interval--; /* count down */
}
break;
case OP_ST: /* ST */
addr = get_acstart(reg);
sim_interval--; /* count down */
at = 1; /* Use to indicate first cycle */
while ((cr2 = AC[addr]) != 0) {
if (at) {
cr2 &= 0xf;
if (flags & fmsk & SIGN)
cr2 |= 040; /* Minus */
else
cr2 |= 060; /* Plus */
at = 0;
} else {
if ((cr2 & 0xf) == 0) {
cr2 &= 060;
cr2 |= 012;
}
if ((cr2 & 060) == 040 || (cr2 & 060) == 020)
cr2 |= 0100;
}
WriteP(MA, cr2);
Next(MA);
addr = next_addr[addr];
sim_interval--; /* count down */
}
/* Adjust next character */
cr1 = ReadP(MA, MCHCHK);
if (at == 0 && cr1 == 10)
cr1 = 0;
if ((cr1 & 060) == 0)
cr1 |= 060;
WriteP(MA, cr1);
sim_interval--; /* count down */
break;
case OP_SGN: /* SGN */
cr1 = ReadP(MA, MCHCHK);
/* Adjust memory to zero zone or blank */
if (cr1 & 017) {
WriteP(MA, cr1 & 017);
} else {
WriteP(MA, 020);
}
sim_interval--; /* count down */
/* Make AC either + or - */
flags &= ~fmsk;
cr1 &= 060;
if (cr1 == 040)
flags |= SIGN & fmsk;
else
cr1 |= 060;
/* One char in AC */
addr = get_acstart(reg);
AC[addr] = cr1;
addr = next_addr[addr];
AC[addr] = 0;
break;
case OP_NTR: /* NORM TR */
if ((MAC % 5) != 4) {
flags |= INSTFLAG|ANYFLAG;
break;
}
addr = get_acstart(reg);
at = 1;
zero = 0;
/* Space to end storage */
while(AC[addr] != 0) {
addr = next_addr[addr];
if (at) {
zero = 1;
at = 0;
} else
zero = 0;
sim_interval--; /* count down */
}
/* Zero or one digit, exit */
if (at || zero)
break;
/* Back up one */
addr = prev_addr[addr];
if (AC[addr] == 10) {
AC[addr] = 0;
IC = MA;
sim_interval --; /* count down */
}
break;
case OP_SET: /* SET */
addr = get_acstart(reg);
flags |= (fmsk & ZERO); /* Might be zero */
at = 0; /* No smt yet */
/* Scan for mark */
while (MAC != 0) {
if (at)
AC[addr] = 10; /* Zero fill */
else if (AC[addr] == 0) {
at = 1; /* Indicate that we found smt */
AC[addr] = 10;
} else if (AC[addr] != 10)
flags &= ~(ZERO & fmsk); /* No zero, adjust flag */
MAC--;
addr = next_addr[addr];
sim_interval --; /* count down */
if (sim_interval <= 0) { /* event queue? */
reason = sim_process_event();
if (reason != 0)
break;
chan_proc();
}
}
/* Insert a mark at new end */
AC[addr] = 0;
/* Clear sign if zero */
flags &= ~(((flags & fmsk) >> 2) & SIGN);
break;
case OP_SHR: /* SHR */
if (cpu_type != CPU_702 && reg != 0) {
flags |= INSTFLAG|ANYFLAG;
break;
}
addr = get_acstart(reg);
while (MA != 0) {
MA--;
addr = next_addr[addr];
sim_interval --; /* count down */
}
if (cpu_type == CPU_702 && reg != 0) {
spcb = addr;
} else {
if (cpu_type == CPU_702)
spc = addr;
else if (reg == 0)
spc = (spc & 0x700) | (addr & 0xff);
}
flags |= (fmsk & ZERO); /* Might be zero */
/* Check if zero */
while (AC[addr] != 0) {
if (AC[addr] != 10) {
flags &= ~(ZERO & fmsk);
break;
}
addr = next_addr[addr];
sim_interval --; /* count down */
}
/* Clear sign if zero */
flags &= ~(((flags & fmsk) >> 2) & SIGN);
break;
case OP_LEN: /* LEN */
if (cpu_type != CPU_702 && reg != 0) {
flags |= INSTFLAG|ANYFLAG;
break;
}
addr = get_acstart(reg);
addr = prev_addr[addr];
while(MA != 0) {
AC[addr] = 10;
addr = prev_addr[addr];
MA--;
sim_interval --; /* count down */
}
AC[addr] = 0;
addr = next_addr[addr]; /* Back up one */
if (cpu_type == CPU_702 && reg != 0)
spcb = addr;
else {
if (cpu_type == CPU_702)
spc = addr;
else if (reg == 0)
spc = (spc & 0x700) | (addr & 0xff);
}
break;
case OP_RND: /* RND */
if (cpu_type != CPU_702 && reg != 0) {
flags |= INSTFLAG|ANYFLAG;
break;
}
addr = get_acstart(reg);
flags |= (fmsk & ZERO); /* Might be zero */
if (MA != 0) {
int smt = 0;
/* Adjust Address */
while (MA != 0) {
MA--;
addr = next_addr[addr];
sim_interval --; /* count down */
}
/* Adjust start pointer */
if (cpu_type == CPU_702 && reg != 0) {
spcb = addr;
} else {
if (cpu_type == CPU_702)
spc = addr;
else if (reg == 0)
spc = (spc & 0x700) | (addr & 0xff);
}
addr = prev_addr[addr]; /* Back up one */
/* Process while valid digit in memory */
t = 5;
do {
uint8 cr1;
if (AC[addr] == 0) {
smt = 1;
cr1 = t;
t = 0;
} else {
cr1 = bcd_bin[AC[addr]&0xf] + t;
}
if (t != 5 && cr1 != 0)
flags &= ~(ZERO & fmsk);
t = cr1 >= 10;
AC[addr] = (AC[addr] & 060) | bin_bcd[cr1];
addr = next_addr[addr];
sim_interval --; /* count down */
} while (t != 0); /* Loop while carry */
/* If we overflowed, set flag */
if (smt) {
flags |= ACOFLAG|ANYFLAG;
AC[addr] = 0; /* Write storage mark */
}
}
/* Check if zero */
while (AC[addr] != 0) {
if (AC[addr] != 10) {
flags &= ~(ZERO & fmsk);
break;
}
addr = next_addr[addr];
sim_interval --; /* count down */
}
/* Clear sign if zero */
flags &= ~(((flags & fmsk) >> 2) & SIGN);
break;
case OP_SPR: /* ST PR */
addr = get_acstart(reg);
sign = ((reg)?(flags >> 1): flags) & ASIGN;
WriteP(MA, (sign)?040:020);
sim_interval --; /* count down */
while(AC[addr] != 0) {
Next(MA);
cr1 = ReadP(MA, MCHCHK);
if (cr1 != CHR_COM && cr1 != CHR_DOT) {
cr2 = AC[addr];
WriteP(MA, cr2);
addr = next_addr[addr];
}
sim_interval --; /* count down */
}
while (1) {
cr1 = ReadP(MA, MCHCHK);
sim_interval --; /* count down */
if (cr1 == CHR_COM || cr1 == 10) {
WriteP(MA, 020);
} else
break;
Prev(MA);
}
break;
case OP_ADM: /* ADM */
/* Cycle 1 */
addr = get_acstart(reg);
zero = 1;
cr1 = ReadP(MA, MCHCHK);
cr2 = AC[addr];
sim_interval --; /* count down */
/* Set sign to sign of Ac */
sign = (flags & fmsk & SIGN)?1:0;
carry = 0;
/* Check sign if not valid then treat as 0 */
if (cr1 & 040) {
int smt = 1;
int met = 1;
int msign;
/* Numeric */
/* Check sign */
msign = (cr1 & 020)? 0: 1; /* + - */
/* Compliment if signs differ */
t = (msign != sign)? 1: 0; /* -+,+- --,++ */
carry = t;
if (cr2 == 0) { /* Check for storage mark */
smt = 0;
cr2 = 10;
}
cr1 &= 0xf;
temp = (t)? comp_bcd[cr2 & 0xf]:bcd_bin[cr2 & 0xf];
temp = bcd_bin[cr1 & 0xf] + temp + carry;
carry = temp >= 10;
WriteP(MA, (msign? 040:060) | bin_bcd[temp]);
Next(MA);
addr = next_addr[addr];
do {
if (smt) {
cr2 = AC[addr];
if (cr2 == 0)
smt = 0;
} else
cr2 = 10;
cr1 = ReadP(MA, MCHCHK);
if (cr1 < 1 || cr1 > 10) {
met = 0;
} else {
temp = (t)? comp_bcd[cr2 & 0xf]:bcd_bin[cr2 & 0xf];
temp = bcd_bin[cr1 & 0xf] + temp + carry;
carry = temp >= 10;
WriteP(MA, bin_bcd[temp]);
sim_interval --; /* count down */
addr = next_addr[addr];
Next(MA);
cr1 = ReadP(MA, MCHCHK);
}
} while (met);
/* Recompliment */
if (t && carry == 0) {
MA = MAC;
cr1 = ReadP(MA, MCHCHK);
sim_interval --; /* count down */
cr1 ^= 020; /* Compliment sign */
temp = comp_bcd[cr1 & 0xf] + 1;
carry = temp >= 10;
WriteP(MA, (cr1 & 060) | bin_bcd[temp]);
Next(MA);
while(1) {
cr1 = ReadP(MA, MCHCHK);
if (cr1 < 1 || cr1 > 10)
break;
temp = comp_bcd[cr1 & 0xf] + carry;
carry = temp >= 10;
WriteP(MA, bin_bcd[temp]);
sim_interval --; /* count down */
Next(MA);
}
}
} else {
int zcarry = 0;
/* Non-numeric */
while (cr2 != 0) {
temp = bcd_bin[(cr2 & 0xf)] + bcd_bin[(cr1 & 0xf)] + carry;
carry = temp >= 10;
if (temp > 10)
temp -= 10;
t = (cr2 & 0x30) + (cr1 & 0x30) + zcarry; /* Zone add */
zcarry = (t & 0x40)?0x10:0;
addr = next_addr[addr];
cr2 = AC[addr];
if (cr2 == 0 && carry)
t += 0x10;
temp = (temp & 0xf) | (t & 0x30);
if (temp == 0)
temp = 10;
WriteP(MA, temp);
Next(MA);
cr1 = ReadP(MA, MCHCHK);
sim_interval --; /* count down */
}
}
break;
case OP_SUB: /* SUB */
do_addsub(1, reg, 0, fmsk);
break;
case OP_ADD: /* ADD */
do_addsub(0, reg, 0, fmsk);
break;
case OP_RSU: /* R SUB */
do_addsub(1, reg, 1, fmsk);
break;
case OP_RAD: /* R ADD */
do_addsub(0, reg, 1, fmsk);
break;
case OP_MPY: /* MPY */
do_mult(reg, fmsk);
break;
case OP_DIV: /* DIV */
do_divide(reg, fmsk);
break;
case OP_RCV: /* RCV 705 only */
if (cpu_type == CPU_702)
flags |= INSTFLAG|ANYFLAG;
else
MAC2 = MAC;
break;
case OP_TMT: /* TMT 705 only */
if (cpu_type == CPU_702) {
flags |= INSTFLAG|ANYFLAG;
break;
}
if (reg == 0) {
/* Copy in blocks of 5 characters */
if ((MAC2 % 5) != 4 || (MAC % 5) != 4) {
flags |= INSTFLAG|ANYFLAG;
break;
}
do {
addr = Read5(MAC, MCHCHK);
Write5(MAC2, addr);
Prev5(MAC2);
Prev5(MAC);
sim_interval -= 10; /* count down */
} while ((addr & 077) != CHR_RM);
} else {
/* One char at a time */
addr = get_acstart(reg);
while(AC[addr] != 0) {
cr1 = ReadP(MAC, MCHCHK);
WriteP(MAC2, cr1);
Prev(MAC);
Prev(MAC2);
addr = next_addr[addr];
sim_interval -= 2; /* count down */
}
}
break;
case OP_SEL: /* SEL */
/* Convert device to hex number */
selreg = MAC % 10;
MAC /= 10;
selreg |= (MAC % 10) << 4;
MAC /= 10;
selreg |= (MAC % 10) << 8;
MAC /= 10;
selreg |= (MAC % 10) << 12;
MAC /= 10;
break;
case OP_CTL: /* CTL */
temp = 0;
if (reg > 1) {
/* Process ASU modes non-zero */
switch (reg) {
/* 7080 */
case 12: /* ECB */
/* Enable backwards compare */
if (CPU_MODEL == CPU_7080 && cpu_type > CPU_705)
bkcmp = 1;
else
flags |= INSTFLAG|ANYFLAG;
break;
case 13: /* CHR */
/* Clear io error flags */
chan_chr_13();
memset(ioflags, 0, sizeof(ioflags));
flags &= ~(IRQFLAGS);
break;
case 14: /* EEM */
/* Enter 80 mode */
if (CPU_MODEL == CPU_7080) {
flags |= EIGHTMODE;
EMEMSIZE = MEMSIZE;
cpu_type = CPU_7080;
} else
flags |= INSTFLAG|ANYFLAG;
break;
case 15: /* LEM */
/* Leave 80 mode */
if (CPU_MODEL == CPU_7080) {
flags &= ~EIGHTMODE;
cpu_type = (cpu_unit.flags & EMULATE3)?
CPU_7053:CPU_705;
EMEMSIZE = MEMSIZE;
if (cpu_unit.flags & EMULATE2 &&
EMEMSIZE > 40000)
EMEMSIZE = 40000;
if (cpu_type == CPU_705 &&
(cpu_unit.flags & EMULATE2) == 0 &&
EMEMSIZE > 20000)
EMEMSIZE = 20000;
if (EMEMSIZE > 80000)
EMEMSIZE = 80000;
} else
flags |= INSTFLAG|ANYFLAG;
break;
}
break;
}
switch (MAC) {
case 0: /* IOF */
ioflags[selreg/8] &= ~(1<<(selreg&07));
if ((selreg & 0xff00) == 0x200) {
/* Handle tapes at either location */
temp = (selreg & 0xf) +
((selreg & 0xff0) << 8);
if (temp < 0x2400)
ioflags[temp/8] &= ~(1<<(temp & 07));
}
if ((selreg & 0xf000) == 0x2000) {
temp = (selreg & 0xf) +
((selreg >> 8) & 0xff0);
ioflags[temp/8] &= ~(1<<(temp & 07));
}
temp = 0;
break;
case 1: /* WTM */
temp = IO_WEF << 8;
break;
case 2: /* REW */
if (cpu_type > CPU_705 && reg == 1)
temp = IO_RUN << 8;
else
temp = IO_REW << 8;
break;
case 3: /* ION */
ioflags[selreg/8] |= 1<<(selreg&07);
if ((selreg & 0xff00) == 0x200) {
/* Handle tapes at either location */
temp = (selreg & 0xf) +
((selreg & 0xff0) << 8);
if (temp < 0x2400)
ioflags[temp/8] |=
1<<(temp & 07);
}
if ((selreg & 0xf000) == 0x2000) {
temp = (selreg & 0xf) +
((selreg >> 8) & 0xff0);
ioflags[temp/8] |= 1<<(temp & 07);
}
temp = 0;
break;
case 4: /* BSR */
if (cpu_type >= CPU_7053 && reg == 1)
temp = IO_BSF << 8;
else
temp = IO_BSR << 8;
break;
case 5:
case 9: /* SKP */
temp = IO_ERG << 8;
break;
case 37: /* SDL */
temp = IO_SDL << 8;
break;
case 38: /* SDH */
temp = IO_SDH << 8;
break;
default:
flags |= ANYFLAG|INSTFLAG;
break;
}
if (temp != 0) {
switch (chan_cmd(selreg, temp, 0)) {
case SCPE_OK:
break;
case SCPE_BUSY:
iowait = 1;
break;
case SCPE_NODEV:
reason = STOP_IOCHECK;
break;
case SCPE_IOERR:
flags |= ANYFLAG|INSTFLAG;
break;
}
}
break;
case OP_RD: /* READ */
temp = (IO_RDS << 8) | reg;
switch (chan_cmd(selreg, temp, MAC)) {
case SCPE_OK:
break;
case SCPE_BUSY:
iowait = 1;
break;
case SCPE_NODEV:
reason = STOP_IOCHECK;
break;
case SCPE_IOERR:
flags |= ANYFLAG|INSTFLAG;
break;
}
break;
case OP_WR: /* WRITE */
temp = (IO_WRS << 8) | reg;
switch (chan_cmd(selreg, temp, MAC)) {
case SCPE_OK:
break;
case SCPE_BUSY:
iowait = 1;
break;
case SCPE_NODEV:
reason = STOP_IOCHECK;
break;
case SCPE_IOERR:
flags |= ANYFLAG|INSTFLAG;
break;
}
break;
case OP_WRE: /* WR ER */
temp = (IO_WRS << 8) | reg | CHAN_ZERO;
switch (chan_cmd(selreg, temp, MAC)){
case SCPE_OK:
break;
case SCPE_BUSY:
iowait = 1;
break;
case SCPE_NODEV:
reason = STOP_IOCHECK;
break;
case SCPE_IOERR:
flags |= ANYFLAG|INSTFLAG;
break;
}
break;
case OP_RWW: /* RWW 705 only */
MAC2 = MAC;
selreg2 = selreg | 0x8000;
break;
/* 7080 opcodes */
case OP_CTL2:
if (cpu_type != CPU_7080) {
flags |= ANYFLAG|INSTFLAG;
break;
}
switch(reg) {
case 0: /* SPC */
/* Set starting point */
/* Selects on char of 8 char words */
temp = (MA % 10) & 7; /* Units digit */
MA /= 10;
t = MA % 10; /* Tens digit */
temp += (t&3) << 3; /* One of words */
MA /= 10;
t = MA % 10; /* Hundreds */
temp += (t&7) << 5; /* One of four word sets */
MA /= 10; /* Thousands */
t = MA % 10;
temp += (t&7) << 8; /* Bank */
spc = temp;
break;
case 2: /* LFC */
/* load four chars */
addr = spc;
do {
t = ReadP(MA, MCHCHK);
if (t == CHR_LESS)
t = 0;
AC[addr] = t;
addr = next_addr[addr];
Next(MA);
sim_interval --; /* count down */
} while((MA % 5) != 0);
break;
case 3: /* UFC */
/* unload four chars */
addr = spc;
do {
t = AC[addr];
addr = next_addr[addr];
if (t == 0)
t = CHR_LESS;
WriteP(MA, t);
Next(MA);
sim_interval --; /* count down */
} while((MA % 5) != 0);
break;
case 4: /* LSB */
/* Load storage bank */
addr = spc & 0x700;
temp = 256;
while(temp-- > 0) {
t = ReadP(MA, MCHCHK);
if (t == CHR_LESS)
t = 0;
AC[addr] = t;
addr = next_addr[addr];
Next(MA);
sim_interval --; /* count down */
}
break;
case 5: /* USB */
/* Unload storage bank */
addr = spc & 0x700;
temp = 256;
while(temp-- > 0) {
t = AC[addr];
addr = next_addr[addr];
if (t == 0)
t = CHR_LESS;
WriteP(MA, t);
Next(MA);
sim_interval --; /* count down */
}
break;
case 6: /* EIM */
/* Enter interrupt mode */
intmode = 1;
break;
case 7: /* LIM */
/* Leave interrupt mode */
intmode = 0;
break;
case 8: /* TCT */
/* Ten char transmit */
/* Copy in blocks of 10 characters */
if ((MAC2 % 10) != 9 || (MAC % 10) != 9) {
flags |= INSTFLAG|ANYFLAG;
break;
}
do {
addr = Read5(MAC-5, MCHCHK);
Write5(MAC2-5, addr);
addr = Read5(MAC, MCHCHK);
Write5(MAC2, addr);
Prev10(MAC);
Prev10(MAC2);
sim_interval -= 20; /* count down */
} while ((addr & 077) != CHR_RM);
break;
case 10: /* EIA */
/* Enable indirect address */
indflag = 1;
break;
case 11: /* CNO */
/* Nop */
break;
case 12: /* TLU */
/* Table lookup equal. */
/* Walk backward in memory until equal, or GM */
do {
do_compare(0, 1);
if ((flags & CMPFLAG) == 0)
break;
while ((cr1 = ReadP(MA, MCHCHK)) != CHR_RM ||
cr1 != CHR_GM)
{ Next(MA); }
} while(cr1 != CHR_GM);
MAC2 = MA;
break;
case 13: /* TLU */
/* Table lookup equal or hi */
/* Walk backward in memory until equal, or GM */
do {
do_compare(0, 1);
if ((flags & LOWFLAG) == 0)
break;
while ((cr1 = ReadP(MA, MCHCHK)) != CHR_RM ||
cr1 != CHR_GM) {
Next(MA);
}
} while(cr1 != CHR_GM);
MAC2 = MA;
break;
case 14: /* TIP */
/* Transfer to interrupt program */
if ((MAC % 5) != 4) {
flags |= INSTFLAG|ANYFLAG;
break;
}
store_cpu(0x3E0, 1);
intprog = 1;
spc = 0x200;
IC = MA;
flags &= ~IRQFLAGS;
break;
case 15: /* LIP */
/* Leave interrupt program */
if (MA != 9) {
/* Selects on char of 8 char words */
temp = (MA % 10) & 7; /* Units digit */
MA /= 10;
t = MA % 10; /* Tens digit */
temp += (t&3) << 3; /* One of words */
MA /= 10;
t = MA % 10; /* Hundreds */
temp += (t&7) << 5; /* One of four word sets */
MA /= 10; /* Thousands */
t = MA % 10;
temp += (t&7) << 8; /* Bank */
store_cpu(temp, 0);
}
/* Fully load new context */
load_cpu(0x3E0, 1);
intprog = 0;
break;
}
break;
case OP_CTL3:
if (cpu_type != CPU_7080) {
flags |= ANYFLAG|INSTFLAG;
break;
}
addr = get_acstart(reg);
switch(reg) {
case 8: /* TCR */
/* Ten char recieve */
/* Copy in blocks of 10 characters */
if ((MAC2 % 10) != 9 || (MAC % 10) != 9) {
flags |= INSTFLAG|ANYFLAG;
break;
}
do {
addr = Read5(MAC2-5, MCHCHK);
Write5(MAC-5, addr);
addr = Read5(MAC2, MCHCHK);
Write5(MAC, addr);
Prev10(MAC);
Prev10(MAC2);
sim_interval -= 2; /* count down */
} while ((addr & 077) != CHR_RM);
break;
break;
case 14: /* SMT */
write_addr(MAC2, 0, 0);
WriteP(MA, 10); /* Finish with zero */
store_addr(MAC2, addr);
sim_interval -= 10;
break;
}
break;
case OP_AAM: /* AAM */
/* Add address in store to memory */
if (CPU_MODEL < CPU_7053 || (MAC % 5) != 4) {
flags |= INSTFLAG|ANYFLAG;
break;
}
addr = get_acstart(reg);
t = ReadP(MA, MCHCHK); /* Read low order digit */
sim_interval --; /* count down */
if (AC[addr] != 0) {
temp = AC[addr];
addr = next_addr[addr];
} else
temp = 10;
temp = bcd_bin[temp & 0xf] + bcd_bin[t & 0xf];
carry = temp > 9;
if (carry)
temp -= 10;
t = (t & 060) | temp;
if (t == 0)
t = 10;
WriteP(MA, t);
Next(MA);
t = ReadP(MA, MCHCHK); /* Read tens order digit */
sim_interval --; /* count down */
if (AC[addr] != 0) {
temp = AC[addr];
addr = next_addr[addr];
} else
temp = 10;
at = (t & 060) + (temp & 060);
temp = bcd_bin[temp & 0xf] + bcd_bin[t & 0xf] + carry;
carry = temp > 9;
if (carry)
temp -= 10;
t = (at & 060) | temp;
if (t == 0)
t = 10;
WriteP(MA, t);
Next(MA);
t = ReadP(MA, MCHCHK); /* Read hundreds order digit */
sim_interval --; /* count down */
if (AC[addr] != 0) {
temp = AC[addr];
addr = next_addr[addr];
} else
temp = 10;
at = ((at & 0100) >> 2) + (t & 060) + (temp & 060);
temp = bcd_bin[temp & 0xf] + bcd_bin[t & 0xf] + carry;
carry = temp > 9;
if (carry)
temp -= 10;
t = (at & 060) | temp;
if (t == 0)
t = 10;
WriteP(MA, t);
Next(MA);
t = ReadP(MA, MCHCHK); /* Read thousands order digit */
sim_interval --; /* count down */
if (AC[addr] != 0) {
temp = AC[addr];
addr = next_addr[addr];
} else
temp = 10;
temp = bcd_bin[temp & 0xf] + bcd_bin[t & 0xf] + carry;
carry = (temp > 9)?0x10:0;
if (carry)
temp -= 10;
t = (t & 060) | temp;
temp = 0;
/* Decode digits 5 and 6 */
if (AC[addr] != 0) {
temp = bcd_bin[AC[addr] & 0xf];
addr = next_addr[addr];
if (AC[addr] != 0 && CPU_MODEL == CPU_7080 &&
flags & EIGHTMODE)
temp += (1 & bcd_bin[(AC[addr] & 0xf)]) * 10;
temp &= 0xf;
}
/* Add zone bits for top digit */
t += ((temp & 3) << 4) + carry;
carry = (t & 0100) != 0;
t &= 077;
if ((t & 0xf) == 10)
t &= 060;
if (t == 0)
t = 10;
WriteP(MA, t);
/* Merge high order bits into units if needed */
switch (CPU_MODEL) {
case CPU_7080: /* 7080 */
if (flags & EIGHTMODE) {
t = ReadP(MAC, MCHCHK);
temp = (temp >> 2) + carry;
if (t & 040)
temp++;
if (t & 020)
temp += 2;
t = (t & 0xf) | ((temp & 0x1) << 5) |
((temp & 0x2) << 3);
if ((t & 0xf) == 10)
t &= 060;
if (t == 0)
t = 10;
WriteP(MAC, t);
sim_interval --; /* count down */
break;
} else if ((cpu_unit.flags & EMULATE3) == 0)
break;
case CPU_7053: /* 705-iii */
if ((cpu_unit.flags & EMULATE2) == 0) {
t = ReadP(MAC, MCHCHK);
temp = ((temp >> 2) & 1) + carry;
if (t & 040)
temp++;
t = (t & 0x1f) | ((temp & 0x1) << 5);
if ((t & 0xf) == 10)
t &= 060;
if (t == 0)
t = 10;
WriteP(MAC, t);
sim_interval --; /* count down */
}
break;
case CPU_705: /* 705 */
case CPU_702: /* 702 */
break;
}
break;
case OP_LDA: /* LDA */
/* Load address */
if (CPU_MODEL < CPU_7053 || (MAC % 5) != 4) {
flags |= INSTFLAG|ANYFLAG;
break;
}
flags |= ZERO & fmsk;
fmsk = ~(ZERO | fmsk);
addr = get_acstart(reg);
t = ReadP(MA, MCHCHK); /* Read low order digit */
temp = (t & 060) >> 2;
t &= 0xf;
if (t == 0)
t = 10;
else if (t > 10)
flags |= INSTFLAG|ANYFLAG;
else if (t != 10)
flags &= fmsk; /* Clear zero */
AC[addr] = t;
addr = next_addr[addr];
Next(MA);
t = ReadP(MA, MCHCHK); /* next digit */
t &= 0xf;
if (t == 0)
t = 10;
else if (t > 10)
flags |= INSTFLAG|ANYFLAG;
else if (t != 10)
flags &= fmsk; /* Clear zero */
AC[addr] = t;
addr = next_addr[addr];
Next(MA);
t = ReadP(MA, MCHCHK); /* Read third digit */
t &= 0xf;
if (t == 0)
t = 10;
else if (t > 10)
flags |= INSTFLAG|ANYFLAG;
else if (t != 10)
flags &= fmsk; /* Clear zero */
AC[addr] = t;
addr = next_addr[addr];
Next(MA);
t = ReadP(MA, MCHCHK); /* Save High order address */
temp |= (t & 060) >> 4;
t &= 0xf;
if (t == 0)
t = 10;
else if (t > 10)
flags |= INSTFLAG|ANYFLAG;
else if (t != 10)
flags &= fmsk; /* Clear zero */
AC[addr] = t;
addr = next_addr[addr];
temp = lda_flip[temp];
switch (CPU_MODEL) {
case CPU_702: /* 702 */
break;
case CPU_7080: /* 7080 */
if (flags & EIGHTMODE) {
if (temp > 10) {
AC[addr] = bin_bcd[temp - 10];
addr = next_addr[addr];
AC[addr] = 1;
} else {
AC[addr] = bin_bcd[temp];
addr = next_addr[addr];
AC[addr] = 10;
}
break;
} else if ((cpu_unit.flags & EMULATE3) == 0)
temp &= 03;
case CPU_7053: /* 705-iii */
temp &= 07;
AC[addr] = bin_bcd[temp];
if (AC[addr] != 10)
zero = 0;
break;
case CPU_705: /* 705 */
temp &= 03;
AC[addr] = bin_bcd[temp];
if (AC[addr] != 10)
zero = 0;
break;
}
if (temp != 0)
flags &= fmsk; /* Clear zero */
addr = next_addr[addr];
AC[addr] = 0;
sim_interval -= 5; /* count down */
break;
case OP_ULA: /* ULA */
/* Unload address */
if (CPU_MODEL < CPU_7053 || (MAC % 5) != 4) {
flags |= INSTFLAG|ANYFLAG;
break;
}
addr = get_acstart(reg);
t = ReadP(MA, MCHCHK) & 0360; /* Read unitsr digit */
if (AC[addr] == 0) {
t |= 10;
} else {
t |= AC[addr] & 0xf;
addr = next_addr[addr];
}
if ((t & 0xf) == 10)
t &= 0360;
if (t == 0)
t = 10;
WriteP(MA, t);
Next(MA);
t = ReadP(MA, MCHCHK) & 0360; /* next digit */
if (AC[addr] == 0) {
t |= 10;
} else {
t |= AC[addr] & 0xf;
addr = next_addr[addr];
}
if ((t & 0xf) == 10)
t &= 0360;
if (t == 0)
t = 10;
WriteP(MA, t);
Next(MA);
t = ReadP(MA, MCHCHK) & 0360; /* Read third digit */
if (AC[addr] == 0) {
t |= 10;
} else {
t |= AC[addr] & 0xf;
addr = next_addr[addr];
}
if ((t & 0xf) == 10)
t &= 0360;
if (t == 0)
t = 10;
WriteP(MA, t);
Next(MA);
t = ReadP(MA, MCHCHK) & 0360; /* Save High order address */
if (AC[addr] == 0) {
t |= 10;
} else {
t |= AC[addr] & 0xf;
addr = next_addr[addr];
}
temp = 0;
/* Decode digits 5 and 6 */
if (AC[addr] != 0) {
temp = bcd_bin[AC[addr] & 0xf];
addr = next_addr[addr];
if (AC[addr] != 0 && cpu_type == CPU_7080)
temp += (1 & bcd_bin[(AC[addr] & 0xf)]) * 10;
}
/* Add zone bits for top digit */
temp = zone_dig[temp & 0xf];
t &= 0xf;
t |= (temp & 0xc) << 2;
if ((t & 0xf) == 10)
t &= 0360;
if (t == 0)
t = 10;
WriteP(MA, t);
/* Merge high order bits into units if needed */
switch (cpu_type) {
case CPU_7080: /* 7080 */
t = ReadP(MAC, MCHCHK) & 0xf;
t |= (temp & 0x3) << 4;
if ((t & 0xf) == 10)
t &= 0360;
if (t == 0)
t = 10;
WriteP(MAC, t);
break;
case CPU_7053: /* 705-iii */
/* Check if 80K machine */
if ((cpu_unit.flags & EMULATE2) == 0) {
t = ReadP(MAC, MCHCHK) & 0x1f;
t |= (temp & 0x2) << 4;
if ((t & 0xf) == 10)
t &= 0360;
if (t == 0)
t = 10;
WriteP(MAC, t);
}
break;
case CPU_705: /* 705 */
case CPU_702: /* 702 , Illegal on this machine */
break;
}
sim_interval -= 5; /* count down */
break;
case OP_SND: /* SND */
/* Only on 705/3 and above */
/* Addresses must be on 5 char boundry */
if (CPU_MODEL < CPU_7053 || (MAC2 % 5) != 4 || (MAC % 5) != 4) {
flags |= INSTFLAG|ANYFLAG;
selreg2 = 0;
break;
}
/* If RWW pending, SND does a memory check until end of block */
if (selreg2 != 0) {
selreg2 = 0;
while((MAC % 200000) != 19999) {
(void)Read5(MAC, MCHCHK);
Prev5(MAC);
sim_interval -= 5; /* count down */
}
break;
}
addr = get_acstart(reg);
while(AC[addr] != 0) {
uint32 v;
v = Read5(MAC, MCHCHK);
Write5(MAC2, v);
Prev5(MAC2);
Prev5(MAC);
addr = next_addr[addr];
sim_interval -= 5; /* count down */
}
break;
case OP_BLM: /* BLM */
/* Blank memory */ /* ASU 0 5 char, ASU 1 1 char */
if (CPU_MODEL < CPU_7053) {
flags |= INSTFLAG|ANYFLAG;
break;
}
/* Blank in blocks of 5 characters */
if (reg == 0) {
if ((MAC2 % 5) != 4) {
flags |= INSTFLAG|ANYFLAG;
break;
}
while(MAC > 0) {
Write5(MAC2, CHR_BLANK << (4 * 6)|
CHR_BLANK << (3 * 6)|CHR_BLANK << (2 * 6)|
CHR_BLANK << (1 * 6)|CHR_BLANK);
Prev5(MAC2);
MAC--;
sim_interval -= 5; /* count down */
}
} else if (reg == 1) {
while(MAC > 0) {
WriteP(MAC2, CHR_BLANK);
Prev(MAC2);
MAC--;
sim_interval --; /* count down */
}
} else {
flags |= INSTFLAG|ANYFLAG;
}
break;
case OP_SBZ: /* SBZ|A|R|N */
/* reg 1-6: bit# <- 0 */
/* reg 7: bitA ^= 1 */
/* reg 8: bit error ^= 1 */
/* reg 9-14: bit# <- 1 */
if (CPU_MODEL < CPU_7053) {
flags |= INSTFLAG|ANYFLAG;
break;
}
t = ReadP(MA, 0);
if (t & 0100)
flags |= MCHCHK|ANYFLAG;
sim_interval --; /* count down */
switch(reg) {
case 0: /* Nop */
break;
case 1: /* 1 */
case 2: /* 2 */
case 3: /* 4 */
case 4: /* 8 */
case 5: /* A */
case 6: /* B */
t &= ~(1<<(reg-1));
break;
case 7: /* Reverse A */
t ^= 020;
break;
case 8: /* Reverse C */
t = M[MA % EMEMSIZE] ^ 0100;
break;
case 9: /* 1 */
case 10: /* 2 */
case 11: /* 4 */
case 12: /* 8 */
case 13: /* A */
case 14: /* B */
t |= 1<<(reg-9);
break;
}
WriteP(MA, t);
break;
default:
flags |= ANYFLAG|INSTFLAG;
break;
}
if (hst_lnt) { /* history enabled? */
hst[hst_p].flags = flags;
addr = get_acstart(reg);
for (t = 0; t < 254; t++) {
hst[hst_p].store[t] = AC[addr];
addr = next_addr[addr];
if (hst[hst_p].store[t] == 0)
break;
}
}
}
if (instr_count != 0 && --instr_count == 0)
return SCPE_STEP;
} /* end while */
/* Simulation halted */
return reason;
}
/* Read and convert address of instruction */
uint32 read_addr(uint8 *reg, uint8 *zone) {
uint8 t;
uint32 addr;
t = ReadP(MA, INSTFLAG); /* Read low order digit */
*zone = (t & 060) >> 2;
addr = bcd_bin[t & 0xf];
if ((t & 0xf) > 10) /* Check valid numeric */
flags |= INSTFLAG|ANYFLAG;
MA--;
t = ReadP(MA, INSTFLAG); /* next digit */
*reg = (t & 060) >> 4;
if ((t & 0xf) > 10)
flags |= INSTFLAG|ANYFLAG;
addr += dig2[t & 0xf];
MA--;
t = ReadP(MA, INSTFLAG); /* Read third digit */
*reg |= (t & 060) >> 2;
if ((t & 0xf) > 10)
flags |= INSTFLAG|ANYFLAG;
addr += dig3[t & 0xf];
MA--;
t = ReadP(MA, INSTFLAG); /* Save High order address */
*zone |= (t & 060) >> 4;
if ((t & 0xf) > 10)
flags |= INSTFLAG|ANYFLAG;
addr += dig4[t & 0xf];
MA--;
switch (cpu_type) {
case CPU_7080: /* 7080 */
addr += dig_zone[*zone];
*zone = 0;
break;
case CPU_7053: /* 705-iii */
addr += dig_zone[*zone & 013];
*zone &= 04;
break;
case CPU_705: /* 705 */
/* Can't have any value */
addr += dig_zone[*zone & 03];
*zone &= 014;
break;
case CPU_702: /* 702 */
if (*zone == 02) { /* B bit in highest digit select AC B */
*reg = 1;
} else if (*zone != 0)
flags |= INSTFLAG|ANYFLAG;
*zone = 0;
break;
}
return addr;
}
/* Write converted address of instruction */
void write_addr(uint32 addr, uint8 reg, uint8 zone) {
uint8 value[4];
int i;
if ((MA % 5) != 0) {
flags |= INSTFLAG|ANYFLAG;
return;
}
/* Convert address into BCD first */
for(i = 0; i < 4; i++) {
value[i] = bin_bcd[addr % 10];
addr /= 10;
}
addr = zone_dig[addr & 0xf];
/* Decode extra addresses and ASU setting */
switch (cpu_type) {
case CPU_7080: /* 7080 */
value[0] |= (addr & 03) << 4;
value[3] |= (addr & 0xc) << 2;
break;
case CPU_7053: /* 705-iii */
/* If 80k emulation */
if ((cpu_unit.flags & EMULATE2) == 0)
value[0] |= (addr & 02) << 4;
value[3] |= (addr & 0xc) << 2;
break;
case CPU_705: /* 705 */
/* If doing 40k machine */
if ((cpu_unit.flags & EMULATE2))
value[3] |= (addr & 0xc) << 2;
else /* 20k */
value[3] |= (addr & 0x8) << 2;
break;
case CPU_702: /* 702 */
if (reg == 1)
value[3] |= 040; /* Set minus */
reg = 0;
break;
}
value[2] |= (reg & 03) << 4;
value[1] |= (reg & 014) << 2;
/* Or in zone values */
value[0] |= (zone & 014) << 2;
value[3] |= (zone & 03) << 4;
/* Write it out to memory backwards */
for(i = 0; i< 4; i++) {
MA--;
if ((value[i] & 0xf) == 10)
value[i] &= 0360;
if (value[i] == 0)
value[i] = 10;
WriteP(MA, value[i]);
}
}
/* Store converted address in storage */
void store_addr(uint32 addr, int loc) {
uint8 value[4];
int i;
/* Convert address into BCD first */
value[0] = bin_bcd[addr % 10];
addr /= 10;
value[1] = bin_bcd[addr % 10];
addr /= 10;
value[2] = bin_bcd[addr % 10];
addr /= 10;
value[3] = bin_bcd[addr % 10];
addr /= 10;
addr = zone_dig[addr & 0xf];
switch (cpu_type) {
case CPU_7080: /* 7080 */
value[0] |= (addr & 03) << 4;
value[3] |= (addr & 0xc) << 2;
break;
case CPU_7053: /* 705-iii */
/* If 80k emulation */
if ((cpu_unit.flags & EMULATE2) == 0)
value[0] |= (addr & 02) << 4;
value[3] |= (addr & 0xc) << 2;
break;
case CPU_705: /* 705 */
/* If doing 40k machine */
if ((cpu_unit.flags & EMULATE2))
value[3] |= (addr & 0xc) << 2;
else /* 20k */
value[3] |= (addr & 0x8) << 2;
break;
case CPU_702: /* 702 */
break;
}
/* Write it out to storage backwards */
for(i = 0; i< 4; i++) {
if ((value[i] & 0xf) == 10)
value[i] &= 0360;
if (value[i] == 0)
value[i] = 10;
AC[loc] = value[i];
loc = next_addr[loc];
}
}
/* Read address from storage */
uint32 load_addr(int loc) {
uint8 t;
uint8 zone;
uint32 addr;
t = AC[loc]; /* First digit */
loc = next_addr[loc];
zone = (t & 060) >> 2;
addr = bcd_bin[t & 0xf];
t = AC[loc]; /* Second digit */
loc = next_addr[loc];
addr += dig2[bcd_bin[t & 0xf]];
t = AC[loc]; /* Read third digit */
loc = next_addr[loc];
addr += dig3[bcd_bin[t & 0xf]];
t = AC[loc]; /* Save High order address */
loc = next_addr[loc];
zone |= (t & 060) >> 4;
addr += dig4[bcd_bin[t & 0xf]];
switch (cpu_type) {
case CPU_7080: /* 7080 */
break;
case CPU_7053: /* 705-iii */
/* If doing 40k */
if (cpu_unit.flags & EMULATE2)
zone &= 3; /* 40k */
else
zone &= 013; /* 80k */
break;
case CPU_705: /* 705 */
if (cpu_unit.flags & EMULATE2)
zone &= 3; /* 40K */
else
zone &= 1; /* 20k */
break;
case CPU_702: /* 702 */
zone = 0; /* 10k Memory */
break;
}
addr += dig_zone[zone];
return addr;
}
/* Store converted hex address in storage */
void store_hex(uint32 addr, int loc) {
/* Convert address into BCD first */
AC[loc] = bin_bcd[addr & 0xf];
loc = next_addr[loc];
AC[loc] = bin_bcd[(addr >> 4) & 0xf];
loc = next_addr[loc];
AC[loc] = bin_bcd[(addr >> 8) & 0xf];
loc = next_addr[loc];
AC[loc] = bin_bcd[(addr >> 12) & 0xf];
}
/* Read hex address from storage */
uint32 load_hex(int loc) {
uint8 t;
uint32 addr;
t = AC[loc]; /* First digit */
addr = bcd_bin[t & 0xf];
loc = next_addr[loc];
t = AC[loc]; /* Second digit */
addr += bcd_bin[t & 0xf] << 4;
loc = next_addr[loc];
t = AC[loc]; /* Read third digit */
addr += bcd_bin[t & 0xf] << 8;
loc = next_addr[loc];
t = AC[loc]; /* Save High order address */
addr += bcd_bin[t & 0xf] << 12;
return addr;
}
/* Compute starting point in Storage for accumulator */
uint16 get_acstart(uint8 reg) {
if (reg == 0)
return spc;
if (cpu_type == CPU_702) {
return spcb;
} else {
uint16 addr;
addr = (spc & 0x700) | 0x100 | ((reg - 1) << 4);
if (addr > 0x4ff)
addr &= 0x4ff;
return addr;
}
}
/* Store CPU state in CASU 15 */
void store_cpu(uint32 addr, int full) {
uint8 t;
store_addr(IC, addr);
addr = next_addr[addr];
addr = next_addr[addr];
addr = next_addr[addr];
addr = next_addr[addr];
/* Save status characters */
t = flags & 0xf;
AC[addr] = 040 | ((t + 8) & 027);
addr = next_addr[addr];
t = (flags >> 4) & 0xf;
AC[addr] = 040 | ((t + 8) & 027);
addr = next_addr[addr];
t = (flags >> 8) & 0xf;
AC[addr] = 040 | ((t + 8) & 027);
addr = next_addr[addr];
t = (flags >> 12) & 0x3;
AC[addr] = 040 | t;
if (full) {
addr = next_addr[addr];
AC[addr] = bin_bcd[spc & 7];
addr = next_addr[addr];
AC[addr] = bin_bcd[(spc >> 3) & 3];
addr = next_addr[addr];
AC[addr] = bin_bcd[(spc >> 5) & 7];
addr = next_addr[addr];
AC[addr] = bin_bcd[(spc >> 8) & 7];
addr = next_addr[addr];
for(; addr < 0x3F8; addr++)
AC[addr] = 10;
for(; addr < 0x400; addr++)
AC[addr] = 0;
store_addr(MAC2, 0x3F0);
store_hex(selreg, 0x3F8);
}
}
/* Load CPU State from storage */
void load_cpu(uint32 addr, int full) {
uint8 t;
IC = load_addr(addr);
addr = next_addr[addr];
addr = next_addr[addr];
addr = next_addr[addr];
addr = next_addr[addr];
flags = 0;
t = AC[addr++];
flags |= (t & 0x7) | ((t >> 1) & 0x8);
t = AC[addr++];
flags |= ((t & 0x7) | ((t >> 1) & 0x8)) << 4;
t = AC[addr++];
flags |= ((t & 0x7) | ((t >> 1) & 0x8)) << 8;
t = AC[addr++];
flags |= (t & 0x3) << 12;
/* Adjust Max memory if mode changed */
EMEMSIZE = MEMSIZE;
if (flags & EIGHTMODE) {
cpu_type = CPU_7080;
} else {
cpu_type = (cpu_unit.flags & EMULATE3)? CPU_7053:CPU_705;
EMEMSIZE = MEMSIZE;
if (cpu_unit.flags & EMULATE2 && EMEMSIZE > 40000)
EMEMSIZE = 40000;
if (cpu_type == CPU_705 && (cpu_unit.flags & EMULATE2) == 0
&& EMEMSIZE > 20000)
EMEMSIZE = 20000;
if (EMEMSIZE > 80000)
EMEMSIZE = 80000;
}
if (full) {
spc = bcd_bin[AC[addr++]] & 07; /* Units digit */
/* One of words */
spc += (bcd_bin[AC[addr++]] & 3) << 3; /* Tens digit */
/* One of four word sets */
spc += (bcd_bin[AC[addr++]] & 7) << 5; /* Hundreds */
/* Bank */
spc += (bcd_bin[AC[addr++]] & 7) << 8; /* Thousands */
addr += 4;
MAC2 = load_addr(addr);
addr += 8;
selreg = load_hex(addr);
}
}
/* Do add or subtract instruction.
mode == 1 for subtract
mode == 0 for addition.
Register is ASU or zero for A.
smt == 0 if ADD/SUB
smt == 1 if RSU/RAD
fmsk is the flags mask to set or clear */
t_stat do_addsub(int mode, int reg, int smt, uint16 fmsk) {
uint8 cr1, cr2;
int sign;
int msign;
int carry;
uint32 addr;
int met = 1;
int addsub;
addr = get_acstart(reg);
cr1 = ReadP(MA, MCHCHK);
Next(MA);
sim_interval --; /* count down */
/* Check sign if not valid then treat as 0 */
msign = 0;
switch(cr1 & 060) {
case 000:
case 020:
flags |= SGNFLAG|ANYFLAG;
case 060:
break;
case 040:
msign = 1;
break;
}
/* Fix cr1 to decimal */
cr1 &= 0xf;
/* Set sign to sign of Ac */
sign = (flags & fmsk & SIGN)?1:0;
/* Set Zero and clear Sign */
flags |= fmsk & ZERO;
flags &= ~(fmsk & SIGN);
/* Decide mode of operation */
addsub = 0;
if (smt) {
sign = (mode)?(!msign):msign; /* Fix sign */
cr2 = 0; /* After end, force zero */
} else {
if(mode) { /* Decide mode based on signs */
if (sign == msign)
addsub = 1;
} else {
if (sign != msign)
addsub = 1;
}
cr2 = AC[addr];
if (cr2 == 0) /* Check for storage mark */
smt = 0; /* Done storage */
}
smt = !smt;
carry = addsub;
/* Process while valid digit in memory */
while(smt || met) {
cr2 &= 0xf;
cr1 = bcd_bin[cr1&0xf] + ((addsub)? comp_bcd[cr2]: bcd_bin[cr2])
+ carry;
carry = cr1 >= 10;
AC[addr] = bin_bcd[cr1];
/* Update zero flag */
if (cr1 != 0 && cr1 != 10)
flags &= ~(fmsk & ZERO);
addr = next_addr[addr];
if (met) {
cr1 = ReadP(MA, MCHCHK);
if (cr1 == 0 || cr1 > 10) {
met = 0; /* End of memory */
cr1 = 0; /* zero */
}
Next(MA);
} else {
cr1 = 0; /* Force to zero */
}
/* Grab storage value */
if (smt) {
cr2 = AC[addr];
if (cr2 == 0) /* Check for storage mark */
smt = 0; /* Done storage */
} else {
cr2 = 0; /* After end, force zero */
}
sim_interval --; /* count down */
}
AC[addr] = 0; /* Force storage mark */
/* Handle last digit */
if (carry) {
if (addsub) {
sign = !sign;
} else {
/* Overflow, extend by one digit */
AC[addr] = 1;
addr = next_addr[addr];
AC[addr] = 0; /* Storage mark */
flags |= ACOFLAG|ANYFLAG;
flags &= ~(fmsk & ZERO);
}
} else {
if (addsub) {
/* Recomplement storage */
addr = get_acstart(reg);
carry = 1;
flags |= fmsk & ZERO;
while ( AC[addr] != 0) {
cr2 = AC[addr];
cr2 = comp_bcd[cr2] + carry;
carry = cr2 >= 10; /* Update carry */
AC[addr] = bin_bcd[cr2];
/* Update zero flag */
if (cr2 != 0 && cr2 != 10)
flags &= ~(fmsk & ZERO);
addr = next_addr[addr];
sim_interval --; /* count down */
}
}
}
/* Update sign and zero */
flags |= (fmsk & SIGN) & (sign | (sign << 1));
flags &= ~(((flags & ZERO) >> 2) & fmsk);
return SCPE_OK;
}
/* Multiply memory to AC */
t_stat
do_mult(int reg, uint16 fmsk)
{
uint8 t;
uint8 at;
uint8 cr1, cr2;
uint16 addr;
uint16 prod;
int mult;
int msign = 0;
/* Type I cycle */
addr = get_acstart(reg);
mult = AC[addr];
AC[addr] &= 0xf;
if (AC[addr] == 0) /* If initial storage mark, replace */
AC[addr] = 10; /* With zero */
prod = next_half[addr];
flags |= fmsk & ZERO;
t = 1;
at = 0;
/* Check for mark */
while (mult != 0) {
/* Type II */
/* Check signs of B and A. */
cr1 = ReadP(MA, MCHCHK);
sim_interval --; /* count down */
Next(MA);
/* Compute sign */
if (t) {
switch(cr1 & 060) {
case 000:
case 020:
flags |= SGNFLAG|ANYFLAG;
case 060:
break;
case 040:
msign = fmsk & SIGN;
break;
}
t = 0;
cr1 = bin_bcd[cr1 & 0xf];
}
mult = bcd_bin[mult & 0xf];
/* Type III */
cr2 = 0;
while(cr1 >= 1 && cr1 <= 10 ) {
cr2 += mult * bcd_bin[cr1];
if (at)
cr2 += bcd_bin[AC[prod]];
AC[prod] = bin_bcd[cr2 % 10];
if (AC[prod] != 10)
flags &= ~(fmsk & ZERO);
cr2 /= 10;
prod = next_addr[prod];
cr1 = ReadP(MA, MCHCHK);
Next(MA);
sim_interval --; /* count down */
}
if (cr2 != 0)
flags &= ~(fmsk & ZERO);
AC[prod] = bin_bcd[cr2];
prod = next_addr[prod];
AC[prod] = 0; /* Set storage mark */
/* Type IV */
at = 1; /* Parcial product exists */
addr = next_addr[addr];
prod = next_half[addr]; /* Were to put results */
mult = AC[addr]; /* Grab next digit */
AC[addr] &= 0xf; /* Clear zone */
MA = MAC; /* Back to start of field */
t = 1; /* Set to handle sign */
}
/* Type V */
/* Update position */
addr = get_acstart(reg);
addr = next_half[addr]; /* Adjust pointer */
if (CPU_MODEL == CPU_702 && reg != 0) {
spcb = addr;
} else {
if (CPU_MODEL == CPU_702)
spc = addr;
else if (reg == 0)
spc = (spc & 0x700) | (addr & 0xff);
}
/* Update sign and zero */
flags ^= msign;
flags &= ~(((flags & ZERO) >> 2) & fmsk);
return SCPE_OK;
}
t_stat
do_divide(int reg, uint16 fmsk)
{
int cr1;
int cr2;
int tsac;
int tspc;
int at;
int smt;
int msign;
int remtrig;
int carry;
int dzt;
/* Step I, put storage mark before start of AC */
at = 0;
tspc = get_acstart(reg);
AC[prev_addr[tspc]] = 0;
smt = 1;
carry = 0;
msign = 0;
/* Step II, step address until we find storage mark */
step2:
while(AC[tspc] != 0) {
AC[tspc] &= 0xf; /* Make all numeric */
tspc = next_addr[tspc];
sim_interval --; /* count down */
}
tsac = next_half[tspc];
tspc = prev_addr[tspc];
/* Step III, step second address 128/256 locations. */
dzt = 1;
if (at) {
tspc = next_half[tspc];
goto done;
}
AC[tsac] = 0;
at = 1;
smt = 0;
tsac = tspc;
sim_interval --; /* count down */
/* Step IV, back up first address while advancing MA */
do {
sim_interval --; /* count down */
cr1 = ReadP(MA, MCHCHK);
if (AC[tsac] == 0) { /* Short */
tsac = next_addr[tsac];
tspc = tsac;
goto done;
}
if (at) {
switch(cr1 & 060) {
case 000:
case 020:
flags |= SGNFLAG|ANYFLAG;
/* Fall through */
case 060:
msign = 0;
break;
case 040:
msign = (fmsk & SIGN);
break;
}
at = 0;
} else if (cr1 == 0 || cr1 > 10) { /* Next sign digit */
at = 1;
MA = MAC;
tspc = tsac;
goto step5;
}
tsac = prev_addr[tsac];
Next(MA);
} while(1); /* Next sign digit */
/* Type V, perform first subtract */
step5:
remtrig = 0;
MA = MAC;
while (1) {
/* Step V, subtract Memory from storage */
cr1 = ReadP(MA, MCHCHK);
cr2 = AC[tsac];
sim_interval --; /* count down */
if (cr2 == 0) {
tspc = next_addr[tspc];
goto step9;
} else if (at) {
carry = 1;
cr1 &= 017;
at = 0;
} else if (cr1 == 0 || cr1 > 10) {
cr1 = comp_bcd[cr2] + carry;
carry = cr1 >= 10;
AC[tsac] = bin_bcd[cr1];
MA = MAC;
tsac = next_half[tsac];
at = 1;
goto step6;
}
Next(MA);
cr1 = comp_bcd[cr2] + bcd_bin[cr1] + carry;
carry = cr1 >= 10;
AC[tsac] = bin_bcd[cr1];
if (AC[tsac] != 10)
remtrig = 1;
tsac = next_addr[tsac];
}
step6:
cr2 = AC[tsac];
cr1 = 1;
if (carry) {
smt = 0;
if (remtrig) {
if (at) {
AC[tsac] = 10;
} else {
at = 1;
}
tsac = tspc;
goto step8;
} else {
int t;
if (at)
cr2 = 0;
else
cr2 = bin_bcd[cr2];
t = cr2 + 1;
AC[tsac] = bin_bcd[t];
tsac = tspc;
if (t >= 10) {
flags |= ACOFLAG|ANYFLAG;
at = 1;
goto step2;
}
dzt = 0;
at = 0;
goto step9;
}
} else {
int t;
if (at)
cr2 = 0;
else
cr2 = bcd_bin[cr2];
t = cr2 + 1;
AC[tsac] = bin_bcd[t];
tsac = tspc;
remtrig = 0;
at = 1;
if (t >= 10) {
flags |= ACOFLAG|ANYFLAG;
goto step2;
}
dzt = 0;
}
smt = 0;
while(!smt) {
cr1 = ReadP(MA, MCHCHK);
Next(MA);
sim_interval --; /* count down */
cr2 = AC[tsac];
if (cr2 == 0) {
smt = 1; /* Check usage here */
break; /* goto step6; */
}
if (at) {
cr1 &= 017;
at = 0;
} else if (cr1 == 0 || cr1 > 10) {
cr2 = bcd_bin[cr2] + carry;
carry = cr2 >= 10;
AC[tsac] = bin_bcd[cr2];
if (AC[tsac] != 10)
remtrig = 1;
MA = MAC;
tsac = next_half[tsac];
break; /* goto step6; */
}
cr2 = bcd_bin[cr2] + bcd_bin[cr1] + carry;
carry = cr2 >= 10;
AC[tsac] = bin_bcd[cr2];
if (AC[tsac] != 10)
remtrig = 1;
tsac = next_addr[tsac];
}
goto step6;
step8:
smt = 0;
while(!smt) {
cr1 = ReadP(MA, MCHCHK);
Next(MA);
sim_interval --; /* count down */
cr2 = AC[tsac];
if (cr2 == 0)
smt = 1;
if (at) {
at = 0;
cr1 &= 017;
carry = 1;
} else {
if (cr1 == 0 || cr1 > 10) {
cr2 = comp_bcd[cr2] + carry;
carry = cr2 >= 10;
AC[tsac] = bin_bcd[cr2];
MA = MAC;
tsac = tspc;
goto step9;
}
}
cr2 = comp_bcd[cr2] + bcd_bin[cr1] + carry;
carry = cr2 >= 10;
AC[tsac] = bin_bcd[cr2];
tsac = next_addr[tsac];
};
/* Step 9 */
step9:
if (at) {
tspc = next_half[tspc];
Next(MA);
goto step10;
} else {
tsac = prev_addr[tsac];
tspc = prev_addr[tspc];
remtrig = 0;
at = 1;
goto step5;
}
/* Step X */
step10:
do {
cr1 = ReadP(MA, MCHCHK);
Next(MA);
sim_interval --; /* count down */
tspc = next_addr[tspc];
} while (cr1 > 0 && cr1 <= 10);
done:
if (CPU_MODEL == CPU_702)
spc = tspc;
else
spc = (spc & 0x700) | (tspc & 0xff);
if (dzt)
flags |= (fmsk & ZERO);
else
flags &= ~(fmsk & ZERO);
/* Update sign and zero */
flags ^= msign;
flags &= ~(((flags & ZERO) >> 2) & fmsk);
return SCPE_OK;
}
t_stat
do_compare(int reg, int tluop) {
int addr;
uint8 cr1;
uint8 cr2;
addr = get_acstart(reg);
flags &= ~CMPFLAG;
while(AC[addr] != 0) {
int sup8;
cmpnext:
cr2 = AC[addr];
if (cr2 == 0)
break;
cr1 = ReadP(MA, MCHCHK);
sim_interval--; /* count down */
/* Stop table opcode on GM or RM */
if (tluop && (cr1 == CHR_GM || cr1 == CHR_RM)) {
bkcmp = 0;
return SCPE_OK;
}
if ((cr1 & 0xf) > 10)
sup8 = 007;
else
sup8 = 017;
if(bkcmp) {
Prev(MA);
} else {
Next(MA);
}
addr = next_addr[addr];
if (cr1 == CHR_BLANK) {
if (cr2 != CHR_BLANK) {
flags &= ~CMPFLAG;
flags |= HIGHFLAG;
}
goto cmpnext;
}
if (cr2 == CHR_BLANK) {
flags &= ~CMPFLAG;
flags |= LOWFLAG;
} else {
int t1 = cr1 & 017;
int t2 = cr2 & 017;
if ((t1 == 11) || (t1 == 12)) { /* CR1 Special? */
if ((t2 != 11) && (t2 != 12)) { /* CR2 not special */
flags &= ~CMPFLAG;
flags |= HIGHFLAG;
goto cmpnext;
}
} else if ((t2 == 11) || (t2 == 12)) {/* CR2 special */
if ((t1 != 11) && (t1 != 12)) { /* CR1 not special */
flags &= ~CMPFLAG;
flags |= LOWFLAG;
goto cmpnext;
}
}
if ((cr1 & 060) != (cr2 & 060)) { /* Check zones */
flags &= ~CMPFLAG;
t1 = (cr1 & 060) + (060 ^ (cr2 & 060));
flags |= (t1 & 0100) ? HIGHFLAG:LOWFLAG;
} else { /* Zones same */
if ((cr1 == 040) || (cr1 == 060)) {
if ((cr2 != 040) && (cr2 != 060)) {
flags &= ~CMPFLAG;
flags |= LOWFLAG;
goto cmpnext;
}
} else if ((cr2 == 040) || (cr2 == 060)) {
flags &= ~CMPFLAG;
flags |= HIGHFLAG;
goto cmpnext;
}
/* Compare actual digits */
t1 = bcd_bin[t1 & sup8] + comp_bcd[t2] + 1;
if (t1 != 10) {
flags &= ~CMPFLAG;
flags |= (t1 <= 10)?HIGHFLAG:LOWFLAG;
}
}
}
}
bkcmp = 0;
return SCPE_OK;
}
/* Initialize memory to all blank */
void
mem_init() {
int i;
/* Force memory to be blanks on load */
for(i = 0; i < (MAXMEMSIZE-1); i++)
M[i] = CHR_BLANK;
MEMSIZE = (((cpu_unit.flags & UNIT_MSIZE) >> UNIT_V_MSIZE) + 1) * 10000;
EMEMSIZE = MEMSIZE;
}
/* Reset routine */
t_stat
cpu_reset(DEVICE * dptr)
{
int i;
int n,p,h;
/* Set next and previous address arrays based on CPU type */
if (CPU_MODEL == CPU_702) {
for(i = 0; i < 512; i++) {
n = (i + 1) & 0777; /* A */
p = (i - 1) & 0777;
h = (i + 256) & 0777;
next_addr[i] = n; /* A */
prev_addr[i] = p;
next_half[i] = h;
next_addr[i+512] = 512 + n; /* B */
prev_addr[i+512] = 512 + p;
next_half[i+512] = 512 + h;
}
cpu_reg[1].depth = 512;
cpu_reg[2].offset = 512;
cpu_reg[2].depth = 512;
cpu_reg[2].loc = &AC[512];
} else {
for(i = 0; i < 256; i++) {
n = next_addr[i] = (i + 1) & 0377; /* A */
p = prev_addr[i] = (i - 1) & 0377;
h = next_half[i] = (i + 128) & 0377;
next_addr[i+256] = 256 + n; /* Bank 1 */
prev_addr[i+256] = 256 + p;
next_half[i+256] = 256 + h;
next_addr[i+512] = 512 + n; /* Bank 2 */
prev_addr[i+512] = 512 + p;
next_half[i+512] = 512 + h;
next_addr[i+768] = 768 + n; /* Bank 3 */
prev_addr[i+768] = 768 + p;
next_half[i+768] = 768 + h;
next_addr[i+1024] = 1024 + n; /* Bank 4 */
prev_addr[i+1024] = 1024 + p;
next_half[i+1024] = 1024 + h;
next_addr[i+1280] = 1280 + n; /* Bank 5 */
prev_addr[i+1280] = 1280 + p;
next_half[i+1280] = 1280 + h;
}
cpu_reg[1].depth = 256;
cpu_reg[2].offset = 256;
for(i = 0; i < 15; i++) {
cpu_reg[i+2].loc = &AC[256 + 16*i];
cpu_reg[i+2].depth = 256;
}
}
/* Clear io error flags */
memset(ioflags, 0, sizeof(ioflags));
/* Clear accumulators to storage mark */
memset(AC, 0, sizeof(AC));
flags = 0;
intmode = 0;
intprog = 0;
irqflags = 0;
selreg = 0;
selreg2 = 0;
IC = 4;
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] & 077;
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 & 077;
return SCPE_OK;
}
t_stat
cpu_set_size(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
{
t_uint64 mc = 0;
uint32 size;
uint32 i;
size = val >> UNIT_V_MSIZE;
size++;
size *= 10000;
if (size > MAXMEMSIZE)
return SCPE_ARG;
for (i = size-1; i < MEMSIZE; i++) {
if (M[i] != CHR_BLANK) {
mc = 1;
break;
}
}
if ((mc != 0) && (!get_yn("Really truncate memory [N]?", FALSE)))
return SCPE_OK;
cpu_unit.flags &= ~UNIT_MSIZE;
cpu_unit.flags |= val;
EMEMSIZE = MEMSIZE = size;
for (i = MEMSIZE - 1; i < (MAXMEMSIZE-1); i++)
M[i] = CHR_BLANK;
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;
int len;
t_stat r;
t_value sim_eval[50];
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 OP MA REG\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, "%06d %c %06d %02d ", h->ic & 0x3ffff,
mem_to_ascii[h->op], h->ea, h->reg);
sim_eval[0] = (h->inst >> (4 * 6)) & 077;
sim_eval[1] = (h->inst >> (3 * 6)) & 077;
sim_eval[2] = (h->inst >> (2 * 6)) & 077;
sim_eval[3] = (h->inst >> (1 * 6)) & 077;
sim_eval[4] = h->inst & 077;
(void)fprint_sym (st, h->ic, sim_eval, &cpu_unit, SWMASK('M'));
for(len = 0; len < 256 && (h->store[len] & 077) != 0; len++);
fprintf(st, "\t%-2d %c%c %c%c %c@", len,
(h->flags & AZERO)?'Z':' ', (h->flags & ASIGN)?'-':'+',
(h->flags & BZERO)?'Z':' ', (h->flags & BSIGN)?'-':'+',
(h->flags & LOWFLAG)? 'l' :
((h->flags & HIGHFLAG) ? 'h' : 'e'));
for(len--; len >= 0; len--)
fputc(mem_to_ascii[h->store[len] & 077], st);
fputc('@', st);
if (h->flags & 0x7f0) {
int i;
fputc(' ', st);
for (i = 0; i < 7; i++) {
if (h->flags & (0x10 << i))
fputc('0' + i, st);
}
}
fputc('\n', st); /* end line */
} /* end else instruction */
} /* end for */
return SCPE_OK;
}
const char *
cpu_description (DEVICE *dptr)
{
return "IBM 7080 CPU";
}
t_stat
cpu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
{
fprintf (st, "The CPU can be set to a IBM 702, IBM 705, IBM 705/3 or IBM 7080\n");
fprintf (st, "The type of CPU can be set by one of the following commands\n\n");
fprintf (st, " sim> set CPU 702 sets IBM 704 emulation\n");
fprintf (st, " sim> set CPU 705 sets IBM 705 emulation\n");
fprintf (st, " sim> set CPU 7053 sets IBM 705/3 emulation\n");
fprintf (st, " sim> set CPU 7080 sets IBM 7080 emulation\n\n");
fprintf (st, "These switches are recognized when examining or depositing in CPU memory:\n\n");
fprintf (st, " -c examine/deposit characters\n");
fprintf (st, " -s examine 50 characters\n");
fprintf (st, " -d examine 50 characters\n");
fprintf (st, " -m examine/deposit IBM 7080 instructions\n\n");
fprintf (st, "The memory of the CPU can be set in 10K incrememts from 10K to 160K with the\n\n");
fprintf (st, " sim> SET CPU xK\n\n");
fprintf (st, "For the IBM 7080 the following options can be enabled\n\n");
fprintf (st, " sim> SET CPU EMU40K enables memory above 40K\n");
fprintf (st, " sim> SET CPU NOEMU40K disables memory above 40K\n\n");
fprintf (st, " sim> SET CPU EMU705 enables IBM7080 to support 705 Emulation.\n");
fprintf (st, " sim> SET CPU NOEMU705 disables IBM7080 to support 705 Emulation.\n\n");
fprintf (st, " sim> SET CPU NOSTOP CPU will not stop on invalid conditions\n");
fprintf (st, " sim> SET CPU PRORAM CPU stop under program control\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\n");
fprint_set_help(st, dptr);
fprint_show_help(st, dptr);
return SCPE_OK;
}