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