Card reader handle EOF correctly. Line printer proper handling of paging. Magtape clean up debug message. Update 7010, 7070, 7080 for EOF handling.
3587 lines
134 KiB
C
3587 lines
134 KiB
C
/* 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 UNIT_V_IOIRQ (UNIT_V_NONSTOP + 1)
|
||
#define IOIRQ (1 << UNIT_V_IOIRQ)
|
||
#define UNIT_V_40K (UNIT_V_IOIRQ + 1)
|
||
#define EMU40K (1 << UNIT_V_40K)
|
||
|
||
#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(uint32 *loc);
|
||
void store_addr(uint32 addr, uint32 *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 (ANYFLAG)
|
||
|
||
uint8 M[MAXMEMSIZE] = { 0 }; /* memory */
|
||
uint32 EMEMSIZE; /* Physical memory size */
|
||
uint8 AC[6*512]; /* 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[6200/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[];
|
||
|
||
|
||
/* 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")},
|
||
{SAVEDATA(ADATA, AC) },
|
||
{VBRDATAD(A, AC[0], 8, 8, 256, "A Register"), REG_VMIO|REG_CIRC },
|
||
{VBRDATAD(B, AC[256], 8, 8, 256, "B Register"), REG_VMIO|REG_CIRC },
|
||
{VBRDATAD(ASU1, AC[256], 8, 8, 16, "ASU1 Register"), REG_VMIO|REG_CIRC},
|
||
{VBRDATAD(ASU2, AC[272], 8, 8, 16, "ASU2 Register"), REG_VMIO|REG_CIRC},
|
||
{VBRDATAD(ASU3, AC[288], 8, 8, 16, "ASU3 Register"), REG_VMIO|REG_CIRC},
|
||
{VBRDATAD(ASU4, AC[304], 8, 8, 16, "ASU4 Register"), REG_VMIO|REG_CIRC},
|
||
{VBRDATAD(ASU5, AC[320], 8, 8, 16, "ASU5 Register"), REG_VMIO|REG_CIRC},
|
||
{VBRDATAD(ASU6, AC[336], 8, 8, 16, "ASU6 Register"), REG_VMIO|REG_CIRC},
|
||
{VBRDATAD(ASU7, AC[352], 8, 8, 16, "ASU7 Register"), REG_VMIO|REG_CIRC},
|
||
{VBRDATAD(ASU8, AC[368], 8, 8, 16, "ASU8 Register"), REG_VMIO|REG_CIRC},
|
||
{VBRDATAD(ASU9, AC[384], 8, 8, 16, "ASU9 Register"), REG_VMIO|REG_CIRC},
|
||
{VBRDATAD(ASU10, AC[400], 8, 8, 16, "ASU10 Register"), REG_VMIO|REG_CIRC},
|
||
{VBRDATAD(ASU11, AC[416], 8, 8, 16, "ASU11 Register"), REG_VMIO|REG_CIRC},
|
||
{VBRDATAD(ASU12, AC[432], 8, 8, 16, "ASU12 Register"), REG_VMIO|REG_CIRC},
|
||
{VBRDATAD(ASU13, AC[448], 8, 8, 16, "ASU13 Register"), REG_VMIO|REG_CIRC},
|
||
{VBRDATAD(ASU14, AC[464], 8, 8, 16, "ASU14 Register"), REG_VMIO|REG_CIRC},
|
||
{VBRDATAD(ASU15, AC[480], 8, 8, 32, "ASU15 Register"), REG_VMIO|REG_CIRC},
|
||
{BINRDATA(SW, SW, 6), 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},
|
||
{IOIRQ, 0, "NOIOIRQ", "NOIOIRQ", NULL, NULL, NULL},
|
||
{IOIRQ, IOIRQ, "IOIRQ", "IOIRQ", NULL, NULL, NULL},
|
||
{EMU40K, 0, "NOEMU40K", "NOEMU40K", NULL, NULL, NULL},
|
||
{EMU40K, EMU40K, "EMU40K", "EMU40K", 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;
|
||
addr %= EMEMSIZE;
|
||
if ((flags & EMU40K) != 0) {
|
||
addr %= 40000;
|
||
}
|
||
value = M[addr];
|
||
if (value & 0100) {
|
||
if (flag == 0)
|
||
return value;
|
||
flags |= flag|ANYFLAG;
|
||
} else if (value == 0) {
|
||
flags |= flag|ANYFLAG;
|
||
}
|
||
return value;
|
||
}
|
||
|
||
/* 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 1 character to memory. */
|
||
void WriteP(uint32 addr, uint8 value) {
|
||
addr %= EMEMSIZE;
|
||
if ((flags & EMU40K) != 0) {
|
||
addr %= 40000;
|
||
}
|
||
M[addr] = 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 */
|
||
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;
|
||
}
|
||
}
|
||
|
||
/* 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(®, &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:
|
||
case SCPE_EOF:
|
||
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;
|
||
}
|
||
if (CPU_MODEL == CPU_7080 &&
|
||
(cpu_unit.flags & IOIRQ) != 0 && reg < 4 &&
|
||
(flags & EIGHTMODE) == 0) {
|
||
flags |= INSTFLAG|ANYFLAG;
|
||
t = 0;
|
||
}
|
||
} 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 (CPU_MODEL == CPU_7080 &&
|
||
(cpu_unit.flags & IOIRQ) != 0 &&
|
||
(flags & EIGHTMODE) == 0) {
|
||
temp = (selreg >> 8) & 0xff;
|
||
if (temp != 9 && temp != 5) {
|
||
flags |= INSTFLAG|ANYFLAG;
|
||
t = 0;
|
||
}
|
||
}
|
||
}
|
||
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;
|
||
flags |= MCHCHK|ANYFLAG;
|
||
}
|
||
}
|
||
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 */
|
||
if (AC[addr] & 0100) {
|
||
flags |= MCHCHK|ANYFLAG;
|
||
}
|
||
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);
|
||
if (CPU_MODEL == CPU_7080 &&
|
||
(cpu_unit.flags & IOIRQ) != 0 &&
|
||
(flags & EIGHTMODE) == 0 &&
|
||
((selreg >> 8) & 0xff) != 5) {
|
||
flags |= ANYFLAG|INSTFLAG;
|
||
}
|
||
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_EOF:
|
||
case SCPE_IOERR:
|
||
flags |= ANYFLAG|INSTFLAG;
|
||
break;
|
||
}
|
||
}
|
||
if (iowait == 0 && CPU_MODEL == CPU_7080 &&
|
||
(cpu_unit.flags & IOIRQ) != 0 &&
|
||
(flags & EIGHTMODE) == 0 &&
|
||
((selreg >> 8) & 0xff) != 5) {
|
||
flags |= ANYFLAG|INSTFLAG;
|
||
}
|
||
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_EOF:
|
||
case SCPE_IOERR:
|
||
flags |= ANYFLAG|INSTFLAG;
|
||
break;
|
||
}
|
||
if (iowait == 0 && CPU_MODEL == CPU_7080 &&
|
||
(cpu_unit.flags & IOIRQ) != 0 &&
|
||
(flags & EIGHTMODE) == 0 &&
|
||
((selreg >> 8) & 0xff) != 5) {
|
||
flags |= ANYFLAG|INSTFLAG;
|
||
}
|
||
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_EOF:
|
||
case SCPE_IOERR:
|
||
flags |= ANYFLAG|INSTFLAG;
|
||
break;
|
||
}
|
||
if (iowait == 0 && CPU_MODEL == CPU_7080 &&
|
||
(cpu_unit.flags & IOIRQ) != 0 &&
|
||
(flags & EIGHTMODE) == 0 &&
|
||
((selreg >> 8) & 0xff) != 5) {
|
||
flags |= ANYFLAG|INSTFLAG;
|
||
}
|
||
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_EOF:
|
||
case SCPE_IOERR:
|
||
flags |= ANYFLAG|INSTFLAG;
|
||
break;
|
||
}
|
||
if (iowait == 0 && CPU_MODEL == CPU_7080 &&
|
||
(cpu_unit.flags & IOIRQ) != 0 &&
|
||
(flags & EIGHTMODE) == 0 &&
|
||
((selreg >> 8) & 0xff) != 5) {
|
||
flags |= ANYFLAG|INSTFLAG;
|
||
}
|
||
break;
|
||
|
||
case OP_RWW: /* RWW 705 only */
|
||
MAC2 = MAC;
|
||
if (iowait == 0 && CPU_MODEL == CPU_7080 &&
|
||
(cpu_unit.flags & IOIRQ) != 0 &&
|
||
(flags & EIGHTMODE) == 0 &&
|
||
((selreg >> 8) & 0xff) != 5) {
|
||
flags |= ANYFLAG|INSTFLAG;
|
||
selreg2 = 0;
|
||
} else {
|
||
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);
|
||
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 */
|
||
if (t & 0100)
|
||
flags |= MCHCHK|ANYFLAG;
|
||
t &= ~(1<<(reg-1));
|
||
t &= 077;
|
||
break;
|
||
case 7: /* Reverse A */
|
||
if (t & 0100)
|
||
flags |= MCHCHK|ANYFLAG;
|
||
t ^= 020;
|
||
t &= 077;
|
||
break;
|
||
case 8: /* Reverse C */
|
||
if (t & 0100)
|
||
flags |= MCHCHK;
|
||
t = M[MA % EMEMSIZE] ^ 0100;
|
||
break;
|
||
case 9: /* 1 */
|
||
case 10: /* 2 */
|
||
case 11: /* 4 */
|
||
case 12: /* 8 */
|
||
case 13: /* A */
|
||
case 14: /* B */
|
||
if (t & 0100)
|
||
flags |= MCHCHK|ANYFLAG;
|
||
t |= 1<<(reg-9);
|
||
t &= 077;
|
||
break;
|
||
}
|
||
WriteP(MA, t);
|
||
break;
|
||
|
||
default:
|
||
flags |= ANYFLAG|INSTFLAG;
|
||
break;
|
||
}
|
||
if (hst_lnt) { /* history enabled? */
|
||
hst[hst_p].flags = flags;
|
||
addr = spc;
|
||
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, uint32 *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 & 0xc) << 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(uint32 *loc) {
|
||
uint8 t;
|
||
uint8 f;
|
||
uint8 zone;
|
||
uint32 addr;
|
||
|
||
t = AC[*loc]; /* First digit */
|
||
f = t;
|
||
zone = (t & 060) >> 2;
|
||
addr = bcd_bin[t & 0xf];
|
||
*loc = next_addr[*loc];
|
||
t = AC[*loc]; /* Second digit */
|
||
f |= t;
|
||
addr += dig2[bcd_bin[t & 0xf]];
|
||
*loc = next_addr[*loc];
|
||
t = AC[*loc]; /* Read third digit */
|
||
f |= t;
|
||
addr += dig3[bcd_bin[t & 0xf]];
|
||
*loc = next_addr[*loc];
|
||
t = AC[*loc]; /* Save High order address */
|
||
f |= t;
|
||
zone |= (t & 060) >> 4;
|
||
addr += dig4[bcd_bin[t & 0xf]];
|
||
*loc = next_addr[*loc];
|
||
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 &= 7; /* 80k */
|
||
break;
|
||
case CPU_705: /* 705 */
|
||
if (cpu_unit.flags & EMULATE2)
|
||
zone &= 3; /* 40K */
|
||
else
|
||
zone &= 3; /* 20k */
|
||
break;
|
||
case CPU_702: /* 702 */
|
||
zone = 0; /* 10k Memory */
|
||
break;
|
||
}
|
||
addr += dig_zone[zone];
|
||
/* Set Machine Check if got redundant data */
|
||
if (f & 0100) {
|
||
flags |= MCHCHK|ANYFLAG;
|
||
}
|
||
return addr;
|
||
}
|
||
|
||
/* Store converted hex address in storage */
|
||
void store_hex(uint32 addr, uint32 *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];
|
||
*loc = next_addr[*loc];
|
||
}
|
||
|
||
/* Read hex address from storage */
|
||
uint32 load_hex(uint32 *loc) {
|
||
uint8 t;
|
||
uint8 f;
|
||
uint32 addr;
|
||
|
||
t = AC[*loc]; /* First digit */
|
||
f = t;
|
||
addr = bcd_bin[t & 0xf];
|
||
*loc = next_addr[*loc];
|
||
t = AC[*loc]; /* Second digit */
|
||
f |= t;
|
||
addr += bcd_bin[t & 0xf] << 4;
|
||
*loc = next_addr[*loc];
|
||
t = AC[*loc]; /* Read third digit */
|
||
f |= t;
|
||
addr += bcd_bin[t & 0xf] << 8;
|
||
*loc = next_addr[*loc];
|
||
t = AC[*loc]; /* Save High order address */
|
||
f |= t;
|
||
addr += bcd_bin[t & 0xf] << 12;
|
||
*loc = next_addr[*loc];
|
||
/* Set Machine Check if got redundant data */
|
||
if (f & 0100) {
|
||
flags |= MCHCHK|ANYFLAG;
|
||
}
|
||
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);
|
||
/* 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];
|
||
AC[addr] = 10;
|
||
addr = next_addr[addr];
|
||
AC[addr] = 10;
|
||
addr = next_addr[addr];
|
||
AC[addr] = 10;
|
||
addr = next_addr[addr];
|
||
AC[addr] = 10;
|
||
addr = next_addr[addr];
|
||
store_addr(MAC2, &addr);
|
||
AC[addr] = 10;
|
||
addr = next_addr[addr];
|
||
AC[addr] = 10;
|
||
addr = next_addr[addr];
|
||
AC[addr] = 10;
|
||
addr = next_addr[addr];
|
||
AC[addr] = 10;
|
||
addr = next_addr[addr];
|
||
store_hex(selreg, &addr);
|
||
AC[addr] = 0;
|
||
addr = next_addr[addr];
|
||
AC[addr] = 0;
|
||
addr = next_addr[addr];
|
||
AC[addr] = 0;
|
||
addr = next_addr[addr];
|
||
AC[addr] = 0;
|
||
}
|
||
}
|
||
|
||
/* Load CPU State from storage */
|
||
void load_cpu(uint32 addr, int full) {
|
||
uint8 t;
|
||
uint8 f;
|
||
|
||
flags = 0;
|
||
IC = load_addr(&addr);
|
||
t = AC[addr];
|
||
addr = next_addr[addr];
|
||
f = t;
|
||
flags |= (t & 0x7) | ((t >> 1) & 0x8);
|
||
t = AC[addr];
|
||
addr = next_addr[addr];
|
||
f |= t;
|
||
flags |= ((t & 0x7) | ((t >> 1) & 0x8)) << 4;
|
||
t = AC[addr];
|
||
addr = next_addr[addr];
|
||
f |= t;
|
||
flags |= ((t & 0x7) | ((t >> 1) & 0x8)) << 8;
|
||
t = AC[addr];
|
||
addr = next_addr[addr];
|
||
f |= t;
|
||
flags |= (t & 0x3) << 12;
|
||
/* Update emulation mode */
|
||
if (CPU_MODEL == CPU_7080) {
|
||
if (flags & EIGHTMODE) {
|
||
EMEMSIZE = MEMSIZE;
|
||
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) {
|
||
int i;
|
||
t = AC[addr];
|
||
addr = next_addr[addr];
|
||
f |= t;
|
||
spc = bcd_bin[t & 0xf] & 07; /* Units digit */
|
||
/* One of words */
|
||
t = AC[addr];
|
||
addr = next_addr[addr];
|
||
f |= t;
|
||
spc += (bcd_bin[t & 0xf] & 3) << 3; /* Tens digit */
|
||
/* One of four word sets */
|
||
t = AC[addr];
|
||
addr = next_addr[addr];
|
||
f |= t;
|
||
spc += (bcd_bin[t & 0xf] & 7) << 5; /* Hundreds */
|
||
/* Bank */
|
||
t = AC[addr];
|
||
addr = next_addr[addr];
|
||
f |= t;
|
||
spc += (bcd_bin[t & 0xf] & 7) << 8; /* Thousands */
|
||
for (i = 0; i < 4; i++) {
|
||
f |= AC[addr];
|
||
addr = next_addr[addr];
|
||
}
|
||
MAC2 = load_addr(&addr);
|
||
for (i = 0; i < 4; i++) {
|
||
f |= AC[addr];
|
||
addr = next_addr[addr];
|
||
}
|
||
selreg = load_hex(&addr);
|
||
for (i = 0; i < 4; i++) {
|
||
f |= AC[addr];
|
||
addr = next_addr[addr];
|
||
}
|
||
}
|
||
if (f & 0100) {
|
||
flags |= MCHCHK | ANYFLAG;
|
||
}
|
||
}
|
||
|
||
/* 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;
|
||
int over;
|
||
|
||
/* 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;
|
||
over = 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;
|
||
msign = 0;
|
||
over = 1;
|
||
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;
|
||
msign = 0;
|
||
over = 1;
|
||
goto step2;
|
||
}
|
||
dzt = 0;
|
||
}
|
||
smt = 0;
|
||
while(!smt) {
|
||
cr1 = ReadP(MA, MCHCHK);
|
||
Next(MA);
|
||
sim_interval --; /* count down */
|
||
cr2 = AC[tsac];
|
||
if (cr2 == 0)
|
||
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;
|
||
if (over == 0) {
|
||
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;
|
||
static int initialized;
|
||
REG *reg;
|
||
|
||
if (initialized == 0) {
|
||
initialized = 1;
|
||
mem_init();
|
||
}
|
||
|
||
/* 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;
|
||
}
|
||
reg = find_reg("A", NULL, dptr);
|
||
reg->depth = 512;
|
||
reg->offset = 0;
|
||
reg = find_reg("B", NULL, dptr);
|
||
reg->offset = 0;
|
||
reg->depth = 512;
|
||
reg->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;
|
||
}
|
||
reg = find_reg("A", NULL, dptr);
|
||
reg->depth = 256; /* A register */
|
||
reg->offset = 0;
|
||
reg = find_reg("B", NULL, dptr);
|
||
reg->depth = 256; /* B register */
|
||
reg->offset = 0;
|
||
reg->loc = &AC[256];
|
||
/* Set up ASU locations */
|
||
reg = find_reg("ASU1", NULL, dptr);
|
||
for(i = 0; i < 15; i++)
|
||
(reg + i)->loc = &AC[256 + 16*i];
|
||
}
|
||
|
||
/* 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');
|
||
/* Leave 80 mode */
|
||
if (CPU_MODEL == CPU_7080) {
|
||
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;
|
||
}
|
||
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);
|
||
if (h->store[len] & 0100) {
|
||
fputc('|', 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;
|
||
}
|
||
|