/* i7010_cpu.c: IBM 7010 CPU simulator | |
Copyright (c) 2006, 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 7010 central processor | |
The IBM 1410 and 7010 were designed as enhancements to the IBM 1401, | |
these were somewhat source compatable, but not binary compatable. | |
The 1410 was introduced on September, 12 1960 and the 7010 in 1962. | |
The 1410 was withdrawn on March 30, 1970. The 7010 featured | |
4 I/O channels where the 1410 had 2. Also the 7010 could access 100,000 | |
characters of memory as opposed to the 80,000 for the 1410. The 7010 also | |
featured optional decimal floating point instructions. Memory was | |
divided into feilds seperated by a special flag called a word mark. | |
Instructions end at the first character with the word mark set. They | |
consist of a operation code, followed by 1 or 2 5-digit addresses, and | |
an optional instruction modifier. If the 10's and 100's digit have zone | |
bits set the address is modified by the contents of the five characters | |
at locations 25-100. Each register is 5 characters long and word marks | |
are ignored. The 1410 and 7010 could also be optionaly equiped with | |
priority mode to allow for device complete interupts. | |
The 7010 or 1410 cpu has no registers. All operations on done from | |
memory. | |
i7010_defs.h add device definitions | |
i7010_sys.c add sim_devices table entry | |
*/ | |
#include "i7010_defs.h" | |
#include "sim_card.h" | |
#include <time.h> | |
#define UNIT_V_MSIZE (UNIT_V_UF + 0) | |
#define UNIT_MSIZE (017 << UNIT_V_MSIZE) | |
#define UNIT_V_CPUMODEL (UNIT_V_UF + 5) | |
#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 OPTION_PRIO (1 << (UNIT_V_UF + 13)) | |
#define OPTION_FLOAT (1 << (UNIT_V_UF + 14)) | |
#define OPTION_PROT (1 << (UNIT_V_UF_31)) | |
#define TMR_RTC 100 | |
#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 0x100000 | |
#define HIST_MSK 0x0FFFFF | |
#define HIST_1401 0x200000 /* 1401 instruction */ | |
struct InstHistory | |
{ | |
uint32 ic; | |
uint8 inst[15]; | |
uint32 astart; | |
uint32 bstart; | |
uint32 aend; | |
uint32 bend; | |
uint8 dlen; | |
uint8 bdata[50]; | |
}; | |
t_stat cpu_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, | |
const char *cptr); | |
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); | |
int do_addint(int val); | |
t_stat do_addsub(int mode); | |
t_stat do_mult(); | |
t_stat do_divide(); | |
/* Interval timer option */ | |
t_stat rtc_srv(UNIT * uptr); | |
t_stat rtc_reset(DEVICE * dptr); | |
int32 rtc_tps = 200; | |
/* General registers */ | |
uint8 M[MAXMEMSIZE] = { 0 }; /* memory */ | |
int32 IAR; /* program counter */ | |
int32 AAR; /* A Address Register */ | |
int32 BAR; /* B Address Register */ | |
int32 CAR; /* C Address Register */ | |
int32 DAR; /* D Address Register */ | |
uint8 SW; /* Switch register */ | |
uint32 XR; /* IO Address register */ | |
uint8 cind; /* Compare indicators */ | |
uint8 zind; /* Zero balence */ | |
uint8 oind; /* Overflow indicator */ | |
uint8 dind; /* Divide Over indicator */ | |
uint8 tind; /* Tape indicator */ | |
uint8 op_mod; /* Opcode modifier */ | |
uint8 euind; /* Exp underflow indicator */ | |
uint8 eoind; /* Exp overflow indicator */ | |
uint8 fault; /* Access fault */ | |
uint8 pri_enb = 1; /* Priority mode flags */ | |
uint8 inquiry = 0; /* Inquiry IRQ pending */ | |
uint8 urec_irq[NUM_CHAN]; /* Unit record IRQ pending */ | |
uint8 astmode = 1; /* Astrisk mode */ | |
uint8 chan_io_status[NUM_CHAN]; /* Channel status */ | |
uint8 chan_seek_done[NUM_CHAN]; /* Channel seek finished */ | |
uint8 chan_irq_enb[NUM_CHAN]; /* IRQ type opcode */ | |
uint8 lpr_chan9[NUM_CHAN]; /* Line printer at channel 9 */ | |
uint8 lpr_chan12[NUM_CHAN]; /* Line printer at channel 12 */ | |
extern uint32 caddr[NUM_CHAN]; /* Channel addresses */ | |
int low_addr = -1; /* Low protection address */ | |
int high_addr = -1; /* High protection address */ | |
int reloc = 0; /* Dislocate address flag */ | |
uint8 prot_fault = 0; /* Protection fault indicators. */ | |
uint8 prot_enb = 0; /* Protection enables */ | |
uint8 relo_flags = 0; /* Relocation flags */ | |
uint8 timer_irq = 0; /* Interval timer interrupt */ | |
uint8 timer_enable = 0; /* Interval timer enable */ | |
int timer_interval = 0; /* Interval timer interval */ | |
int chwait = 0; /* Wait for channel to finish */ | |
int io_flags = 0; /* Io flags for 1401 */ | |
int cycle_time = 28; /* Cycle time in 100ns */ | |
uint8 time_digs[] = {0, 2, 3, 5, 7, 8}; | |
/* History information */ | |
int32 hst_p = 0; /* History pointer */ | |
int32 hst_lnt = 0; /* History length */ | |
struct InstHistory *hst = NULL; /* History stack */ | |
extern UNIT chan_unit[]; | |
/* Simulator debug controls */ | |
DEBTAB cpu_debug[] = { | |
{"CHANNEL", DEBUG_CHAN}, | |
{"TRAP", DEBUG_TRAP}, | |
{"CMD", DEBUG_CMD}, | |
{"DETAIL", DEBUG_DETAIL}, | |
{"EXP", DEBUG_EXP}, | |
{"PRI", DEBUG_PRIO}, | |
{0, 0} | |
}; | |
/* 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(rtc_srv, MODEL(2)|MEMAMOUNT(9)|OPTION_PRIO|OPTION_FLOAT, | |
MAXMEMSIZE), 10000 }; | |
REG cpu_reg[] = { | |
{DRDATAD(IAR, IAR, 18, "Instruction Address Register"), REG_FIT}, | |
{DRDATAD(A, AAR, 18, "A Address register"), REG_FIT}, | |
{DRDATAD(B, BAR, 18, "B Address register"), REG_FIT}, | |
{DRDATAD(C, CAR, 18, "C Address register"), REG_FIT}, | |
{DRDATAD(D, DAR, 18, "D Address register"), REG_FIT}, | |
{DRDATAD(E, caddr[0], 18, "Channel 0 address"), REG_FIT}, | |
{DRDATAD(F, caddr[1], 18, "Channel 1 address"), REG_FIT}, | |
{DRDATAD(G, caddr[2], 18, "Channel 2 address"), REG_FIT}, | |
{DRDATAD(H, caddr[3], 18, "Channel 3 address"), REG_FIT}, | |
{FLDATAD(ASTRISK, astmode, 1, "Asterix Mode"), REG_FIT}, | |
{BRDATAD(SW, &SW, 2, 7, 1, "Sense Switch register"), REG_FIT}, | |
{FLDATAD(SW1, SW, 0, "Sense Switch 0"), REG_FIT}, | |
{FLDATAD(SW2, SW, 1, "Sense Switch 1"), REG_FIT}, | |
{FLDATAD(SW3, SW, 2, "Sense Switch 2"), REG_FIT}, | |
{FLDATAD(SW4, SW, 3, "Sense Switch 3"), REG_FIT}, | |
{FLDATAD(SW5, SW, 4, "Sense Switch 4"), REG_FIT}, | |
{FLDATAD(SW6, SW, 5, "Sense Switch 5"), REG_FIT}, | |
{FLDATAD(SW7, SW, 6, "Sense Switch 6"), REG_FIT}, | |
{NULL} | |
}; | |
MTAB cpu_mod[] = { | |
{UNIT_MODEL, MODEL(1), "1401", "1401", NULL, NULL, NULL, "Emulate a 1401"}, | |
{UNIT_MODEL, MODEL(2), "7010", "7010", NULL, NULL, NULL, "Emulate a 7010"}, | |
{UNIT_MSIZE, MEMAMOUNT(0), "10K", "10K", &cpu_set_size}, | |
{UNIT_MSIZE, MEMAMOUNT(1), "20K", "20K", &cpu_set_size}, | |
{UNIT_MSIZE, MEMAMOUNT(2), "30K", "30K", &cpu_set_size}, | |
{UNIT_MSIZE, MEMAMOUNT(3), "40K", "40K", &cpu_set_size}, | |
{UNIT_MSIZE, MEMAMOUNT(4), "50K", "50K", &cpu_set_size}, | |
{UNIT_MSIZE, MEMAMOUNT(5), "60K", "60K", &cpu_set_size}, | |
{UNIT_MSIZE, MEMAMOUNT(6), "70K", "70K", &cpu_set_size}, | |
{UNIT_MSIZE, MEMAMOUNT(7), "80K", "80K", &cpu_set_size}, | |
{UNIT_MSIZE, MEMAMOUNT(8), "90K", "90K", &cpu_set_size}, | |
{UNIT_MSIZE, MEMAMOUNT(9), "100K", "100K", &cpu_set_size}, | |
{OPTION_PRIO, 0, NULL, "NOPRIORITY", NULL, NULL, NULL, | |
"No Priority Mode"}, | |
{OPTION_PRIO, OPTION_PRIO, "PRIORITY", "PRIORITY", NULL, NULL, NULL, | |
"Priority Mode"}, | |
{OPTION_FLOAT, 0, NULL, "NOFLOAT", NULL, NULL,NULL, | |
"No Floating Point"}, | |
{OPTION_FLOAT, OPTION_FLOAT, "FLOAT", "FLOAT", NULL, NULL, NULL, | |
"Floating point"}, | |
{OPTION_PROT, 0, NULL, "NOPROT", NULL, NULL,NULL, | |
"No memory protection"}, | |
{OPTION_PROT, OPTION_PROT, "PROT", "PROT", NULL, NULL, NULL, | |
"Memory Protection"}, | |
{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, cpu_debug, | |
NULL, NULL, &cpu_help, NULL, NULL, &cpu_description | |
}; | |
/*0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F */ | |
uint8 bcd_bin[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 3, 4, 5, 6, 7}; | |
uint8 bin_bcd[20] = { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, | |
10, 1, 2, 3, 4, 5, 6, 7, 8, 9}; | |
uint32 dscale[4][16] = { | |
{0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 0,30,0,0,0,0}, | |
{0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 0,0,0,0,0,0}, | |
{0, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 0,0,0,0,0,0}, | |
{0, 10000, 20000, 30000, 40000, 50000, 60000, 70000, 80000, 90000, | |
0,0,0,0,0,0} | |
}; | |
#define NORELA 0x2 | |
#define NORELB 0x4 | |
uint8 digit_addone[16] = { | |
0,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x10,0x01,0x0b,0x0c,0x0d,0x0e, | |
0x0f}; | |
uint8 cmp_order[0100] = { | |
/* b 1 2 3 4 5 6 7 */ | |
0, 55, 56, 57, 58, 59, 60, 61, | |
/* 8 9 0 # @ : > tm */ | |
62, 63, 54, 20, 21, 22, 23, 24, | |
/*cent / S T U V W X */ | |
19, 13, 46, 47, 48, 49, 50, 51, | |
/* Y Z rm , % = ' " */ | |
52, 53, 45, 14, 15, 16, 17, 18, | |
/* - J K L M N O P */ | |
12, 36, 37, 38, 39, 40, 41, 42, | |
/* Q R ! $ * ) ; del */ | |
43, 44, 35, 7, 8, 9, 10, 11, | |
/* & A B C D E F G */ | |
6, 26, 27, 28, 29, 30, 31, 32, | |
/* H I ? . sq ( < gm */ | |
33, 34, 25, 1, 2, 3, 4, 5 | |
}; | |
#define O_A 001 /* Can take A */ | |
#define O_B 002 /* Can take B */ | |
#define O_AB (O_A|O_B) /* Can take both A & B */ | |
#define O_M 004 /* Can take modifier */ | |
#define O_X 010 /* Special Operand */ | |
#define O_C 020 /* Load C register on frist argument */ | |
#define O_D 0100 /* Load D register on second argument */ | |
#define O_DBL 0200 /* When chained A same as B */ | |
#define O_ABCD (O_A|O_B|O_C|O_D) | |
uint8 op_args[64] = { | |
/* 00 01 02 03 04 05 06 07 */ | |
/* CC2 SSF2 */ | |
0, 0, O_M, 0, O_M, 0, 0, 0, /* 00 */ | |
/* FP M */ | |
0, 0, 0, O_A|O_M, O_AB, 0, 0, 0, /* 10 */ | |
/* CS S T UC BWE BBE IO2 */ | |
0,O_AB|O_DBL,O_AB|O_DBL,O_AB|O_M,O_X|O_M,O_AB|O_M,O_AB|O_M,O_A|O_M|O_DBL,/* 20 */ | |
/* PRI MSZ SWM D */ | |
O_A|O_M,O_AB,0,O_AB|O_DBL, O_AB, 0, 0, 0, /* 30 */ | |
/* B SSF1 RDW RD NOP */ | |
0,O_A|O_M|O_DBL,O_M,O_X|O_B|O_M,O_X|O_B|O_M, 0, 0, 0,/* 40 */ | |
/* IO1 ZS STS */ | |
0, O_A|O_M|O_DBL,O_AB|O_DBL,O_A|O_M, 0, 0, 0, 0, /* 50 */ | |
/* A BCE C MOV E CC1 SAR */ | |
0, O_AB|O_DBL,O_AB|O_M,O_AB,O_AB|O_M,O_AB, O_M,O_C|O_M,/* 60 */ | |
/* 0 ZA H CWM */ | |
0, 0, O_AB|O_DBL,O_A,O_AB|O_DBL, 0, 0, 0, /* 70 */ | |
}; | |
uint8 op_1401[64] = { | |
/* 00 01 02 03 04 05 06 07 */ | |
/* b 1 2 3 4 5 6 7 */ | |
/* RCD PRT PUN */ | |
0, O_A, O_A|O_M, O_A, O_A, O_A, O_A|O_M, O_A|O_M, /* 00 */ | |
/* 8 9 0 # @ : > tm */ | |
/* M */ | |
0, 0, 0, O_AB|O_DBL, O_AB, 0, 0, 0, /* 10 */ | |
/*cent / S T U V W X */ | |
/* CS S BWZ BBE */ | |
0,O_AB|O_DBL,O_AB|O_DBL,0,O_X|O_M,O_AB|O_M,O_AB|O_M,0,/* 20 */ | |
/* Y Z rm , % = ' " */ | |
/* MZ MCS SWM MA */ | |
O_AB, O_AB,0,O_AB|O_DBL, O_AB, O_AB, 0, 0, /* 30 */ | |
/* - J K L M N O P */ | |
/* RDW MLCWA MLC NOP MRCM */ | |
0, 0,O_M|O_A,O_AB, O_AB,O_AB,0, O_AB,/* 40 */ | |
/* Q R ! $ * ) ; del */ | |
/* SAR ZS */ | |
O_C, 0, O_AB|O_DBL,0, 0, 0, 0, 0, /* 50 */ | |
/* & A B C D E F G */ | |
/* A B C MLNS */ | |
0, O_AB|O_DBL,O_AB|O_M,O_AB,O_AB,O_AB, O_M|O_A,0,/* 60 */ | |
/* H I ? . sq ( < gm */ | |
/* SBR ZA H CWM */ | |
O_C|O_B,0, O_AB|O_DBL,O_A,O_AB|O_DBL, 0, 0, 0, /* 70 */ | |
}; | |
uint8 FetchP(uint32 MA) { | |
uint32 MAR = MA & AMASK; | |
if (reloc && (MA & BBIT) == 0 && MAR > 100) { | |
if (low_addr > 0) { | |
MAR += low_addr; | |
if (MAR >= 100000) | |
MAR -= 100000; | |
} | |
if (prot_enb && (high_addr > 0) && (MAR > (uint32)high_addr)) { | |
fault = STOP_PROT; | |
return 0; | |
} | |
} else if (prot_enb && (MA & BBIT) == 0 && MAR > 100) { | |
if (low_addr < 0 && high_addr == 0) { | |
fault = STOP_PROT; | |
return 0; | |
} | |
} | |
if (MAR >= MEMSIZE) { | |
fault = STOP_INVADDR; | |
return 0; | |
} | |
return M[MAR]; | |
} | |
uint8 ReadP(uint32 MA) { | |
uint32 MAR = MA & AMASK; | |
if (fault) | |
return 0; | |
if (reloc && (MA & BBIT) == 0 && MAR > 100) { | |
if (low_addr > 0) { | |
MAR += low_addr; | |
if (MAR >= 100000) | |
MAR -= 100000; | |
} | |
if (prot_enb && (high_addr > 0) && (MAR > (uint32)high_addr)) { | |
fault = STOP_PROT; | |
return 0; | |
} | |
} else if (prot_enb && (MA & BBIT) == 0 && MAR > 100) { | |
if (low_addr < 0 && high_addr == 0) { | |
fault = STOP_PROT; | |
return 0; | |
} | |
if (((low_addr >= 0) && (MAR < (uint32)low_addr)) || | |
((high_addr > 0) && (MAR > (uint32)high_addr))) { | |
fault = STOP_PROT; | |
return 0; | |
} | |
} | |
if (MAR >= MEMSIZE) { | |
fault = STOP_INVADDR; | |
return 0; | |
} | |
return M[MAR]; | |
} | |
void WriteP(uint32 MA, uint8 v) { | |
uint32 MAR = MA & AMASK; | |
if (fault) | |
return; | |
if (reloc && (MA & BBIT) == 0 && MAR > 100) { | |
if (low_addr > 0) { | |
MAR += low_addr; | |
if (MAR >= 100000) | |
MAR -= 100000; | |
} | |
if (prot_enb && (high_addr > 0) && (MAR > (uint32)high_addr)) { | |
fault = STOP_PROT; | |
return; | |
} | |
} else if (prot_enb && (MA & BBIT) == 0 && MAR > 100) { | |
if (low_addr < 0 && high_addr == 0) { | |
fault = STOP_PROT; | |
return; | |
} | |
if (((low_addr >= 0) && (MAR < (uint32)low_addr)) || | |
((high_addr > 0) && (MAR > (uint32)high_addr))) { | |
fault = STOP_PROT; | |
return; | |
} | |
} | |
if (MAR >= MEMSIZE) { | |
fault = STOP_INVADDR; | |
return; | |
} | |
M[MAR] = v; | |
} | |
void ReplaceMask(uint32 MA, uint8 v, uint8 mask) { | |
uint32 MAR = MA & AMASK; | |
if (fault) | |
return; | |
if (reloc && (MA & BBIT) == 0 && MAR > 100) { | |
if (low_addr > 0) { | |
MAR += low_addr; | |
if (MAR >= 100000) | |
MAR -= 100000; | |
} | |
if (prot_enb && (high_addr > 0) && (MAR > (uint32)high_addr)) { | |
fault = STOP_PROT; | |
return; | |
} | |
} else if (prot_enb && (MA & BBIT) == 0 && MAR > 100) { | |
if (low_addr < 0 && high_addr == 0) { | |
fault = STOP_PROT; | |
return; | |
} | |
if (((low_addr >= 0) && (MAR < (uint32)low_addr)) || | |
((high_addr > 0) && (MAR > (uint32)high_addr))) { | |
fault = STOP_PROT; | |
return; | |
} | |
} | |
if (MAR >= MEMSIZE) { | |
fault = STOP_INVADDR; | |
return; | |
} | |
M[MAR] &= ~mask; | |
M[MAR] |= v; | |
} | |
void SetBit(uint32 MA, uint8 v) { | |
uint32 MAR = MA & AMASK; | |
if (fault) | |
return; | |
if (reloc && (MA & BBIT) == 0 && MAR > 100) { | |
if (low_addr > 0) { | |
MAR += low_addr; | |
if (MAR >= 100000) | |
MAR -= 100000; | |
} | |
if (prot_enb && (high_addr > 0) && (MAR > (uint32)high_addr)) { | |
fault = STOP_PROT; | |
return; | |
} | |
} else if (prot_enb && (MA & BBIT) == 0 && MAR > 100) { | |
if (low_addr < 0 && high_addr == 0) { | |
fault = STOP_PROT; | |
return; | |
} | |
if (((low_addr >= 0) && (MAR < (uint32)low_addr)) || | |
((high_addr > 0) && (MAR > (uint32)high_addr))) { | |
fault = STOP_PROT; | |
return; | |
} | |
} | |
if (MAR >= MEMSIZE) { | |
fault = STOP_INVADDR; | |
return; | |
} | |
M[MAR] |= v; | |
} | |
void ClrBit(uint32 MA, uint8 v) { | |
uint32 MAR = MA & AMASK; | |
if (fault) | |
return; | |
if (reloc && (MA & BBIT) == 0 && MAR > 100) { | |
if (low_addr > 0) { | |
MAR += low_addr; | |
if (MAR >= 100000) | |
MAR -= 100000; | |
} | |
if (prot_enb && (high_addr > 0) && (MAR > (uint32)high_addr)) { | |
fault = STOP_PROT; | |
return; | |
} | |
} else if (prot_enb && (MA & BBIT) == 0 && MAR > 100) { | |
if (low_addr < 0 && high_addr == 0) { | |
fault = STOP_PROT; | |
return; | |
} | |
if (((low_addr >= 0) && (MAR < (uint32)low_addr)) || | |
((high_addr > 0) && (MAR > (uint32)high_addr))) { | |
fault = STOP_PROT; | |
return; | |
} | |
} | |
if (MAR >= MEMSIZE) { | |
fault = STOP_INVADDR; | |
return; | |
} | |
M[MAR] &= ~v; | |
} | |
#define UpReg(reg) reg++; if ((reg & AMASK) == MEMSIZE) { \ | |
reason = STOP_INVADDR; break; } | |
#define DownReg(reg) if ((reg & AMASK) == 0) { \ | |
reason = STOP_INVADDR; break; } else { reg--; } | |
#define ValidAddr(reg) if ((reg & AMASK)== 0 || !MEM_ADDR_OK(reg)) { \ | |
reason = STOP_INVADDR; break; \ | |
} | |
#define ZeroAddr(reg) if ((reg & AMASK)== 0) { \ | |
reason = STOP_INVADDR; break; \ | |
} | |
t_stat | |
sim_instr(void) | |
{ | |
t_stat reason; | |
uint16 t; | |
int temp; | |
int32 STAR; | |
uint8 op, op_info; | |
int state; | |
uint8 ix; | |
uint8 br; | |
uint8 ar; | |
int sign, qsign; | |
uint8 ch; | |
int cy; | |
int i; | |
int jump; /* Do transfer to AAR after op */ | |
int instr_count = 0;/* Number of instructions to execute */ | |
if (sim_step != 0) { | |
instr_count = sim_step; | |
sim_cancel_step(); | |
} | |
reason = 0; | |
fault = 0; | |
if (cpu_unit.flags & OPTION_PROT) | |
sim_activate(&cpu_unit, sim_rtcn_calb(cpu_unit.wait, TMR_RTC)); | |
while (reason == 0) { /* loop until halted */ | |
chan_proc(); | |
if (chwait != 0) { | |
if (chan_active(chwait & 07)) { | |
sim_interval = 0; | |
} else { | |
if ((chwait & 040) == 0) { | |
BAR = caddr[chwait & 07]; | |
if (hst_lnt) /* History enabled? */ | |
hst[hst_p].bend = BAR; | |
} | |
chan_io_status[chwait & 07] &= ~0100; | |
chwait = 0; | |
} | |
} | |
if (sim_interval <= 0) { /* event queue? */ | |
reason = sim_process_event(); | |
if (reason != SCPE_OK) { | |
break; /* process */ | |
} | |
} | |
if (chwait == 0 && sim_brk_summ && sim_brk_test(IAR, SWMASK('E'))) { | |
reason = STOP_IBKPT; | |
break; | |
} | |
if (chwait == 0) { | |
uint8 bbit = 0; | |
if (hst_lnt) { /* History enabled? */ | |
hst_p = (hst_p+1); /* Next entry */ | |
if (hst_p >= hst_lnt) | |
hst_p = 0; | |
hst[hst_p].ic = IAR | HIST_PC; | |
if (CPU_MODEL == 1) | |
hst[hst_p].ic |= HIST_1401; | |
} | |
op = FetchP(IAR++); | |
/* Check if over the top */ | |
if (fault) | |
goto check_prot; | |
if (hst_lnt) /* History enabled? */ | |
hst[hst_p].inst[0] = op; | |
sim_interval -= 2; | |
if ((op & WM) == 0) { | |
reason = STOP_NOWM; | |
goto check_prot; | |
} | |
op &= 077; | |
op_info = (CPU_MODEL != 1)? op_args[op]: op_1401[op]; | |
state = 1; | |
i = 1; | |
temp = IAR + 5; /* Save for intertupt routine */ | |
while(((br = FetchP(IAR)) & WM) == 0 && op_info != 0 && fault == 0) { | |
IAR++; | |
sim_interval -= 2; | |
if (hst_lnt) /* History enabled? */ | |
hst[hst_p].inst[i++] = br; | |
br &= 077; | |
if (CPU_MODEL != 1) { | |
switch(state) { | |
case 1: /* could be operand or address */ | |
ar = br; | |
state = 2; | |
if (ar & 040) | |
bbit = 1; | |
else | |
bbit = 0; | |
break; | |
case 2: /* Has to be address, check if goes to C or AB */ | |
state = 3; | |
if (op_info & O_X) { | |
XR = (ar << 12) | (br << 6); | |
} else if (op_info & (O_C|O_A)) { | |
STAR = dscale[3][bcd_bin[ar & 0xf]]; | |
STAR += dscale[2][bcd_bin[br & 0xf]]; | |
if ((ar & 020) || (br & 060)) | |
reason = STOP_INVADDR; | |
} | |
break; | |
case 3: /* Has to be address, check if goes to C or AB */ | |
state = 4; | |
if (op_info & O_X) { | |
XR |= br; | |
state = 6; | |
} else if (op_info & (O_C|O_A)) { /* hundreds */ | |
ix = (br & 0x30) >> 2; | |
STAR += dscale[1][bcd_bin[br & 0xf]]; | |
} | |
break; | |
case 4: /* Has to be address, check if goes to C or AB */ | |
state = 5; | |
if (op_info & (O_C|O_A)) { /* tens */ | |
ix |= (br & 0x30) >> 4; | |
STAR += dscale[0][bcd_bin[br & 0xf]]; | |
} | |
break; | |
case 5: /* Has to be address, check if goes to C or AB */ | |
state = 6; | |
if (op_info & (O_C|O_A) && br & 060) { | |
reason = STOP_INVADDR; | |
break; | |
} | |
if (op_info & (O_C|O_A)) /* units */ | |
STAR += bcd_bin[br & 0xf]; | |
if ((op_info & O_A) && (ix != 0)) { | |
int j, a, s; | |
/* do indexing */ | |
ix = (ix * 5) + 24; | |
s = ((ReadP(ix) & 060) == 040)?1: 0; | |
a = bcd_bin[ReadP(ix--) & 0xf]; | |
for(j = 0; j < 4; j++) | |
a += dscale[j][bcd_bin[ReadP(ix--) & 0xf]]; | |
STAR += (s)?(99999 - a):a; | |
STAR += s; | |
STAR %= 100000; | |
sim_interval -= 10; | |
} | |
if (bbit) | |
STAR |= BBIT; | |
bbit = 0; | |
if (op_info & O_C) | |
CAR = STAR; | |
if (op_info & O_A) { | |
AAR = STAR; | |
if (op_info & O_DBL) { | |
if (op_info & O_D) | |
DAR = AAR; | |
BAR = AAR; | |
} | |
} | |
temp = IAR; /* Save for intertupt routine */ | |
break; | |
case 6: /* Could be either B address or operand. */ | |
state = 7; | |
ar = br; | |
if (ar & 040) | |
bbit = 1; | |
else | |
bbit = 0; | |
break; | |
case 7: /* Has to be B address */ | |
state = 8; | |
/* ten thousand, thousand */ | |
if (op_info & (O_B|O_D)) { | |
STAR = dscale[3][bcd_bin[ar & 0xf]]; | |
STAR += dscale[2][bcd_bin[br & 0xf]]; | |
if ((ar & 020) || (br & 060)) | |
reason = STOP_INVADDR; | |
} | |
if ((op_info & O_M) == 0) | |
op_mod = 0; | |
break; | |
case 8: /* Has to be B address */ | |
state = 9; | |
/* hundreds */ | |
if (op_info & (O_B|O_D)) { | |
STAR += dscale[1][bcd_bin[br & 0xf]]; | |
ix = (br & 0x30) >> 2; | |
} | |
break; | |
case 9: /* Has to be B address */ | |
state = 10; | |
/* tens */ | |
if (op_info & (O_B|O_D)) { | |
STAR += dscale[0][bcd_bin[br & 0xf]]; | |
ix |= (br & 0x30) >> 4; | |
} | |
break; | |
case 10: /* Units digit of B address */ | |
state = 11; | |
if (op_info & (O_B|O_D)) { | |
if (br & 060) { | |
reason = STOP_INVADDR; | |
break; | |
} | |
STAR += bcd_bin[br & 0xf]; | |
} | |
if (op_info & O_B && ix != 0) { | |
int j, a, s; | |
/* do indexing */ | |
ix = (ix * 5) + 24; | |
s = ((ReadP(ix) & 060) == 040)?1: 0; | |
a = bcd_bin[ReadP(ix--) & 0xf]; | |
for(j = 0; j < 4; j++) | |
a += dscale[j][bcd_bin[ReadP(ix--) & 0xf]]; | |
STAR += (s)?(99999 - a):a; | |
STAR += s; | |
STAR %= 100000; | |
sim_interval -= 10; | |
} | |
if (bbit) | |
STAR |= BBIT; | |
bbit = 0; | |
if (op_info & O_D) | |
DAR = STAR; | |
if (op_info & O_B) | |
BAR = STAR; | |
break; | |
case 11: /* Has to be modifier */ | |
state = 12; | |
ar = br; | |
break; | |
case 12: /* Too long */ | |
reason = STOP_NOWM; | |
state = 13; | |
break; | |
} | |
} else { /* Handle 1401 emulation mode */ | |
switch(state) { | |
case 1: /* could be operand or address */ | |
/* BA */ | |
/* 00 0-999 */ | |
/* 01 1000-1999 */ | |
/* 10 2000-2999 */ | |
/* 11 3000-3999 */ | |
ar = br; | |
if (op_info & O_X || | |
((op == CHR_M || op == CHR_L) && br == CHR_RPARN)) { | |
XR = br << 12; | |
op_info |= O_X; | |
} | |
state = 2; | |
break; | |
case 2:/* Has to be address, check if goes to C or AB */ | |
/* BA */ | |
/* 00 - none */ | |
/* 01 - 1 87,88,89, 90,91 */ | |
/* 10 - 2 92,93,94, 95,96 */ | |
/* 11 - 3 97,98,99 */ | |
state = 3; | |
if (op_info & O_X) | |
XR |= br << 6; | |
if (op_info & (O_C|O_A)) { | |
STAR = dscale[1][bcd_bin[ar & 0xf]]; | |
STAR += dscale[0][bcd_bin[br & 0xf]]; | |
STAR += ((ar & 0x30) >> 4) * 1000; | |
ix = (br & 0x30) >> 4; | |
} | |
break; | |
case 3:/* Has to be address, check if goes to C or AB */ | |
/* BA */ | |
/* 00 0-3999 */ | |
/* 01 4000-7999 */ | |
/* 10 8000-11999 */ | |
/* 11 12000-15999 */ | |
state = 4; | |
if (op_info & O_X) | |
XR |= br; | |
if (op_info & (O_C|O_A)) { /* hundreds */ | |
STAR += bcd_bin[br & 0xf]; | |
STAR += ((br & 0x30) >> 4) * 4000; | |
if (ix != 0) { | |
int a; | |
/* do indexing */ | |
ix = (ix * 5) + 82; | |
a = dscale[1][bcd_bin[M[ix] & 0xf]]; | |
a += dscale[0][bcd_bin[M[ix+1] & 0xf]]; | |
a += bcd_bin[M[ix+2] & 0xf]; | |
a += dscale[2][((M[ix] & 060) >> 4)]; | |
a += ((M[ix+2] & 060) >> 4) * 4000; | |
STAR += a; | |
STAR %= 16000; | |
sim_interval -= 3; | |
} | |
} | |
if (op_info & O_C) | |
CAR = STAR; | |
if (op_info & O_A) { | |
AAR = STAR; | |
if (op_info & O_DBL) { | |
if (op_info & O_D) | |
DAR = AAR; | |
BAR = AAR; | |
} | |
} | |
break; | |
case 4: /* Could be either B address or operand. */ | |
state = 5; | |
ar = br; | |
break; | |
case 5: /* Has to be B address */ | |
state = 6; | |
/* ten thousand, thousand */ | |
if (op_info & (O_B|O_D)) { | |
STAR = dscale[1][bcd_bin[ar & 0xf]]; | |
STAR += dscale[0][bcd_bin[br & 0xf]]; | |
STAR += ((ar & 0x30) >> 4) * 1000; | |
ix = (br & 0x30) >> 4; | |
} | |
if ((op_info & O_M) == 0) | |
op_mod = 0; | |
break; | |
case 6: /* Has to be B address */ | |
state = 7; | |
/* hundreds */ | |
if (op_info & (O_B|O_D)) { | |
STAR += bcd_bin[br & 0xf]; | |
STAR += ((br & 0x30) >> 4) * 4000; | |
if (ix != 0) { | |
int a; | |
/* do indexing */ | |
ix = (ix * 5) + 82; | |
a = dscale[1][bcd_bin[M[ix] & 0xf]]; | |
a += dscale[0][bcd_bin[M[ix+1] & 0xf]]; | |
a += bcd_bin[M[ix+2] & 0xf]; | |
a += dscale[2][((M[ix] & 060) >> 4)]; | |
a += ((M[ix+2] & 060) >> 4) * 4000; | |
STAR += a; | |
STAR %= 16000; | |
sim_interval -= 3; | |
} | |
} | |
if (op_info & O_D) | |
DAR = STAR; | |
if (op_info & O_B) | |
BAR = STAR; | |
break; | |
case 7: /* Has to be modifier */ | |
state = 8; | |
ar = br; | |
break; | |
case 8: /* Too long */ | |
if (op != OP_NOP && op != CHR_B) | |
reason = STOP_NOWM; | |
state = 9; | |
break; | |
} | |
/* Some instructions don't have to have word marks */ | |
if (op == OP_SWM && state == 7) | |
break; | |
if (op == CHR_B && state == 5 && ar == CHR_ABLANK) | |
break; | |
if (op == CHR_B && state == 9) | |
break; | |
} | |
if (reason != 0) | |
goto check_prot; | |
} | |
if (hst_lnt) /* History enabled? */ | |
hst[hst_p].inst[i++] = WM; /* Term hist ins */ | |
jump = 0; | |
if (CPU_MODEL == 1) { | |
if (hst_lnt) { /* History enabled? */ | |
hst[hst_p].astart = AAR; | |
hst[hst_p].bstart = BAR; | |
hst[hst_p].inst[state] = WM; | |
} | |
/* Translate instruction from 1401 to 1410 */ | |
switch(op) { | |
case CHR_B: /* Fix branch to correct kind */ | |
switch(state) { | |
case 8: op_mod = ar; /* B ddd iii c */ | |
case 7: /* B ddd iii */ | |
case 1: /* B */ | |
op = OP_BCE; | |
break; | |
case 4: ar = CHR_ABLANK; /* B ddd */ | |
case 2: /* B c ?? */ | |
default: /* B ddd c */ | |
case 5: op = OP_B; op_mod = ar; break; | |
} | |
break; | |
case CHR_U: | |
case CHR_W: | |
case CHR_V: if (state == 8 || state == 2 || state == 5) | |
op_mod = ar; | |
break; | |
case CHR_K: | |
case CHR_F: | |
temp = (op == CHR_K)?010100:010200; | |
if (state == 2 || state == 5) | |
op_mod = ar; | |
temp |= op_mod; | |
while((t = chan_cmd(temp, (IO_CTL<<8), 0)) | |
== SCPE_BUSY); | |
if (t != SCPE_OK) { | |
t = (temp >> 6) & 07; | |
io_flags &= ~t; | |
} | |
if (state == 4 || state == 5) | |
jump = 1; | |
op = OP_NOP; | |
break; | |
/* Translate Move into 1410 move */ | |
case CHR_M: if (op_info & O_X) { | |
chan_io_status[1] = 0; | |
op_mod = ar; | |
} else { | |
op = OP_MOV; | |
op_mod = CHR_C; | |
} | |
break; | |
case CHR_L: if (op_info & O_X) { | |
chan_io_status[1] = 0; | |
op_mod = ar; | |
} else { | |
op = OP_MOV; | |
op_mod = CHR_X; | |
} | |
break; | |
case CHR_D: op = OP_MOV; op_mod = CHR_1; break; | |
case CHR_P: op = OP_MOV; op_mod = CHR_DOT; break; | |
case CHR_Y: op = OP_MOV; op_mod = CHR_2; break; | |
/* Handle 1401 I/O opcodes */ | |
case CHR_1: /* Reader */ | |
case CHR_2: /* Print */ | |
case CHR_3: /* Print and read */ | |
case CHR_4: /* Punch */ | |
case CHR_5: /* Read and Punch */ | |
case CHR_6: /* Print and Punch */ | |
case CHR_7: /* Print,Read and Punch */ | |
op_mod = op; | |
op = OP_NOP; | |
while(op_mod != 0 || chwait != 0) { | |
while (chan_active(1) && reason == 0) { | |
sim_interval = 0; | |
reason = sim_process_event(); | |
chan_proc(); | |
} | |
if (chwait != 0) { | |
BAR = caddr[1]; | |
if (hst_lnt) /* History enabled? */ | |
hst[hst_p].bend = BAR; | |
chwait = 0; | |
} | |
/* Stop if something wrong */ | |
if (reason != 0) | |
break; | |
/* Convert to channel instruction */ | |
if (op_mod & 02) { /* Print line */ | |
temp = 010200; | |
if ((state == 2 || state == 5) | |
&& ar == CHR_LPARN) | |
temp |= 1; | |
else | |
temp |= 012; | |
t = (IO_WRS << 8); | |
BAR = 201; | |
} else if (op_mod & 01) { /* Reader */ | |
temp = 010100; | |
t = (IO_RDS << 8); | |
BAR = 1; | |
} else if (op_mod & 04) { /* Punch */ | |
temp = 010400; | |
t = (IO_WRS << 8); | |
BAR = 101; | |
} else | |
break; | |
/* Try to start command */ | |
switch (chan_cmd(temp, t, BAR)) { | |
case SCPE_OK: | |
t = (temp >> 6) & 07; | |
io_flags &= ~t; | |
op_mod &= ~t; | |
chwait = 01; | |
if (chan_stat(1, CHS_EOF)) | |
io_flags |= (t << 3) | t; | |
break; | |
case SCPE_BUSY: | |
sim_interval = 0; | |
reason = sim_process_event(); | |
chan_proc(); | |
break; | |
case SCPE_NODEV: | |
case SCPE_IOERR: | |
chan_io_status[1] = 01; | |
io_flags |= (temp >> 6) & 07; | |
op_mod = 0; /* Abort */ | |
break; | |
} | |
}; | |
/* Handle branching */ | |
if (state == 4 || state == 5) | |
jump = 1; | |
break; | |
case CHR_8: /* Start read feed */ | |
case CHR_9: /* Start punch feed */ | |
/* Not supportable by sim */ | |
op = OP_NOP; | |
break; | |
case CHR_EQ: /* Handle modify address here */ | |
op = OP_NOP; | |
DAR = BAR; /* Save for later */ | |
ar = ReadP(AAR); | |
br = ReadP(BAR); | |
sim_interval -= 2; | |
ix = (ar & 060) + (br & 060); /* Add zone */ | |
ar = bcd_bin[br & 017] + bcd_bin[ar & 017]; | |
cy = ar > 9; | |
WriteP(BAR, (br & WM) | (ix & 060) | bin_bcd[ar]); | |
DownReg(AAR); | |
DownReg(BAR); | |
ar = ReadP(AAR); | |
br = ReadP(BAR); | |
sim_interval -= 2; | |
ar = bcd_bin[br & 017] + bcd_bin[ar & 017] + cy; | |
cy = ar > 9; | |
WriteP(BAR, (br & (WM | 060)) | bin_bcd[ar]); | |
DownReg(AAR); | |
DownReg(BAR); | |
ar = ReadP(AAR); | |
br = ReadP(BAR); | |
sim_interval -= 2; | |
ix = (ar & 060) + (br & 060); /* Add zone */ | |
ar = bcd_bin[br & 017] + bcd_bin[ar & 017] + cy; | |
if (ar > 9) | |
ix += 020; | |
WriteP(BAR, (br & WM) | (ix & 060) | bin_bcd[ar]); | |
DownReg(AAR); | |
if (ix & 0100) { /* Carry out of low zone */ | |
BAR = DAR; /* Restore */ | |
br = ReadP(BAR); | |
ix = (br & 060) + 020; /* Add zone */ | |
WriteP(BAR, (br & (WM|017)) | (ix & 060)); | |
sim_interval--; | |
} | |
DownReg(BAR); | |
break; | |
case CHR_Q: /* Handle SAR here */ | |
BAR = AAR; /* Copy AAR to BAR */ | |
case CHR_H: /* Handle SBR here */ | |
op = OP_NOP;/* done and at WM, so skip rest */ | |
if (state > 2) | |
AAR = CAR; | |
temp = BAR % 1000; /* Compute base address */ | |
i = (BAR - temp) / 1000; | |
ch = temp % 10; | |
temp /= 10; | |
ch = bin_bcd[ch] | ((i & 014) << 2); | |
ReplaceMask(AAR, ch, 077); | |
sim_interval--; | |
DownReg(AAR); | |
ch = temp % 10; | |
temp /= 10; | |
ch = bin_bcd[ch]; | |
ReplaceMask(AAR, ch, 077); | |
sim_interval--; | |
DownReg(AAR); | |
ch = temp; | |
ch = bin_bcd[ch] | ((i & 03) << 4); | |
ReplaceMask(AAR, ch, 077); | |
sim_interval--; | |
DownReg(AAR); | |
break; | |
default: | |
/* no change needed */ | |
break; | |
} | |
} else { | |
if (fault) | |
goto check_prot; | |
/* Check instruction length */ | |
switch(op) { | |
case OP_S: | |
case OP_A: | |
case OP_ZS: | |
case OP_ZA: | |
case OP_M: | |
case OP_D: | |
case OP_C: | |
case OP_CS: | |
case OP_SWM: | |
case OP_CWM: | |
case OP_MSZ: | |
case OP_E: | |
/* Valid forms */ | |
/* Op */ | |
/* Op AAAAA */ | |
/* Op AAAAA BBBBB */ | |
if (state != 1 && state != 6 && state != 11) | |
reason = STOP_INVLEN; | |
break; | |
case OP_BCE: | |
case OP_BBE: | |
case OP_BWE: | |
case OP_MOV: | |
case OP_T: | |
/* Valid forms */ | |
/* Op */ | |
/* Op mod */ | |
/* Op AAAAA */ | |
/* Op AAAAA mod */ | |
/* Op AAAAA BBBBB */ | |
/* Op AAAAA BBBBB mod */ | |
/* Check for modifier */ | |
if (state == 2 || state == 7 || state == 12) { | |
op_mod = ar; | |
break; | |
} | |
/* Make sure len correct */ | |
if (state != 1 && state != 6 && state != 11) | |
reason = STOP_INVLEN; | |
break; | |
case OP_IO1: | |
case OP_IO2: | |
case OP_IO3: | |
case OP_IO4: | |
/* Not in protected mode */ | |
if (prot_enb || reloc) { | |
reason = STOP_PROG; | |
break; | |
} | |
case OP_STS: | |
/* Not in protected mode */ | |
if (prot_enb) { | |
reason = STOP_PROG; | |
break; | |
} | |
case OP_PRI: | |
case OP_B: | |
case OP_SAR: | |
case OP_FP: | |
/* Valid forms */ | |
/* Op */ | |
/* Op mod */ | |
/* Op AAAAA */ | |
/* Op AAAAA mod */ | |
/* Check for modifier */ | |
if (state == 2 || state == 7) { | |
op_mod = ar; | |
break; | |
} | |
/* Make sure len correct */ | |
if (state != 1 && state != 6) | |
reason = STOP_INVLEN; | |
break; | |
case OP_H: | |
/* Not in protected mode */ | |
if (prot_enb || reloc) { | |
reason = STOP_PROG; | |
break; | |
} | |
/* Valid forms */ | |
/* Op */ | |
/* Op AAAAA */ | |
if (state != 1 && state != 6) | |
reason = STOP_INVLEN; | |
break; | |
case OP_UC: | |
/* Not in protected mode */ | |
if (prot_enb || reloc) { | |
reason = STOP_PROG; | |
break; | |
} | |
/* Valid forms */ | |
/* Op xxx mod */ | |
/* Check for modifier */ | |
if (state == 7) { | |
op_mod = ar; | |
break; | |
} | |
/* Make sure len correct */ | |
if (state != 7) | |
reason = STOP_INVLEN; | |
break; | |
case OP_CC1: | |
case OP_CC2: | |
case OP_SSF1: | |
case OP_SSF2: | |
/* Not in protected mode */ | |
if (prot_enb || reloc) { | |
reason = STOP_PROG; | |
break; | |
} | |
/* Valid forms */ | |
/* Op mod */ | |
/* Check for modifier */ | |
if (state == 2) { | |
op_mod = ar; | |
break; | |
} | |
/* Make sure len correct */ | |
reason = STOP_INVLEN; | |
break; | |
case OP_RD: | |
case OP_RDW: | |
/* Not in protected mode */ | |
if (prot_enb || reloc) { | |
reason = STOP_PROG; | |
break; | |
} | |
/* Valid forms */ | |
/* Op xxx mod */ | |
/* Op xxx BBBBB mod */ | |
/* Check for modifier */ | |
if (state == 7 || state == 12 ) { | |
op_mod = ar; | |
break; | |
} | |
reason = STOP_INVLEN; | |
break; | |
case OP_NOP: | |
break; | |
} | |
if (hst_lnt) { /* History enabled? */ | |
hst[hst_p].astart = AAR; | |
hst[hst_p].bstart = BAR; | |
if (op_info & O_M && | |
(state == 1 || state == 6 || state == 11)) { | |
hst[hst_p].inst[state] = op_mod; | |
hst[hst_p].inst[state+1] = WM; | |
} | |
} | |
/* Handle fault */ | |
if (reason != 0) { | |
goto check_prot; | |
} | |
/* Check to see if we should interupt */ | |
if (cpu_unit.flags & OPTION_PRIO && (pri_enb || timer_enable)) { | |
int irq = inquiry; | |
int ok_irq = 0; | |
for(i = 1; i < NUM_CHAN; i++ ) { | |
if ((chan_io_status[i] & 0300) == 0300 && | |
chan_irq_enb[i]) | |
irq = 1; | |
if (chan_test(i, SNS_ATTN1)) | |
irq = 1; | |
if (urec_irq[i]) | |
irq = 1; | |
} | |
if (irq || (timer_enable && timer_irq == 1)) { | |
/* Check if we can interupt this opcode */ | |
switch(op) { | |
case OP_S: | |
case OP_A: | |
case OP_ZS: | |
case OP_ZA: | |
case OP_M: | |
case OP_D: | |
case OP_SWM: | |
case OP_CWM: | |
case OP_MOV: | |
case OP_MSZ: | |
case OP_E: | |
case OP_C: | |
case OP_CS: | |
if (state > 10) | |
ok_irq = 1; | |
break; | |
case OP_T: | |
case OP_BCE: | |
case OP_BBE: | |
case OP_BWE: | |
if (state > 11) | |
ok_irq = 1; | |
break; | |
case OP_IO1: | |
case OP_IO2: | |
case OP_IO3: | |
case OP_IO4: | |
if (op_mod != 0) | |
break; | |
case OP_B: | |
if (state > 6) | |
ok_irq = 1; | |
break; | |
case OP_SAR: | |
case OP_H: | |
case OP_NOP: | |
case OP_RD: | |
case OP_RDW: | |
case OP_CC1: | |
case OP_CC2: | |
case OP_SSF1: | |
case OP_SSF2: | |
case OP_UC: | |
case OP_PRI: | |
case OP_STS: | |
case OP_FP: | |
break; | |
} | |
if (ok_irq) { | |
sim_debug(DEBUG_PRIO, &cpu_dev, "Irq IAR=%d\n",IAR); | |
prot_enb = reloc = 0; | |
if (pri_enb && irq) { | |
IAR = temp; | |
AAR = 101; | |
op = OP_PRI; | |
op_mod = CHR_X; /* X */ | |
if (hst_lnt) { /* History enabled? */ | |
hst[hst_p].inst[0] = op; | |
hst[hst_p].inst[1] = op_mod; | |
hst[hst_p].inst[2] = WM; | |
} | |
} else if (timer_enable && timer_irq == 1) { | |
IAR = temp; | |
AAR = 301; | |
timer_irq = 2; | |
op = OP_PRI; | |
op_mod = CHR_X; /* X */ | |
if (hst_lnt) { /* History enabled? */ | |
hst[hst_p].inst[0] = op; | |
hst[hst_p].inst[1] = op_mod; | |
hst[hst_p].inst[2] = WM; | |
} | |
} | |
} | |
} | |
} | |
} | |
/* Execute instructions */ | |
switch(op) { | |
case OP_S: | |
/* Check if over the top */ | |
ValidAddr(AAR); | |
ValidAddr(BAR); | |
reason = do_addsub(1); | |
break; | |
case OP_A: | |
/* Check if over the top */ | |
ValidAddr(AAR); | |
ValidAddr(BAR); | |
reason = do_addsub(0); | |
break; | |
case OP_M: | |
/* Check if over the top */ | |
ValidAddr(AAR); | |
ValidAddr(BAR); | |
reason = do_mult(); | |
break; | |
case OP_D: | |
/* Check if over the top */ | |
ValidAddr(AAR); | |
ValidAddr(BAR); | |
reason = do_divide(); | |
break; | |
case OP_ZS: | |
/* Check if over the top */ | |
ar = ReadP(AAR); | |
DownReg(AAR); | |
if ((ar & 060) == 040) | |
ar |= 060; | |
else { | |
ar &= 017|WM; | |
ar |= 040; | |
} | |
goto zadd; | |
case OP_ZA: | |
/* Check if over the top */ | |
ar = ReadP(AAR); | |
DownReg(AAR); | |
if ((ar & 060) != 040) | |
ar |= 060; | |
else { | |
ar &= 017|WM; | |
ar |= 040; | |
} | |
zadd: | |
zind = 1; | |
/* Copy digits until A or B word mark */ | |
br = ReadP(BAR) & WM; | |
STAR = BAR; | |
DownReg(BAR); | |
sim_interval -= 4; | |
while (1) { | |
WriteP(STAR, br | bin_bcd[bcd_bin[ar & 0xf]] | (ar & 060)); | |
if (bcd_bin[ar & 0xf] != 0) /* Update zero flag */ | |
zind = 0; | |
if (br & WM) | |
break; | |
sim_interval -= 4; | |
if (ar & WM) | |
ar = 10|WM; | |
else { | |
ar = ReadP(AAR) & (WM|017); | |
DownReg(AAR); | |
} | |
br = ReadP(BAR) & WM; | |
STAR = BAR; | |
DownReg(BAR); | |
} | |
break; | |
case OP_SAR: | |
if ((CAR & AMASK) < 5 || !MEM_ADDR_OK(CAR)) { | |
reason = STOP_INVADDR; | |
break; | |
} | |
switch(op_mod) { | |
case CHR_A: temp = AAR; | |
if (reloc && low_addr >= 0 && temp & BBIT) { | |
if (temp < low_addr) | |
temp += 100000 - low_addr; | |
else | |
temp -= low_addr; | |
} | |
break; /* A */ | |
case CHR_B: temp = BAR; | |
if (reloc && low_addr >= 0 && temp & BBIT) { | |
if (temp < low_addr) | |
temp += 100000 - low_addr; | |
else | |
temp -= low_addr; | |
} | |
break; /* B */ | |
case CHR_E: temp = caddr[1]; break; /* E */ | |
case CHR_F: temp = caddr[2]; break; /* F */ | |
case CHR_G: temp = caddr[3]; break; /* G */ | |
case CHR_H: temp = caddr[4]; break; /* H */ | |
case CHR_T: /* T */ | |
{ | |
time_t curtim; | |
struct tm *tptr; | |
temp = 99999; | |
curtim = time(NULL); /* get time */ | |
tptr = localtime(&curtim); /* decompose */ | |
if (tptr != NULL && tptr->tm_sec != 59) { | |
/* Convert minutes to 100th hour */ | |
temp = time_digs[tptr->tm_min % 6]; | |
temp += 10 * (tptr->tm_min / 6); | |
temp += 100 * tptr->tm_hour; | |
} | |
} | |
break; | |
default: temp = 0; break; | |
} | |
temp &= AMASK; | |
for(i = 0; i<= 4; i++) { | |
sim_interval --; | |
ch = temp % 10; | |
temp /= 10; | |
if (ch == 0) | |
ch = 10; | |
ReplaceMask(CAR, ch, 017); | |
DownReg(CAR); | |
} | |
break; | |
case OP_SWM: | |
SetBit(AAR, WM); | |
DownReg(AAR); | |
SetBit(BAR, WM); | |
DownReg(BAR); | |
sim_interval -= 4; | |
break; | |
case OP_CWM: | |
ClrBit(AAR, WM); | |
DownReg(AAR); | |
ClrBit(BAR, WM); | |
DownReg(BAR); | |
sim_interval -= 4; | |
break; | |
case OP_CS: | |
/* Clear memory until BAR equal xxx99 */ | |
do { | |
WriteP(BAR, 0); | |
sim_interval -= 2; | |
if ((BAR & AMASK) == 0) { | |
if (CPU_MODEL == 1) | |
BAR = 15999; | |
else | |
BAR = MAXMEMSIZE-1; | |
break; | |
} | |
BAR--; | |
} while (((BAR & AMASK) % 100) != 99); | |
/* If two address, do branch */ | |
if (state > 6) | |
jump = 1; | |
break; | |
case OP_H: | |
if (state > 2) | |
jump = 1; | |
reason = STOP_HALT; | |
break; | |
/* Treat invalid op as a NOP */ | |
default: | |
reason = STOP_UUO; | |
/* Fall through */ | |
case OP_NOP: | |
/* Skip until next word mark */ | |
while((FetchP(IAR) & WM) == 0 && fault == 0) { | |
sim_interval -= 2; | |
UpReg(IAR); | |
} | |
break; | |
case OP_MOV: | |
/* Set terminate to false */ | |
sign = 1; | |
while(sign) { | |
sim_interval -= 4; | |
ar = ReadP(AAR); | |
STAR = BAR; | |
br = ReadP(BAR); | |
/* Adjust addresses. */ | |
if (op_mod & 010) { | |
UpReg(AAR); | |
UpReg(BAR); | |
} else { | |
DownReg(AAR); | |
DownReg(BAR); | |
} | |
switch(op_mod & 070) { | |
case 020: /* A, No B or 8 bit */ | |
if (ar & WM) /* 1st WM - A-field */ | |
sign = 0; | |
break; | |
case 040: /* B, no 8 or A bit */ | |
if (br & WM) /* 1st WM - B-field */ | |
sign = 0; | |
break; | |
case 010: /* No A or B, 8 bit */ | |
case 060: /* B and A bit, no 8 bit */ | |
if (ar & WM || br & WM) /* 1st WM - A or B-field */ | |
sign = 0; | |
break; | |
case 030: /* A & 8 bit, No B */ | |
if ((ar & 077) == CHR_RM) /* 1st RM - A-field */ | |
sign = 0; | |
break; | |
case 050: /* B and 8, no A bit */ | |
if ((ar & 0277) == (CHR_GM|WM)) /* 1st GM,WM - A-field*/ | |
sign = 0; | |
break; | |
case 070: /* B and A and 8 bit */ | |
/* 1st RM or GM,WM - A-field */ | |
if ((ar & 077) == CHR_RM || (ar & 0277) == (CHR_GM|WM)) | |
sign = 0; | |
break; | |
case 000: /* No A or B or 8 bit */ | |
sign = 0; /* After one position */ | |
break; | |
} | |
/* Copy bits */ | |
if (op_mod & 001) { | |
br &= ~0xf; | |
br |= ar & 0xf; | |
} | |
if (op_mod & 002) { | |
br &= ~0x30; | |
br |= ar & 0x30; | |
} | |
if (op_mod & 004) { | |
br &= ~WM; | |
br |= ar & WM; | |
} | |
/* Restore value */ | |
WriteP(STAR, br); | |
} | |
break; | |
case OP_MSZ: | |
ar = ReadP(AAR); /* First character, no zone, force WM */ | |
WriteP(BAR, (ar & 017) |WM); | |
DownReg(AAR); | |
DownReg(BAR); | |
t = 1; /* Suppress zeros. */ | |
sim_interval -= 4; | |
while ((ar & WM) == 0) { /* Copy record */ | |
ar = ReadP(AAR); | |
WriteP(BAR, ar & 077); | |
sim_interval -= 4; | |
DownReg(AAR); | |
DownReg(BAR); | |
} | |
/* Scan backward from end to Word Mark suppressing zeros */ | |
UpReg(BAR); | |
br = ReadP(BAR); /* Forward one */ | |
sim_interval -= 2; | |
while(1) { | |
ch = br & 077; | |
if (ch > 0 && ch < 10) | |
t = 0; | |
else if (ch == 0 || ch == 10 || ch == CHR_COM) | |
ch = (t)?0:ch; /* B blank, zero, comma */ | |
else if (ch != CHR_MINUS && ch != CHR_DOT) | |
t = 1; /* B - or . */ | |
WriteP(BAR, ch); | |
UpReg(BAR); | |
if (br & WM) | |
break; | |
br = ReadP(BAR); /* Forward one */ | |
} | |
break; | |
case OP_C: | |
cind = 2; /* Set equal */ | |
do { | |
/* scan digits until A or B word mark */ | |
ar = ReadP(AAR); | |
br = ReadP(BAR); | |
sim_interval -= 4; | |
sign = cmp_order[br & 077] - cmp_order[ar & 077]; | |
if (sign > 0) | |
cind = 4; | |
else if (sign < 0) | |
cind = 1; | |
DownReg(AAR); | |
DownReg(BAR); | |
} while ((br & WM) == 0 && (ar & WM) == 0); | |
if ((br & WM) == 0 && (ar & WM)) | |
cind = 4; | |
break; | |
case OP_T: | |
/* Check opcode */ | |
if ((op_mod & 070) != 0) { | |
reason = STOP_UUO; | |
break; | |
} | |
cind = 2; | |
qsign = 1; /* Set unit/body */ | |
CAR = AAR; | |
ar = ReadP(AAR); | |
DownReg(AAR); | |
while(1) { | |
/* Scan digits until A or B word mark */ | |
sim_interval -= 4; | |
ZeroAddr(AAR); | |
br = ReadP(BAR); | |
DownReg(BAR); | |
if (qsign) { | |
sign = cmp_order[br & 077] - cmp_order[ar & 077]; | |
if (sign > 0) | |
cind = 4; | |
else if (sign < 0) | |
cind = 1; | |
} | |
/* Hit end of search argument */ | |
if (ar & WM) { | |
if (cind & op_mod) /* Check if match */ | |
break; | |
if (br & WM) { | |
AAR = CAR; | |
ar = ReadP(AAR); | |
DownReg(AAR); | |
qsign = 1; /* Set unit/body */ | |
cind = 2; | |
} else | |
qsign = 0; | |
} else if (br & WM) { /* Found end of table */ | |
cind = 4; | |
break; | |
} else { | |
ar = ReadP(AAR); | |
DownReg(AAR); | |
} | |
} | |
break; | |
case OP_E: | |
cy = 0x10; /* latchs */ | |
/* 1 Supress zero latch */ | |
/* 2 Decimal latch */ | |
/* 4 * Fill latch */ | |
/* 8 $ Fill latch */ | |
/* 0x10 Unit latch */ | |
/* 0x20 Body latch */ | |
/* 0x40 Ext latch */ | |
ar = ReadP(AAR); | |
DownReg(AAR); | |
sim_interval -= 2; | |
sign = (ar & 060) == 040; | |
ch = ar & 017; | |
/* First scan cycle */ | |
while (1) { | |
br = ReadP(STAR = BAR); | |
DownReg(BAR); | |
sim_interval -= 2; | |
if (cy & 0x40) | |
ch = br & 077; | |
switch (br & 077) { | |
case CHR_MINUS: /* - */ | |
case CHR_C: /* C */ | |
case CHR_R: /* R */ | |
if (sign || cy & 0x20) /* - or body */ | |
WriteP(STAR, br & 077); | |
else | |
WriteP(STAR, 0); | |
break; | |
case CHR_COM: /* , */ | |
if (cy & 0x40) | |
WriteP(STAR, 0); | |
else | |
WriteP(STAR, br & 077); | |
break; | |
case CHR_PLUS: /* & */ | |
WriteP(STAR, 0); | |
break; | |
case CHR_DOL: /* $ */ | |
case CHR_STAR: /* * */ | |
if ((cy & 0x20) == 0) { /* not body, skip */ | |
WriteP(STAR, br & 077); | |
break; | |
} | |
if ((cy & 0xd) == 1) { /* Set fill flag */ | |
cy |= ((br & 077) == CHR_DOL)?0x8:0x4; | |
} | |
case CHR_0: /* 0 */ | |
/* Supression off */ | |
if ((br & 077) == CHR_0 && (cy & 1) == 0) { | |
ch |= WM; | |
cy |= 1; /* Set on */ | |
} | |
case CHR_ABLANK: /* blank */ | |
WriteP(STAR, ch); | |
if ((br & WM) == 0) { | |
if (ar & WM) { | |
cy &= ~0x70; /* Set Ext */ | |
cy |= 0x40; | |
} else { | |
ar = ReadP(AAR); /* Set Body */ | |
DownReg(AAR); | |
ch = ar & 077; | |
cy &= ~0x70; | |
cy |= 0x20; | |
} | |
} | |
break; | |
default: | |
WriteP(STAR, br & 077); /* Clear word mark */ | |
break; | |
} | |
if (br & WM) | |
break; | |
} | |
/* A */ | |
/* If suppression off and first char not zero stop */ | |
if ((cy & 0x1) == 0 && (ReadP(BAR) & 077) != CHR_0) | |
break; | |
UpReg(BAR); | |
/* Do second scan */ | |
while (1) { | |
br = ReadP(STAR = BAR); | |
UpReg(BAR); | |
sim_interval -= 2; | |
ch = br & 077; | |
switch (ch) { | |
case 1: case 2: case 3: case 4: case 5: | |
case 6: case 7: case 8: case 9: | |
cy &= ~1; /* Turn off suppression latch */ | |
break; | |
case CHR_COM: /* , */ | |
if ((cy & 3) == 2) { /* Decimal suppress */ | |
ch = (cy & 0x4)?CHR_STAR:0; /* * or blank */ | |
} | |
case CHR_0: /* 0 */ | |
case CHR_ABLANK: /* blank */ | |
if ((cy & 3) == 1) { /* Supress, no dec */ | |
ch = (cy & 0x4)?CHR_STAR:0; /* * or blank */ | |
} | |
break; | |
case CHR_DOT: /* . */ | |
if (cy & 1) | |
cy |= 2; /* Set dec */ | |
case CHR_MINUS: /* - */ | |
break; | |
default: | |
if ((cy & 0x3) == 0) | |
cy |= 1; /* Set 0 if not dec */ | |
break; | |
} | |
WriteP(STAR, ch); /* Store char back */ | |
if (br & WM) | |
break; | |
} | |
/* Dec not set & $ fill or zero and $ fill not set */ | |
if ((cy & 0xA) == 0 || (cy & 0xB) == 2 || | |
((cy & 0xB) == 3 && ch == CHR_MINUS)) | |
break; | |
DownReg(BAR); | |
/* Third scan pass */ | |
while(1) { | |
ch = ReadP(STAR = BAR) & 077; | |
DownReg(BAR); | |
sim_interval -= 2; | |
if (ch == 0) { | |
if (cy & 0x4) { | |
WriteP(STAR, CHR_STAR); /* * */ | |
} else if (cy & 0x8) { | |
WriteP(STAR, CHR_DOL); /* $ */ | |
break; /* Stop after $ */ | |
} | |
} else if (ch == CHR_0) { /* 0 */ | |
if (cy & 1) { | |
WriteP(STAR, (cy & 04)?CHR_STAR:0); /* * */ | |
} | |
} else if (ch == CHR_DOT) { /* . */ | |
if (cy & 1) { | |
WriteP(STAR, (cy & 04)?CHR_STAR:0); /* * */ | |
break; | |
} | |
if ((cy & 0xA) == 0xA) /* Both . and $ set */ | |
break; | |
} | |
} | |
break; | |
case OP_B: | |
switch(op_mod) { | |
case CHR_ABLANK: /* 1401 same */ | |
jump = 1; | |
break; | |
case CHR_Z: /* Z Arith overflow */ /* 1401 same */ | |
jump = oind; | |
oind = 0; | |
break; | |
case CHR_S: /* S Equal */ /* 1401 same */ | |
jump = (cind == 2); | |
break; | |
case CHR_U: /* U High */ /* 1401 same */ | |
jump = (cind == 4); | |
break; | |
case CHR_T: /* T Low */ /* 1401 same */ | |
jump = (cind == 1); | |
break; | |
case CHR_SLSH: /* / High or Low */ /* 1401 same */ | |
jump = (cind != 2); | |
break; | |
case CHR_W: /* W Divide overflow */ | |
jump = dind; | |
dind = 0; | |
break; | |
case CHR_V: /* V Zero Balence */ | |
jump = zind; | |
break; | |
case CHR_X: /* X floating point */ | |
if ((cpu_unit.flags & OPTION_FLOAT) == 0) | |
reason = STOP_UUO; | |
jump = euind; | |
euind = 0; | |
break; | |
case CHR_Y: /* Y floating point */ | |
if ((cpu_unit.flags & OPTION_FLOAT) == 0) | |
reason = STOP_UUO; | |
jump = eoind; | |
eoind = 0; | |
break; | |
case CHR_K: /* K Tape indicator */ | |
/* 1401 end of real */ | |
if (CPU_MODEL == 1) { | |
jump = chan_stat(1, CHS_EOF|CHS_EOT); | |
} else if (tind) { | |
jump = 1; | |
tind = 0; | |
} else { | |
for(i = 1; i <= NUM_CHAN && jump == 0; i++) | |
jump = chan_stat(i, STA_PEND); | |
if (jump) | |
sim_debug(DEBUG_CMD, &cpu_dev, "Tape Ind\n"); | |
} | |
break; | |
case CHR_Q: /* Q Inq req ch 1 */ | |
jump = inquiry; | |
break; | |
case CHR_STAR: /* * Inq req ch 2 */ | |
break; | |
case CHR_1: /* 1 Overlap in Proc Ch 1 */ | |
jump = ((chan_io_status[1] & 0300) == 0200) && | |
chan_active(1); | |
break; | |
case CHR_2: /* 2 Overlap in Proc Ch 2 */ | |
jump = ((chan_io_status[2] & 0300) == 0200) && | |
chan_active(2); | |
break; | |
case CHR_4: /* 4 Channel 3 */ | |
jump = ((chan_io_status[3] & 0300) == 0200) && | |
chan_active(3); | |
break; | |
case CHR_RPARN: /* ) Channel 4 */ | |
jump = ((chan_io_status[4] & 0300) == 0200) && | |
chan_active(4); | |
break; | |
case CHR_9: /* 9 Carriage 9 CH1 */ /* 1401 same */ | |
jump = lpr_chan9[1]; | |
break; | |
case CHR_EXPL: /* ! Carriage 9 CH2 */ | |
/* 1401 punch error */ | |
jump = lpr_chan9[2]; | |
break; | |
case CHR_R: /* R Carriage Busy CH1 */ /* 1401 same */ | |
/* Try to start command */ | |
switch (chan_cmd(010200, IO_TRS << 8, 0)) { | |
case SCPE_BUSY: | |
jump = 1; | |
break; | |
case SCPE_OK: | |
case SCPE_NODEV: | |
case SCPE_IOERR: | |
break; | |
} | |
break; | |
case CHR_L: /* L Carriage Busy CH2 */ | |
/* 1401 tape error */ | |
if (CPU_MODEL == 1) { | |
jump = chan_stat(1, CHS_ERR); | |
break; | |
} | |
/* Try to start command */ | |
switch (chan_cmd(020200, IO_TRS << 8, 0)) { | |
case SCPE_BUSY: | |
jump = 1; | |
break; | |
case SCPE_OK: | |
case SCPE_NODEV: | |
case SCPE_IOERR: | |
break; | |
} | |
break; | |
case CHR_QUOT: /* @ Cariage Overflow 12 CH 1 */ | |
/* 1401 same */ | |
jump = lpr_chan12[1]; | |
break; | |
case CHR_LPARN: /* sq Cariage Overflow 12 CH 2 */ | |
/* 1401 process check switch off */ | |
jump = lpr_chan12[2]; | |
break; | |
case CHR_A: /* 1401 sense switch A */ | |
if (CPU_MODEL == 1) { | |
jump = (SW & 0x01) | (io_flags & 010); | |
io_flags &= ~010; | |
} else { | |
reason = STOP_UUO; | |
} | |
break; | |
case CHR_B: /* 1401 sense switch B */ | |
if (CPU_MODEL == 1) { | |
jump = SW & 0x02; | |
} else { | |
reason = STOP_UUO; | |
} | |
break; | |
case CHR_C: /* 1401 sense switch C */ | |
if (CPU_MODEL == 1) { | |
jump = SW & 0x04; | |
} else { | |
reason = STOP_UUO; | |
} | |
break; | |
case CHR_D: /* 1401 sense switch D */ | |
if (CPU_MODEL == 1) { | |
jump = SW & 0x08; | |
} else { | |
reason = STOP_UUO; | |
} | |
break; | |
case CHR_E: /* 1401 sense switch E */ | |
if (CPU_MODEL == 1) { | |
jump = SW & 0x10; | |
} else { | |
reason = STOP_UUO; | |
} | |
break; | |
case CHR_F: /* 1401 sense switch F */ | |
if (CPU_MODEL == 1) { | |
jump = SW & 0x20; | |
} else { | |
reason = STOP_UUO; | |
} | |
break; | |
case CHR_G: /* 1401 sense switch G */ | |
if (CPU_MODEL == 1) { | |
jump = SW & 0x40; | |
} else { | |
reason = STOP_UUO; | |
} | |
break; | |
case CHR_QUEST: /* 1401 reader error */ | |
if (CPU_MODEL == 1) { | |
jump = io_flags & 1; | |
io_flags &= ~01; | |
} else { | |
reason = STOP_UUO; | |
} | |
break; | |
case CHR_RM: /* 1401 print error */ | |
if (CPU_MODEL == 1) { | |
jump = io_flags & 2; | |
io_flags &= ~02; | |
} else { | |
reason = STOP_UUO; | |
} | |
break; | |
case CHR_I: /* 1401 punch error */ | |
if (CPU_MODEL == 1) { | |
jump = io_flags & 4; | |
io_flags &= ~04; | |
} else { | |
reason = STOP_UUO; | |
} | |
break; | |
} | |
break; | |
case OP_BCE: | |
sim_interval -= 2; | |
cind = 2; /* Set equal */ | |
sign = cmp_order[ReadP(BAR) & ~WM] - cmp_order[op_mod]; | |
if (sign > 0) | |
cind = 4; | |
else if (sign < 0) | |
cind = 1; | |
if (cind == 2) | |
jump = 1; | |
DownReg(BAR); | |
break; | |
case OP_BBE: | |
sim_interval -= 2; | |
if (ReadP(BAR) & op_mod) | |
jump = 1; | |
DownReg(BAR); | |
break; | |
case OP_BWE: | |
sim_interval -= 2; | |
br = ReadP(BAR); | |
if (((op_mod & 01) && (br & WM)) || | |
((op_mod & 02) && (br & 060) == (op_mod & 060))) | |
jump = 1; | |
DownReg(BAR); | |
break; | |
case OP_RD: | |
case OP_RDW: | |
/* Decode operands */ | |
/* X1 digit 1 == channel 034 % non-overlap */ | |
/* 2 == channel 074 sq non-overlap */ | |
/* 3 == channel 072 ? non-overlap */ | |
/* 4 == channel 052 ! non-overlap */ | |
/* 1 == channel 014 @ overlap */ | |
/* 2 == channel 054 * overlap */ | |
/* X2 digit device */ | |
/* 1 == Reader 001 */ | |
/* 2 == Printer 002 */ | |
/* 4 == Punch 004 */ | |
/* U == Tape BCD 024 */ | |
/* B == Tape Binary 062 */ | |
/* T == Console 023 */ | |
/* F == Disk 066 */ | |
/* K == Com 042 */ | |
/* X3 digit device option or unit number */ | |
/* op_mod R == Read 051 */ | |
/* $ == Read 053 ignore word/group */ | |
/* W == Write 026 */ | |
/* X == Write 027 ignore word/group */ | |
/* Q == Nop 050 input */ | |
/* V == Nop 025 output */ | |
switch ((XR >> 12) & 077) { | |
case CHR_RPARN: ch = 011; break; /* %/( 1 - non-overlap */ | |
case CHR_LPARN: ch = 012; break; /* sq 2 - non-overlap */ | |
case CHR_QUEST: ch = 013; break; /* ? 3 - non-overlap */ | |
case CHR_EXPL: ch = 014; break; /* ! 4 - non-overlap */ | |
case CHR_QUOT: ch = 001; break; /* @/' 1 - overlap */ | |
case CHR_STAR: ch = 002; break; /* * 2 - overlap */ | |
case CHR_DOL: ch = 003; break; /* $ 3 - overlap */ | |
case CHR_EQ: ch = 004; break; /* = 4 - overlap */ | |
default: ch = 0; | |
reason = STOP_IOCHECK; | |
break; | |
} | |
temp = ch << 12; | |
if ((XR & 07700) == 06200) { | |
if ((XR & 017) != 10) | |
temp |= XR & 017; | |
temp |= 02420; | |
} else if ((XR & 07700) == 02400) { | |
if ((XR & 017) != 10) | |
temp |= XR & 017; | |
temp |= 02400; | |
} else { | |
temp |= XR & 07777; | |
} | |
switch(op_mod) { | |
case CHR_R: t = (IO_RDS << 8); break; /* R */ | |
case CHR_DOL: t = (IO_RDS << 8) | 0100; break; /* $ */ | |
case CHR_W: t = (IO_WRS << 8); break; /* W */ | |
case CHR_X: t = (IO_WRS << 8) | 0100; break; /* X */ | |
case CHR_Q: t = (IO_TRS << 8); ch &= 07; break; /* Q */ | |
case CHR_V: t = (IO_TRS << 8) | 0100; ch &= 07; break; /* Y */ | |
case CHR_S: t = (IO_TRS << 8); break; /* S sense */ | |
case CHR_C: t = (IO_CTL << 8); break; /* C control */ | |
default: t = 0; | |
reason = STOP_UUO; | |
break; | |
} | |
if (reason != 0) | |
break; | |
while (chan_active(ch & 07) && reason == 0) { | |
sim_interval = 0; | |
reason = sim_process_event(); | |
chan_proc(); | |
} | |
if (reason != 0) | |
break; | |
if (op == OP_RDW) | |
t |= 0200; | |
if ((ch & 010) == 0) | |
t &= ~0100; /* Can't be overlaped */ | |
/* Try to start command */ | |
switch (chan_cmd(temp, t, BAR & AMASK)) { | |
case SCPE_OK: | |
if (ch & 010) { | |
chan_io_status[ch & 07] = 0; | |
chwait = ch & 07; | |
chan_irq_enb[ch & 7] = 0; | |
} else { | |
chan_io_status[ch & 07] = IO_CHS_OVER; | |
chan_irq_enb[ch & 7] = 1; | |
} | |
sim_debug(DEBUG_CMD, &cpu_dev, | |
"%d %c on %o %o %s %c\n", IAR, sim_six_to_ascii[op], | |
ch & 07, temp, | |
(ch & 010)?"":"overlap", | |
sim_six_to_ascii[op_mod]); | |
break; | |
case SCPE_BUSY: | |
sim_debug(DEBUG_CMD, &cpu_dev, | |
"%d %c Busy on %o %s %c %o\n", IAR, | |
sim_six_to_ascii[op], ch & 07, | |
(ch & 010)?"": "overlap", | |
sim_six_to_ascii[op_mod], chan_io_status[ch & 07]); | |
chan_io_status[ch & 07] = IO_CHS_BUSY; | |
break; | |
case SCPE_NODEV: | |
case SCPE_IOERR: | |
chan_io_status[ch & 07] = IO_CHS_NORDY; | |
break; | |
} | |
if (CPU_MODEL == 1) | |
chan_io_status[ch & 07] &= 0177; | |
break; | |
case OP_CC1: | |
t = (IO_CTL << 8); | |
temp = 010200 | op_mod; | |
ch = 1; | |
chan_io: | |
switch (chan_cmd(temp, t, 0)) { | |
case SCPE_OK: | |
chan_io_status[ch & 07] = 0000; | |
if (ch & 010) | |
chwait = (ch & 07) | 040; | |
chan_irq_enb[ch & 7] = 0; | |
break; | |
case SCPE_BUSY: | |
chan_io_status[ch & 07] = IO_CHS_BUSY; | |
break; | |
case SCPE_NODEV: | |
case SCPE_IOERR: | |
chan_io_status[ch & 07] = IO_CHS_NORDY; | |
break; | |
} | |
break; | |
case OP_CC2: | |
t = (IO_CTL << 8); | |
temp = 020200 | op_mod; | |
ch = 2; | |
goto chan_io; | |
case OP_SSF1: | |
t = (IO_CTL << 8); | |
temp = 010100 | op_mod; | |
ch = 1; | |
goto chan_io; | |
case OP_SSF2: | |
t = (IO_CTL << 8); | |
temp = 020100 | op_mod; | |
ch = 2; | |
goto chan_io; | |
case OP_UC: | |
switch ((XR >> 12) & 077) { | |
case CHR_RPARN: ch = 011; break; /* %/) 1 - non-overlap */ | |
case CHR_LPARN: ch = 012; break; /* sq 2 - non-overlap */ | |
case CHR_QUEST: ch = 013; break; /* ? 3 - non-overlap */ | |
case CHR_EXPL: ch = 014; break; /* ! 4 - non-overlap */ | |
case CHR_QUOT: ch = 001; break; /* @/' 1 - overlap */ | |
case CHR_STAR: ch = 002; break; /* * 2 - overlap */ | |
case CHR_DOL: ch = 003; break; /* $ 3 - overlap */ | |
case CHR_EQ: ch = 004; break; /* = 4 - overlap */ | |
default: ch = 0; | |
reason = STOP_IOCHECK; | |
break; | |
} | |
temp = ch << 12; | |
if ((XR & 07700) != 02400 && (XR & 07700) != 06200) { | |
reason = STOP_UUO; | |
break; | |
} | |
if ((XR & 017) != 10) | |
temp |= XR & 017; | |
temp |= 02400; | |
t = 0; | |
switch(op_mod) { | |
case CHR_B: t = (IO_BSR << 8); ch |= 010; break; | |
case CHR_A: t = (IO_SKR << 8); ch |= 010; break; | |
case CHR_R: t = (IO_REW << 8); ch |= 010; break; | |
case CHR_GT: t = (IO_RUN << 8); ch |= 010; break; | |
case CHR_E: t = (IO_ERG << 8); ch |= 010; break; | |
case CHR_M: t = (IO_WEF << 8); break; | |
default: t = 0; reason = STOP_UUO; break; | |
} | |
while (chan_active(ch & 07) && reason == 0) { | |
sim_interval = 0; | |
reason = sim_process_event(); | |
chan_proc(); | |
} | |
if (reason != 0) | |
break; | |
/* For nop, set command done */ | |
if (t == 0) { | |
chan_io_status[ch & 07] = 0000; | |
break; | |
} | |
/* Issue command */ | |
switch (chan_cmd(temp, t, 0)) { | |
case SCPE_OK: | |
chan_io_status[ch & 07] = 0000; | |
if (ch & 010) { | |
chwait = (ch & 07) | 040; | |
} else if (op_mod == CHR_M) { | |
chan_io_status[ch & 07] = IO_CHS_OVER; | |
} | |
chan_irq_enb[ch & 7] = 0; | |
sim_debug(DEBUG_CMD, &cpu_dev, | |
"%d UC on %o %o %s %c %o\n", IAR, ch & 07, temp, | |
(ch & 010)?"": "overlap", | |
sim_six_to_ascii[op_mod], chan_io_status[ch & 07]); | |
break; | |
case SCPE_BUSY: | |
chan_io_status[ch & 07] = IO_CHS_BUSY; | |
break; | |
case SCPE_NODEV: | |
case SCPE_IOERR: | |
chan_io_status[ch & 07] = IO_CHS_NORDY; | |
break; | |
} | |
if (CPU_MODEL == 1) | |
chan_io_status[ch & 07] &= 0177; | |
sim_interval -= 100; | |
break; | |
case OP_IO1: | |
/* Wait for channel to finish before continuing */ | |
ch = 1; | |
checkchan: | |
chan_proc(); | |
if (chan_io_status[ch] & op_mod) { | |
jump = 1; | |
} | |
chan_io_status[ch] &= 077; | |
sim_debug(DEBUG_CMD, &cpu_dev, "Check chan %d %o %x\n", ch, | |
chan_io_status[ch], chan_flags[ch]); | |
break; | |
case OP_IO2: | |
ch = 2; | |
goto checkchan; | |
case OP_IO3: | |
ch = 3; | |
goto checkchan; | |
case OP_IO4: | |
ch = 4; | |
goto checkchan; | |
case OP_FP: | |
if ((cpu_unit.flags & OPTION_FLOAT) == 0) { | |
reason = STOP_UUO; | |
break; | |
} | |
/* Check if over the top */ | |
ValidAddr(AAR); | |
/* AAR pointes to exponent of FP */ | |
/* BAR point to FP register locations 280 - 299 */ | |
BAR = 299; | |
if (hst_lnt) /* History enabled? */ | |
hst[hst_p].bstart = BAR; | |
switch(op_mod) { | |
case CHR_R: /* R - Floating Reset Add */ | |
/* Copy exponent to accumulator */ | |
zind = 1; | |
ar = ReadP(AAR); | |
DownReg(AAR); | |
if ((ar & 060) != 040) | |
ar |= 060; | |
else { | |
ar |= 040; | |
ar &= 057; | |
} | |
WriteP(BAR--, bin_bcd[bcd_bin[ar & 0xf]] | (ar & 060)); | |
sim_interval -= 4; | |
ar = ReadP(AAR); | |
DownReg(AAR); | |
WriteP(BAR--, bin_bcd[bcd_bin[ar & 0xf]] | (ar & (WM|060))); | |
/* Prepare to copy rest. */ | |
br = ReadP(STAR = BAR--) & WM; | |
sim_interval -= 4; | |
ar = ReadP(AAR); | |
DownReg(AAR); | |
while (1) { | |
WriteP(STAR, ar); | |
if ((ar & 0xf) != 10) /* Update zero flag */ | |
zind = 0; | |
if (ar & WM) /* Done yet? */ | |
break; | |
if (BAR == 279) /* Stop at lower limit */ | |
break; | |
sim_interval -= 4; | |
ar = ReadP(AAR); | |
DownReg(AAR); | |
br = ReadP(STAR = BAR--) & WM; | |
} | |
SetBit(STAR, WM); | |
break; | |
case CHR_L: /* L - Floating store */ | |
/* Copy two digit exponent */ | |
br = ReadP(BAR--); | |
if ((br & 060) != 040) | |
br |= 060; | |
else { | |
br &= 017|WM; | |
br |= 040; | |
} | |
WriteP(AAR, bin_bcd[bcd_bin[br & 0xf]] | (br & 060)); | |
DownReg(AAR); | |
br = ReadP(BAR--); | |
WriteP(AAR, bin_bcd[bcd_bin[br & 0xf]] | (br & (WM|060))); | |
DownReg(AAR); | |
sim_interval -= 4; | |
/* Copy digits until A or B word mark */ | |
zind = 1; | |
ar = ReadP(STAR = AAR) & WM; | |
DownReg(AAR); | |
br = ReadP(BAR--); | |
while (1) { | |
WriteP(STAR, br); | |
if ((br & 0xf) != 10) /* Update zero flag */ | |
zind = 0; | |
if (br & WM || ar & WM || BAR == 279) | |
break; | |
sim_interval -= 4; | |
ar = ReadP(STAR = AAR) & WM; | |
DownReg(AAR); | |
br = ReadP(BAR--); | |
} | |
SetBit(STAR, WM); | |
break; | |
case CHR_S: /* S - Floating sub */ | |
case CHR_A: /* A - Floating add */ | |
zind = 1; | |
/* Compute A exponent */ | |
ar = ReadP(AAR); | |
DownReg(AAR); | |
qsign = (ar & 060) == 040; | |
cy = bcd_bin[ar & 0xf]; | |
ar = ReadP(AAR); | |
DownReg(AAR); | |
cy += 10 * bcd_bin[ar & 0xf]; | |
if (qsign) | |
cy = -cy; | |
/* Compute B exponent */ | |
br = ReadP(BAR--); | |
sign = (br & 060) == 040; | |
temp = bcd_bin[br & 0xf]; | |
br = ReadP(BAR--); | |
temp += 10 * bcd_bin[br & 0xf]; | |
if (sign) | |
temp = -temp; | |
sim_interval -= 10; | |
temp -= cy; | |
ar = ReadP(AAR); | |
DownReg(AAR); | |
sign = (ar & 060) == 040; | |
if (temp == 0) /* Same go add */ | |
goto fadd; | |
if (temp > 17) { /* Normalize */ | |
/* Move BAR to just below WM */ | |
do { | |
br = ReadP(BAR--); | |
} while((br & WM) == 0); | |
goto fnorm; | |
} | |
if (temp < -17) { /* Copy A to ACC */ | |
fcopy: | |
BAR = 299; /* Copy exponent */ | |
if (cy < 0) | |
cy = -cy; | |
WriteP(BAR--, bin_bcd[cy % 10] | ((qsign)? 040: 060)); | |
WriteP(BAR--, bin_bcd[cy / 10] | WM); | |
br = ReadP(STAR = BAR--) & WM; | |
/* Flip sign if doing subtract */ | |
if (op_mod == CHR_S) { | |
ar &= WM|017; | |
ar |= sign?060:040; | |
} | |
while (1) { | |
WriteP(STAR, ar); | |
if ((ar & 0xf) != 10) /* Update zero flag */ | |
zind = 0; | |
if (br & WM || ar & WM) | |
break; | |
if (BAR == 280) | |
SetBit(BAR, WM); | |
sim_interval -= 4; | |
ar = ReadP(AAR); | |
DownReg(AAR); | |
br = ReadP(STAR = BAR--) & WM; | |
} | |
SetBit(STAR, WM); | |
goto fnorm; | |
} | |
if (temp > 0) { /* Shift A */ | |
while (temp-- > 0 && (ar & WM) == 0) { | |
sim_interval -= 2; | |
ar = ReadP(AAR); | |
DownReg(AAR); | |
} | |
if (ar & WM && temp != 0) { | |
/* Move BAR to just below WM */ | |
while((ReadP(BAR--) & WM) == 0); | |
goto fnorm; | |
} | |
} else { /* Shift B */ | |
ix = br = ReadP(BAR--); | |
while (temp++ < 0) { | |
if (br & WM || BAR == 279) | |
break; | |
sim_interval -= 2; | |
br = ReadP(BAR--); | |
} | |
if (br & WM && temp < 0) { | |
/* Copy exponent to ACC first */ | |
BAR = 299; | |
if (cy < 0) | |
cy = -cy; | |
WriteP(BAR--, bin_bcd[cy % 10] | ((qsign)? 040: 060)); | |
WriteP(BAR--, bin_bcd[cy / 10] | WM); | |
sim_interval -= 4; | |
goto fcopy; | |
} | |
DAR = 297; | |
/* Copy B up */ | |
while(1) { | |
WriteP(DAR--, (br & 017) | (ix & 060)); | |
ix = 0; | |
if (br & WM || BAR == 279) | |
break; | |
br = ReadP(BAR--); | |
} | |
/* Zero fill new locations */ | |
while(DAR != BAR) | |
ReplaceMask(DAR--, 10, 077); | |
/* Copy A exponent */ | |
BAR = 299; | |
if (cy < 0) | |
cy = -cy; | |
WriteP(BAR--, bin_bcd[cy % 10] | ((qsign)? 040: 060)); | |
WriteP(BAR--, bin_bcd[cy / 10] | WM); | |
} | |
fadd: | |
if (op_mod == CHR_S) | |
sign ^= 1; /* Change sign for subtract oper */ | |
zind = 1; | |
DAR = BAR; | |
sim_interval -= 2; | |
if ((ReadP(297) & 060) == 040) | |
sign ^= 1; | |
cy = sign; | |
br = ReadP(STAR = BAR--); | |
ix = 0; | |
/* Add until word mark on A or B */ | |
while(1) { | |
ix |= ar & WM; | |
ch = bcd_bin[ar & 0xf]; | |
ch = bcd_bin[br& 0xf] + ((sign)? (9 - ch):ch) + cy; | |
cy = ch > 9; /* Update carry */ | |
ch = bin_bcd[ch]; | |
if (ch != CHR_0) /* Clear zero */ | |
zind = 0; | |
WriteP(STAR, (br & 0360) | ch); | |
if (br & WM || BAR == 279) | |
break; | |
if (ix) | |
ar = CHR_0; | |
else { | |
ar = ReadP(AAR); | |
DownReg(AAR); | |
sim_interval -= 2; | |
} | |
br = ReadP(STAR = BAR--); | |
sim_interval -= 4; | |
} | |
/* If cy and qsign, tens-compliment result and flip sign */ | |
if (sign && cy == 0) { | |
STAR = BAR = DAR; | |
br = ReadP(BAR--); | |
sim_interval -= 2; | |
if ((br & 060) == 040) | |
br |= 060; | |
else { | |
br &= ~020; /* Switch B sign */ | |
br |= 040; | |
} | |
zind = 1; | |
cy = 1; | |
/* Compliment until B word mark */ | |
while(1) { | |
ch = (9 - bcd_bin[br& 0xf]) + cy; | |
cy = ch > 9; /* Update carry */ | |
ch = bin_bcd[ch]; | |
if (ch != CHR_0) /* Clear zero */ | |
zind = 0; | |
WriteP(STAR, (br & 0360) | ch); | |
if (br & WM) | |
break; | |
sim_interval -= 2; | |
br = ReadP(STAR = BAR--); | |
} | |
} | |
/* If carry fix exponent and shift result */ | |
if ((sign == 0 && cy) || ix == 0) { | |
BAR = 299; | |
eoind = do_addint(1); | |
/* Now shift mantissa right one */ | |
br = ReadP(STAR = BAR--); | |
ar = ReadP(BAR); | |
while ((br & WM) == 0) { | |
WriteP(STAR, (ar & 017) | (br & 060)); | |
if (BAR == 279) | |
break; | |
sim_interval -= 4; | |
br = ReadP(STAR = BAR--); | |
ar = ReadP(BAR); | |
} | |
WriteP(STAR, WM|1); /* New high order 1 + WM */ | |
zind = 0; | |
} | |
fnorm: | |
temp = 0; | |
DAR = BAR; | |
br = ReadP(++BAR) & 077; | |
zind = 1; | |
while ((br & WM) == 0) { | |
if ((br & 017) != 10) { | |
zind = 0; | |
break; | |
} | |
temp++; | |
br = ReadP(++BAR); | |
} | |
if (br & WM) { /* Zero result, set exponent to zero */ | |
SetBit(BAR-1, 060); /* Force plus */ | |
WriteP(BAR++, WM | 9); | |
WriteP(BAR, 040 | 9); | |
break; | |
} | |
if (temp > 0) { /* Need to shift it temp places */ | |
ar = ReadP(++DAR); | |
while (1) { | |
WriteP(DAR, (ar & WM) | (br & 017)); | |
ar = ReadP(++DAR); | |
br = ReadP(++BAR); | |
if (br & WM) | |
break; | |
} | |
while(DAR != BAR) { | |
ReplaceMask(DAR++, 10, 017); | |
} | |
/* Adjust exponent */ | |
BAR = 299; | |
if (do_addint(-temp)) { | |
undfacc: | |
euind = 1; | |
zerofacc: | |
zind = 1; | |
/* Move zero to accumulator */ | |
BAR=299; | |
WriteP(BAR--, 040 | 9); | |
WriteP(BAR--, WM | 9); | |
br = ReadP(BAR) | 060; | |
while(1) { | |
WriteP(BAR--, (br & (WM|060)) | 10); | |
if (br & WM) | |
break; | |
br = ReadP(BAR) & WM; | |
} | |
} | |
} | |
break; | |
case CHR_M: /* M - Floating mul */ | |
temp = oind; | |
oind = 0; | |
reason = do_addsub(0); | |
ch = oind; | |
oind = temp; | |
if (reason != SCPE_OK) | |
break; | |
if (ch) { | |
zind = 0; | |
if ((ReadP(299) & 060) == 040) | |
goto undfacc; | |
eoind = 1; | |
break; | |
} | |
CAR = AAR; | |
DAR = 279; | |
/* Scan for A word mark */ | |
qsign = 1; | |
ar = ReadP(AAR); | |
DownReg(AAR); | |
while (1) { | |
if ((ar & 017) != 10) | |
qsign = 0; | |
ClrBit(DAR--, WM); /* Clear word marks */ | |
if (ar & WM || AAR == 0) | |
break; | |
ar = ReadP(AAR); | |
DownReg(AAR); | |
sim_interval -= 4; | |
}; | |
ClrBit(DAR--, WM); /* Extra zero */ | |
if (qsign) | |
goto zerofacc; | |
/* Scan for B word mark */ | |
zind = 1; | |
br = ReadP(BAR--); | |
while (1) { | |
if ((br & 017) != 10) | |
zind = 0; | |
WriteP(DAR--, br); | |
if (br & WM || BAR == 279) | |
break; | |
br = ReadP(BAR--); | |
sim_interval -= 2; | |
}; | |
/* If B zero, scan to A word mark and set B zero */ | |
if (zind || qsign) | |
goto zerofacc; | |
temp = BAR; /* Save for later */ | |
BAR = 279; | |
AAR = CAR; | |
reason = do_mult(); | |
if (reason != SCPE_OK) | |
break; | |
/* Count number of leading zeros */ | |
ix = 0; | |
BAR++; /* Skip first zero */ | |
while (BAR != 280) { | |
br = ReadP(++BAR); | |
if ((br & 017) != 10) | |
break; | |
ix++; | |
} | |
if (ix != 0) { | |
DAR = BAR; | |
BAR = 299; | |
if(do_addint(-ix)) | |
goto undfacc; | |
BAR = DAR; | |
} | |
/* Find end of result */ | |
CAR = 297; | |
ar = ReadP(CAR--); | |
while((ar & WM) == 0) | |
ar = ReadP(CAR--); | |
br = (ReadP(BAR) & 017) | WM; | |
/* Copy result */ | |
while(CAR != 297 && BAR != 279) { | |
WriteP(++CAR, br); | |
br = ReadP(++BAR) & 017; | |
} | |
while(CAR != 297) /* Zero fill rest */ | |
WriteP(++CAR, 10); | |
SetBit(297, ReadP(279) & 060); /* Copy sign */ | |
break; | |
case CHR_D: /* D - Floating div */ | |
temp = oind; | |
oind = 0; | |
reason = do_addsub(1); | |
BAR = 299; | |
ch = oind; | |
sign = do_addint(1); /* Add 1 to exp */ | |
oind = temp; | |
if (reason != SCPE_OK) | |
break; | |
CAR = AAR; | |
br = ReadP(BAR--); | |
ar = ReadP(AAR); | |
DownReg(AAR); | |
/* Scan for B word mark */ | |
qsign = 1; | |
zind = 1; | |
while (1) { | |
if ((ar & 017) != 10) | |
qsign = 0; | |
if ((br & 017) != 10) | |
zind = 0; | |
if (br & WM || BAR == 279) | |
break; | |
if (ar & WM || AAR == 0) | |
break; | |
br = ReadP(BAR--); | |
ar = ReadP(AAR); | |
DownReg(AAR); | |
sim_interval -= 4; | |
}; | |
/* Are fractions same size? */ | |
if ((br & WM) && (ar & WM) == 0) | |
goto zerofacc; | |
/* Is A zero? */ | |
if (qsign) { | |
if (ch || sign) { | |
eoind = 1; | |
} | |
dind = 1; | |
break; | |
} | |
/* Copy B to work area and fill zeros for A size */ | |
DAR = 279; | |
br = ReadP(297); | |
/* Set sign */ | |
WriteP(DAR--, (br & 060) | 10); | |
sim_interval -= 2; | |
/* Zero remainder area */ | |
for(i = 297 - BAR; i > 1; i--) { | |
WriteP(DAR--, 10); | |
sim_interval -= 2; | |
} | |
/* Save unit position */ | |
temp = DAR; | |
/* Copy accumulator to work */ | |
BAR = 297; | |
br = ReadP(BAR--); | |
sim_interval -= 2; | |
while(1) { | |
WriteP(DAR--, br & 017); | |
if (br & WM) | |
break; | |
br = ReadP(BAR--); | |
sim_interval -= 2; | |
} | |
/* Two extra zeros */ | |
WriteP(DAR--, 10); | |
WriteP(DAR--, 10); | |
/* Set up for divide */ | |
BAR = temp; | |
temp = DAR; | |
/* Check for error conditions */ | |
if (zind) { | |
if (ch) | |
goto undfacc; | |
goto zerofacc; | |
} | |
if (sign) { | |
eoind = 1; | |
break; | |
} | |
if (ch) | |
goto undfacc; | |
AAR = CAR; | |
/* Do actual divide */ | |
reason = do_divide(); | |
if (reason != 0) | |
break; | |
/* Scan backward for word mark */ | |
qsign = ReadP(BAR+1); | |
sim_interval -= 2; | |
/* Count number of leading zeros */ | |
ix = 0; | |
DAR = BAR+2; | |
CAR = temp+1; /* restore address */ | |
while (CAR != 280) { | |
br = ReadP(CAR); | |
sim_interval -= 2; | |
if ((br & 017) != 10) | |
break; | |
CAR++; | |
ix++; | |
} | |
/* Adjust exponent if any leading zeros */ | |
if (ix != 0) { | |
BAR = 299; | |
if (do_addint(-ix)) | |
goto undfacc; | |
} | |
/* Find end of result */ | |
BAR = 297; | |
ar = ReadP(BAR--); | |
while((ar & WM) == 0) | |
ar = ReadP(BAR--); | |
temp = BAR; | |
br = (br & 017) | WM; | |
/* Copy result */ | |
while(BAR != 297 && CAR != DAR) { | |
WriteP(++BAR, br); | |
br = ReadP(++CAR) & 017; | |
sim_interval -= 4; | |
} | |
while(BAR != 297) | |
WriteP(++BAR, 10); | |
SetBit(297, qsign & 060); | |
BAR = temp; | |
break; | |
} | |
break; | |
case OP_STS: /* Store CPU Status */ | |
/* Check if over the top */ | |
ValidAddr(AAR); | |
BAR = AAR; | |
ch = 0; | |
switch(op_mod) { | |
/* Restore channel status */ | |
case CHR_1: /* 1 */ | |
ch = 1; | |
break; | |
case CHR_2: /* 2 */ | |
ch = 2; | |
break; | |
case CHR_3: /* 3 */ | |
ch = 3; | |
break; | |
case CHR_4: /* 4 */ | |
ch = 4; | |
break; | |
/* Store channel status */ | |
case CHR_E: /* E - 1 */ | |
ch = 011; | |
break; | |
case CHR_F: /* F - 2 */ | |
ch = 012; | |
break; | |
case CHR_G: /* G - 3 */ | |
ch = 013; | |
break; | |
case CHR_H: /* H - 4 */ | |
ch = 014; | |
break; | |
/* Store CPU Status */ | |
case CHR_S: /* S store */ | |
br = 0; | |
ch = 0; | |
switch (cind) { | |
case 2: br |= 1; break; | |
case 4: br |= 2; break; | |
case 1: br |= 4; break; | |
} | |
if (zind) | |
br |= 8; | |
if (oind) | |
br |= 16; | |
if (dind) | |
br |= 32; | |
WriteP(BAR, br); | |
DownReg(BAR); | |
break; | |
/* Restore CPU Status */ | |
case CHR_R: /* R restore */ | |
br = ReadP(BAR); | |
DownReg(BAR); | |
ch = 0; | |
oind = (br & 32)?1:0; | |
dind = (br & 16)?1:0; | |
zind = (br & 8)?1:0; | |
cind = (br & 1)?2:0; | |
cind = (br & 2)?4:cind; | |
cind = (br & 4)?1:cind; | |
break; | |
/* Protected mode store */ | |
case CHR_P: /* P */ | |
if (cpu_unit.flags & OPTION_PROT) { | |
if (prot_enb /*|| reloc != 0*/) { /* Abort */ | |
reason = STOP_PROG; | |
sim_debug(DEBUG_DETAIL, &cpu_dev, "High set in prot mode\n"); | |
} else { | |
temp = bcd_bin[ReadP(BAR) & 017]; | |
DownReg(BAR); | |
temp += 10 * bcd_bin[ReadP(BAR) & 017]; | |
DownReg(BAR); | |
high_addr = 1000 * temp; | |
sim_debug(DEBUG_DETAIL, &cpu_dev, "High set to %d\n", high_addr); | |
} | |
} | |
break; | |
case CHR_QUEST: /* ? - 3*/ | |
if (cpu_unit.flags & OPTION_PROT) { | |
if (prot_enb || reloc != 0) { /* Abort */ | |
reason = STOP_PROG; | |
sim_debug(DEBUG_DETAIL, &cpu_dev, "Low set in prot mode\n"); | |
} else { | |
temp = bcd_bin[ReadP(BAR) & 017]; | |
DownReg(BAR); | |
temp += 10 * bcd_bin[ReadP(BAR) & 017]; | |
DownReg(BAR); | |
low_addr = 1000 * temp; | |
sim_debug(DEBUG_DETAIL, &cpu_dev, "Low set to %d\n", low_addr); | |
} | |
} | |
break; | |
default: | |
reason = STOP_UUO; | |
break; | |
} | |
if (ch) { | |
/* Wait for channel idle before operate */ | |
while (chan_active(ch & 07) && reason == 0) { | |
sim_interval = 0; | |
reason = sim_process_event(); | |
chan_proc(); | |
} | |
/* Do load or store channel */ | |
if (ch & 010) | |
WriteP(BAR, chan_io_status[ch & 07] & 0277); | |
else | |
chan_io_status[ch] = ReadP(BAR) & 077; | |
DownReg(BAR); | |
} | |
break; | |
/* Priority mode operations */ | |
case OP_PRI: | |
jump = 0; | |
switch(op_mod) { | |
case CHR_U: /* U branch if ch 1 i-o unit priority */ | |
jump = urec_irq[1]; | |
urec_irq[1] = 0; | |
break; | |
case CHR_F: /* F branch if ch 2 i-o unit priority */ | |
jump = urec_irq[2]; | |
urec_irq[2] = 0; | |
break; | |
case CHR_1: /* 1 branch if ch 1 overlap priority */ | |
if (chan_irq_enb[1]) | |
jump = (chan_io_status[1] & 0300) == 0300; | |
break; | |
case CHR_2: /* 2 branch if ch 2 overlap priority */ | |
if (chan_irq_enb[2]) | |
jump = (chan_io_status[2] & 0300) == 0300; | |
break; | |
case CHR_3: /* 3 branch if ch 3 overlap priority */ | |
if (chan_irq_enb[3]) | |
jump = (chan_io_status[3] & 0300) == 0300; | |
break; | |
case CHR_4: /* 4 branch if ch 4 overlap priority */ | |
if (chan_irq_enb[4]) | |
jump = (chan_io_status[4] & 0300) == 0300; | |
break; | |
case CHR_Q: /* Q branch if inquiry ch 1 */ | |
jump = inquiry; | |
break; | |
case CHR_LBRK: /* * branch if inquiry ch 2 */ | |
break; | |
case CHR_N: /* N branch if outquiry ch 1 */ | |
break; | |
case CHR_TRM: /* rm branch if outquiry ch 2 */ | |
break; | |
case CHR_S: /* S branch if seek priority ch 1 */ | |
jump = chan_seek_done[1]; | |
chan_seek_done[1] = 0; | |
break; | |
case CHR_T: /* T branch if seek priority ch 2 */ | |
jump = chan_seek_done[2]; | |
chan_seek_done[2] = 0; | |
break; | |
case CHR_Y: /* Y branch if seek priority ch 3 */ | |
jump = chan_seek_done[3]; | |
chan_seek_done[3] = 0; | |
break; | |
case CHR_RPARN: /* ) branch if seek priority ch 4 */ | |
jump = chan_seek_done[4]; | |
chan_seek_done[4] = 0; | |
break; | |
case CHR_X: /* X branch and exit */ | |
pri_enb = 0; | |
sim_debug(DEBUG_PRIO, &cpu_dev, "dis irq\n"); | |
jump = 1; | |
break; | |
case CHR_E: /* E branch and enter */ | |
pri_enb = 1; | |
sim_debug(DEBUG_PRIO, &cpu_dev, "enb irq\n"); | |
jump = 1; | |
break; | |
case CHR_A: /* A branch if ch1 attention */ | |
jump = chan_stat(1, SNS_ATTN1); | |
break; | |
case CHR_B: /* B branch if ch2 attention */ | |
jump = chan_stat(2, SNS_ATTN1); | |
break; | |
case CHR_C: /* C branch if ch3 attention */ | |
jump = chan_stat(3, SNS_ATTN1); | |
break; | |
case CHR_D: /* D branch if ch4 attention */ | |
jump = chan_stat(4, SNS_ATTN1); | |
break; | |
/* Protection mode operations */ | |
case CHR_QUEST: /* ? Enable protection mode */ | |
if (cpu_unit.flags & OPTION_PROT) { | |
sim_debug(DEBUG_DETAIL, &cpu_dev, | |
"Prot enter %d\n", AAR & AMASK); | |
/* If in protect mode, abort */ | |
if (prot_enb) { | |
reason = STOP_PROG; | |
} else { | |
/* Else enter protected mode */ | |
prot_enb = 1; | |
prot_fault = 0; | |
jump = 1; | |
} | |
} | |
break; | |
case CHR_9: /* 9 Leave Prot mode */ | |
if (cpu_unit.flags & OPTION_PROT) { | |
sim_debug(DEBUG_DETAIL, &cpu_dev, | |
"Leave Protect mode %d %d %d\n", | |
AAR & AMASK, prot_enb, reloc); | |
/* If in protect mode, abort */ | |
if ((prot_enb /*|| reloc*/) /*&& (AAR & BBIT) == 0*/) { | |
reason = STOP_PROG; | |
} else { | |
/* Test protect mode */ | |
if (reloc && (AAR & BBIT) == 0) { | |
reason = STOP_PROG; | |
} else { | |
jump = 1; | |
prot_enb = 0; | |
reloc = 0; | |
high_addr = -1; | |
low_addr = -1; | |
} | |
} | |
} | |
break; | |
case CHR_P: /* P Check Protection faults */ | |
if (cpu_unit.flags & OPTION_PROT) { | |
/* If in protect mode, abort */ | |
sim_debug(DEBUG_DETAIL, &cpu_dev, | |
"Check protect fault %d %d\n", | |
AAR, prot_fault&1); | |
if (prot_enb) { | |
reason = STOP_PROG; | |
} else { | |
jump = prot_fault & 1; | |
prot_fault &= 2; /* Clear fault */ | |
} | |
} | |
break; | |
case CHR_H: /* H Test for Prog faults */ | |
if (cpu_unit.flags & OPTION_PROT) { | |
sim_debug(DEBUG_DETAIL, &cpu_dev, | |
"Check prog fault %d %d\n", | |
AAR, prot_fault&2); | |
/* If in protect mode, abort */ | |
if (prot_enb) { | |
reason = STOP_PROG; | |
} else { | |
jump = prot_fault & 2; | |
prot_fault &= 1; /* Clear fault */ | |
} | |
} | |
break; | |
case CHR_SLSH: /* Enable relocation - mode */ | |
if (cpu_unit.flags & OPTION_PROT) { | |
/* If in protect mode, abort */ | |
sim_debug(DEBUG_DETAIL, &cpu_dev, | |
"Enable relocation %d\n", | |
AAR & AMASK); | |
if (prot_enb) { | |
reason = STOP_PROG; | |
} else { | |
reloc = 1; | |
prot_fault = 0; | |
BAR = IAR; | |
IAR = AAR; | |
if ((IAR & BBIT) == 0 && low_addr >= 0) { | |
if (IAR < low_addr) | |
IAR += 100000 - low_addr; | |
else | |
IAR -= low_addr; | |
} | |
/* Fix BAR for correct return address */ | |
if ((BAR & BBIT) == 0 && low_addr >= 0) { | |
if (BAR < low_addr) | |
BAR += 100000 - low_addr; | |
else | |
BAR -= low_addr; | |
} | |
AAR = BAR; | |
} | |
} | |
break; | |
case CHR_DOL: /* Enable relocation + prot mode */ | |
if (cpu_unit.flags & OPTION_PROT) { | |
/* If in protect mode, abort */ | |
sim_debug(DEBUG_DETAIL, &cpu_dev, | |
"Enable relocation + prot %d\n", | |
AAR & AMASK); | |
if (prot_enb) { | |
reason = STOP_PROG; | |
} else { | |
prot_enb = 1; | |
reloc = 1; | |
prot_fault = 0; | |
BAR = IAR; | |
IAR = AAR; | |
if ((IAR & BBIT) == 0 && low_addr >= 0) { | |
if (IAR < low_addr) | |
IAR += 100000 - low_addr; | |
else | |
IAR -= low_addr; | |
} | |
/* Fix BAR for correct return address */ | |
if ((BAR & BBIT) == 0 && low_addr >= 0) { | |
if (BAR < low_addr) | |
BAR += 100000 - low_addr; | |
else | |
BAR -= low_addr; | |
} | |
AAR = BAR; | |
} | |
} | |
break; | |
case CHR_I: /* I ???? */ | |
if (cpu_unit.flags & OPTION_PROT) { | |
sim_debug(DEBUG_DETAIL, &cpu_dev, | |
"Prot opcode %02o %d\n", op_mod, AAR); | |
} | |
break; | |
case CHR_GM: /* | timer release? */ | |
if (cpu_unit.flags & OPTION_PROT) { | |
jump = timer_irq; | |
timer_irq &= 1; | |
sim_debug(DEBUG_DETAIL, &cpu_dev, | |
"Timer release %d\n", jump); | |
} | |
break; | |
case CHR_QUOT: /* ' Turn on 20ms timer */ | |
if (cpu_unit.flags & OPTION_PROT) { | |
timer_enable = 1; | |
timer_interval = 10; | |
timer_irq = 0; | |
sim_debug(DEBUG_DETAIL, &cpu_dev, "Timer start\n"); | |
} | |
jump = 1; | |
break; | |
case CHR_DOT: /* . Turn off 20ms timer */ | |
jump = 1; | |
if (cpu_unit.flags & OPTION_PROT) { | |
timer_enable = 0; | |
timer_irq = 0; | |
sim_debug(DEBUG_DETAIL, &cpu_dev, "Timer stop\n"); | |
} | |
break; | |
} | |
break; | |
} | |
/* Do a jump to new location. */ | |
if (jump) { | |
BAR = IAR; /* Save current for posterity */ | |
IAR = AAR & AMASK; | |
} | |
if (hst_lnt) { /* History enabled? */ | |
int len, start; | |
hst[hst_p].aend = AAR; | |
hst[hst_p].bend = BAR; | |
len = hst[hst_p].bend - hst[hst_p].bstart; | |
if (len < 0) { | |
len = -len; | |
start = hst[hst_p].bend + 1; | |
if (len > 50) { | |
start = hst[hst_p].bstart - 50; | |
len = 50; | |
} | |
} else { | |
if (len > 50) | |
len = 50; | |
start = hst[hst_p].bstart; | |
} | |
if (jump) { | |
len = 0; | |
start = hst[hst_p].bstart; | |
} | |
for(i = 0; i < len; i++) | |
hst[hst_p].bdata[i] = ReadP(start+i); | |
hst[hst_p].dlen = len; | |
} | |
} | |
/* Handle protection faults */ | |
check_prot: | |
if (fault) { | |
reason = fault; | |
fault = 0; | |
} | |
if (reason != 0 && cpu_unit.flags & OPTION_PROT && (prot_enb || reloc != 0)) { | |
switch(reason) { | |
case STOP_NOWM: | |
sim_debug(DEBUG_DETAIL, &cpu_dev, | |
"IAR = %d No WM AAR=%d BAR=%d\n", IAR, AAR, BAR); | |
prot_fault |= 2; | |
reason = 0; | |
break; | |
case STOP_INVADDR: | |
sim_debug(DEBUG_DETAIL, &cpu_dev, | |
"IAR = %d Inv Addr AAR=%d BAR=%d\n", IAR, AAR, BAR); | |
prot_fault |= 2; | |
reason = 0; | |
break; | |
case STOP_UUO: | |
sim_debug(DEBUG_DETAIL, &cpu_dev, | |
"IAR = %d Inv Op AAR=%d BAR=%d\n", IAR, AAR, BAR); | |
prot_fault |= 2; | |
reason = 0; | |
break; | |
case STOP_INVLEN: | |
sim_debug(DEBUG_DETAIL, &cpu_dev, | |
"IAR = %d Invlen Op AAR=%d BAR=%d\n", IAR, AAR, BAR); | |
prot_fault |= 2; | |
reason = 0; | |
break; | |
case STOP_IOCHECK: | |
sim_debug(DEBUG_DETAIL, &cpu_dev, | |
"IAR = %d I/O Check AAR=%d BAR=%d\n", IAR, AAR, BAR); | |
prot_fault |= 2; | |
reason = 0; | |
break; | |
case STOP_PROG: | |
sim_debug(DEBUG_DETAIL, &cpu_dev, | |
"IAR = %d Prog check AAR=%d BAR=%d low=%d high=%d\n", | |
IAR, AAR, BAR, low_addr, high_addr); | |
prot_fault |= 2; | |
reason = 0; | |
break; | |
case STOP_PROT: | |
sim_debug(DEBUG_DETAIL, &cpu_dev, | |
"IAR = %d Prot check AAR=%d BAR=%d low=%d high=%d\n", | |
IAR, AAR, BAR, low_addr, high_addr); | |
prot_fault |= 1; | |
reason = 0; | |
break; | |
default: /* Anything else halt sim */ | |
break; | |
} | |
/* If faults, B 8, otherwise stop sim */ | |
if (prot_fault && reason == 0) { | |
prot_enb = 0; | |
high_addr = -1; | |
low_addr = -1; | |
reloc = 0; | |
BAR = IAR; /* Save current for posterity */ | |
IAR = AAR = 8; | |
} | |
} | |
if (instr_count != 0 && --instr_count == 0) | |
return SCPE_STEP; | |
} /* end while */ | |
/* Simulation halted */ | |
return reason; | |
} | |
#define UpAddr(reg) reg++; if ((reg & AMASK) == MEMSIZE) { \ | |
return STOP_INVADDR; } | |
#define DownAddr(reg) if ((reg & AMASK) == 0) { \ | |
return STOP_INVADDR; } else { reg--; } | |
/* Add constant, two digits only, used by FP code */ | |
int do_addint(int val) { | |
uint8 br; | |
int sign; | |
uint8 ch; | |
int cy; | |
br = ReadP(BAR); | |
sign = (br & 060) == 040; | |
if (val < 0) { | |
sign = !sign; | |
val = -val; | |
} | |
cy = sign; | |
ch = val % 10; | |
ch = bcd_bin[br& 0xf] + (sign?(9-ch):ch) + cy; | |
cy = ch > 9; /* Update carry */ | |
ch = bin_bcd[ch]; | |
WriteP(BAR--, (br & 060) | ch); | |
br = ReadP(BAR); | |
ch = val / 10; | |
ch = bcd_bin[br& 0xf] + (sign?(9-ch):ch) + cy; | |
cy = ch > 9; /* Update carry */ | |
ch = bin_bcd[ch]; | |
WriteP(BAR--, WM | (br & 060) | ch); | |
sim_interval -= 2; | |
if (sign && cy == 0) { | |
BAR += 2; /* Back up */ | |
br = ReadP(BAR); | |
sim_interval -= 2; | |
if ((br & 060) == 040) | |
br |= 060; | |
else { | |
br &= ~020; /* Switch B sign */ | |
br |= 040; | |
} | |
cy = 1; | |
/* Compliment until B word mark */ | |
ch = (9 - bcd_bin[br& 0xf]) + cy; | |
cy = ch > 9; /* Update carry */ | |
ch = bin_bcd[ch]; | |
WriteP(BAR--, (br & 0360) | ch); | |
sim_interval -= 2; | |
br = ReadP(BAR); | |
ch = (9 - bcd_bin[br& 0xf]) + cy; | |
cy = ch > 9; /* Update carry */ | |
ch = bin_bcd[ch]; | |
WriteP(BAR--, (br & 0360) | ch); | |
} | |
if (sign == 0 && cy) | |
return 1; | |
return 0; | |
} | |
t_stat do_addsub(int mode) { | |
uint8 br; | |
uint8 ar; | |
int sign; | |
uint8 ch; | |
int cy; | |
uint32 STAR; | |
DAR = BAR; | |
ar = ReadP(AAR); | |
br = ReadP(STAR = BAR); | |
sim_interval -= 2; | |
DownAddr(AAR); | |
DownAddr(BAR); | |
if (mode) /* Subtraction */ | |
sign = (ar & 060) != 040; | |
else /* Addition */ | |
sign = (ar & 060) == 040; | |
zind = 1; | |
if ((br & 060) == 040) | |
sign ^= 1; | |
cy = sign; | |
if (CPU_MODEL == 1 && sign) | |
br |= ((br & 060) != 040)?060:0; | |
/* Add until word mark on A or B */ | |
while(1) { | |
ch = bcd_bin[ar & 0xf]; | |
ch = bcd_bin[br & 0xf] + ((sign)? (9 - ch):ch) + cy; | |
cy = ch > 9; /* Update carry */ | |
ch = bin_bcd[ch]; | |
if (ch != CHR_0) /* Clear zero */ | |
zind = 0; | |
WriteP(STAR, (br & 0360) | ch); | |
if (br & WM) { | |
if (CPU_MODEL == 1 && !sign && cy) | |
WriteP(STAR, | |
WM | ch |(060&(br + 020))); | |
break; | |
} | |
if (ar & WM) | |
ar = WM|CHR_0; | |
else { | |
sim_interval--; | |
ar = ReadP(AAR); | |
DownAddr(AAR); | |
} | |
sim_interval--; | |
br = ReadP(STAR = BAR); | |
DownAddr(BAR); | |
if (CPU_MODEL == 1) { | |
if ((br & WM) == 0 || sign) | |
br &= WM | 0xf; | |
} | |
} | |
/* If cy and qsign, tens-compliment result and flip sign */ | |
if (sign && cy == 0) { | |
STAR = BAR = DAR; | |
br = ReadP(BAR); | |
DownAddr(BAR); | |
sim_interval--; | |
if ((br & 060) == 040) | |
br |= 060; | |
else { | |
br &= ~020; /* Switch B sign */ | |
br |= 040; | |
} | |
zind = 1; | |
cy = 1; | |
/* Compliment until B word mark */ | |
while(1) { | |
ch = (9 - bcd_bin[br& 0xf]) + cy; | |
cy = ch > 9; /* Update carry */ | |
ch = bin_bcd[ch]; | |
if (ch != CHR_0) /* Clear zero */ | |
zind = 0; | |
WriteP(STAR, (br & 0360) | ch); | |
if (br & WM) | |
break; | |
br = ReadP(STAR = BAR); | |
DownAddr(BAR); | |
sim_interval--; | |
if (CPU_MODEL == 1) | |
br &= WM|0xf; | |
} | |
} | |
/* If carry set overflow */ | |
if (sign == 0 && cy) | |
oind = 1; | |
return SCPE_OK; | |
} | |
t_stat | |
do_mult() | |
{ | |
uint8 br; | |
uint8 ar; | |
int sign; | |
uint8 ch; | |
int cy; | |
CAR = AAR; | |
DAR = BAR; | |
ar = ReadP(AAR); | |
DownAddr(AAR); | |
zind = 1; | |
sign = ((ar & 060) == 040); | |
/* Scan A for word mark setting B digits to zero */ | |
while (1) { | |
WriteP(BAR, 10); | |
sim_interval -= 4; | |
DownAddr(BAR); | |
if (ar & WM) | |
break; | |
ar = ReadP(AAR); | |
DownAddr(AAR); | |
}; | |
/* Skip last digit of product */ | |
WriteP(BAR, 10); | |
DownAddr(BAR); | |
sim_interval -= 2; | |
/* Check signs of B and A. */ | |
br = ReadP(BAR); | |
/* Compute sign */ | |
sign ^= ((br & 060) == 040); | |
sign = (sign)?040:060; | |
/* Do multiple loop until B word mark */ | |
while(1) { | |
/* Interloop, multiply one digit */ | |
ch = bcd_bin[br & 0xf]; | |
while (ch != 0) { | |
WriteP(BAR, bin_bcd[ch - 1] | (br & WM)); | |
BAR = DAR; | |
br = ReadP(BAR); | |
cy = 0; | |
AAR = CAR; | |
ar = ReadP(AAR); | |
DownAddr(AAR); | |
while(1) { | |
ch = bcd_bin[br & 0xf]; | |
ch = bcd_bin[ar & 0xf] + ch + cy; | |
if (ch != 0) /* Clear zero */ | |
zind = 0; | |
cy = ch > 9; /* Update carry */ | |
WriteP(BAR, bin_bcd[ch] | (br & WM)); | |
DownAddr(BAR); | |
br = ReadP(BAR); | |
if (ar & WM) | |
break; | |
ar = ReadP(AAR); | |
DownAddr(AAR); | |
sim_interval -= 4; | |
} | |
/* Add carry to next digit */ | |
ch = bcd_bin[br & 0xf] + cy; | |
if (ch != 0) /* Clear zero */ | |
zind = 0; | |
sim_interval -= 2; | |
WriteP(BAR, bin_bcd[ch] | (br & WM)); | |
DownAddr(BAR); | |
br = ReadP(BAR); | |
ch = bcd_bin[br & 0xf]; | |
} | |
WriteP(BAR, CHR_0 | (br & WM)); | |
DownAddr(BAR); | |
SetBit(DAR, sign); | |
DownAddr(DAR); | |
sign = 0; /* Only on first digit */ | |
if (br & WM) | |
break; | |
br = ReadP(BAR); | |
} | |
return SCPE_OK; | |
} | |
t_stat | |
do_divide() | |
{ | |
uint16 t; | |
int temp; | |
uint8 br; | |
uint8 ar; | |
int sign, qsign; | |
uint8 ch; | |
int cy; | |
qsign = 9; /* Set compliment and carry in */ | |
cy = 1; | |
temp = 0; /* MDL latch */ | |
sign = 0; | |
CAR = AAR; | |
DAR = BAR; | |
while (1) { | |
AAR = CAR; | |
BAR = DAR; | |
ar = ReadP(AAR); | |
DownAddr(AAR); | |
br = ReadP(BAR); | |
if (qsign == 0 && br & 040) { | |
sign = ((ar & 060) == 040); /* Compute sign */ | |
sign ^= ((br & 060) == 040); | |
sign = (sign)?040:060; | |
temp = 1; /* Set last cycle */ | |
} | |
while (1) { | |
sim_interval -= 4; | |
t = bcd_bin[ar& 0xf]; | |
ch = ((qsign)?(9-t):t) + bcd_bin[br & 0xf] + cy; | |
cy = ch > 9; /* Update carry */ | |
ReplaceMask(BAR, bin_bcd[ch], 017); | |
DownAddr(BAR); | |
br = ReadP(BAR); | |
sim_interval -= 2; | |
if (ar & WM) { | |
ch = qsign + bcd_bin[br & 0xf] + cy; | |
cy = ch > 9; /* Update carry */ | |
ReplaceMask(BAR, bin_bcd[ch], 017); | |
DownAddr(BAR); | |
br = ReadP(BAR); | |
sim_interval -= 2; | |
break; | |
} else { | |
ar = ReadP(AAR); | |
DownAddr(AAR); | |
} | |
} | |
if (qsign == 9) { | |
if (cy) { | |
ch = bcd_bin[br & 0xf] + cy; | |
ReplaceMask(BAR, bin_bcd[ch], 017); | |
DownAddr(BAR); | |
if (ch > 9) { | |
if (CPU_MODEL == 1) | |
oind = 1; | |
else | |
dind = 1; | |
break; | |
} | |
} else { | |
qsign = 0; | |
} | |
} else { | |
if (temp) { | |
ch = 9 + bcd_bin[br & 0xf] + cy; | |
WriteP(BAR, bin_bcd[ch] | sign | (br & WM)); | |
DownAddr(BAR); | |
break; | |
} | |
qsign = 9; | |
cy = 1; | |
UpAddr(DAR); /* Back up one digit */ | |
} | |
} | |
return SCPE_OK; | |
} | |
/* Interval timer routines */ | |
t_stat | |
rtc_srv(UNIT * uptr) | |
{ | |
int32 t; | |
t = sim_rtcn_calb (rtc_tps, TMR_RTC); | |
sim_activate_after(uptr, 1000000/rtc_tps); | |
if (timer_enable) { | |
if (--timer_interval == 0) { | |
timer_irq |= 1; | |
timer_interval = 10; | |
} | |
} | |
return SCPE_OK; | |
} | |
/* Reset routine */ | |
t_stat | |
cpu_reset(DEVICE * dptr) | |
{ | |
IAR = 1; | |
AAR = 0; | |
BAR = 0; | |
sim_brk_types = sim_brk_dflt = SWMASK('E'); | |
pri_enb = 0; | |
timer_enable = 0; | |
cind = 2; | |
zind = oind = dind = euind = eoind = 0; | |
if (cpu_unit.flags & OPTION_PROT) | |
sim_rtcn_init_unit (&cpu_unit, 10000, TMR_RTC); | |
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 | WM); | |
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 | WM); | |
return SCPE_OK; | |
} | |
t_stat | |
cpu_set_size(UNIT * uptr, int32 val, CONST char *cptr, void *desc) | |
{ | |
uint8 mc = 0; | |
int32 i; | |
int32 v; | |
v = val >> UNIT_V_MSIZE; | |
v++; | |
v *= 10000; | |
if ((v < 0) || (v > MAXMEMSIZE)) | |
return SCPE_ARG; | |
for (i = v-1; i < MAXMEMSIZE; i++) | |
mc |= M[i]; | |
if ((mc != 0) && (!get_yn("Really truncate memory [N]?", FALSE))) | |
return SCPE_OK; | |
cpu_unit.capac = v; | |
cpu_unit.flags &= ~UNIT_MSIZE; | |
cpu_unit.flags |= val; | |
for (i = MEMSIZE; i < MAXMEMSIZE; i++) | |
M[i] = 0; | |
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, i, di, lnt, pc; | |
char *cptr = (char *) desc; | |
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 A B Aend Bend \n"); | |
for (k = 0; k < lnt; k++) { /* print specified */ | |
h = &hst[(++di) % hst_lnt]; /* entry pointer */ | |
if (h->ic & HIST_PC) { /* instruction? */ | |
pc = h->ic & HIST_MSK; | |
fprintf(st, "%05d ", pc); | |
fprintf(st, "%05d ", h->astart & AMASK); | |
fprintf(st, "%05d ", h->bstart & AMASK); | |
fprintf(st, "%05d%c", h->aend & AMASK, (h->aend & BBIT)?'+':' '); | |
fprintf(st, "%05d%c|", h->bend & AMASK, (h->bend & BBIT)?'+':' '); | |
for(i = 0; i < h->dlen; i++) | |
fputc(mem_to_ascii[h->bdata[i]&077], st); | |
fputc('|', st); | |
fputc(' ', st); | |
for(i = 0; i< 15; i++) | |
sim_eval[i] = h->inst[i]; | |
(void)fprint_sym(st, pc, sim_eval, &cpu_unit, SWMASK((h->ic & HIST_1401)?'N':'M')); | |
fputc('\n', st); /* end line */ | |
} /* end else instruction */ | |
} /* end for */ | |
return SCPE_OK; | |
} | |
const char * | |
cpu_description (DEVICE *dptr) | |
{ | |
return "IBM 7010 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 1401 or IBM 1410/7010\n"); | |
fprintf (st, "The type of CPU can be set by one of the following commands\n\n"); | |
fprintf (st, " sim> set CPU 1401 sets IBM 1401 emulation\n"); | |
fprintf (st, " sim> set CPU 7010 sets IBM 1410/7010 emulation\n\n"); | |
fprintf (st, "These switches are recognized when examining or depositing in CPU memory:\n\n"); | |
fprintf (st, " -c examine/deposit characters, 6 per word\n"); | |
fprintf (st, " -l examine/deposit half words\n"); | |
fprintf (st, " -m examine/deposit IBM 7010 instructions\n\n"); | |
fprintf (st, "The memory of the CPU can be set in 10K incrememts from 10K to 100K with the\n\n"); | |
fprintf (st, " sim> SET CPU xK\n\n"); | |
fprintf (st, "For the IBM 7010 the following options can be enabled\n\n"); | |
fprintf (st, " sim> SET CPU PRIORITY enables Priority Interupts\n"); | |
fprintf (st, " sim> SET CPU NOPRIORITY disables Priority Interupts\n\n"); | |
fprintf (st, " sim> SET CPU FLOAT enables Floating Point\n"); | |
fprintf (st, " sim> SET CPU NOFLOAT disables Floating Point\n\n"); | |
fprintf (st, " sim> SET CPU PROT enables memory protection feature\n"); | |
fprintf (st, " sim> SET CPU NOPROT disables memory protection feature\n\n"); | |
fprintf (st, "The CPU can maintain a history of the most recently executed instructions.\n"); | |
fprintf (st, "This is controlled by the SET CPU HISTORY and SHOW CPU HISTORY commands:\n\n"); | |
fprintf (st, " sim> SET CPU HISTORY clear history buffer\n"); | |
fprintf (st, " sim> SET CPU HISTORY=0 disable history\n"); | |
fprintf (st, " sim> SET CPU HISTORY=n{:file} enable history, length = n\n"); | |
fprintf (st, " sim> SHOW CPU HISTORY print CPU history\n"); | |
fprint_set_help(st, dptr); | |
fprint_show_help(st, dptr); | |
return SCPE_OK; | |
} | |