These include simulators for the IBM 701, IBM 702, IBM 704, IBM 705, IBM 705/3, IBM 709, IBM 1410/IBM 7010, IBM 7070, IBM 7080, IBM 7090 and IBM7094. These basically were a collection of machines that shared a common set it peripherals, Each group had its own instruction set, hence different simulators. IBM 701 -> i701 IBM 702/705/705/3/7080 -> i7080 IBM 7070/7074 -> i7070 IBM 1410/7010 -> i7010 IBM 704 -> i704 IBM 704/709/7090/7094 -> i7090 The i7090 can be set to simulate a IBM 704 however you end up disabling almost everything, since the 704 did not have any channels. A build option exists that allows this one to be built without all the extra features. The i7090 simulator’s implementation of the IBM 7094 is a more complete implementation of the IBM 7094 which can run CTSS while the existing simh I7094 can’t.
3957 lines
156 KiB
C
3957 lines
156 KiB
C
/* 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;
|
||
}
|
||
|