mirror of
https://github.com/simh/simh.git
synced 2026-02-18 21:38:16 +00:00
Notes For V2.9-11
1. New Features 1.1 GRI-909 - This is a new simulator for the GRI-909. - It has been hand-tested; so far, no software has been discovered. 1.2 VAX - SET CPU CONHALT will cause a HALT instruction to return to the boot ROM console rather than to SIMH. SET CPU SIMHALT restores the default behavior. - BRB/W self at IPL 1F stops the simulator. This is the default behavior of VMS at exit. 1.3 PDP-18b - ATTACH -A PTR/PTP attaches the reader and punch in ASCII mode. In ASCII mode, the reader automatically sets the high order bit of incoming alphabetic data, and the punch clears the high order bit of outgoing data. 1.4 SCP - DO -V echoes commands from the file as they are executed. - Under Windows, execution priority is set BELOW_NORMAL when the simulator is running. 2. Release Notes 2.1 Bugs Fixed - PDP-11 CPU: fixed updating of MMR0 on a memory management error. - VAX FPA: changed function names to avoid conflict with C math library. - 1401 MT: read end of record generates group mark without word mark. - 1401 DP: fixed address generation and checking. - SCP: an EXIT within a DO command will cause the simulator to exit. 3. In Progress - Interdata 16b/32b: coded, not tested. - SDS 940: coded, not tested. - IBM 1620: coded, not tested. If you would like to help with the debugging of the untested simulators, they can be made available by special request.
This commit is contained in:
committed by
Mark Pizzolato
parent
701f0fe028
commit
df6475181c
885
GRI/gri_cpu.c
Normal file
885
GRI/gri_cpu.c
Normal file
@@ -0,0 +1,885 @@
|
||||
/* gri_cpu.c: GRI-909 CPU simulator
|
||||
|
||||
Copyright (c) 2001-2002, Robert M. Supnik
|
||||
|
||||
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
|
||||
ROBERT M SUPNIK 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.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
The system state for the GRI-909 is:
|
||||
|
||||
AX<0:15> arithmetic input
|
||||
AY<0:15> arithmetic input
|
||||
BSW<0:15> byte swapper
|
||||
BPK<0:15> byte packer
|
||||
GR[0:5]<0:15> extended general registers
|
||||
MSR<0:15> machine status register
|
||||
TRP<0:15> trap register (subroutine return)
|
||||
SC<0:14> sequence counter
|
||||
|
||||
The GRI-909 has, nominally, just one instruction format: move.
|
||||
|
||||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| source | op | destination | move
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
|
||||
<6:9> operation
|
||||
|
||||
xx1x complement
|
||||
01xx add 1
|
||||
10xx rotate left 1
|
||||
11xx rotate right 1
|
||||
|
||||
In fact, certain of the source and destination operators have side
|
||||
effects, yielding four additional instruction formats: function out,
|
||||
skip on function, memory reference, and conditional jump.
|
||||
*/
|
||||
|
||||
/* The function out format is:
|
||||
|
||||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| 0 0 0 0 1 0| pulse | destination | function out
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
|
||||
The skip on function format is:
|
||||
|
||||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| source | skip |rv| 0 0 0 0 1 0| skip function
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
|
||||
The memory reference format is (src and/or dst = 006):
|
||||
|
||||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| source | op | mode| destination | memory ref
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| address or immediate |
|
||||
+-----------------------------------------------+
|
||||
|
||||
<6:9> operation
|
||||
|
||||
xx0x direct, ea = M[SC+1]
|
||||
xx1x immediate, ea = SC+1
|
||||
xxx1 indirect, M[ea] = M[ea]+1, then ea = M[ea]
|
||||
01xx add 1
|
||||
10xx rotate left 1
|
||||
11xx rotate right 1
|
||||
|
||||
The conditional jump format is (src != 006):
|
||||
|
||||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| source | cond|rv|df| 0 0 0 0 1 1| cond jump
|
||||
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||
| jump address |
|
||||
+-----------------------------------------------+
|
||||
|
||||
<6:9> operation
|
||||
|
||||
xxx0 direct, ea = M[SC+1]
|
||||
xxx1 indirect, ea = M[SC+1], M[ea] = M[ea]+1,
|
||||
then ea = M[ea]
|
||||
xx1x reverse conditional sense
|
||||
x1xx jump if src == 0
|
||||
1xxx jump if src < 0
|
||||
*/
|
||||
|
||||
/* This routine is the instruction decode routine for the GRI-909.
|
||||
It is called from the simulator control program to execute
|
||||
instructions in simulated memory, starting at the simulated PC.
|
||||
It runs until 'reason' is set non-zero.
|
||||
|
||||
General notes:
|
||||
|
||||
1. Reasons to stop. The simulator can be stopped by:
|
||||
|
||||
HALT instruction
|
||||
breakpoint encountered
|
||||
unknown source or destination and STOP_OPR flag set
|
||||
I/O error in I/O simulator
|
||||
|
||||
2. Interrupts. The interrupt structure is kept in two parallel variables:
|
||||
|
||||
dev_done device done flags
|
||||
ISR interrupt status register (enables)
|
||||
|
||||
In addition, there is a master interrupt enable, and a one cycle
|
||||
interrupt defer, both kept in dev_done.
|
||||
|
||||
3. Non-existent memory. On the GRI-909, reads to non-existent memory
|
||||
return zero, and writes are ignored. In the simulator, the
|
||||
largest possible memory is instantiated and initialized to zero.
|
||||
Thus, only writes need be checked against actual memory size.
|
||||
|
||||
4. Adding I/O devices. These modules must be modified:
|
||||
|
||||
gri_defs.h add interrupt request definition
|
||||
gri_cpu.c add dispatches to dev_tab
|
||||
gri_sys.c add pointer to data structures to sim_devices
|
||||
*/
|
||||
|
||||
#include "gri_defs.h"
|
||||
|
||||
#define SCQ_SIZE 64 /* must be 2**n */
|
||||
#define SCQ_MASK (SCQ_SIZE - 1)
|
||||
#define SCQ_ENTRY scq[scq_p = (scq_p - 1) & SCQ_MASK] = SC
|
||||
#define UNIT_V_NOEAO (UNIT_V_UF) /* EAO absent */
|
||||
#define UNIT_NOEAO (1 << UNIT_V_NOEAO)
|
||||
#define UNIT_V_MSIZE (UNIT_V_UF + 1) /* dummy mask */
|
||||
#define UNIT_MSIZE (1 << UNIT_V_MSIZE)
|
||||
|
||||
uint16 M[MAXMEMSIZE] = { 0 }; /* memory */
|
||||
uint32 SC; /* sequence cntr */
|
||||
uint32 AX, AY, AO; /* arithmetic unit */
|
||||
uint32 IR; /* instr reg */
|
||||
uint32 MA; /* memory addr */
|
||||
uint32 TRP; /* subr return */
|
||||
uint32 MSR; /* machine status */
|
||||
uint32 ISR; /* interrupt status */
|
||||
uint32 BSW, BPK; /* byte swap, pack */
|
||||
uint32 GR[6]; /* extended general regs */
|
||||
uint32 SWR; /* switch reg */
|
||||
uint32 DR; /* display register */
|
||||
uint32 thwh = 0; /* thumbwheel */
|
||||
uint32 dev_done = 0; /* device flags */
|
||||
uint32 bkp = 0; /* bkpt pending */
|
||||
uint32 stop_opr = 1; /* stop ill operator */
|
||||
int16 scq[SCQ_SIZE] = { 0 }; /* PC queue */
|
||||
int32 scq_p = 0; /* PC queue ptr */
|
||||
REG *scq_r = NULL; /* PC queue reg ptr */
|
||||
extern int32 sim_interval;
|
||||
extern int32 sim_int_char;
|
||||
extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */
|
||||
|
||||
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, char *cptr, void *desc);
|
||||
t_stat bus_op (uint32 src, uint32 op, uint32 dst);
|
||||
|
||||
/* Dispatch tables for source, dest, function out, skip on function */
|
||||
|
||||
uint32 no_rd (uint32 src);
|
||||
t_stat no_wr (uint32 dst, uint32 val);
|
||||
t_stat no_fo (uint32 op);
|
||||
uint32 no_sf (uint32 op);
|
||||
uint32 zero_rd (uint32 src);
|
||||
t_stat zero_wr (uint32 dst, uint32 val);
|
||||
t_stat zero_fo (uint32 op);
|
||||
uint32 zero_sf (uint32 op);
|
||||
uint32 ir_rd (uint32 op);
|
||||
t_stat ir_fo (uint32 op);
|
||||
uint32 trp_rd (uint32 src);
|
||||
uint32 isr_rd (uint32 src);
|
||||
t_stat isr_wr (uint32 dst, uint32 val);
|
||||
t_stat isr_fo (uint32 op);
|
||||
uint32 isr_sf (uint32 op);
|
||||
uint32 ma_rd (uint32 src);
|
||||
uint32 mem_rd (uint32 src);
|
||||
t_stat mem_wr (uint32 dst, uint32 val);
|
||||
uint32 sc_rd (uint32 src);
|
||||
t_stat sc_wr (uint32 dst, uint32 val);
|
||||
uint32 swr_rd (uint32 src);
|
||||
uint32 ax_rd (uint32 src);
|
||||
t_stat ax_wr (uint32 dst, uint32 val);
|
||||
uint32 ay_rd (uint32 src);
|
||||
t_stat ay_wr (uint32 dst, uint32 val);
|
||||
uint32 ao_rd (uint32 src);
|
||||
t_stat ao_fo (uint32 op);
|
||||
uint32 ao_sf (uint32 op);
|
||||
uint32 ao_update (void);
|
||||
t_stat eao_fo (uint32 op);
|
||||
uint32 msr_rd (uint32 src);
|
||||
t_stat msr_wr (uint32 dst, uint32 val);
|
||||
uint32 bsw_rd (uint32 src);
|
||||
t_stat bsw_wr (uint32 dst, uint32 val);
|
||||
uint32 bpk_rd (uint32 src);
|
||||
t_stat bpk_wr (uint32 dst, uint32 val);
|
||||
uint32 gr_rd (uint32 src);
|
||||
t_stat gr_wr (uint32 dst, uint32 val);
|
||||
|
||||
extern t_stat rtc_fo (uint32 op);
|
||||
extern uint32 rtc_sf (uint32 op);
|
||||
extern uint32 hsrp_rd (uint32 src);
|
||||
extern t_stat hsrp_wr (uint32 dst, uint32 val);
|
||||
extern t_stat hsrp_fo (uint32 op);
|
||||
extern uint32 hsrp_sf (uint32 op);
|
||||
extern uint32 tty_rd (uint32 src);
|
||||
extern t_stat tty_wr (uint32 dst, uint32 val);
|
||||
extern t_stat tty_fo (uint32 op);
|
||||
extern uint32 tty_sf (uint32 op);
|
||||
|
||||
struct gdev dev_tab[64] = {
|
||||
{ &zero_rd, &zero_wr, &zero_fo, &zero_sf }, /* 00: zero */
|
||||
{ &ir_rd, &zero_wr, &ir_fo, &zero_sf }, /* ir */
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf }, /* fo/sf */
|
||||
{ &trp_rd, &no_wr, &zero_fo, &zero_sf }, /* trp */
|
||||
{ &isr_rd, &isr_wr, &isr_fo, &isr_sf }, /* isr */
|
||||
{ &ma_rd, &no_wr, &no_fo, &no_sf }, /* MA */
|
||||
{ &mem_rd, &mem_wr, &zero_fo, &zero_sf }, /* memory */
|
||||
{ &sc_rd, &sc_wr, &zero_fo, &zero_sf }, /* sc */
|
||||
{ &swr_rd, &no_wr, &no_fo, &no_sf }, /* swr */
|
||||
{ &ax_rd, &ax_wr, &zero_fo, &zero_sf }, /* ax */
|
||||
{ &ay_rd, &ay_wr, &zero_fo, &zero_sf }, /* ay */
|
||||
{ &ao_rd, &zero_wr, &ao_fo, &ao_sf }, /* ao */
|
||||
{ &zero_rd, &zero_wr, &eao_fo, &zero_sf }, /* eao */
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &msr_rd, &msr_wr, &zero_fo, &zero_sf }, /* msr */
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf }, /* 20 */
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &bsw_rd, &bsw_wr, &no_fo, &no_sf }, /* bsw */
|
||||
{ &bpk_rd, &bpk_wr, &no_fo, &no_sf }, /* bpk */
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &gr_rd, &gr_wr, &zero_fo, &zero_sf }, /* 30: gr1 */
|
||||
{ &gr_rd, &gr_wr, &zero_fo, &zero_sf }, /* gr2 */
|
||||
{ &gr_rd, &gr_wr, &zero_fo, &zero_sf }, /* gr3 */
|
||||
{ &gr_rd, &gr_wr, &zero_fo, &zero_sf }, /* gr4 */
|
||||
{ &gr_rd, &gr_wr, &zero_fo, &zero_sf }, /* gr5 */
|
||||
{ &gr_rd, &gr_wr, &zero_fo, &zero_sf }, /* gr6 */
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf }, /* 40 */
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf }, /* 50 */
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf }, /* 60 */
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf }, /* 70 */
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &no_rd, &no_wr, &no_fo, &no_sf },
|
||||
{ &zero_rd, &zero_wr, &rtc_fo, &rtc_sf }, /* rtc */
|
||||
{ &hsrp_rd, &hsrp_wr, &hsrp_fo, &hsrp_sf }, /* hsrp */
|
||||
{ &tty_rd, &tty_wr, &tty_fo, &tty_sf } }; /* tty */
|
||||
|
||||
static const int32 vec_map[16] = {
|
||||
VEC_TTO, VEC_TTI, VEC_HSP, VEC_HSR,
|
||||
-1, -1, -1, -1,
|
||||
-1, -1, -1, VEC_RTC,
|
||||
-1, -1, -1, -1 };
|
||||
|
||||
/* CPU data structures
|
||||
|
||||
cpu_dev CPU device descriptor
|
||||
cpu_unit CPU unit descriptor
|
||||
cpu_reg CPU register list
|
||||
cpu_mod CPU modifiers list
|
||||
*/
|
||||
|
||||
UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) };
|
||||
|
||||
REG cpu_reg[] = {
|
||||
{ ORDATA (SC, SC, 15) },
|
||||
{ ORDATA (AX, AX, 16) },
|
||||
{ ORDATA (AY, AY, 16) },
|
||||
{ ORDATA (AO, AO, 16), REG_RO },
|
||||
{ ORDATA (TRP, TRP, 16) },
|
||||
{ ORDATA (MSR, MSR, 16) },
|
||||
{ ORDATA (ISR, ISR, 16) },
|
||||
{ ORDATA (BSW, BSW, 16) },
|
||||
{ ORDATA (BPK, BPK, 16) },
|
||||
{ ORDATA (GR1, GR[0], 16) },
|
||||
{ ORDATA (GR2, GR[1], 16) },
|
||||
{ ORDATA (GR3, GR[2], 16) },
|
||||
{ ORDATA (GR4, GR[3], 16) },
|
||||
{ ORDATA (GR5, GR[4], 16) },
|
||||
{ ORDATA (GR6, GR[5], 16) },
|
||||
{ FLDATA (BOV, MSR, MSR_V_BOV) },
|
||||
{ FLDATA (L, MSR, MSR_V_L) },
|
||||
{ GRDATA (FOA, MSR, 8, 2, MSR_V_FOA) },
|
||||
{ FLDATA (AOV, MSR, MSR_V_AOV) },
|
||||
{ ORDATA (IR, IR, 16), REG_RO },
|
||||
{ ORDATA (MA, MA, 16), REG_RO },
|
||||
{ ORDATA (SWR, SWR, 16) },
|
||||
{ ORDATA (DR, DR, 16) },
|
||||
{ ORDATA (THW, thwh, 6) },
|
||||
{ ORDATA (IREQ, dev_done, INT_V_NODEF) },
|
||||
{ FLDATA (ION, dev_done, INT_V_ON) },
|
||||
{ FLDATA (INODEF, dev_done, INT_V_NODEF) },
|
||||
{ FLDATA (BKP, bkp, 0) },
|
||||
{ BRDATA (SCQ, scq, 8, 15, SCQ_SIZE), REG_RO+REG_CIRC },
|
||||
{ ORDATA (SCQP, scq_p, 6), REG_HRO },
|
||||
{ FLDATA (NOEAO, cpu_unit.flags, UNIT_V_NOEAO), REG_HRO },
|
||||
{ FLDATA (STOP_OPR, stop_opr, 0) },
|
||||
{ ORDATA (WRU, sim_int_char, 8) },
|
||||
{ NULL } };
|
||||
|
||||
MTAB cpu_mod[] = {
|
||||
{ UNIT_NOEAO, UNIT_NOEAO, "no EAO", "NOEAO", NULL },
|
||||
{ UNIT_NOEAO, 0, "EAO", "EAO", NULL },
|
||||
{ UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 20480, NULL, "20K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 28672, NULL, "28K", &cpu_set_size },
|
||||
{ UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE cpu_dev = {
|
||||
"CPU", &cpu_unit, cpu_reg, cpu_mod,
|
||||
1, 8, 15, 1, 8, 16,
|
||||
&cpu_ex, &cpu_dep, &cpu_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
t_stat sim_instr (void)
|
||||
{
|
||||
uint32 src, dst, op, t, jmp;
|
||||
t_stat reason;
|
||||
extern UNIT rtc_unit;
|
||||
|
||||
/* Restore register state */
|
||||
|
||||
SC = SC & AMASK; /* load local PC */
|
||||
reason = 0;
|
||||
AO = ao_update (); /* update AO */
|
||||
sim_rtc_init (rtc_unit.wait); /* init calibration */
|
||||
|
||||
/* Main instruction fetch/decode loop */
|
||||
|
||||
while (reason == 0) { /* loop until halted */
|
||||
|
||||
if (sim_interval <= 0) { /* check clock queue */
|
||||
if (reason = sim_process_event ()) break; }
|
||||
|
||||
if (bkp) { /* breakpoint? */
|
||||
bkp = 0; /* clear request */
|
||||
dev_done = dev_done & ~INT_ON; /* int off */
|
||||
M[VEC_BKP] = SC; /* save SC */
|
||||
SC = VEC_BKP + 1; } /* new SC */
|
||||
|
||||
else if ((dev_done & (INT_PENDING | ISR)) > (INT_PENDING)) { /* intr? */
|
||||
int32 i, vec;
|
||||
t = dev_done & ISR; /* find hi pri */
|
||||
for (i = 15; i >= 0; i--) {
|
||||
if ((t >> i) & 1) break; }
|
||||
if ((i < 0) || ((vec = vec_map[i]) < 0)) { /* undefined? */
|
||||
reason = STOP_ILLINT; /* stop */
|
||||
break; }
|
||||
dev_done = dev_done & ~INT_ON; /* int off */
|
||||
M[vec] = SC; /* save SC */
|
||||
SC = vec + 1; /* new SC */
|
||||
continue; }
|
||||
|
||||
if (sim_brk_summ && sim_brk_test (SC, SWMASK ('E'))) { /* breakpoint? */
|
||||
reason = STOP_IBKPT; /* stop simulation */
|
||||
break; }
|
||||
|
||||
MA = SC; /* set mem addr */
|
||||
IR = M[MA]; /* fetch instr */
|
||||
dev_done = dev_done | INT_NODEF; /* clr ion defer */
|
||||
sim_interval = sim_interval - 1;
|
||||
|
||||
/* Decode instruction types */
|
||||
|
||||
src = I_GETSRC (IR); /* src unit */
|
||||
dst = I_GETDST (IR); /* dst unit */
|
||||
op = I_GETOP (IR); /* bus op */
|
||||
|
||||
if (src == U_FSK) { /* func out? */
|
||||
reason = dev_tab[dst].FO (op); /* send function */
|
||||
SC = (SC + 1) & AMASK; } /* incr SC */
|
||||
|
||||
else if (dst == U_FSK) { /* skip func? */
|
||||
t = dev_tab[src].SF (op & ~1); /* issue SF */
|
||||
reason = t >> SF_V_REASON;
|
||||
if ((t ^ op) & 1) SC = SC + 2; /* skip? */
|
||||
SC = (SC + 1) & AMASK; } /* incr SC */
|
||||
|
||||
else if ((src != U_MEM) && (dst == U_TRP)) { /* cond jump */
|
||||
t = dev_tab[src].Src (src); /* get source */
|
||||
switch (op >> 1) { /* case on jump */
|
||||
case 00: /* never */
|
||||
jmp = 0;
|
||||
break;
|
||||
case 01: /* always */
|
||||
jmp = 1;
|
||||
break;
|
||||
case 02: /* src == 0 */
|
||||
jmp = (t == 0);
|
||||
break;
|
||||
case 03: /* src != 0 */
|
||||
jmp = (t != 0);
|
||||
break;
|
||||
case 04: /* src < 0 */
|
||||
jmp = (t >= SIGN);
|
||||
break;
|
||||
case 05: /* src >= 0 */
|
||||
jmp = (t < SIGN);
|
||||
break;
|
||||
case 06:
|
||||
jmp = (t == 0) || (t & SIGN); /* src <= 0 */
|
||||
break;
|
||||
case 07:
|
||||
jmp = (t != 0) && !(t & SIGN); /* src > 0 */
|
||||
break; }
|
||||
if (jmp) { /* jump taken? */
|
||||
SCQ_ENTRY; /* save SC */
|
||||
SC = (SC + 1) & AMASK; /* incr SC once */
|
||||
MA = M[SC]; /* get jump addr */
|
||||
if (op & TRP_DEF) { /* defer? */
|
||||
t = (M[MA] + 1) & DMASK; /* autoinc */
|
||||
if (MEM_ADDR_OK (MA)) M[MA] = t;
|
||||
MA = t & AMASK; } /* ind addr */
|
||||
TRP = SC; /* save SC */
|
||||
SC = MA; } /* load new SC */
|
||||
else SC = (SC + 2) & AMASK; } /* incr SC twice */
|
||||
|
||||
else if ((src != U_MEM) && (dst != U_MEM)) { /* reg-reg? */
|
||||
reason = bus_op (src, op, dst); /* xmt and modify */
|
||||
SC = (SC + 1) & AMASK; } /* incr SC */
|
||||
|
||||
/* Memory reference. The second SC increment occurs after the first
|
||||
execution cycle. For direct, defer, and immediate defer, this is
|
||||
after the first memory read and before the bus transfer; but for
|
||||
immediate, it is before the bus transfer.
|
||||
*/
|
||||
|
||||
else { SC = (SC + 1) & AMASK; /* incr SC */
|
||||
switch (op & MEM_MOD) { /* case on addr mode */
|
||||
case MEM_DIR: /* direct */
|
||||
MA = M[SC] & AMASK; /* get address */
|
||||
SC = (SC + 1) & AMASK; /* incr SC again */
|
||||
reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */
|
||||
break;
|
||||
case MEM_DEF: /* defer */
|
||||
MA = M[SC] & AMASK; /* get ind addr */
|
||||
SC = (SC + 1) & AMASK; /* incr SC again */
|
||||
t = (M[MA] + 1) & DMASK; /* autoinc */
|
||||
if (MEM_ADDR_OK (MA)) M[MA] = t;
|
||||
MA = t & AMASK; /* ind addr */
|
||||
reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */
|
||||
break;
|
||||
case MEM_IMM: /* immediate */
|
||||
MA = SC; /* eff addr */
|
||||
reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */
|
||||
SC = (SC + 1) & AMASK; /* incr SC again */
|
||||
break;
|
||||
case MEM_IDF: /* immediate defer */
|
||||
MA = SC; /* get ind addr */
|
||||
t = (M[MA] + 1) & DMASK; /* autoinc */
|
||||
if (MEM_ADDR_OK (MA)) M[MA] = t;
|
||||
MA = t & AMASK; /* ind addr */
|
||||
SC = (SC + 1) & AMASK; /* incr SC again */
|
||||
reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */
|
||||
break; } /* end switch */
|
||||
} /* end mem ref */
|
||||
} /* end while */
|
||||
|
||||
/* Simulation halted */
|
||||
|
||||
AO = ao_update (); /* update AO */
|
||||
return reason;
|
||||
}
|
||||
|
||||
/* Bus operations */
|
||||
|
||||
t_stat bus_op (uint32 src, uint32 op, uint32 dst)
|
||||
{
|
||||
uint32 t, old_t;
|
||||
|
||||
t = dev_tab[src].Src (src); /* get src */
|
||||
if (op & BUS_COM) t = t ^ DMASK; /* complement? */
|
||||
switch (op & BUS_FNC) { /* case op */
|
||||
case BUS_P1: /* plus 1 */
|
||||
t = t + 1; /* do add */
|
||||
if (t & CBIT) MSR = MSR | MSR_BOV; /* set cry out */
|
||||
else MSR = MSR & ~MSR_BOV;
|
||||
break;
|
||||
case BUS_L1: /* left 1 */
|
||||
t = (t << 1) | ((MSR & MSR_L)? 1: 0); /* rotate */
|
||||
if (t & CBIT) MSR = MSR | MSR_L; /* set link out */
|
||||
else MSR = MSR & ~MSR_L;
|
||||
break;
|
||||
case BUS_R1: /* right 1 */
|
||||
old_t = t;
|
||||
t = (t >> 1) | ((MSR & MSR_L)? SIGN: 0); /* rotate */
|
||||
if (old_t & 1) MSR = MSR | MSR_L; /* set link out */
|
||||
else MSR = MSR & ~MSR_L;
|
||||
break; } /* end case op */
|
||||
if (dst == thwh) DR = t & DMASK; /* display dst? */
|
||||
return dev_tab[dst].Dst (dst, t & DMASK); /* store dst */
|
||||
}
|
||||
|
||||
/* Non-existent device */
|
||||
|
||||
uint32 no_rd (uint32 src)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
t_stat no_wr (uint32 dst, uint32 dat)
|
||||
{
|
||||
return stop_opr;
|
||||
}
|
||||
|
||||
t_stat no_fo (uint32 fnc)
|
||||
{
|
||||
return stop_opr;
|
||||
}
|
||||
|
||||
uint32 no_sf (uint32 fnc)
|
||||
{
|
||||
return (stop_opr << SF_V_REASON);
|
||||
}
|
||||
|
||||
/* Zero device */
|
||||
|
||||
uint32 zero_rd (uint32 src)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
t_stat zero_wr (uint32 dst, uint32 val)
|
||||
{
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat zero_fo (uint32 op)
|
||||
{
|
||||
switch (op & 3) { /* FOM link */
|
||||
case 1: /* CLL */
|
||||
MSR = MSR & ~MSR_L;
|
||||
break;
|
||||
case 2: /* STL */
|
||||
MSR = MSR | MSR_L;
|
||||
break;
|
||||
case 3: /* CML */
|
||||
MSR = MSR ^ MSR_L;
|
||||
break; }
|
||||
if (op & 4) return STOP_HALT; /* HALT */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
uint32 zero_sf (uint32 op)
|
||||
{
|
||||
if ((op & 010) || /* power always ok */
|
||||
((op & 4) && (MSR & MSR_L)) || /* link set? */
|
||||
((op & 2) && (MSR & MSR_BOV))) return 1; /* BOV set? */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Instruction register (01) */
|
||||
|
||||
uint32 ir_rd (uint32 src)
|
||||
{
|
||||
return IR;
|
||||
}
|
||||
|
||||
t_stat ir_fo (uint32 op)
|
||||
{
|
||||
if (op & 2) bkp = 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Trap register (03) */
|
||||
|
||||
uint32 trp_rd (uint32 src)
|
||||
{
|
||||
return TRP;
|
||||
}
|
||||
|
||||
/* Interrupt status register (04) */
|
||||
|
||||
uint32 isr_rd (uint32 src)
|
||||
{
|
||||
return ISR;
|
||||
}
|
||||
|
||||
t_stat isr_wr (uint32 dst, uint32 dat)
|
||||
{
|
||||
ISR = dat;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat isr_fo (uint32 op)
|
||||
{
|
||||
if (op & ISR_ON) dev_done = (dev_done | INT_ON) & ~INT_NODEF;
|
||||
if (op & ISR_OFF) dev_done = dev_done & ~INT_ON;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
uint32 isr_sf (uint32 op)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Memory address (05) */
|
||||
|
||||
uint32 ma_rd (uint32 src)
|
||||
{
|
||||
return MA;
|
||||
}
|
||||
|
||||
/* Memory (06) */
|
||||
|
||||
uint32 mem_rd (uint32 src)
|
||||
{
|
||||
return M[MA];
|
||||
}
|
||||
|
||||
t_stat mem_wr (uint32 dst, uint32 dat)
|
||||
{
|
||||
|
||||
if (MEM_ADDR_OK (MA)) M[MA] = dat;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Sequence counter (07) */
|
||||
|
||||
uint32 sc_rd (uint32 src)
|
||||
{
|
||||
return SC;
|
||||
}
|
||||
|
||||
t_stat sc_wr (uint32 dst, uint32 dat)
|
||||
{
|
||||
SCQ_ENTRY;
|
||||
SC = dat & AMASK;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Switch register (10) */
|
||||
|
||||
uint32 swr_rd (uint32 src)
|
||||
{
|
||||
return SWR;
|
||||
}
|
||||
|
||||
/* Machine status register (17) */
|
||||
|
||||
uint32 msr_rd (uint32 src)
|
||||
{
|
||||
return MSR;
|
||||
}
|
||||
|
||||
t_stat msr_wr (uint32 src, uint32 dat)
|
||||
{
|
||||
MSR = dat; /* new MSR */
|
||||
ao_update (); /* update AOV */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Arithmetic operators (11:14) */
|
||||
|
||||
uint32 ao_update (void)
|
||||
{
|
||||
int32 t;
|
||||
int32 af = MSR_GET_FOA (MSR);
|
||||
|
||||
switch (af) {
|
||||
case AO_ADD:
|
||||
t = (AX + AY) & DMASK; /* add */
|
||||
break;
|
||||
case AO_AND:
|
||||
t = AX & AY; /* and */
|
||||
break;
|
||||
case AO_XOR: /* xor */
|
||||
t = AX ^ AY;
|
||||
break;
|
||||
case AO_IOR:
|
||||
t = AX | AY; /* or */
|
||||
break; }
|
||||
if ((AX + AY) & CBIT) MSR = MSR | MSR_AOV; /* always calc AOV */
|
||||
else MSR = MSR & ~MSR_AOV;
|
||||
return t;
|
||||
}
|
||||
|
||||
uint32 ax_rd (uint32 src)
|
||||
{
|
||||
return AX;
|
||||
}
|
||||
|
||||
t_stat ax_wr (uint32 dst, uint32 dat)
|
||||
{
|
||||
AX = dat;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
uint32 ay_rd (uint32 src)
|
||||
{
|
||||
return AY;
|
||||
}
|
||||
|
||||
t_stat ay_wr (uint32 dst, uint32 dat)
|
||||
{
|
||||
AY = dat;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
uint32 ao_rd (uint32 src)
|
||||
{
|
||||
AO = ao_update ();
|
||||
return AO;
|
||||
}
|
||||
|
||||
t_stat ao_fo (uint32 op)
|
||||
{
|
||||
uint32 t = OP_GET_FOA (op); /* get func */
|
||||
MSR = MSR_PUT_FOA (MSR, t); /* store in MSR */
|
||||
ao_update (); /* update AOV */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat eao_fo (uint32 op)
|
||||
{
|
||||
uint32 t;
|
||||
|
||||
if (cpu_unit.flags & UNIT_NOEAO) return stop_opr; /* EAO installed? */
|
||||
if (op == EAO_MUL) { /* mul? */
|
||||
t = AX * AY; /* AX * AY */
|
||||
AX = (t >> 16) & DMASK; /* to AX'GR1 */
|
||||
GR[0] = t & DMASK; }
|
||||
if (op == EAO_DIV) { /* div? */
|
||||
if (AY && (AX < AY)) {
|
||||
t = (AX << 16) | GR[0]; /* AX'GR1 / AY */
|
||||
GR[0] = t / AY; /* quo to GR1 */
|
||||
AX = t % AY; } /* rem to AX */
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
uint32 ao_sf (uint32 op)
|
||||
{
|
||||
if (((op & 2) && (MSR & MSR_AOV)) || /* arith carry? */
|
||||
((op & 4) && (SIGN & /* arith overflow? */
|
||||
((AX ^ (AX + AY)) & (~AX ^ AY))))) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Byte swapper (24) */
|
||||
|
||||
uint32 bsw_rd (uint32 src)
|
||||
{
|
||||
return BSW;
|
||||
}
|
||||
|
||||
t_stat bsw_wr (uint32 dst, uint32 val)
|
||||
{
|
||||
BSW = ((val >> 8) & 0377) | ((val & 0377) << 8);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Byte packer (25) */
|
||||
|
||||
uint32 bpk_rd (uint32 src)
|
||||
{
|
||||
return BPK;
|
||||
}
|
||||
|
||||
t_stat bpk_wr (uint32 dst, uint32 val)
|
||||
{
|
||||
BPK = ((BPK & 0377) << 8) | (val & 0377);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* General registers (30:35) */
|
||||
|
||||
uint32 gr_rd (uint32 src)
|
||||
{
|
||||
return GR[src - U_GR];
|
||||
}
|
||||
|
||||
t_stat gr_wr (uint32 dst, uint32 dat)
|
||||
{
|
||||
GR[dst - U_GR] = dat;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine */
|
||||
|
||||
t_stat cpu_reset (DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
AX = AY = AO = 0;
|
||||
TRP = 0;
|
||||
ISR = 0;
|
||||
MSR = 0;
|
||||
MA = IR = 0;
|
||||
BSW = BPK = 0;
|
||||
for (i = 0; i < 6; i++) GR[i] = 0;
|
||||
dev_done = dev_done & ~INT_PENDING;
|
||||
scq_r = find_reg ("SCQ", NULL, dptr);
|
||||
if (scq_r) scq_r -> qptr = 0;
|
||||
else return SCPE_IERR;
|
||||
sim_brk_types = sim_brk_dflt = SWMASK ('E');
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Memory examine */
|
||||
|
||||
t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
|
||||
{
|
||||
if (addr >= MEMSIZE) return SCPE_NXM;
|
||||
if (vptr != NULL) *vptr = M[addr] & DMASK;
|
||||
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 & DMASK;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
int32 mc = 0;
|
||||
t_addr i;
|
||||
|
||||
if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0))
|
||||
return SCPE_ARG;
|
||||
for (i = val; i < MEMSIZE; i++) mc = mc | M[i];
|
||||
if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE)))
|
||||
return SCPE_OK;
|
||||
MEMSIZE = val;
|
||||
for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0;
|
||||
return SCPE_OK;
|
||||
}
|
||||
218
GRI/gri_defs.h
Normal file
218
GRI/gri_defs.h
Normal file
@@ -0,0 +1,218 @@
|
||||
/* gri_defs.h: GRI-909 simulator definitions
|
||||
|
||||
Copyright (c) 2001-2002, Robert M. Supnik
|
||||
|
||||
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
|
||||
ROBERT M SUPNIK 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.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
There are several discrepancies between the original GRI-909 Reference
|
||||
Manual of 1969 and the only surviving code sample, the MIT Crystal Growing
|
||||
System of 1972:
|
||||
|
||||
1. Ref Manual documents two GR's at codes 26-27; MITCS documents six GR's
|
||||
at 30-35.
|
||||
2. Ref Manual documents only unsigned overflow (carry) for arithmetic
|
||||
operator; MITCS uses both unsigned overflow (AOV) and signed overflow
|
||||
(SOV).
|
||||
3. Ref Manual documents a ROM-subroutine multiply operator and mentions
|
||||
but does not document a "fast multiply"; MITCS uses an extended
|
||||
arithmetic operator with multiply, divide, and shifts. The behavior
|
||||
of the extended arithmetic operator can only be inferred partially;
|
||||
the shifts are never used, and there is no indication of how divide
|
||||
overflow is handled.
|
||||
|
||||
The simulator follows the code in these instances.
|
||||
|
||||
Outstanding issues:
|
||||
|
||||
1. Is there any interaction between the byte swapper and the byte packer?
|
||||
2. Is SOV testable even if the FOA is not ADD?
|
||||
3. How does the EAO handle divide overflow?
|
||||
4. What are the other EAO functions beside multiply and divide?
|
||||
*/
|
||||
|
||||
#include "sim_defs.h" /* simulator defns */
|
||||
|
||||
/* Simulator stop codes */
|
||||
|
||||
#define STOP_DEV 1 /* must be 1 */
|
||||
#define STOP_HALT 2 /* HALT */
|
||||
#define STOP_IBKPT 3 /* breakpoint */
|
||||
#define STOP_ILLINT 4 /* illegal intr */
|
||||
|
||||
/* Memory */
|
||||
|
||||
#define MAXMEMSIZE 32768 /* max memory size */
|
||||
#define AMASK 077777 /* logical addr mask */
|
||||
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
|
||||
#define MEM_ADDR_OK(x) (((t_addr) (x)) < MEMSIZE)
|
||||
|
||||
/* Architectural constants */
|
||||
|
||||
#define SIGN 0100000 /* sign */
|
||||
#define DMASK 0177777 /* data mask */
|
||||
#define CBIT (DMASK + 1) /* carry bit */
|
||||
|
||||
/* Instruction format */
|
||||
|
||||
#define I_M_SRC 077 /* source */
|
||||
#define I_V_SRC 10
|
||||
#define I_GETSRC(x) (((x) >> I_V_SRC) & I_M_SRC)
|
||||
#define I_M_OP 017 /* operator */
|
||||
#define I_V_OP 6
|
||||
#define I_GETOP(x) (((x) >> I_V_OP) & I_M_OP)
|
||||
#define I_M_DST 077 /* destination */
|
||||
#define I_V_DST 0
|
||||
#define I_GETDST(x) (((x) >> I_V_DST) & I_M_DST)
|
||||
#define SF_V_REASON 1 /* SF reason */
|
||||
|
||||
/* IO return */
|
||||
|
||||
#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */
|
||||
|
||||
/* Operators */
|
||||
|
||||
#define U_ZERO 000 /* zero */
|
||||
#define U_IR 001 /* instruction reg */
|
||||
#define U_FSK 002 /* func out/skip */
|
||||
#define U_TRP 003 /* trap */
|
||||
#define U_ISR 004 /* intr status */
|
||||
#define U_MA 005 /* mem addr */
|
||||
#define U_MEM 006 /* mem data */
|
||||
#define U_SC 007 /* seq counter */
|
||||
#define U_SWR 010 /* switch register */
|
||||
#define U_AX 011 /* arith in 1 */
|
||||
#define U_AY 012 /* arith in 2 */
|
||||
#define U_AO 013 /* arith out */
|
||||
#define U_EAO 014 /* ext arith */
|
||||
#define U_MSR 017 /* machine status */
|
||||
#define U_BSW 024 /* byte swap */
|
||||
#define U_BPK 025 /* byte pack */
|
||||
/* #define U_GR 026 /* dual general regs */
|
||||
#define U_GR 030 /* hex general regs */
|
||||
#define U_RTC 075 /* clock */
|
||||
#define U_HS 076 /* paper tape */
|
||||
#define U_TTY 077 /* console */
|
||||
|
||||
struct gdev {
|
||||
int32 (*Src)(); /* source */
|
||||
t_stat (*Dst)(); /* dest */
|
||||
t_stat (*FO)(); /* func out */
|
||||
int32 (*SF)(); /* skip func */
|
||||
};
|
||||
|
||||
/* Trap (jump) */
|
||||
|
||||
#define TRP_DIR 00 /* direct */
|
||||
#define TRP_DEF 01 /* defer */
|
||||
|
||||
/* Interrupt status */
|
||||
|
||||
#define ISR_OFF 01 /* int off */
|
||||
#define ISR_ON 02 /* int on */
|
||||
|
||||
/* Bus modifiers */
|
||||
|
||||
#define BUS_COM 002 /* complement */
|
||||
#define BUS_FNC 014 /* function mask */
|
||||
#define BUS_P1 004 /* + 1 */
|
||||
#define BUS_L1 010 /* rotate left */
|
||||
#define BUS_R1 014 /* rotate right */
|
||||
|
||||
/* Memory address modes */
|
||||
|
||||
#define MEM_MOD 03
|
||||
#define MEM_DIR 00 /* direct */
|
||||
#define MEM_DEF 01 /* defer */
|
||||
#define MEM_IMM 02 /* immediate */
|
||||
#define MEM_IDF 03 /* immediate defer */
|
||||
|
||||
/* Arithmetic unit */
|
||||
|
||||
#define FO_V_FOA 8 /* arith func */
|
||||
#define FO_M_FOA 03
|
||||
#define OP_GET_FOA(x) (((x) >> (FO_V_FOA - I_V_OP)) & FO_M_FOA)
|
||||
#define AO_ADD 00 /* add */
|
||||
#define AO_AND 01 /* and */
|
||||
#define AO_XOR 02 /* xor */
|
||||
#define AO_IOR 03 /* or */
|
||||
#define EAO_MUL 01 /* multiply */
|
||||
#define EAO_DIV 02 /* divide */
|
||||
#define EAO_ASR 03 /* arith rshft */
|
||||
|
||||
/* Machine status */
|
||||
|
||||
#define MSR_V_BOV 15 /* bus carry */
|
||||
#define MSR_BOV (1u << MSR_V_BOV)
|
||||
#define MSR_V_L 14 /* bus link */
|
||||
#define MSR_L (1u << MSR_V_L) /* bus link */
|
||||
#define MSR_V_FOA 8 /* arith func */
|
||||
#define MSR_M_FOA 03
|
||||
#define MSR_V_AOV 0 /* arith carry */
|
||||
#define MSR_AOV (1u << MSR_V_AOV)
|
||||
#define MSR_GET_FOA(x) (((x) >> MSR_V_FOA) & MSR_M_FOA)
|
||||
#define MSR_PUT_FOA(x,n) (((x) & ~(MSR_M_FOA << MSR_V_FOA)) | \
|
||||
(((n) & MSR_M_FOA) << MSR_V_FOA))
|
||||
|
||||
/* Real time clock */
|
||||
|
||||
#define RTC_OFF 001 /* off */
|
||||
#define RTC_ON 002 /* clock on */
|
||||
#define RTC_OV 010 /* clock flag */
|
||||
#define RTC_CTR 0103 /* counter */
|
||||
|
||||
/* Terminal */
|
||||
|
||||
#define TTY_ORDY 002 /* output flag */
|
||||
#define TTY_IRDY 010 /* input flag */
|
||||
|
||||
/* Paper tape */
|
||||
|
||||
#define PT_STRT 001 /* start reader */
|
||||
#define PT_ORDY 002 /* output flag */
|
||||
#define PT_IRDY 010 /* input flag */
|
||||
|
||||
/* Interrupt masks (ISR) */
|
||||
|
||||
#define INT_V_TTO 0 /* console out */
|
||||
#define INT_V_TTI 1 /* console in */
|
||||
#define INT_V_HSP 2 /* paper tape punch */
|
||||
#define INT_V_HSR 3 /* paper tape reader */
|
||||
#define INT_V_RTC 11 /* clock */
|
||||
#define INT_V_NODEF 16 /* nodefer */
|
||||
#define INT_V_ON 17 /* enable */
|
||||
#define INT_TTO (1u << INT_V_TTO)
|
||||
#define INT_TTI (1u << INT_V_TTI)
|
||||
#define INT_HSP (1u << INT_V_HSP)
|
||||
#define INT_HSR (1u << INT_V_HSR)
|
||||
#define INT_RTC (1u << INT_V_RTC)
|
||||
#define INT_NODEF (1u << INT_V_NODEF)
|
||||
#define INT_ON (1u << INT_V_ON)
|
||||
#define INT_PENDING (INT_ON | INT_NODEF)
|
||||
|
||||
/* Vectors */
|
||||
|
||||
#define VEC_BKP 0000 /* breakpoint */
|
||||
#define VEC_TTO 0011 /* console out */
|
||||
#define VEC_TTI 0014 /* console in */
|
||||
#define VEC_HSP 0017 /* paper tape punch */
|
||||
#define VEC_HSR 0022 /* paper tape reader */
|
||||
#define VEC_RTC 0100 /* clock */
|
||||
307
GRI/gri_doc.txt
Normal file
307
GRI/gri_doc.txt
Normal file
@@ -0,0 +1,307 @@
|
||||
To: Users
|
||||
From: Bob Supnik
|
||||
Subj: GRI-909 Simulator Usage
|
||||
Date: 15-Jul-02
|
||||
|
||||
COPYRIGHT NOTICE
|
||||
|
||||
The following copyright notice applies to both the SIMH source and binary:
|
||||
|
||||
Original code published in 1993-2002, written by Robert M Supnik
|
||||
Copyright (c) 1993-2002, Robert M Supnik
|
||||
|
||||
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
|
||||
ROBERT M SUPNIK 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.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
This memorandum documents the GRI-909 simulator.
|
||||
|
||||
|
||||
1. Simulator Files
|
||||
|
||||
sim/ sim_defs.h
|
||||
scp.c
|
||||
scp_tty.c
|
||||
sim_rev.c
|
||||
|
||||
sim/gri/ gri_defs.h
|
||||
gri_cpu.c
|
||||
gri_stddev.c
|
||||
gri_sys.c
|
||||
|
||||
2. GRI-909 Features
|
||||
|
||||
The GRI-909 is configured as follows:
|
||||
|
||||
device simulates
|
||||
name(s)
|
||||
|
||||
CPU GRI-909 CPU with up to 32KW of memory
|
||||
HSR S42-004 high speed reader
|
||||
HSP S42-004 high speed punch
|
||||
TTI S42-001 Teletype input
|
||||
TTO S42-002 Teletype output
|
||||
RTC real-time clock
|
||||
|
||||
The GRI-909 simulator implements the following unique stop conditions:
|
||||
|
||||
- an unimplemented operator is referenced, and register
|
||||
STOP_OPR is set
|
||||
- an invalid interrupt request is made
|
||||
|
||||
The LOAD and DUMP commands are not implemented.
|
||||
|
||||
2.1 CPU
|
||||
|
||||
The only CPU options are the presence of the extended arithmetic operator
|
||||
and the size of main memory.
|
||||
|
||||
SET CPU EAO enable extended arithmetic operator
|
||||
SET CPU NOEAO disable extended arithmetic operator
|
||||
SET CPU 4K set memory size = 4K
|
||||
SET CPU 8K set memory size = 8K
|
||||
SET CPU 12K set memory size = 12K
|
||||
SET CPU 16K set memory size = 16K
|
||||
SET CPU 20K set memory size = 20K
|
||||
SET CPU 24K set memory size = 24K
|
||||
SET CPU 28K set memory size = 28K
|
||||
SET CPU 32K set memory size = 32K
|
||||
|
||||
If memory size is being reduced, and the memory being truncated contains
|
||||
non-zero data, the simulator asks for confirmation. Data in the truncated
|
||||
portion of memory is lost. Initial memory size is 32K.
|
||||
|
||||
CPU registers include the visible state of the processor as well as the
|
||||
control registers for the interrupt system.
|
||||
|
||||
name size comments
|
||||
|
||||
SC 14 sequence counter
|
||||
AX 16 arithmetic operator input register 1
|
||||
AY 16 arithmetic operator input register 2
|
||||
AO 16 arithmetic operator output register
|
||||
TRP 16 TRP register
|
||||
MSR 16 machine status register
|
||||
ISR 16 interrupt status register
|
||||
BSW 16 byte swapper buffer
|
||||
BPK 16 byte packer buffer
|
||||
GR1..GR6 16 general registers 1 to 6
|
||||
BOV 1 bus overflow (MSR<15>)
|
||||
L 1 link (MSR<14>)
|
||||
FOA 2 arithmetic operator function (MSR<9:8>)
|
||||
AOV 1 arithmetic overflow (MSR<0>)
|
||||
IR 16 instruction register (read only)
|
||||
MA 16 memory address register (read only)
|
||||
SWR 16 switch register
|
||||
DR 16 display register
|
||||
THW 6 thumbwheels (selects operator displayed in DR)
|
||||
IREQ 16 interrupt requests
|
||||
ION 1 interrupts enabled
|
||||
INODEF 1 interrupts not deferred
|
||||
BKP 1 breakpoint request
|
||||
SCQ[0:63] 16 SC prior to last jump or interrupt;
|
||||
most recent SC change first
|
||||
STOP_OPR 1 stop on undefined operator
|
||||
WRU 8 interrupt character
|
||||
|
||||
2.2 Programmed I/O Devices
|
||||
|
||||
2.2.1 S42-004 High Speed Reader (HSR)
|
||||
|
||||
The paper tape reader (HSR) reads data from or a disk file. The POS
|
||||
register specifies the number of the next data item to be read. Thus,
|
||||
by changing POS, the user can backspace or advance the reader.
|
||||
|
||||
The paper tape reader supports the BOOT command. BOOT HSR copies the
|
||||
boot loader into memory and starts it running.
|
||||
|
||||
The paper tape reader implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
BUF 8 last data item processed
|
||||
IRDY 1 device ready flag
|
||||
IENB 1 device interrupt enable flag
|
||||
POS 32 position in the input file
|
||||
TIME 24 time from I/O initiation to interrupt
|
||||
STOP_IOE 1 stop on I/O error
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error STOP_IOE processed as
|
||||
|
||||
not attached 1 report error and stop
|
||||
0 out of tape
|
||||
|
||||
end of file 1 report error and stop
|
||||
0 out of tape
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
2.2.2 S42-006 High Speed Punch (HSP)
|
||||
|
||||
The paper tape punch (HSP) writes data to a disk file. The POS
|
||||
register specifies the number of the next data item to be written.
|
||||
Thus, by changing POS, the user can backspace or advance the punch.
|
||||
|
||||
The paper tape punch implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
BUF 8 last data item processed
|
||||
ORDY 1 device ready flag
|
||||
IENB 1 device interrupt enable flag
|
||||
POS 32 position in the output file
|
||||
TIME 24 time from I/O initiation to interrupt
|
||||
STOP_IOE 1 stop on I/O error
|
||||
|
||||
Error handling is as follows:
|
||||
|
||||
error STOP_IOE processed as
|
||||
|
||||
not attached 1 report error and stop
|
||||
0 out of tape
|
||||
|
||||
OS I/O error x report error and stop
|
||||
|
||||
2.2.3 S42-001 Teletype Input (TTI)
|
||||
|
||||
The Teletype input (TTI) polls the console keyboard for input. It
|
||||
implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
BUF 8 last data item processed
|
||||
IRDY 1 device ready flag
|
||||
IENB 1 device interrupt enable flag
|
||||
POS 32 position in the output file
|
||||
TIME 24 keyboard polling interval
|
||||
|
||||
2.2.4 S42-002 Teletype Output (TTO)
|
||||
|
||||
The Teletype output (TTO) writes to the simulator console window.
|
||||
It implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
BUF 8 last data item processed
|
||||
ORDY 1 device ready flag
|
||||
IENB 1 device interrupt enable flag
|
||||
POS 32 number of characters output
|
||||
TIME 24 time from I/O initiation to interrupt
|
||||
|
||||
2.2.5 Real-Time Clock (RTC)
|
||||
|
||||
The real-time clock (CLK) implements these registers:
|
||||
|
||||
name size comments
|
||||
|
||||
RDY 1 device ready flag
|
||||
IENB 1 interrupt enable flag
|
||||
TIME 24 clock interval
|
||||
|
||||
The real-time clock autocalibrates; the clock interval is adjusted up or
|
||||
down so that the clock tracks actual elapsed time.
|
||||
|
||||
2.3 Symbolic Display and Input
|
||||
|
||||
The GRI-909 simulator implements symbolic display and input. Display is
|
||||
controlled by command line switches:
|
||||
|
||||
-a display as ASCII character
|
||||
-c display as packed ASCII characters
|
||||
-m display instruction mnemonics
|
||||
|
||||
Input parsing is controlled by the first character typed in or by command
|
||||
line switches:
|
||||
|
||||
' or -a ASCII character
|
||||
" or -c two packed ASCII characters
|
||||
alphabetic instruction mnemonic
|
||||
numeric octal number
|
||||
|
||||
Instruction input uses modified GRI-909 basic assembler syntax. There are
|
||||
thirteen different instruction formats. Operators, functions, and tests may
|
||||
be octal or symbolic; jump conditions and bus operators are always symbolic.
|
||||
|
||||
Function out, general
|
||||
Syntax: FO function,operator
|
||||
Function symbols: INP, IRDY, ORDY, STRT
|
||||
Example: FO ORDY,TTO
|
||||
|
||||
Function out, named
|
||||
Syntax: FO{M|I|A} function
|
||||
Function symbols: M: CLL, CML, STL, HLT; I: ICF, ICO;
|
||||
A: ADD, AND, XOR, OR
|
||||
Example: FOA XOR
|
||||
|
||||
Sense function, general
|
||||
Syntax: SF operator,{NOT} tests
|
||||
Test symbols: IRDY, ORDY
|
||||
Example: SF HSR,IRDY
|
||||
|
||||
Sense function, named
|
||||
Syntax: SF{M|A} {NOT} tests
|
||||
Test symbols: M: POK BOV LNK; A: SOV AOV
|
||||
Example: SFM NOT BOV
|
||||
|
||||
Register to register
|
||||
Syntax: RR{C} src,{bus op,}dst
|
||||
Bus op symbols: P1, L1, R1
|
||||
Example: RRC AX,P1,AY
|
||||
|
||||
Zero to register
|
||||
Syntax: ZR{C} {bus op,}dst
|
||||
Bus op symbols: P1, L1, R1
|
||||
Example: ZR P1,GR1
|
||||
|
||||
Register to self
|
||||
Syntax: RS{C} dst{,bus op}
|
||||
Bus op symbols: P1, L1, R1
|
||||
Example: RS AX,L1
|
||||
|
||||
Jump unconditional or named condition
|
||||
Syntax: J{U|O|N}{D} address
|
||||
Example: JUD 1400
|
||||
|
||||
Jump conditional
|
||||
Syntax: JC{D} src,cond,address
|
||||
Cond symbols: NEVER,ALWAYS,ETZ,NEZ,LTZ,GEZ,LEZ,GTZ
|
||||
Example: JC AX,LEZ,200
|
||||
|
||||
Register to memory
|
||||
syntax: RM{I|D|ID} src,{bus op,}address
|
||||
Bus op symbols: P1, L1, R1
|
||||
Example: RMD AX,P1,1315
|
||||
|
||||
Zero to memory
|
||||
Syntax: ZM{I|D|ID} {bus op,}address
|
||||
Bus op symbols: P1, L1, R1
|
||||
Example: ZM P1,5502
|
||||
|
||||
Memory to register
|
||||
Syntax: MR{I|D|ID} address,{bus op,}dst
|
||||
Bus op symbols: P1, L1, R1
|
||||
Example: MRI 1405,GR6
|
||||
|
||||
Memory to self:
|
||||
Syntax: MS{I|D|ID} address{,bus op}
|
||||
Bus op symbols: P1, L1, R1
|
||||
Example: MS 3333,P1
|
||||
366
GRI/gri_stddev.c
Normal file
366
GRI/gri_stddev.c
Normal file
@@ -0,0 +1,366 @@
|
||||
/* gri_stddev.c: GRI-909 standard devices
|
||||
|
||||
Copyright (c) 2001-2002, Robert M Supnik
|
||||
|
||||
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
|
||||
ROBERT M SUPNIK 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.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
|
||||
tti S42-001 terminal input
|
||||
tto S42-002 terminal output
|
||||
hsr S42-004 high speed reader
|
||||
hsp S42-006 high speed punch
|
||||
rtc real time clock
|
||||
*/
|
||||
|
||||
#include "gri_defs.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */
|
||||
#define UNIT_UC (1 << UNIT_V_UC)
|
||||
|
||||
uint32 hsr_stopioe = 1, hsp_stopioe = 1;
|
||||
|
||||
extern uint16 M[];
|
||||
extern uint32 dev_done, ISR;
|
||||
|
||||
t_stat tti_svc (UNIT *uhsr);
|
||||
t_stat tto_svc (UNIT *uhsr);
|
||||
t_stat tti_reset (DEVICE *dhsr);
|
||||
t_stat tto_reset (DEVICE *dhsr);
|
||||
t_stat hsr_svc (UNIT *uhsr);
|
||||
t_stat hsp_svc (UNIT *uhsr);
|
||||
t_stat hsr_reset (DEVICE *dhsr);
|
||||
t_stat hsp_reset (DEVICE *dhsr);
|
||||
t_stat rtc_svc (UNIT *uhsr);
|
||||
t_stat rtc_reset (DEVICE *dhsr);
|
||||
int32 rtc_tps = 1000;
|
||||
|
||||
/* TTI data structures
|
||||
|
||||
tti_dev TTI device descriptor
|
||||
tti_unit TTI unit descriptor
|
||||
tti_reg TTI register list
|
||||
tti_mod TTI modifiers list
|
||||
*/
|
||||
|
||||
UNIT tti_unit = { UDATA (&tti_svc, UNIT_UC, 0), KBD_POLL_WAIT };
|
||||
|
||||
REG tti_reg[] = {
|
||||
{ ORDATA (BUF, tti_unit.buf, 8) },
|
||||
{ FLDATA (IRDY, dev_done, INT_V_TTI) },
|
||||
{ FLDATA (IENB, ISR, INT_V_TTI) },
|
||||
{ DRDATA (POS, tti_unit.pos, 32), PV_LEFT },
|
||||
{ DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT },
|
||||
{ FLDATA (UC, tti_unit.flags, UNIT_V_UC), REG_HRO },
|
||||
{ NULL } };
|
||||
|
||||
MTAB tti_mod[] = {
|
||||
{ UNIT_UC, 0, "lower case", "LC", NULL },
|
||||
{ UNIT_UC, UNIT_UC, "upper case", "UC", NULL },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE tti_dev = {
|
||||
"TTI", &tti_unit, tti_reg, tti_mod,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &tti_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* TTO data structures
|
||||
|
||||
tto_dev TTO device descriptor
|
||||
tto_unit TTO unit descriptor
|
||||
tto_reg TTO register list
|
||||
*/
|
||||
|
||||
UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT };
|
||||
|
||||
REG tto_reg[] = {
|
||||
{ ORDATA (BUF, tto_unit.buf, 8) },
|
||||
{ FLDATA (ORDY, dev_done, INT_V_TTO) },
|
||||
{ FLDATA (IENB, ISR, INT_V_TTO) },
|
||||
{ DRDATA (POS, tto_unit.pos, 32), PV_LEFT },
|
||||
{ DRDATA (TIME, tto_unit.wait, 24), PV_LEFT },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE tto_dev = {
|
||||
"TTO", &tto_unit, tto_reg, NULL,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &tto_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* HSR data structures
|
||||
|
||||
hsr_dev HSR device descriptor
|
||||
hsr_unit HSR unit descriptor
|
||||
hsr_reg HSR register list
|
||||
hsr_mod HSR modifiers list
|
||||
*/
|
||||
|
||||
UNIT hsr_unit = {
|
||||
UDATA (&hsr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), SERIAL_IN_WAIT };
|
||||
|
||||
REG hsr_reg[] = {
|
||||
{ ORDATA (BUF, hsr_unit.buf, 8) },
|
||||
{ FLDATA (IRDY, dev_done, INT_V_HSR) },
|
||||
{ FLDATA (IENB, ISR, INT_V_HSR) },
|
||||
{ DRDATA (POS, hsr_unit.pos, 32), PV_LEFT },
|
||||
{ DRDATA (TIME, hsr_unit.wait, 24), REG_NZ + PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, hsr_stopioe, 0) },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE hsr_dev = {
|
||||
"HSR", &hsr_unit, hsr_reg, NULL,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &hsr_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* HSP data structures
|
||||
|
||||
hsp_dev HSP device descriptor
|
||||
hsp_unit HSP unit descriptor
|
||||
hsp_reg HSP register list
|
||||
*/
|
||||
|
||||
UNIT hsp_unit = {
|
||||
UDATA (&hsp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
|
||||
|
||||
REG hsp_reg[] = {
|
||||
{ ORDATA (BUF, hsp_unit.buf, 8) },
|
||||
{ FLDATA (ORDY, dev_done, INT_V_HSP) },
|
||||
{ FLDATA (IENB, ISR, INT_V_HSP) },
|
||||
{ DRDATA (POS, hsp_unit.pos, 32), PV_LEFT },
|
||||
{ DRDATA (TIME, hsp_unit.wait, 24), PV_LEFT },
|
||||
{ FLDATA (STOP_IOE, hsp_stopioe, 0) },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE hsp_dev = {
|
||||
"HSP", &hsp_unit, hsp_reg, NULL,
|
||||
1, 10, 31, 1, 8, 8,
|
||||
NULL, NULL, &hsp_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* RTC data structures
|
||||
|
||||
rtc_dev RTC device descriptor
|
||||
rtc_unit RTC unit descriptor
|
||||
rtc_reg RTC register list
|
||||
*/
|
||||
|
||||
UNIT rtc_unit = { UDATA (&rtc_svc, 0, 0), 16000 };
|
||||
|
||||
REG rtc_reg[] = {
|
||||
{ FLDATA (RDY, dev_done, INT_V_RTC) },
|
||||
{ FLDATA (IENB, ISR, INT_V_RTC) },
|
||||
{ DRDATA (TIME, rtc_unit.wait, 24), REG_NZ + PV_LEFT },
|
||||
{ DRDATA (TPS, rtc_tps, 8), REG_NZ + PV_LEFT + REG_HIDDEN },
|
||||
{ NULL } };
|
||||
|
||||
DEVICE rtc_dev = {
|
||||
"RTC", &rtc_unit, rtc_reg, NULL,
|
||||
1, 0, 0, 0, 0, 0,
|
||||
NULL, NULL, &rtc_reset,
|
||||
NULL, NULL, NULL };
|
||||
|
||||
/* Console terminal function processors */
|
||||
|
||||
int32 tty_rd (int32 src, int32 ea)
|
||||
{
|
||||
return tti_unit.buf; /* return data */
|
||||
}
|
||||
|
||||
t_stat tty_wr (uint32 dst, uint32 val)
|
||||
{
|
||||
tto_unit.buf = val & 0377; /* save char */
|
||||
dev_done = dev_done & ~INT_TTO; /* clear ready */
|
||||
sim_activate (&tto_unit, tto_unit.wait); /* activate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat tty_fo (uint32 op)
|
||||
{
|
||||
if (op & TTY_IRDY) dev_done = dev_done & ~INT_TTI;
|
||||
if (op & TTY_ORDY) dev_done = dev_done & ~INT_TTO;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
uint32 tty_sf (uint32 op)
|
||||
{
|
||||
if (((op & TTY_IRDY) && (dev_done & INT_TTI)) ||
|
||||
((op & TTY_ORDY) && (dev_done & INT_TTO))) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Service routines */
|
||||
|
||||
t_stat tti_svc (UNIT *uhsr)
|
||||
{
|
||||
int32 temp;
|
||||
|
||||
sim_activate (&tti_unit, tti_unit.wait); /* continue poll */
|
||||
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */
|
||||
temp = temp & 0177;
|
||||
if ((tti_unit.flags & UNIT_UC) && islower (temp))
|
||||
temp = toupper (temp);
|
||||
tti_unit.buf = temp | 0200; /* got char */
|
||||
dev_done = dev_done | INT_TTI; /* set ready */
|
||||
tti_unit.pos = tti_unit.pos + 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat tto_svc (UNIT *uhsr)
|
||||
{
|
||||
int32 temp;
|
||||
|
||||
dev_done = dev_done | INT_TTO; /* set ready */
|
||||
if ((temp = sim_putchar (tto_unit.buf & 0177)) != SCPE_OK) return temp;
|
||||
tto_unit.pos = tto_unit.pos + 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routines */
|
||||
|
||||
t_stat tti_reset (DEVICE *dhsr)
|
||||
{
|
||||
tti_unit.buf = 0; /* clear buffer */
|
||||
dev_done = dev_done & ~INT_TTI; /* clear ready */
|
||||
sim_activate (&tti_unit, tti_unit.wait); /* activate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat tto_reset (DEVICE *dhsr)
|
||||
{
|
||||
tto_unit.buf = 0; /* clear buffer */
|
||||
dev_done = dev_done | INT_TTO; /* set ready */
|
||||
sim_cancel (&tto_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* High speed paper tape function processors */
|
||||
|
||||
int32 hsrp_rd (int32 src, int32 ea)
|
||||
{
|
||||
return hsr_unit.buf; /* return data */
|
||||
}
|
||||
|
||||
t_stat hsrp_wr (uint32 dst, uint32 val)
|
||||
{
|
||||
hsp_unit.buf = val & 0377; /* save char */
|
||||
dev_done = dev_done & ~INT_HSP; /* clear ready */
|
||||
sim_activate (&hsp_unit, hsp_unit.wait); /* activate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat hsrp_fo (uint32 op)
|
||||
{
|
||||
if (op & PT_IRDY) dev_done = dev_done & ~INT_HSR;
|
||||
if (op & PT_ORDY) dev_done = dev_done & ~INT_HSP;
|
||||
if (op & PT_STRT) sim_activate (&hsr_unit, hsr_unit.wait);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
uint32 hsrp_sf (uint32 op)
|
||||
{
|
||||
if (((op & PT_IRDY) && (dev_done & INT_HSR)) ||
|
||||
((op & PT_ORDY) && (dev_done & INT_HSP))) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
t_stat hsr_svc (UNIT *uhsr)
|
||||
{
|
||||
int32 temp;
|
||||
|
||||
if ((hsr_unit.flags & UNIT_ATT) == 0) /* attached? */
|
||||
return IORETURN (hsr_stopioe, SCPE_UNATT);
|
||||
if ((temp = getc (hsr_unit.fileref)) == EOF) { /* read char */
|
||||
if (feof (hsr_unit.fileref)) { /* err or eof? */
|
||||
if (hsr_stopioe) printf ("HSR end of file\n");
|
||||
else return SCPE_OK; }
|
||||
else perror ("HSR I/O error");
|
||||
clearerr (hsr_unit.fileref);
|
||||
return SCPE_IOERR; }
|
||||
dev_done = dev_done | INT_HSR; /* set ready */
|
||||
hsr_unit.buf = temp & 0377; /* save char */
|
||||
hsr_unit.pos = hsr_unit.pos + 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat hsp_svc (UNIT *uhsr)
|
||||
{
|
||||
dev_done = dev_done | INT_HSP; /* set ready */
|
||||
if ((hsp_unit.flags & UNIT_ATT) == 0) /* attached? */
|
||||
return IORETURN (hsp_stopioe, SCPE_UNATT);
|
||||
if (putc (hsp_unit.buf, hsp_unit.fileref) == EOF) { /* write char */
|
||||
perror ("HSP I/O error"); /* error? */
|
||||
clearerr (hsp_unit.fileref);
|
||||
return SCPE_IOERR; }
|
||||
hsp_unit.pos = hsp_unit.pos + 1;
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routines */
|
||||
|
||||
t_stat hsr_reset (DEVICE *dhsr)
|
||||
{
|
||||
hsr_unit.buf = 0; /* clear buffer */
|
||||
dev_done = dev_done & ~INT_HSR; /* clear ready */
|
||||
sim_cancel (&hsr_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat hsp_reset (DEVICE *dhsr)
|
||||
{
|
||||
hsp_unit.buf = 0; /* clear buffer */
|
||||
dev_done = dev_done | INT_HSP; /* set ready */
|
||||
sim_cancel (&hsp_unit); /* deactivate unit */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Clock function processors */
|
||||
|
||||
t_stat rtc_fo (int32 op)
|
||||
{
|
||||
if (op & RTC_OFF) sim_cancel (&rtc_unit); /* clock off? */
|
||||
if ((op & RTC_ON) && !sim_is_active (&rtc_unit)) /* clock on? */
|
||||
sim_activate (&rtc_unit, sim_rtc_init (rtc_unit.wait));
|
||||
if (op & RTC_OV) dev_done = dev_done & ~INT_RTC; /* clr ovflo? */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
int32 rtc_sf (int32 op)
|
||||
{
|
||||
if ((op & RTC_OV) && (dev_done & INT_RTC)) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
t_stat rtc_svc (UNIT *uhsr)
|
||||
{
|
||||
M[RTC_CTR] = (M[RTC_CTR] + 1) & DMASK; /* incr counter */
|
||||
if (M[RTC_CTR] == 0) dev_done = dev_done | INT_RTC; /* ovflo? set ready */
|
||||
sim_activate (&rtc_unit, sim_rtc_calb (rtc_tps)); /* reactivate */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat rtc_reset (DEVICE *dhsr)
|
||||
{
|
||||
dev_done = dev_done & ~INT_RTC; /* clear ready */
|
||||
sim_cancel (&rtc_unit); /* stop clock */
|
||||
return SCPE_OK;
|
||||
}
|
||||
578
GRI/gri_sys.c
Normal file
578
GRI/gri_sys.c
Normal file
@@ -0,0 +1,578 @@
|
||||
/* gri_sys.c: GRI-909 simulator interface
|
||||
|
||||
Copyright (c) 2001-2002, Robert M Supnik
|
||||
|
||||
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
|
||||
ROBERT M SUPNIK 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.
|
||||
|
||||
Except as contained in this notice, the name of Robert M Supnik shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization from Robert M Supnik.
|
||||
*/
|
||||
|
||||
#include "gri_defs.h"
|
||||
#include <ctype.h>
|
||||
|
||||
extern DEVICE cpu_dev;
|
||||
extern UNIT cpu_unit;
|
||||
extern DEVICE tti_dev, tto_dev;
|
||||
extern DEVICE hsr_dev, hsp_dev;
|
||||
extern DEVICE rtc_dev;
|
||||
extern REG cpu_reg[];
|
||||
extern uint16 M[];
|
||||
extern int32 sim_switches;
|
||||
|
||||
/* SCP data structures and interface routines
|
||||
|
||||
sim_name simulator name string
|
||||
sim_PC pointer to saved PC register descriptor
|
||||
sim_emax maximum number of words for examine/deposit
|
||||
sim_devices array of pointers to simulated devices
|
||||
sim_stop_messages array of pointers to stop messages
|
||||
sim_load binary loader
|
||||
*/
|
||||
|
||||
char sim_name[] = "GRI-909";
|
||||
|
||||
REG *sim_PC = &cpu_reg[0];
|
||||
|
||||
int32 sim_emax = 2;
|
||||
|
||||
DEVICE *sim_devices[] = {
|
||||
&cpu_dev,
|
||||
&tti_dev,
|
||||
&tto_dev,
|
||||
&hsr_dev,
|
||||
&hsp_dev,
|
||||
&rtc_dev,
|
||||
NULL };
|
||||
|
||||
const char *sim_stop_messages[] = {
|
||||
"Unknown error",
|
||||
"Unimplemented unit",
|
||||
"HALT instruction",
|
||||
"Breakpoint",
|
||||
"Invalid interrupt request" };
|
||||
|
||||
/* Binary loader
|
||||
|
||||
Bootstrap loader format consists of blocks separated by zeroes. Each
|
||||
word in the block has three frames: a control frame (ignored) and two
|
||||
data frames. The user must specify the load address. Switch -c means
|
||||
continue and load all blocks until end of tape.
|
||||
*/
|
||||
|
||||
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
|
||||
{
|
||||
int32 c, org;
|
||||
t_stat r;
|
||||
char gbuf[CBUFSIZE];
|
||||
|
||||
if (*cptr != 0) { /* more input? */
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get origin */
|
||||
org = get_uint (gbuf, 8, AMASK, &r);
|
||||
if (r != SCPE_OK) return r;
|
||||
if (*cptr != 0) return SCPE_ARG; } /* no more */
|
||||
else org = 0200; /* default 200 */
|
||||
|
||||
for (;;) { /* until EOF */
|
||||
while ((c = getc (fileref)) == 0) ; /* skip starting 0's */
|
||||
if (c == EOF) break; /* EOF? done */
|
||||
for ( ; c != 0; ) { /* loop until ctl = 0 */
|
||||
/* ign ctrl frame */
|
||||
if ((c = getc (fileref)) == EOF) /* get high byte */
|
||||
return SCPE_FMT; /* EOF is error */
|
||||
if (!MEM_ADDR_OK (org)) return SCPE_NXM;
|
||||
M[org] = ((c & 0377) << 8); /* store high */
|
||||
if ((c = getc (fileref)) == EOF) /* get low byte */
|
||||
return SCPE_FMT; /* EOF is error */
|
||||
M[org] = M[org] | (c & 0377); /* store low */
|
||||
org = org + 1; /* incr origin */
|
||||
if ((c = getc (fileref)) == EOF) /* get ctrl frame */
|
||||
return SCPE_OK; /* EOF is ok */
|
||||
} /* end block for */
|
||||
if (!(sim_switches & SWMASK ('C'))) return SCPE_OK;
|
||||
} /* end tape for */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Symbol tables */
|
||||
|
||||
#define F_V_FL 16
|
||||
#define F_M_FL 017
|
||||
#define F_V_FO 000 /* function out */
|
||||
#define F_V_FOI 001 /* FO, impl reg */
|
||||
#define F_V_SF 002 /* skip function */
|
||||
#define F_V_SFI 003 /* SF, impl reg */
|
||||
#define F_V_RR 004 /* reg reg */
|
||||
#define F_V_ZR 005 /* zero reg */
|
||||
#define F_V_RS 006 /* reg self */
|
||||
#define F_V_JC 010 /* jump cond */
|
||||
#define F_V_JU 011 /* jump uncond */
|
||||
#define F_V_RM 012 /* reg mem */
|
||||
#define F_V_ZM 013 /* zero mem */
|
||||
#define F_V_MR 014 /* mem reg */
|
||||
#define F_V_MS 015 /* mem self */
|
||||
#define F_2WD 010 /* 2 words */
|
||||
|
||||
#define F_FO (F_V_FO << F_V_FL)
|
||||
#define F_FOI (F_V_FOI << F_V_FL)
|
||||
#define F_SF (F_V_SF << F_V_FL)
|
||||
#define F_SFI (F_V_SFI << F_V_FL)
|
||||
#define F_RR (F_V_RR << F_V_FL)
|
||||
#define F_ZR (F_V_ZR << F_V_FL)
|
||||
#define F_RS (F_V_RS << F_V_FL)
|
||||
#define F_JC (F_V_JC << F_V_FL)
|
||||
#define F_JU (F_V_JU << F_V_FL)
|
||||
#define F_RM (F_V_RM << F_V_FL)
|
||||
#define F_ZM (F_V_ZM << F_V_FL)
|
||||
#define F_MR (F_V_MR << F_V_FL)
|
||||
#define F_MS (F_V_MS << F_V_FL)
|
||||
|
||||
struct fnc_op {
|
||||
uint32 inst; /* instr prot */
|
||||
uint32 imask; /* instr mask */
|
||||
uint32 oper; /* operator */
|
||||
uint32 omask; }; /* oper mask */
|
||||
|
||||
static const int32 masks[] = {
|
||||
0176000, 0176077, 0000077, 0176077,
|
||||
0000300, 0176300, 0000300, 0177777,
|
||||
0000077, 0177777, 0000377, 0176377,
|
||||
0176300, 0176377 };
|
||||
|
||||
/* Instruction mnemonics
|
||||
|
||||
Order is critical, as some instructions are more precise versions of
|
||||
others. For example, JU must precede JC, otherwise, JU will be decoded
|
||||
as JC 0,ETZ,dst. There are some ambiguities, eg, what is 02-xxxx-06?
|
||||
Priority is as follows:
|
||||
|
||||
FO (02-xxxx-rr)
|
||||
SF (rr-xxxx-02)
|
||||
MR (06-xxxx-rr)
|
||||
RM (rr-xxxx-06)
|
||||
JC (rr-xxxx-03)
|
||||
RR
|
||||
*/
|
||||
|
||||
static const char *opcode[] = {
|
||||
"FOM", "FOA", "FOI", "FO", /* FOx before FO */
|
||||
"SFM", "SFA", "SFI", "SF", /* SFx before SF */
|
||||
"ZM", "ZMD", "ZMI", "ZMID", /* ZM before RM */
|
||||
"MS", "MSD", "MSI", "MSID",
|
||||
"RM", "RMD", "RMI", "RMID",
|
||||
"MR", "MRD", "MRI", "MRID",
|
||||
"JO", "JOD", "JN", "JND", /* JU before JC */
|
||||
"JU", "JUD", "JC", "JCD",
|
||||
"ZR", "ZRC", "RR", "RRC", /* ZR before RR */
|
||||
"RS", "RSC",
|
||||
NULL };
|
||||
|
||||
static const uint32 opc_val[] = {
|
||||
0004000+F_FOI, 0004013+F_FOI, 0004004+F_FOI, 0004000+F_FO,
|
||||
0000002+F_SFI, 0026002+F_SFI, 0010002+F_SFI, 0000002+F_SF,
|
||||
0000006+F_ZM, 0000106+F_ZM, 0000206+F_ZM, 0000306+F_ZM,
|
||||
0014006+F_MS, 0014106+F_MS, 0014206+F_MS, 0014306+F_MS,
|
||||
0000006+F_RM, 0000106+F_RM, 0000206+F_RM, 0000306+F_RM,
|
||||
0014000+F_MR, 0014100+F_MR, 0014200+F_MR, 0014300+F_MR,
|
||||
0037003+F_JU, 0037103+F_JU, 0037203+F_JU, 0037303+F_JU,
|
||||
0000403+F_JU, 0000503+F_JU, 0000003+F_JC, 0000103+F_JC,
|
||||
0000000+F_ZR, 0000200+F_ZR, 0000000+F_RR, 0000200+F_RR,
|
||||
0000000+F_RS, 0000200+F_RS };
|
||||
|
||||
/* Unit mnemonics. All 64 units are decoded, most just to octal integers */
|
||||
|
||||
static const char *unsrc[64] = {
|
||||
"0", "IR", "2", "TRP", "ISR", "MA", "MB", "SC", /* 00 - 07 */
|
||||
"SWR", "AX", "AY", "AO", "14", "15", "16", "MSR", /* 10 - 17 */
|
||||
"20", "21", "22", "23", "BSW", "BPK", "26", "27", /* 20 - 27 */
|
||||
"GR1", "GR2", "GR3", "GR4", "GR5", "GR6", "36", "37", /* 30 - 37 */
|
||||
"40", "41", "42", "43", "44", "45", "46", "47",
|
||||
"50", "51", "52", "53", "54", "55", "56", "57",
|
||||
"60", "61", "62", "63", "64", "65", "66", "67",
|
||||
"70", "71", "72", "73", "74", "RTC", "HSR", "TTI" }; /* 70 - 77 */
|
||||
|
||||
static const char *undst[64] = {
|
||||
"0", "IR", "2", "TRP", "ISR", "5", "MB", "SC", /* 00 - 07 */
|
||||
"SWR", "AX", "AY", "13", "EAO", "15", "16", "MSR", /* 10 - 17 */
|
||||
"20", "21", "22", "23", "BSW", "BPK", "26", "27", /* 20 - 27 */
|
||||
"GR1", "GR2", "GR3", "GR4", "GR5", "GR6", "36", "37", /* 30 - 37 */
|
||||
"40", "41", "42", "43", "44", "45", "46", "47",
|
||||
"50", "51", "52", "53", "54", "55", "56", "57",
|
||||
"60", "61", "62", "63", "64", "65", "66", "67",
|
||||
"70", "71", "72", "73", "74", "RTC", "HSP", "TTO" }; /* 70 - 77 */
|
||||
|
||||
/* Operators */
|
||||
|
||||
static const char *opname[4] = {
|
||||
NULL, "P1", "L1", "R1" };
|
||||
|
||||
/* Conditions */
|
||||
|
||||
static const char *cdname[8] = {
|
||||
"NEVER", "ALWAYS", "ETZ", "NEZ", "LTZ", "GEZ", "LEZ", "GTZ" };
|
||||
|
||||
/* Function out/sense function */
|
||||
|
||||
static const char *fname[] = {
|
||||
"NOT", /* any SF */
|
||||
"POK", "LNK", "BOV", /* SFM */
|
||||
"SOV", "AOV", /* SFA */
|
||||
"IRDY", "ORDY", /* any SF */
|
||||
"CLL", "STL", "CML", "HLT", /* FOM */
|
||||
"ICF", "ICO", /* FOI */
|
||||
"ADD", "AND", "XOR", "OR", /* FOA */
|
||||
"INP", "IRDY", "ORDY", "STRT", /* any FO */
|
||||
NULL };
|
||||
|
||||
static const struct fnc_op fop[] = {
|
||||
{ 0000002, 0000077, 001, 001 }, /* NOT */
|
||||
{ 0000002, 0176077, 010, 010 }, /* POK */
|
||||
{ 0000002, 0176077, 004, 004 }, /* LNK */
|
||||
{ 0000002, 0176077, 002, 002 }, /* BOV */
|
||||
{ 0026002, 0176077, 004, 004 }, /* SOV */
|
||||
{ 0026002, 0176077, 002, 002 }, /* AOV */
|
||||
{ 0000002, 0000077, 010, 010 }, /* IRDY */
|
||||
{ 0000002, 0000077, 002, 002 }, /* ORDY */
|
||||
{ 0004000, 0176077, 001, 003 }, /* CLL */
|
||||
{ 0004000, 0176077, 002, 003 }, /* STL */
|
||||
{ 0004000, 0176077, 003, 003 }, /* CML */
|
||||
{ 0004000, 0176077, 004, 004 }, /* HLT */
|
||||
{ 0004004, 0176077, 001, 001 }, /* ICF */
|
||||
{ 0004004, 0176077, 002, 002 }, /* ICO */
|
||||
{ 0004013, 0176077, 000, 014 }, /* ADD */
|
||||
{ 0004013, 0176077, 004, 014 }, /* AND */
|
||||
{ 0004013, 0176077, 010, 014 }, /* XOR */
|
||||
{ 0004013, 0176077, 014, 014 }, /* OR */
|
||||
{ 0004000, 0176000, 011, 011 }, /* INP */
|
||||
{ 0004000, 0176000, 010, 010 }, /* IRDY */
|
||||
{ 0004000, 0176000, 002, 002 }, /* ORDY */
|
||||
{ 0004000, 0176000, 001, 001 } }; /* STRT */
|
||||
|
||||
/* Print opcode field for FO, SF */
|
||||
|
||||
void fprint_op (FILE *of, uint32 inst, uint32 op)
|
||||
{
|
||||
int32 i, nfirst;
|
||||
|
||||
for (i = nfirst = 0; fname[i] != NULL; i++) {
|
||||
if (((inst & fop[i].imask) == fop[i].inst) &&
|
||||
((op & fop[i].omask) == fop[i].oper)) {
|
||||
op = op & ~fop[i].omask;
|
||||
if (nfirst) fputc (' ', of);
|
||||
nfirst = 1;
|
||||
fprintf (of, "%s", fname[i]); }
|
||||
}
|
||||
if (op) fprintf (of, " %o", op);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Symbolic decode
|
||||
|
||||
Inputs:
|
||||
*of = output stream
|
||||
addr = current PC
|
||||
*val = pointer to data
|
||||
*uptr = pointer to unit
|
||||
sw = switches
|
||||
Outputs:
|
||||
return = status code
|
||||
*/
|
||||
|
||||
#define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)
|
||||
|
||||
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
|
||||
UNIT *uptr, int32 sw)
|
||||
{
|
||||
int32 i, j;
|
||||
uint32 inst, src, dst, op, bop;
|
||||
|
||||
inst = val[0];
|
||||
if (sw & SWMASK ('A')) { /* ASCII? */
|
||||
if (inst > 0377) return SCPE_ARG;
|
||||
fprintf (of, FMTASC (inst & 0177));
|
||||
return SCPE_OK; }
|
||||
if (sw & SWMASK ('C')) { /* characters? */
|
||||
fprintf (of, FMTASC ((inst >> 8) & 0177));
|
||||
fprintf (of, FMTASC (inst & 0177));
|
||||
return SCPE_OK; }
|
||||
if (!(sw & SWMASK ('M'))) return SCPE_ARG;
|
||||
|
||||
/* Instruction decode */
|
||||
|
||||
inst = val[0];
|
||||
src = I_GETSRC (inst); /* get fields */
|
||||
op = I_GETOP (inst);
|
||||
dst = I_GETDST (inst);
|
||||
bop = op >> 2; /* bus op */
|
||||
for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
|
||||
j = (opc_val[i] >> F_V_FL) & F_M_FL; /* get class */
|
||||
if ((opc_val[i] & DMASK) == (inst & masks[j])) { /* match? */
|
||||
|
||||
switch (j) { /* case on class */
|
||||
case F_V_FO: /* func out */
|
||||
fprintf (of, "%s ", opcode[i]);
|
||||
fprint_op (of, inst, op);
|
||||
fprintf (of, ",%s", undst[dst]);
|
||||
break;
|
||||
case F_V_FOI: /* func out impl */
|
||||
fprintf (of, "%s ", opcode[i]);
|
||||
fprint_op (of, inst, op);
|
||||
break;
|
||||
case F_V_SF: /* skip func */
|
||||
fprintf (of, "%s %s,", opcode[i], unsrc[src]);
|
||||
fprint_op (of, inst, op);
|
||||
break;
|
||||
case F_V_SFI: /* skip func impl */
|
||||
fprintf (of, "%s ", opcode[i]);
|
||||
fprint_op (of, inst, op);
|
||||
break;
|
||||
case F_V_RR: /* reg reg */
|
||||
if (strcmp (unsrc[src], undst[dst]) == 0) {
|
||||
if (bop) fprintf (of, "%s %s,%s", opcode[i + 2],
|
||||
unsrc[src], opname[bop]);
|
||||
else fprintf (of, "%s %s", opcode[i + 2], unsrc[src]); }
|
||||
else { if (bop) fprintf (of, "%s %s,%s,%s", opcode[i],
|
||||
unsrc[src], opname[bop], undst[dst]);
|
||||
else fprintf (of, "%s %s,%s", opcode[i],
|
||||
unsrc[src], undst[dst]); }
|
||||
break;
|
||||
case F_V_ZR: /* zero reg */
|
||||
if (bop) fprintf (of, "%s %s,%s", opcode[i],
|
||||
opname[bop], undst[dst]);
|
||||
else fprintf (of, "%s %s", opcode[i], undst[dst]);
|
||||
break;
|
||||
case F_V_JC: /* jump cond */
|
||||
fprintf (of, "%s %s,%s,%o", opcode[i],
|
||||
unsrc[src], cdname[op >> 1], val[1]);
|
||||
break;
|
||||
case F_V_JU: /* jump uncond */
|
||||
fprintf (of, "%s %o", opcode[i], val[1]);
|
||||
break;
|
||||
case F_V_RM: /* reg mem */
|
||||
if (bop) fprintf (of, "%s %s,%s,%o", opcode[i],
|
||||
unsrc[src], opname[bop], val[1]);
|
||||
else fprintf (of, "%s %s,%o", opcode[i], unsrc[src], val[1]);
|
||||
break;
|
||||
case F_V_ZM: /* zero mem */
|
||||
if (bop) fprintf (of, "%s %s,%o", opcode[i],
|
||||
opname[bop], val[1]);
|
||||
else fprintf (of, "%s %o", opcode[i], val[1]);
|
||||
break;
|
||||
case F_V_MR: /* mem reg */
|
||||
if (bop) fprintf (of, "%s %o,%s,%s", opcode[i],
|
||||
val[1], opname[bop], undst[dst]);
|
||||
else fprintf (of, "%s %o,%s", opcode[i], val[1], undst[dst]);
|
||||
break;
|
||||
case F_V_MS: /* mem self */
|
||||
if (bop) fprintf (of, "%s %o,%s", opcode[i],
|
||||
val[1], opname[bop]);
|
||||
else fprintf (of, "%s %o", opcode[i], val[1]);
|
||||
break; } /* end case */
|
||||
return (j >= F_2WD)? -1: SCPE_OK; } /* end if */
|
||||
} /* end for */
|
||||
return SCPE_ARG;
|
||||
}
|
||||
|
||||
/* Field parse routines
|
||||
|
||||
get_fnc get function field
|
||||
get_ma get memory address
|
||||
get_sd get source or dest
|
||||
get_op get optional bus operator
|
||||
*/
|
||||
|
||||
char *get_fnc (char *cptr, t_value *val)
|
||||
{
|
||||
char gbuf[CBUFSIZE];
|
||||
int32 i;
|
||||
t_value d;
|
||||
t_stat r;
|
||||
uint32 inst = val[0];
|
||||
uint32 fncv = 0, fncm = 0;
|
||||
|
||||
while (*cptr) {
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
|
||||
d = get_uint (gbuf, 8, 017, &r); /* octal? */
|
||||
if (r == SCPE_OK) { /* ok? */
|
||||
if (d & fncm) return NULL; /* already filled? */
|
||||
fncv = fncv | d; /* save */
|
||||
fncm = fncm | d; } /* field filled */
|
||||
else { /* symbol? */
|
||||
for (i = 0; fname[i] != NULL; i++) { /* search table */
|
||||
if ((strcmp (gbuf, fname[i]) == 0) && /* match for inst? */
|
||||
((inst & fop[i].imask) == fop[i].inst)) {
|
||||
if (fop[i].oper & fncm) return NULL; /* already filled? */
|
||||
fncm = fncm | fop[i].omask;
|
||||
fncv = fncv | fop[i].oper;
|
||||
break; } }
|
||||
if (fname[i] == NULL) return NULL; } /* end else */
|
||||
} /* end while */
|
||||
val[0] = val[0] | (fncv << I_V_OP); /* store fnc */
|
||||
return cptr;
|
||||
}
|
||||
|
||||
char *get_ma (char *cptr, t_value *val, char term)
|
||||
{
|
||||
char gbuf[CBUFSIZE];
|
||||
t_value d;
|
||||
t_stat r;
|
||||
|
||||
cptr = get_glyph (cptr, gbuf, term); /* get glyph */
|
||||
d = get_uint (gbuf, 8, DMASK, &r); /* [0,177777] */
|
||||
if (r != SCPE_OK) return NULL;
|
||||
val[1] = d; /* second wd */
|
||||
return cptr;
|
||||
}
|
||||
|
||||
char *get_sd (char *cptr, t_value *val, char term, t_bool src)
|
||||
{
|
||||
char gbuf[CBUFSIZE];
|
||||
int32 d;
|
||||
t_stat r;
|
||||
|
||||
cptr = get_glyph (cptr, gbuf, term); /* get glyph */
|
||||
for (d = 0; d < 64; d++) { /* symbol match? */
|
||||
if ((strcmp (gbuf, unsrc[d]) == 0) ||
|
||||
(strcmp (gbuf, undst[d]) == 0)) break; }
|
||||
if (d >= 64) { /* no, [0,63]? */
|
||||
d = get_uint (gbuf, 8, 077, &r);
|
||||
if (r != SCPE_OK) return NULL; }
|
||||
val[0] = val[0] | (d << (src? I_V_SRC: I_V_DST)); /* or to inst */
|
||||
return cptr;
|
||||
}
|
||||
|
||||
char *get_op (char *cptr, t_value *val, char term)
|
||||
{
|
||||
char gbuf[CBUFSIZE], *tptr;
|
||||
int32 i;
|
||||
|
||||
tptr = get_glyph (cptr, gbuf, term); /* get glyph */
|
||||
for (i = 1; i < 4; i++) { /* symbol match? */
|
||||
if (strcmp (gbuf, opname[i]) == 0) {
|
||||
val[0] = val[0] | (i << (I_V_OP + 2)); /* or to inst */
|
||||
return tptr; } }
|
||||
return cptr; /* original ptr */
|
||||
}
|
||||
|
||||
/* Symbolic input
|
||||
|
||||
Inputs:
|
||||
*cptr = pointer to input string
|
||||
addr = current PC
|
||||
*uptr = pointer to unit
|
||||
*val = pointer to output values
|
||||
sw = switches
|
||||
Outputs:
|
||||
status = error status
|
||||
*/
|
||||
|
||||
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
|
||||
{
|
||||
int32 i, j, k;
|
||||
char *tptr, gbuf[CBUFSIZE];
|
||||
|
||||
while (isspace (*cptr)) cptr++; /* absorb spaces */
|
||||
if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
|
||||
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
|
||||
val[0] = (t_value) cptr[0] & 0177;
|
||||
return SCPE_OK; }
|
||||
if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* char string? */
|
||||
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
|
||||
val[0] = (((t_value) cptr[0] & 0177) << 8) |
|
||||
((t_value) cptr[1] & 0177);
|
||||
return SCPE_OK; }
|
||||
|
||||
/* Instruction parse */
|
||||
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
|
||||
for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
|
||||
if (opcode[i] == NULL) return SCPE_ARG;
|
||||
val[0] = opc_val[i] & DMASK; /* get value */
|
||||
j = (opc_val[i] >> F_V_FL) & F_M_FL; /* get class */
|
||||
|
||||
switch (j) { /* case on class */
|
||||
case F_V_FO: /* func out */
|
||||
tptr = strchr (cptr, ','); /* find dst */
|
||||
if (!tptr) return SCPE_ARG; /* none? */
|
||||
*tptr = 0; /* split fields */
|
||||
cptr = get_fnc (cptr, val); /* fo # */
|
||||
if (!cptr) return SCPE_ARG;
|
||||
cptr = get_sd (tptr + 1, val, 0, FALSE); /* dst */
|
||||
break;
|
||||
case F_V_FOI: /* func out impl */
|
||||
cptr = get_fnc (cptr, val); /* fo # */
|
||||
break;
|
||||
case F_V_SF: /* skip func */
|
||||
cptr = get_sd (cptr, val, ',', TRUE); /* src */
|
||||
if (!cptr) return SCPE_ARG;
|
||||
case F_V_SFI: /* skip func impl */
|
||||
cptr = get_fnc (cptr, val); /* fo # */
|
||||
break;
|
||||
case F_V_RR: /* reg-reg */
|
||||
cptr = get_sd (cptr, val, ',', TRUE); /* src */
|
||||
if (!cptr) return SCPE_ARG;
|
||||
cptr = get_op (cptr, val, ','); /* op */
|
||||
if (!cptr) return SCPE_ARG;
|
||||
cptr = get_sd (cptr, val, 0, FALSE); /* dst */
|
||||
break;
|
||||
case F_V_ZR: /* zero-reg */
|
||||
cptr = get_op (cptr, val, ','); /* op */
|
||||
if (!cptr) return SCPE_ARG;
|
||||
cptr = get_sd (cptr, val, 0, FALSE); /* dst */
|
||||
break;
|
||||
case F_V_RS: /* reg self */
|
||||
cptr = get_sd (cptr, val, ',', TRUE); /* src */
|
||||
if (!cptr) return SCPE_ARG;
|
||||
val[0] = val[0] | I_GETSRC (val[0]); /* duplicate */
|
||||
cptr = get_op (cptr, val, 0); /* op */
|
||||
break;
|
||||
case F_V_JC: /* jump cond */
|
||||
cptr = get_sd (cptr, val, ',', TRUE); /* src */
|
||||
if (!cptr) return SCPE_ARG;
|
||||
cptr = get_glyph (cptr, gbuf, ','); /* cond */
|
||||
for (k = 0; k < 8; k++) { /* symbol? */
|
||||
if (strcmp (gbuf, cdname[k]) == 0) break; }
|
||||
if (k >= 8) return SCPE_ARG;
|
||||
val[0] = val[0] | (k << (I_V_OP + 1)); /* or to inst */
|
||||
case F_V_JU: /* jump uncond */
|
||||
cptr = get_ma (cptr, val, 0); /* addr */
|
||||
break;
|
||||
case F_V_RM: /* reg mem */
|
||||
cptr = get_sd (cptr, val, ',', TRUE); /* src */
|
||||
if (!cptr) return SCPE_ARG;
|
||||
case F_V_ZM: /* zero mem */
|
||||
cptr = get_op (cptr, val, ','); /* op */
|
||||
if (!cptr) return SCPE_ARG;
|
||||
cptr = get_ma (cptr, val, 0); /* addr */
|
||||
break;
|
||||
case F_V_MR: /* mem reg */
|
||||
cptr = get_ma (cptr, val, ','); /* addr */
|
||||
if (!cptr) return SCPE_ARG;
|
||||
cptr = get_op (cptr, val, ','); /* op */
|
||||
if (!cptr) return SCPE_ARG;
|
||||
cptr = get_sd (cptr, val, 0, FALSE); /* dst */
|
||||
break;
|
||||
case F_V_MS: /* mem self */
|
||||
cptr = get_ma (cptr, val, ','); /* addr */
|
||||
if (!cptr) return SCPE_ARG;
|
||||
cptr = get_op (cptr, val, 0); /* op */
|
||||
break; }
|
||||
if (!cptr || (*cptr != 0)) return SCPE_ARG; /* junk at end? */
|
||||
return (j >= F_2WD)? -1: SCPE_OK;
|
||||
}
|
||||
Reference in New Issue
Block a user