1
0
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:
Bob Supnik
2002-07-14 15:20:00 -07:00
committed by Mark Pizzolato
parent 701f0fe028
commit df6475181c
179 changed files with 36441 additions and 4464 deletions

885
GRI/gri_cpu.c Normal file
View 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
View 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
View 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
View 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
View 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;
}