1
0
mirror of https://github.com/simh/simh.git synced 2026-01-25 19:56:25 +00:00

Notes For V3.8

The makefile now works for Linux and most Unix's. Howevr, for Solaris
and MacOS, you must first export the OSTYPE environment variable:

> export OSTYPE
> make

Otherwise, you will get build errors.

1. New Features

1.1 3.8-0

1.1.1 SCP and Libraries

- BREAK, NOBREAK, and SHOW BREAK with no argument will set, clear, and
  show (respectively) a breakpoint at the current PC.

1.2 GRI

- Added support for the GRI-99 processor.

1.3 HP2100

- Added support for the BACI terminal interface.
- Added support for RTE OS/VMA/EMA, SIGNAL, VIS firmware extensions.

1.4 Nova

- Added support for 64KW memory (implemented in third-party CPU's).

1.5 PDP-11

- Added support for DC11, RC11, KE11A, KG11A.
- Added modem control support for DL11.
- Added ASCII character support for all 8b devices.

2. Bugs Fixed

Please see the revision history on http://simh.trailing-edge.com or
in the source module sim_rev.h.
This commit is contained in:
Bob Supnik
2008-06-24 14:21:00 -07:00
committed by Mark Pizzolato
parent 3cb7c60d5d
commit 59aa4a73b1
136 changed files with 57039 additions and 10915 deletions

View File

@@ -1,6 +1,6 @@
/* pdp11_cpu.c: PDP-11 CPU simulator
Copyright (c) 1993-2007, Robert M Supnik
Copyright (c) 1993-2008, 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"),
@@ -25,6 +25,8 @@
cpu PDP-11 CPU
22-Apr-08 RMS Fixed MMR0 treatment in RESET (found by Walter Mueller)
02-Feb-08 RMS Fixed DMA memory address limit test (found by John Dundas)
28-Apr-07 RMS Removed clock initialization
27-Oct-06 RMS Added idle support
18-Oct-06 RMS Fixed bug in ASH -32 C value
@@ -296,6 +298,7 @@ int32 hst_p = 0; /* history pointer */
int32 hst_lnt = 0; /* history length */
InstHistory *hst = NULL; /* instruction history */
int32 dsmask[4] = { MMR3_KDS, MMR3_SDS, 0, MMR3_UDS }; /* dspace enables */
t_addr cpu_memsize = INIMEMSIZE; /* last mem addr */
extern int32 CPUERR, MAINT;
extern int32 sim_interval;
@@ -646,6 +649,9 @@ t_stat reason;
reason = build_dib_tab (); /* build, chk dib_tab */
if (reason != SCPE_OK) return reason;
if (MEMSIZE < cpu_tab[cpu_model].maxm) /* mem size < max? */
cpu_memsize = MEMSIZE; /* then okay */
else cpu_memsize = cpu_tab[cpu_model].maxm - IOPAGESIZE;/* max - io page */
cpu_type = 1u << cpu_model; /* reset type mask */
cpu_bme = (MMR3 & MMR3_BME) && (cpu_opt & OPT_UBM); /* map enabled? */
PC = saved_PC;
@@ -863,11 +869,11 @@ while (reason == 0) {
case 5: /* RESET */
if (cm == MD_KER) {
reset_all (2); /* skip CPU, sys reg */
PIRQ = 0; /* clear PIRQ, STKLIM, */
STKLIM = 0; /* MMR0<15:12,0>, */
PIRQ = 0; /* clear PIRQ */
STKLIM = 0; /* clear STKLIM */
MMR0 = 0; /* clear MMR0 */
MMR3 = 0; /* clear MMR3 */
for (i = 0; i < IPL_HLVL; i++) int_req[i] = 0;
MMR0 = MMR0 & ~(MMR0_MME | MMR0_FREEZE);
MMR3 = 0; /* MMR3 */
trap_req = trap_req & ~TRAP_INT;
dsenable = calc_ds (cm);
}

View File

@@ -1,6 +1,6 @@
/* pdp11_cpumod.c: PDP-11 CPU model-specific features
Copyright (c) 2004-2007, Robert M Supnik
Copyright (c) 2004-2008, 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"),
@@ -25,6 +25,9 @@
system PDP-11 model-specific registers
20-May-08 RMS Added JCSR default for KDJ11B, KDJ11E
22-Apr-08 RMS Fixed write behavior of 11/70 MBRK, LOSIZE, HISIZE
(found by Walter Mueller)
29-Apr-07 RMS Don't run bus setup routine during RESTORE
30-Aug-05 RMS Added additional 11/60 registers
16-Aug-05 RMS Fixed C++ declaration and cast problems
@@ -65,6 +68,7 @@ int32 CCR = 0; /* cache control reg */
int32 HITMISS = 0; /* hit/miss reg */
int32 MAINT = 0; /* maint reg */
int32 JCSR = 0; /* J11 control */
int32 JCSR_dflt = 0; /* J11 boot ctl def */
int32 JPCR = 0; /* J11 page ctrl */
int32 JASR = 0; /* J11 addtl status */
int32 UDCR = 0; /* UBA diag ctrl */
@@ -118,6 +122,8 @@ t_stat sys_reset (DEVICE *dptr);
int32 toy_read (void);
void toy_write (int32 bit);
uint8 toy_set (int32 val);
t_stat sys_set_jclk_dflt (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat sys_show_jclk_dflt (FILE *st, UNIT *uptr, int32 val, void *desc);
extern t_stat PSW_rd (int32 *data, int32 addr, int32 access);
extern t_stat PSW_wr (int32 data, int32 addr, int32 access);
@@ -243,6 +249,10 @@ static const char *opt_name[] = {
"RH11", "RH70", "PARITY", "NOPARITY", "Unibus map", "No map", NULL
};
static const char *jcsr_val[4] = {
"LINE", "50HZ", "60HZ", "800HZ"
};
/* SYSTEM data structures
sys_dev SYSTEM device descriptor
@@ -264,6 +274,7 @@ REG sys_reg[] = {
{ ORDATA (WCS, WCS, 16) },
{ ORDATA (SYSID, SYSID, 16) },
{ ORDATA (JCSR, JCSR, 16) },
{ ORDATA (JCSR_DFLT, JCSR_dflt, 16), REG_HRO },
{ ORDATA (JPCR, JPCR, 16) },
{ ORDATA (JASR, JASR, 16) },
{ ORDATA (UDCR, UDCR, 16) },
@@ -276,8 +287,14 @@ REG sys_reg[] = {
{ NULL}
};
MTAB sys_mod[] = {
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "JCLK_DFLT", "JCLK_DFLT",
&sys_set_jclk_dflt, &sys_show_jclk_dflt },
{ 0 }
};
DEVICE sys_dev = {
"SYSTEM", &sys_unit, sys_reg, NULL,
"SYSTEM", &sys_unit, sys_reg, sys_mod,
1, 0, 0, 0, 0, 0,
NULL, NULL, &sys_reset,
NULL, NULL, NULL,
@@ -541,7 +558,11 @@ t_stat CPU70_rd (int32 *data, int32 pa, int32 access)
{
switch ((pa >> 1) & 017) { /* decode pa<4:1> */
case 000: case 001: case 011: /* LO,HI ERR, HI SIZE */
case 000: /* low error */
*data = 0;
return SCPE_OK;
case 001: /* high error */
*data = 0;
return SCPE_OK;
@@ -561,10 +582,14 @@ switch ((pa >> 1) & 017) { /* decode pa<4:1> */
*data = HITMISS;
return SCPE_OK;
case 010: /* lower size */
case 010: /* low size */
*data = (MEMSIZE >> 6) - 1;
return SCPE_OK;
case 011: /* high size */
*data = 0;
return SCPE_OK;
case 012: /* system ID */
*data = SYSID;
return SCPE_OK;
@@ -610,12 +635,19 @@ switch ((pa >> 1) & 017) { /* decode pa<4:1> */
case 005: /* Hit/miss */
return SCPE_OK;
case 010: /* low size */
return SCPE_OK;
case 011: /* high size */
return SCPE_OK;
case 013: /* CPUERR */
CPUERR = 0;
return SCPE_OK;
case 014: /* MBRK */
MBRK = data;
ODD_IGN (data);
MBRK = data & MBRK70_WR;
return SCPE_OK;
case 015: /* PIRQ */
@@ -1143,7 +1175,9 @@ MEMERR = 0;
if (!CPUT (CPUT_J)) MAINT = 0;
MBRK = 0;
WCS = 0;
JCSR = 0;
if (CPUT (CPUT_JB|CPUT_JE))
JCSR = JCSR_dflt;
else JCSR = 0;
JPCR = 0;
JASR = 0;
UDCR = 0;
@@ -1156,3 +1190,28 @@ for (i = 0; i < UBM_LNT_LW; i++) ub_map[i] = 0;
for (i = 0; i < TOY_LNT; i++) toy_data[i] = 0;
return SCPE_OK;
}
/* Set/show JCLK default values */
t_stat sys_set_jclk_dflt (UNIT *uptr, int32 val, char *cptr, void *desc)
{
uint32 i;
if ((CPUT (CPUT_JB|CPUT_JE)) && cptr) {
for (i = 0; i < 4; i++) {
if (strncmp (cptr, jcsr_val[i], strlen (cptr)) == 0) {
JCSR_dflt = i << CSRJ_V_LTCSEL;
return SCPE_OK;
}
}
}
return SCPE_ARG;
}
t_stat sys_show_jclk_dflt (FILE *st, UNIT *uptr, int32 val, void *desc)
{
if (CPUT (CPUT_JB|CPUT_JE))
fprintf (st, "JCLK default=%s\n", jcsr_val[CSRJ_LTCSEL (JCSR_dflt)]);
else fprintf (st, "Not implemented\n");
return SCPE_OK;
}

View File

@@ -1,6 +1,6 @@
/* pdp11_cpumod.h: PDP-11 CPU model definitions
Copyright (c) 2004-2005, Robert M Supnik
Copyright (c) 2004-2008, 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"),
@@ -23,6 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
22-Apr-08 RMS Added 11/70 MBRK register
30-Aug-05 RMS Added additional 11/60 registers
*/
@@ -177,6 +178,10 @@
#define CPUE60_RD (CPUE_ODD|CPUE_TMO|CPUE_RED)
/* 11/70 specific registers */
#define MBRK70_WR 0000377 /* microbreak */
/* J11 specific registers */
/* Maintenance register */

651
PDP11/pdp11_dc.c Normal file
View File

@@ -0,0 +1,651 @@
/* pdp11_dc.c: PDP-11 DC11 multiple terminal interface simulator
Copyright (c) 1993-2008, 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.
dci,dco DC11 terminal input/output
The simulator supports both hardwired and modem-like behavior. If modem
control is not enabled, carrier detect, ring, and carrier change are
never set.
*/
#if defined (VM_PDP10) /* PDP10 version */
#error "DC11 is not supported on the PDP-10!"
#elif defined (VM_VAX) /* VAX version */
#error "DC11 is not supported on the VAX!"
#else /* PDP-11 version */
#include "pdp11_defs.h"
#endif
#include "sim_sock.h"
#include "sim_tmxr.h"
#define DCX_MASK (DCX_LINES - 1)
/* Parity and modem control */
#define DCX_V_OPAR (TTUF_V_UF + 0)
#define DCX_V_EPAR (TTUF_V_UF + 1)
#define DCX_V_MDM (TTUF_V_UF + 2)
#define DCX_OPAR (1u << DCX_V_OPAR)
#define DCX_EPAR (1u << DCX_V_EPAR)
#define DCX_MDM (1u << DCX_V_MDM)
/* registers */
#define DCICSR_RD 0173777
#define DCICSR_WR 0003533
#define DCICSR_DTR 0000001 /* DTR (RW) */
#define DCICSR_XBR 0000002 /* xmit brk (RWNI) */
#define DCICSR_CDT 0000004 /* car det (RO) */
#define DCICSR_PAR 0000040 /* odd par (RO) */
#define DCICSR_OVR 0010000 /* overrun (RO) */
#define DCICSR_RNG 0020000 /* ring (RO) */
#define DCICSR_CCH 0040000 /* car change (RO) */
#define DCICSR_ALLERR (DCICSR_OVR|DCICSR_RNG|DCICSR_CCH)
#define DCICSR_ERR 0100000 /* error */
#define DCOCSR_RD 0100737
#define DCOCSR_WR 0000535
#define DCOCSR_RTS 0000001 /* req to send (RW) */
#define DCOCSR_CTS 0000002 /* clr to send (RO) */
#define DCOCSR_MNT 0000004 /* maint (RWNI) */
extern int32 int_req[IPL_HLVL];
extern int32 tmxr_poll;
uint16 dci_csr[DCX_LINES] = { 0 }; /* control/status */
uint8 dci_buf[DCX_LINES] = { 0 };
uint32 dci_ireq = 0;
uint16 dco_csr[DCX_LINES] = { 0 }; /* control/status */
uint8 dco_buf[DCX_LINES] = { 0 };
uint32 dco_ireq = 0;
TMLN dcx_ldsc[DCX_LINES] = { 0 }; /* line descriptors */
TMXR dcx_desc = { DCX_LINES, 0, 0, dcx_ldsc }; /* mux descriptor */
static const uint8 odd_par[] = {
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 00 */
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 10 */
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 20 */
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 30 */
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 40 */
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 50 */
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 60 */
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 70 */
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 80 */
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 90 */
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* A0 */
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* B0 */
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* C0 */
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80,
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* D0 */
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* E0 */
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0,
0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* F0 */
0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80
};
t_stat dcx_rd (int32 *data, int32 PA, int32 access);
t_stat dcx_wr (int32 data, int32 PA, int32 access);
t_stat dcx_reset (DEVICE *dptr);
t_stat dci_svc (UNIT *uptr);
t_stat dco_svc (UNIT *uptr);
t_stat dcx_attach (UNIT *uptr, char *cptr);
t_stat dcx_detach (UNIT *uptr);
t_stat dcx_summ (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat dcx_show (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat dcx_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat dcx_set_lines (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat dcx_show_lines (FILE *st, UNIT *uptr, int32 val, void *desc);
void dcx_enbdis (int32 dis);
void dci_clr_int (int32 ln);
void dci_set_int (int32 ln);
int32 dci_iack (void);
void dco_clr_int (int32 ln);
void dco_set_int (int32 ln);
int32 dco_iack (void);
void dcx_reset_ln (int32 ln);
/* DCI data structures
dci_dev DCI device descriptor
dci_unit DCI unit descriptor
dci_reg DCI register list
*/
DIB dci_dib = {
IOBA_DC, IOLN_DC, &dcx_rd, &dcx_wr,
2, IVCL (DCI), VEC_DCI, { &dci_iack, &dco_iack }
};
UNIT dci_unit = { UDATA (&dci_svc, 0, 0), KBD_POLL_WAIT };
REG dci_reg[] = {
{ BRDATA (BUF, dci_buf, DEV_RDX, 8, DCX_LINES) },
{ BRDATA (CSR, dci_csr, DEV_RDX, 16, DCX_LINES) },
{ GRDATA (IREQ, dci_ireq, DEV_RDX, DCX_LINES, 0) },
{ DRDATA (LINES, dcx_desc.lines, 6), REG_HRO },
{ GRDATA (DEVADDR, dci_dib.ba, DEV_RDX, 32, 0), REG_HRO },
{ GRDATA (DEVIOLN, dci_dib.lnt, DEV_RDX, 32, 0), REG_HRO },
{ GRDATA (DEVVEC, dci_dib.vec, DEV_RDX, 16, 0), REG_HRO },
{ NULL }
};
MTAB dci_mod[] = {
{ UNIT_ATT, UNIT_ATT, "summary", NULL, NULL, &dcx_summ },
{ MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",
&tmxr_dscln, NULL, &dcx_desc },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,
NULL, &dcx_show, NULL },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,
NULL, &dcx_show, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL,
&set_addr, &show_addr, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL,
&set_vec, &dcx_show_vec, NULL },
{ MTAB_XTD | MTAB_VDV, 0, "lines", "LINES",
&dcx_set_lines, &dcx_show_lines },
{ 0 }
};
DEVICE dci_dev = {
"DCI", &dci_unit, dci_reg, dci_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &dcx_reset,
NULL, &dcx_attach, &dcx_detach,
&dci_dib, DEV_UBUS | DEV_QBUS | DEV_DISABLE | DEV_DIS
};
/* DCO data structures
dco_dev DCO device descriptor
dco_unit DCO unit descriptor
dco_reg DCO register list
*/
UNIT dco_unit[] = {
{ UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
{ UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
{ UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
{ UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
{ UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
{ UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
{ UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
{ UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
{ UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
{ UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
{ UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
{ UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
{ UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
{ UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
{ UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT },
{ UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }
};
REG dco_reg[] = {
{ BRDATA (BUF, dco_buf, DEV_RDX, 8, DCX_LINES) },
{ BRDATA (CSR, dco_csr, DEV_RDX, 16, DCX_LINES) },
{ GRDATA (IREQ, dco_ireq, DEV_RDX, DCX_LINES, 0) },
{ URDATA (TIME, dco_unit[0].wait, 10, 31, 0,
DCX_LINES, PV_LEFT) },
{ NULL }
};
MTAB dco_mod[] = {
{ TT_MODE, TT_MODE_UC, "UC", "UC", NULL },
{ TT_MODE, TT_MODE_7B, "7b", "7B", NULL },
{ TT_MODE, TT_MODE_8B, "8b", "8B", NULL },
{ TT_MODE, TT_MODE_7P, "7p", "7P", NULL },
{ DCX_OPAR+DCX_EPAR, 0, "no parity", "NOPARITY", NULL },
{ DCX_OPAR+DCX_EPAR, DCX_OPAR, "odd parity", "ODDPARITY", NULL },
{ DCX_OPAR+DCX_EPAR, DCX_EPAR, "even parity", "EVENPARITY", NULL },
{ DCX_MDM, 0, "no dataset", "NODATASET", NULL },
{ DCX_MDM, DCX_MDM, "dataset", "DATASET", NULL },
{ MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT",
&tmxr_dscln, NULL, &dcx_desc },
{ MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG",
&tmxr_set_log, &tmxr_show_log, &dcx_desc },
{ MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG",
&tmxr_set_nolog, NULL, &dcx_desc },
{ 0 }
};
DEVICE dco_dev = {
"DCO", dco_unit, dco_reg, dco_mod,
DCX_LINES, 10, 31, 1, 8, 8,
NULL, NULL, &dcx_reset,
NULL, NULL, NULL,
NULL, DEV_UBUS | DEV_DISABLE | DEV_DIS
};
/* Terminal input routines */
t_stat dcx_rd (int32 *data, int32 PA, int32 access)
{
int32 ln = ((PA - dci_dib.ba) >> 3) & DCX_MASK;
switch ((PA >> 1) & 03) { /* decode PA<2:1> */
case 00: /* dci csr */
if (dci_csr[ln] & DCICSR_ALLERR)
dci_csr[ln] |= DCICSR_ERR;
else dci_csr[ln] &= ~DCICSR_ERR;
*data = dci_csr[ln] & DCICSR_RD;
dci_csr[ln] &= ~(CSR_DONE|DCICSR_ALLERR|DCICSR_ERR);
return SCPE_OK;
case 01: /* dci buf */
dci_clr_int (ln);
*data = dci_buf[ln];
return SCPE_OK;
case 02: /* dco csr */
*data = dco_csr[ln] & DCOCSR_RD;
return SCPE_OK;
case 03: /* dco buf */
*data = dco_buf[ln];
return SCPE_OK;
} /* end switch PA */
return SCPE_NXM;
}
t_stat dcx_wr (int32 data, int32 PA, int32 access)
{
int32 ln = ((PA - dci_dib.ba) >> 3) & DCX_MASK;
TMLN *lp = &dcx_ldsc[ln];
switch ((PA >> 1) & 03) { /* decode PA<2:1> */
case 00: /* dci csr */
if (access == WRITEB) /* byte write? */
data = (PA & 1)?
(dci_csr[ln] & 0377) | (data << 8):
(dci_csr[ln] & ~0377) | data;
if ((data & CSR_IE) == 0) /* clr ie? */
dci_clr_int (ln); /* clr int req */
else if ((dci_csr[ln] & (CSR_DONE + CSR_IE)) == CSR_DONE)
dci_set_int (ln);
if (((data ^ dci_csr[ln]) & DCICSR_DTR) && /* DTR change? */
(dco_unit[ln].flags & DCX_MDM)) { /* modem ctl? */
if (data & DCICSR_DTR) { /* setting DTR? */
if (lp->conn) { /* ringing? */
dci_csr[ln] = (dci_csr[ln] & ~DCICSR_RNG) |
(DCICSR_CDT|DCICSR_CCH|DCICSR_ERR);
dco_csr[ln] |= DCOCSR_CTS; /* set CDT,CCH,CTS */
if (data & CSR_IE) /* if ie, req int */
dci_set_int (ln);
}
} /* end DTR 0->1 */
else { /* clearing DTR */
if (lp->conn) { /* connected? */
tmxr_linemsg (lp, "\r\nLine hangup\r\n");
tmxr_reset_ln (lp); /* reset line */
if (dci_csr[ln] & DCICSR_CDT) { /* carrier det? */
dci_csr[ln] |= (DCICSR_CCH|DCICSR_ERR);
if (data & CSR_IE) /* if ie, req int */
dci_set_int (ln);
}
}
dci_csr[ln] &= ~(DCICSR_CDT|DCICSR_RNG);
dco_csr[ln] &= ~DCOCSR_CTS; /* clr CDT,RNG,CTS */
} /* end DTR 1->0 */
} /* end DTR chg+modem */
dci_csr[ln] = (uint16) ((dci_csr[ln] & ~DCICSR_WR) | (data & DCICSR_WR));
return SCPE_OK;
case 01: /* dci buf */
return SCPE_OK;
case 02: /* dco csr */
if (access == WRITEB) /* byte write? */
data = (PA & 1)?
(dco_csr[ln] & 0377) | (data << 8):
(dco_csr[ln] & ~0377) | data;
if ((data & CSR_IE) == 0) /* clr ie? */
dco_clr_int (ln); /* clr int req */
else if ((dco_csr[ln] & (CSR_DONE + CSR_IE)) == CSR_DONE)
dco_set_int (ln);
dco_csr[ln] = (uint16) ((dco_csr[ln] & ~DCOCSR_WR) | (data & DCOCSR_WR));
return SCPE_OK;
case 03: /* dco buf */
if ((PA & 1) == 0)
dco_buf[ln] = data & 0377;
dco_csr[ln] &= ~CSR_DONE; /* clr done */
dco_clr_int (ln); /* clr int req */
sim_activate (&dco_unit[ln], dco_unit[ln].wait);
return SCPE_OK;
} /* end switch PA */
return SCPE_NXM;
}
/* Terminal input service */
t_stat dci_svc (UNIT *uptr)
{
int32 ln, c, temp;
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
return SCPE_OK;
sim_activate (uptr, tmxr_poll); /* continue poll */
ln = tmxr_poll_conn (&dcx_desc); /* look for connect */
if (ln >= 0) { /* got one? */
dcx_ldsc[ln].rcve = 1; /* set rcv enb */
if (dco_unit[ln].flags & DCX_MDM) { /* modem control? */
if (dci_csr[ln] & DCICSR_DTR) /* DTR already set? */
dci_csr[ln] |= (DCICSR_CDT|DCICSR_CCH|DCICSR_ERR);
else dci_csr[ln] |= (DCICSR_RNG|DCICSR_ERR); /* no, ring */
if (dci_csr[ln] & CSR_IE) /* if ie, */
dci_set_int (ln); /* req int */
}
else dco_csr[ln] |= DCOCSR_CTS; /* just connect */
}
tmxr_poll_rx (&dcx_desc); /* poll for input */
for (ln = 0; ln < DCX_LINES; ln++) { /* loop thru lines */
if (dcx_ldsc[ln].conn) { /* connected? */
if ((temp = tmxr_getc_ln (&dcx_ldsc[ln])) && /* get char */
!(temp & SCPE_BREAK)) { /* not break? */
c = sim_tt_inpcvt (temp, TT_GET_MODE (dco_unit[ln].flags));
if (dci_csr[ln] & CSR_DONE) /* overrun? */
dci_csr[ln] |= DCICSR_OVR;
else dci_csr[ln] |= CSR_DONE; /* set done */
if (dci_csr[ln] & CSR_IE) /* if ie, */
dci_set_int (ln); /* req int */
if (dco_unit[ln].flags & DCX_OPAR) /* odd parity */
c = (c & 0177) | odd_par[c & 0177];
else if (dco_unit[ln].flags & DCX_EPAR) /* even parity */
c = (c & 0177) | (odd_par[c & 0177] ^ 0200);
dci_buf[ln] = c;
if ((c & 0200) == odd_par[c & 0177]) /* odd par? */
dci_csr[ln] |= DCICSR_PAR;
else dci_csr[ln] &= ~DCICSR_PAR;
}
}
else { /* disconnected */
if ((dco_unit[ln].flags & DCX_MDM) && /* modem control? */
(dci_csr[ln] & DCICSR_CDT)) { /* carrier detect? */
dci_csr[ln] |= (DCICSR_CCH|DCICSR_ERR); /* carrier change */
if (dci_csr[ln] & CSR_IE) /* if ie, */
dci_set_int (ln); /* req int */
}
dci_csr[ln] &= ~(DCICSR_CDT|DCICSR_RNG); /* clr CDT,RNG,CTS */
dco_csr[ln] &= ~DCOCSR_CTS;
}
}
return SCPE_OK;
}
/* Terminal output service */
t_stat dco_svc (UNIT *uptr)
{
int32 c;
int32 ln = uptr - dco_unit; /* line # */
if (dcx_ldsc[ln].conn) { /* connected? */
if (dcx_ldsc[ln].xmte) { /* tx enabled? */
TMLN *lp = &dcx_ldsc[ln]; /* get line */
c = sim_tt_outcvt (dco_buf[ln], TT_GET_MODE (dco_unit[ln].flags));
if (c >= 0) tmxr_putc_ln (lp, c); /* output char */
tmxr_poll_tx (&dcx_desc); /* poll xmt */
}
else {
tmxr_poll_tx (&dcx_desc); /* poll xmt */
sim_activate (uptr, dco_unit[ln].wait); /* wait */
return SCPE_OK;
}
}
dco_csr[ln] |= CSR_DONE; /* set done */
if (dco_csr[ln] & CSR_IE) /* ie set? */
dco_set_int (ln); /* req int */
return SCPE_OK;
}
/* Interrupt routines */
void dci_clr_int (int32 ln)
{
dci_ireq &= ~(1 << ln); /* clr mux rcv int */
if (dci_ireq == 0) /* all clr? */
CLR_INT (DCI);
else SET_INT (DCI); /* no, set intr */
return;
}
void dci_set_int (int32 ln)
{
dci_ireq |= (1 << ln); /* clr mux rcv int */
SET_INT (DCI); /* set master intr */
return;
}
int32 dci_iack (void)
{
int32 ln;
for (ln = 0; ln < DCX_LINES; ln++) { /* find 1st line */
if (dci_ireq & (1 << ln)) {
dci_clr_int (ln); /* clear intr */
return (dci_dib.vec + (ln * 010)); /* return vector */
}
}
return 0;
}
void dco_clr_int (int32 ln)
{
dco_ireq &= ~(1 << ln); /* clr mux rcv int */
if (dco_ireq == 0) /* all clr? */
CLR_INT (DCO);
else SET_INT (DCO); /* no, set intr */
return;
}
void dco_set_int (int32 ln)
{
dco_ireq |= (1 << ln); /* clr mux rcv int */
SET_INT (DCO); /* set master intr */
return;
}
int32 dco_iack (void)
{
int32 ln;
for (ln = 0; ln < DCX_LINES; ln++) { /* find 1st line */
if (dco_ireq & (1 << ln)) {
dco_clr_int (ln); /* clear intr */
return (dci_dib.vec + (ln * 010) + 4); /* return vector */
}
}
return 0;
}
/* Reset */
t_stat dcx_reset (DEVICE *dptr)
{
int32 ln;
dcx_enbdis (dptr->flags & DEV_DIS); /* sync enables */
sim_cancel (&dci_unit); /* assume stop */
if (dci_unit.flags & UNIT_ATT) /* if attached, */
sim_activate (&dci_unit, tmxr_poll); /* activate */
for (ln = 0; ln < DCX_LINES; ln++) /* for all lines */
dcx_reset_ln (ln);
return auto_config (dci_dev.name, dcx_desc.lines); /* auto config */
}
/* Reset individual line */
void dcx_reset_ln (int32 ln)
{
dci_buf[ln] = 0; /* clear buf */
dci_csr[ln] = 0;
dco_buf[ln] = 0; /* clear buf */
dco_csr[ln] = CSR_DONE;
sim_cancel (&dco_unit[ln]); /* deactivate */
dci_clr_int (ln);
dco_clr_int (ln);
return;
}
/* Attach master unit */
t_stat dcx_attach (UNIT *uptr, char *cptr)
{
t_stat r;
r = tmxr_attach (&dcx_desc, uptr, cptr); /* attach */
if (r != SCPE_OK) /* error? */
return r;
sim_activate (uptr, tmxr_poll); /* start poll */
return SCPE_OK;
}
/* Detach master unit */
t_stat dcx_detach (UNIT *uptr)
{
int32 i;
t_stat r;
r = tmxr_detach (&dcx_desc, uptr); /* detach */
for (i = 0; i < DCX_LINES; i++) /* all lines, */
dcx_ldsc[i].rcve = 0; /* disable rcv */
sim_cancel (uptr); /* stop poll */
return r;
}
/* Show summary processor */
t_stat dcx_summ (FILE *st, UNIT *uptr, int32 val, void *desc)
{
int32 i, t;
for (i = t = 0; i < DCX_LINES; i++) t = t + (dcx_ldsc[i].conn != 0);
if (t == 1) fprintf (st, "1 connection");
else fprintf (st, "%d connections", t);
return SCPE_OK;
}
/* SHOW CONN/STAT processor */
t_stat dcx_show (FILE *st, UNIT *uptr, int32 val, void *desc)
{
int32 i, t;
for (i = t = 0; i < DCX_LINES; i++) t = t + (dcx_ldsc[i].conn != 0);
if (t) {
for (i = 0; i < DCX_LINES; i++) {
if (dcx_ldsc[i].conn) {
if (val) tmxr_fconns (st, &dcx_ldsc[i], i);
else tmxr_fstats (st, &dcx_ldsc[i], i);
}
}
}
else fprintf (st, "all disconnected\n");
return SCPE_OK;
}
/* Enable/disable device */
void dcx_enbdis (int32 dis)
{
if (dis) {
dci_dev.flags = dco_dev.flags | DEV_DIS;
dco_dev.flags = dco_dev.flags | DEV_DIS;
}
else {
dci_dev.flags = dci_dev.flags & ~DEV_DIS;
dco_dev.flags = dco_dev.flags & ~DEV_DIS;
}
return;
}
/* SHOW VECTOR processor */
t_stat dcx_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc)
{
return show_vec (st, uptr, dcx_desc.lines * 2, desc);
}
/* Change number of lines */
t_stat dcx_set_lines (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 newln, i, t;
t_stat r;
if (cptr == NULL) return SCPE_ARG;
newln = get_uint (cptr, 10, DCX_LINES, &r);
if ((r != SCPE_OK) || (newln == dcx_desc.lines)) return r;
if (newln == 0) return SCPE_ARG;
if (newln < dcx_desc.lines) {
for (i = newln, t = 0; i < dcx_desc.lines; i++) t = t | dcx_ldsc[i].conn;
if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))
return SCPE_OK;
for (i = newln; i < dcx_desc.lines; i++) {
if (dcx_ldsc[i].conn) {
tmxr_linemsg (&dcx_ldsc[i], "\r\nOperator disconnected line\r\n");
tmxr_reset_ln (&dcx_ldsc[i]); /* reset line */
}
dco_unit[i].flags |= UNIT_DIS;
dcx_reset_ln (i);
}
}
else {
for (i = dcx_desc.lines; i < newln; i++) {
dco_unit[i].flags &= ~UNIT_DIS;
dcx_reset_ln (i);
}
}
dcx_desc.lines = newln;
dci_dib.lnt = newln * 010; /* upd IO page lnt */
return auto_config (dci_dev.name, newln); /* auto config */
}
/* Show number of lines */
t_stat dcx_show_lines (FILE *st, UNIT *uptr, int32 val, void *desc)
{
fprintf (st, "lines=%d", dcx_desc.lines);
return SCPE_OK;
}

View File

@@ -1,6 +1,6 @@
/* pdp11_defs.h: PDP-11 simulator definitions
Copyright (c) 1993-2006, Robert M Supnik
Copyright (c) 1993-2008, 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"),
@@ -26,6 +26,9 @@
The author gratefully acknowledges the help of Max Burnet, Megan Gentry,
and John Wilson in resolving questions about the PDP-11
16-May-08 RMS Added KE11A, DC11 support
02-Feb-08 RMS Fixed DMA memory address limit test (found by John Dundas)
25-Jan-08 RMS Added RC11, KG11A support (from John Dundas)
16-Dec-06 RMS Added TA11 support
29-Oct-06 RMS Added clock coscheduling
06-Jul-06 RMS Added multiple KL11/DL11 support
@@ -92,7 +95,7 @@
#define MAXMEMSIZE 020000000 /* 2**22 */
#define PAMASK (MAXMEMSIZE - 1) /* 2**22 - 1 */
#define MEMSIZE (cpu_unit.capac)
#define ADDR_IS_MEM(x) (((t_addr) (x)) < MEMSIZE)
#define ADDR_IS_MEM(x) (((t_addr) (x)) < cpu_memsize) /* use only in sim! */
#define DMASK 0177777
/* CPU models */
@@ -469,7 +472,8 @@ typedef struct {
#define DZ_MUXES 4 /* max # of DZ muxes */
#define DZ_LINES 8 /* lines per DZ mux */
#define VH_MUXES 4 /* max # of VH muxes */
#define TTX_LINES 16 /* max # of KL11/DL11's */
#define DLX_LINES 16 /* max # of KL11/DL11's */
#define DCX_LINES 16 /* max # of DC11's */
#define MT_MAXFR (1 << 16) /* magtape max rec */
#define AUTO_LNT 34 /* autoconfig ranks */
#define DIB_MAX 100 /* max DIBs */
@@ -521,6 +525,8 @@ typedef struct pdp_dib DIB;
#define IOLN_VH 020
#define IOBA_UBM (IOPAGEBASE + 010200) /* Unibus map */
#define IOLN_UBM (UBM_LNT_LW * sizeof (int32))
#define IOBA_KG (IOPAGEBASE + 010700) /* KG11-A */
#define IOLN_KG 006
#define IOBA_RQ (IOPAGEBASE + 012150) /* RQDX3 */
#define IOLN_RQ 004
#define IOBA_SUP (IOPAGEBASE + 012200) /* supervisor APR's */
@@ -543,6 +549,8 @@ typedef struct pdp_dib DIB;
#define IOLN_TS 004
#define IOBA_PCLK (IOPAGEBASE + 012540) /* KW11P */
#define IOLN_PCLK 006
#define IOBA_DC (IOPAGEBASE + 014000) /* DC11 */
#define IOLN_DC (DCX_LINES * 010)
#define IOBA_RL (IOPAGEBASE + 014400) /* RL11 */
#define IOLN_RL 012
#define IOBA_XQ (IOPAGEBASE + 014440) /* DEQNA/DELQA */
@@ -553,8 +561,8 @@ typedef struct pdp_dib DIB;
#define IOLN_TQ 004
#define IOBA_XU (IOPAGEBASE + 014510) /* DEUNA/DELUA */
#define IOLN_XU 010
#define IOBA_TTIX (IOPAGEBASE + 016500) /* extra KL11/DL11 */
#define IOLN_TTIX (TTX_LINES * 010)
#define IOBA_DL (IOPAGEBASE + 016500) /* extra KL11/DL11 */
#define IOLN_DL (DLX_LINES * 010)
#define IOBA_RP (IOPAGEBASE + 016700) /* RP/RM */
#define IOLN_RP 054
#define IOBA_CR (IOPAGEBASE + 017160) /* CD/CR/CM */
@@ -563,10 +571,14 @@ typedef struct pdp_dib DIB;
#define IOLN_RX 004
#define IOBA_RY (IOPAGEBASE + 017170) /* RY11 */
#define IOLN_RY 004
#define IOBA_KE (IOPAGEBASE + 017300) /* KE11-A */
#define IOLN_KE 020
#define IOBA_TC (IOPAGEBASE + 017340) /* TC11 */
#define IOLN_TC 012
#define IOBA_RK (IOPAGEBASE + 017400) /* RK11 */
#define IOLN_RK 020
#define IOBA_RC (IOPAGEBASE + 017440) /* RC11/RS64 */
#define IOLN_RC 020
#define IOBA_HK (IOPAGEBASE + 017440) /* RK611 */
#define IOLN_HK 040
#define IOBA_RF (IOPAGEBASE + 017460) /* RF11 */
@@ -636,7 +648,8 @@ typedef struct pdp_dib DIB;
#define INT_V_XU 13
#define INT_V_TU 14
#define INT_V_RF 15
#define INT_V_PIR5 16
#define INT_V_RC 16
#define INT_V_PIR5 17
#define INT_V_TTI 0 /* BR4 */
#define INT_V_TTO 1
@@ -646,9 +659,11 @@ typedef struct pdp_dib DIB;
#define INT_V_VHRX 5
#define INT_V_VHTX 6
#define INT_V_CR 7
#define INT_V_TTIX 8
#define INT_V_TTOX 9
#define INT_V_PIR4 10
#define INT_V_DLI 8
#define INT_V_DLO 9
#define INT_V_DCI 10
#define INT_V_DCO 11
#define INT_V_PIR4 12
#define INT_V_PIR3 0 /* BR3 */
#define INT_V_PIR2 0 /* BR2 */
@@ -676,6 +691,7 @@ typedef struct pdp_dib DIB;
#define INT_XU (1u << INT_V_XU)
#define INT_TU (1u << INT_V_TU)
#define INT_RF (1u << INT_V_RF)
#define INT_RC (1u << INT_V_RC)
#define INT_PIR5 (1u << INT_V_PIR5)
#define INT_PTR (1u << INT_V_PTR)
#define INT_PTP (1u << INT_V_PTP)
@@ -685,8 +701,10 @@ typedef struct pdp_dib DIB;
#define INT_VHRX (1u << INT_V_VHRX)
#define INT_VHTX (1u << INT_V_VHTX)
#define INT_CR (1u << INT_V_CR)
#define INT_TTIX (1u << INT_V_TTIX)
#define INT_TTOX (1u << INT_V_TTOX)
#define INT_DLI (1u << INT_V_DLI)
#define INT_DLO (1u << INT_V_DLO)
#define INT_DCI (1u << INT_V_DCI)
#define INT_DCO (1u << INT_V_DCO)
#define INT_PIR4 (1u << INT_V_PIR4)
#define INT_PIR3 (1u << INT_V_PIR3)
#define INT_PIR2 (1u << INT_V_PIR2)
@@ -712,6 +730,7 @@ typedef struct pdp_dib DIB;
#define IPL_XU 5
#define IPL_TU 5
#define IPL_RF 5
#define IPL_RC 5
#define IPL_PTR 4
#define IPL_PTP 4
#define IPL_TTI 4
@@ -720,8 +739,10 @@ typedef struct pdp_dib DIB;
#define IPL_VHRX 4
#define IPL_VHTX 4
#define IPL_CR 4
#define IPL_TTIX 4
#define IPL_TTOX 4
#define IPL_DLI 4
#define IPL_DLO 4
#define IPL_DCI 4
#define IPL_DCO 4
#define IPL_PIR7 7
#define IPL_PIR6 6
@@ -748,6 +769,7 @@ typedef struct pdp_dib DIB;
#define VEC_LPT 0200
#define VEC_RF 0204
#define VEC_HK 0210
#define VEC_RC 0210
#define VEC_RK 0220
#define VEC_DTA 0214
#define VEC_TM 0224
@@ -759,8 +781,10 @@ typedef struct pdp_dib DIB;
#define VEC_TA 0260
#define VEC_RX 0264
#define VEC_RY 0264
#define VEC_TTIX 0300
#define VEC_TTOX 0304
#define VEC_DLI 0300
#define VEC_DLO 0304
#define VEC_DCI 0300
#define VEC_DCO 0304
#define VEC_DZRX 0300
#define VEC_DZTX 0304
#define VEC_VHRX 0310

View File

@@ -23,9 +23,10 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
ttix,ttox DL11 terminal input/output
*/
dli,dlo DL11 terminal input/output
20-May-2008 RMS Added modem control support
*/
#if defined (VM_PDP10) /* PDP10 version */
#error "DL11 is not supported on the PDP-10!"
@@ -39,198 +40,258 @@
#include "sim_sock.h"
#include "sim_tmxr.h"
#define TTX_MASK (TTX_LINES - 1)
#define DLX_MASK (DLX_LINES - 1)
#define DLI_RCI 0 /* rcv ints */
#define DLI_DSI 1 /* dset ints */
#define TTIXCSR_IMP (CSR_DONE + CSR_IE) /* terminal input */
#define TTIXCSR_RW (CSR_IE)
#define TTIXBUF_ERR 0100000
#define TTIXBUF_OVR 0040000
#define TTIXBUF_RBRK 0020000
#define TTOXCSR_IMP (CSR_DONE + CSR_IE) /* terminal output */
#define TTOXCSR_RW (CSR_IE)
/* Modem control */
#define DLX_V_MDM (TTUF_V_UF + 0)
#define DLX_MDM (1u << DLX_V_MDM)
/* registers */
#define DLICSR_DSI 0100000 /* dataset int, RO */
#define DLICSR_RNG 0040000 /* ring, RO */
#define DLICSR_CTS 0020000 /* CTS, RO */
#define DLICSR_CDT 0010000 /* CDT, RO */
#define DLICSR_SEC 0002000 /* sec rcv, RONI */
#define DLICSR_DSIE 0000040 /* DSI ie, RW */
#define DLICSR_SECX 0000010 /* sec xmt, RWNI */
#define DLICSR_RTS 0000004 /* RTS, RW */
#define DLICSR_DTR 0000002 /* DTR, RW */
#define DLICSR_RD (CSR_DONE|CSR_IE) /* DL11C */
#define DLICSR_WR (CSR_IE)
#define DLICSR_RD_M (DLICSR_DSI|DLICSR_RNG|DLICSR_CTS|DLICSR_CDT|DLICSR_SEC| \
CSR_DONE|CSR_IE|DLICSR_DSIE|DLICSR_SECX|DLICSR_RTS|DLICSR_DTR)
#define DLICSR_WR_M (CSR_IE|DLICSR_DSIE|DLICSR_SECX|DLICSR_RTS|DLICSR_DTR)
#define DLIBUF_ERR 0100000
#define DLIBUF_OVR 0040000
#define DLIBUF_RBRK 0020000
#define DLIBUF_RD (DLIBUF_ERR|DLIBUF_OVR|DLIBUF_RBRK|0377)
#define DLOCSR_MNT 0000004 /* maint, RWNI */
#define DLOCSR_XBR 0000001 /* xmit brk, RWNI */
#define DLOCSR_RD (CSR_DONE|CSR_IE|DLOCSR_MNT|DLOCSR_XBR)
#define DLOCSR_WR (CSR_IE|DLOCSR_MNT|DLOCSR_XBR)
extern int32 int_req[IPL_HLVL];
extern int32 tmxr_poll;
uint16 ttix_csr[TTX_LINES] = { 0 }; /* control/status */
uint16 ttix_buf[TTX_LINES] = { 0 };
uint32 ttix_ireq = 0;
uint16 ttox_csr[TTX_LINES] = { 0 }; /* control/status */
uint8 ttox_buf[TTX_LINES] = { 0 };
uint32 ttox_ireq = 0;
TMLN ttx_ldsc[TTX_LINES] = { 0 }; /* line descriptors */
TMXR ttx_desc = { TTX_LINES, 0, 0, ttx_ldsc }; /* mux descriptor */
uint16 dli_csr[DLX_LINES] = { 0 }; /* control/status */
uint16 dli_buf[DLX_LINES] = { 0 };
uint32 dli_ireq[2] = { 0, 0};
uint16 dlo_csr[DLX_LINES] = { 0 }; /* control/status */
uint8 dlo_buf[DLX_LINES] = { 0 };
uint32 dlo_ireq = 0;
TMLN dlx_ldsc[DLX_LINES] = { 0 }; /* line descriptors */
TMXR dlx_desc = { DLX_LINES, 0, 0, dlx_ldsc }; /* mux descriptor */
t_stat ttx_rd (int32 *data, int32 PA, int32 access);
t_stat ttx_wr (int32 data, int32 PA, int32 access);
t_stat ttx_reset (DEVICE *dptr);
t_stat ttix_svc (UNIT *uptr);
t_stat ttox_svc (UNIT *uptr);
t_stat ttx_attach (UNIT *uptr, char *cptr);
t_stat ttx_detach (UNIT *uptr);
t_stat ttx_summ (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat ttx_show (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat ttx_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat ttx_set_lines (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat ttx_show_lines (FILE *st, UNIT *uptr, int32 val, void *desc);
void ttx_enbdis (int32 dis);
void ttix_clr_int (uint32 ln);
void ttix_set_int (int32 ln);
int32 ttix_iack (void);
void ttox_clr_int (int32 ln);
void ttox_set_int (int32 ln);
int32 ttox_iack (void);
void ttx_reset_ln (uint32 ln);
t_stat dlx_rd (int32 *data, int32 PA, int32 access);
t_stat dlx_wr (int32 data, int32 PA, int32 access);
t_stat dlx_reset (DEVICE *dptr);
t_stat dli_svc (UNIT *uptr);
t_stat dlo_svc (UNIT *uptr);
t_stat dlx_attach (UNIT *uptr, char *cptr);
t_stat dlx_detach (UNIT *uptr);
t_stat dlx_summ (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat dlx_show (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat dlx_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc);
t_stat dlx_set_lines (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat dlx_show_lines (FILE *st, UNIT *uptr, int32 val, void *desc);
void dlx_enbdis (int32 dis);
void dli_clr_int (int32 ln, uint32 wd);
void dli_set_int (int32 ln, uint32 wd);
int32 dli_iack (void);
void dlo_clr_int (int32 ln);
void dlo_set_int (int32 ln);
int32 dlo_iack (void);
void dlx_reset_ln (int32 ln);
/* TTIX data structures
/* DLI data structures
ttix_dev TTIX device descriptor
ttix_unit TTIX unit descriptor
ttix_reg TTIX register list
dli_dev DLI device descriptor
dli_unit DLI unit descriptor
dli_reg DLI register list
*/
DIB ttix_dib = {
IOBA_TTIX, IOLN_TTIX, &ttx_rd, &ttx_wr,
2, IVCL (TTIX), VEC_TTIX, { &ttix_iack, &ttox_iack }
DIB dli_dib = {
IOBA_DL, IOLN_DL, &dlx_rd, &dlx_wr,
2, IVCL (DLI), VEC_DLI, { &dli_iack, &dlo_iack }
};
UNIT ttix_unit = { UDATA (&ttix_svc, 0, 0), KBD_POLL_WAIT };
UNIT dli_unit = { UDATA (&dli_svc, 0, 0), KBD_POLL_WAIT };
REG ttix_reg[] = {
{ BRDATA (BUF, ttix_buf, DEV_RDX, 16, TTX_LINES) },
{ BRDATA (CSR, ttix_csr, DEV_RDX, 16, TTX_LINES) },
{ GRDATA (IREQ, ttix_ireq, DEV_RDX, TTX_LINES, 0) },
{ DRDATA (LINES, ttx_desc.lines, 6), REG_HRO },
{ GRDATA (DEVADDR, ttix_dib.ba, DEV_RDX, 32, 0), REG_HRO },
{ GRDATA (DEVVEC, ttix_dib.vec, DEV_RDX, 16, 0), REG_HRO },
REG dli_reg[] = {
{ BRDATA (BUF, dli_buf, DEV_RDX, 16, DLX_LINES) },
{ BRDATA (CSR, dli_csr, DEV_RDX, 16, DLX_LINES) },
{ GRDATA (IREQ, dli_ireq[DLI_RCI], DEV_RDX, DLX_LINES, 0) },
{ GRDATA (DSI, dli_ireq[DLI_DSI], DEV_RDX, DLX_LINES, 0) },
{ DRDATA (LINES, dlx_desc.lines, 6), REG_HRO },
{ GRDATA (DEVADDR, dli_dib.ba, DEV_RDX, 32, 0), REG_HRO },
{ GRDATA (DEVIOLN, dli_dib.lnt, DEV_RDX, 32, 0), REG_HRO },
{ GRDATA (DEVVEC, dli_dib.vec, DEV_RDX, 16, 0), REG_HRO },
{ NULL }
};
MTAB ttix_mod[] = {
{ UNIT_ATT, UNIT_ATT, "summary", NULL, NULL, &ttx_summ },
MTAB dli_mod[] = {
{ UNIT_ATT, UNIT_ATT, "summary", NULL, NULL, &dlx_summ },
{ MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",
&tmxr_dscln, NULL, &ttx_desc },
&tmxr_dscln, NULL, &dlx_desc },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,
NULL, &ttx_show, NULL },
NULL, &dlx_show, NULL },
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,
NULL, &ttx_show, NULL },
NULL, &dlx_show, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL,
&set_addr, &show_addr, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL,
&set_vec, &ttx_show_vec, NULL },
&set_vec, &dlx_show_vec, NULL },
{ MTAB_XTD | MTAB_VDV, 0, "lines", "LINES",
&ttx_set_lines, &ttx_show_lines },
&dlx_set_lines, &dlx_show_lines },
{ 0 }
};
DEVICE ttix_dev = {
"TTIX", &ttix_unit, ttix_reg, ttix_mod,
DEVICE dli_dev = {
"DLI", &dli_unit, dli_reg, dli_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ttx_reset,
NULL, &ttx_attach, &ttx_detach,
&ttix_dib, DEV_UBUS | DEV_QBUS | DEV_DISABLE | DEV_DIS
NULL, NULL, &dlx_reset,
NULL, &dlx_attach, &dlx_detach,
&dli_dib, DEV_UBUS | DEV_QBUS | DEV_DISABLE | DEV_DIS
};
/* TTOX data structures
/* DLO data structures
ttox_dev TTOX device descriptor
ttox_unit TTOX unit descriptor
ttox_reg TTOX register list
dlo_dev DLO device descriptor
dlo_unit DLO unit descriptor
dlo_reg DLO register list
*/
UNIT ttox_unit[] = {
{ UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }
UNIT dlo_unit[] = {
{ UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT },
{ UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }
};
REG ttox_reg[] = {
{ BRDATA (BUF, ttox_buf, DEV_RDX, 8, TTX_LINES) },
{ BRDATA (CSR, ttox_csr, DEV_RDX, 16, TTX_LINES) },
{ GRDATA (IREQ, ttox_ireq, DEV_RDX, TTX_LINES, 0) },
{ URDATA (TIME, ttox_unit[0].wait, 10, 31, 0,
TTX_LINES, PV_LEFT) },
REG dlo_reg[] = {
{ BRDATA (BUF, dlo_buf, DEV_RDX, 8, DLX_LINES) },
{ BRDATA (CSR, dlo_csr, DEV_RDX, 16, DLX_LINES) },
{ GRDATA (IREQ, dlo_ireq, DEV_RDX, DLX_LINES, 0) },
{ URDATA (TIME, dlo_unit[0].wait, 10, 31, 0,
DLX_LINES, PV_LEFT) },
{ NULL }
};
MTAB ttox_mod[] = {
MTAB dlo_mod[] = {
{ TT_MODE, TT_MODE_UC, "UC", "UC", NULL },
{ TT_MODE, TT_MODE_7B, "7b", "7B", NULL },
{ TT_MODE, TT_MODE_8B, "8b", "8B", NULL },
{ TT_MODE, TT_MODE_7P, "7p", "7P", NULL },
{ DLX_MDM, 0, "no dataset", "NODATASET", NULL },
{ DLX_MDM, DLX_MDM, "dataset", "DATASET", NULL },
{ MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT",
&tmxr_dscln, NULL, &ttx_desc },
&tmxr_dscln, NULL, &dlx_desc },
{ MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG",
&tmxr_set_log, &tmxr_show_log, &ttx_desc },
&tmxr_set_log, &tmxr_show_log, &dlx_desc },
{ MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG",
&tmxr_set_nolog, NULL, &ttx_desc },
&tmxr_set_nolog, NULL, &dlx_desc },
{ 0 }
};
DEVICE ttox_dev = {
"TTOX", ttox_unit, ttox_reg, ttox_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ttx_reset,
DEVICE dlo_dev = {
"DLO", dlo_unit, dlo_reg, dlo_mod,
DLX_LINES, 10, 31, 1, 8, 8,
NULL, NULL, &dlx_reset,
NULL, NULL, NULL,
NULL, DEV_UBUS | DEV_QBUS | DEV_DISABLE | DEV_DIS
};
/* Terminal input routines */
t_stat ttx_rd (int32 *data, int32 PA, int32 access)
t_stat dlx_rd (int32 *data, int32 PA, int32 access)
{
uint32 ln = ((PA - ttix_dib.ba) >> 3) & TTX_MASK;
int32 ln = ((PA - dli_dib.ba) >> 3) & DLX_MASK;
switch ((PA >> 1) & 03) { /* decode PA<2:1> */
case 00: /* tti csr */
*data = ttix_csr[ln] & TTIXCSR_IMP;
*data = dli_csr[ln] &
((dlo_unit[ln].flags & DLX_MDM)? DLICSR_RD_M: DLICSR_RD);
dli_csr[ln] &= ~DLICSR_DSI; /* clr DSI flag */
dli_clr_int (ln, DLI_DSI); /* clr dset int req */
return SCPE_OK;
case 01: /* tti buf */
ttix_csr[ln] &= ~CSR_DONE;
ttix_clr_int (ln);
*data = ttix_buf[ln];
*data = dli_buf[ln] & DLIBUF_RD;
dli_csr[ln] &= ~CSR_DONE; /* clr rcv done */
dli_clr_int (ln, DLI_RCI); /* clr rcv int req */
return SCPE_OK;
case 02: /* tto csr */
*data = ttox_csr[ln] & TTOXCSR_IMP;
*data = dlo_csr[ln] & DLOCSR_RD;
return SCPE_OK;
case 03: /* tto buf */
*data = ttox_buf[ln];
*data = dlo_buf[ln];
return SCPE_OK;
} /* end switch PA */
return SCPE_NXM;
}
t_stat ttx_wr (int32 data, int32 PA, int32 access)
t_stat dlx_wr (int32 data, int32 PA, int32 access)
{
uint32 ln = ((PA - ttix_dib.ba) >> 3) & TTX_MASK;
int32 ln = ((PA - dli_dib.ba) >> 3) & DLX_MASK;
TMLN *lp = &dlx_ldsc[ln];
switch ((PA >> 1) & 03) { /* decode PA<2:1> */
case 00: /* tti csr */
if (PA & 1) return SCPE_OK;
if (PA & 1) return SCPE_OK; /* odd byte RO */
if ((data & CSR_IE) == 0)
ttix_clr_int (ln);
else if ((ttix_csr[ln] & (CSR_DONE + CSR_IE)) == CSR_DONE)
ttix_set_int (ln);
ttix_csr[ln] = (uint16) ((ttix_csr[ln] & ~TTIXCSR_RW) | (data & TTIXCSR_RW));
dli_clr_int (ln, DLI_RCI);
else if ((dli_csr[ln] & (CSR_DONE + CSR_IE)) == CSR_DONE)
dli_set_int (ln, DLI_RCI);
if (dlo_unit[ln].flags & DLX_MDM) { /* modem control */
if ((data & DLICSR_DSIE) == 0)
dli_clr_int (ln, DLI_DSI);
else if ((dli_csr[ln] & (DLICSR_DSI|DLICSR_DSIE)) == DLICSR_DSI)
dli_set_int (ln, DLI_DSI);
if ((data ^ dli_csr[ln]) & DLICSR_DTR) { /* DTR change? */
if ((data & DLICSR_DTR) && lp->conn) { /* setting DTR? */
dli_csr[ln] = (dli_csr[ln] & ~DLICSR_RNG) |
(DLICSR_CDT|DLICSR_CTS|DLICSR_DSI);
if (data & DLICSR_DSIE) /* if ie, req int */
dli_set_int (ln, DLI_DSI);
} /* end DTR 0->1 + ring */
else { /* clearing DTR */
if (lp->conn) { /* connected? */
tmxr_linemsg (lp, "\r\nLine hangup\r\n");
tmxr_reset_ln (lp); /* reset line */
if (dli_csr[ln] & DLICSR_CDT) { /* carrier det? */
dli_csr[ln] |= DLICSR_DSI;
if (data & DLICSR_DSIE) /* if ie, req int */
dli_set_int (ln, DLI_DSI);
}
}
dli_csr[ln] &= ~(DLICSR_CDT|DLICSR_RNG|DLICSR_CTS);
/* clr CDT,RNG,CTS */
} /* end DTR 1->0 */
} /* end DTR chg */
dli_csr[ln] = (uint16) ((dli_csr[ln] & ~DLICSR_WR_M) | (data & DLICSR_WR_M));
} /* end modem */
dli_csr[ln] = (uint16) ((dli_csr[ln] & ~DLICSR_WR) | (data & DLICSR_WR));
return SCPE_OK;
case 01: /* tti buf */
@@ -239,18 +300,18 @@ switch ((PA >> 1) & 03) { /* decode PA<2:1> */
case 02: /* tto csr */
if (PA & 1) return SCPE_OK;
if ((data & CSR_IE) == 0)
ttox_clr_int (ln);
else if ((ttox_csr[ln] & (CSR_DONE + CSR_IE)) == CSR_DONE)
ttox_set_int (ln);
ttox_csr[ln] = (uint16) ((ttox_csr[ln] & ~TTOXCSR_RW) | (data & TTOXCSR_RW));
dlo_clr_int (ln);
else if ((dlo_csr[ln] & (CSR_DONE + CSR_IE)) == CSR_DONE)
dlo_set_int (ln);
dlo_csr[ln] = (uint16) ((dlo_csr[ln] & ~DLOCSR_WR) | (data & DLOCSR_WR));
return SCPE_OK;
case 03: /* tto buf */
if ((PA & 1) == 0)
ttox_buf[ln] = data & 0377;
ttox_csr[ln] &= ~CSR_DONE;
ttox_clr_int (ln);
sim_activate (&ttox_unit[ln], ttox_unit[ln].wait);
dlo_buf[ln] = data & 0377;
dlo_csr[ln] &= ~CSR_DONE;
dlo_clr_int (ln);
sim_activate (&dlo_unit[ln], dlo_unit[ln].wait);
return SCPE_OK;
} /* end switch PA */
@@ -259,112 +320,132 @@ return SCPE_NXM;
/* Terminal input service */
t_stat ttix_svc (UNIT *uptr)
t_stat dli_svc (UNIT *uptr)
{
int32 ln, c, temp;
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */
sim_activate (uptr, tmxr_poll); /* continue poll */
ln = tmxr_poll_conn (&ttx_desc); /* look for connect */
if (ln >= 0) ttx_ldsc[ln].rcve = 1; /* got one? rcv enb */
tmxr_poll_rx (&ttx_desc); /* poll for input */
for (ln = 0; ln < TTX_LINES; ln++) { /* loop thru lines */
if (ttx_ldsc[ln].conn) { /* connected? */
if (temp = tmxr_getc_ln (&ttx_ldsc[ln])) { /* get char */
ln = tmxr_poll_conn (&dlx_desc); /* look for connect */
if (ln >= 0) { /* got one? rcv enb */
dlx_ldsc[ln].rcve = 1;
if (dlo_unit[ln].flags & DLX_MDM) { /* modem control? */
if (dli_csr[ln] & DLICSR_DTR) /* DTR already set? */
dli_csr[ln] |= (DLICSR_CDT|DLICSR_CTS|DLICSR_DSI);
else dli_csr[ln] |= (DLICSR_RNG|DLICSR_DSI); /* no, ring */
if (dli_csr[ln] & DLICSR_DSIE) /* if ie, */
dli_set_int (ln, DLI_DSI); /* req int */
} /* end modem */
} /* end new conn */
tmxr_poll_rx (&dlx_desc); /* poll for input */
for (ln = 0; ln < DLX_LINES; ln++) { /* loop thru lines */
if (dlx_ldsc[ln].conn) { /* connected? */
if (temp = tmxr_getc_ln (&dlx_ldsc[ln])) { /* get char */
if (temp & SCPE_BREAK) /* break? */
c = TTIXBUF_ERR|TTIXBUF_RBRK;
else c = sim_tt_inpcvt (temp, TT_GET_MODE (ttox_unit[ln].flags));
if (ttix_csr[ln] & CSR_DONE)
c |= TTIXBUF_ERR|TTIXBUF_OVR;
else {
ttix_csr[ln] |= CSR_DONE;
if (ttix_csr[ln] & CSR_IE) ttix_set_int (ln);
}
ttix_buf[ln] = c;
c = DLIBUF_ERR|DLIBUF_RBRK;
else c = sim_tt_inpcvt (temp, TT_GET_MODE (dlo_unit[ln].flags));
if (dli_csr[ln] & CSR_DONE)
c |= DLIBUF_ERR|DLIBUF_OVR;
else dli_csr[ln] |= CSR_DONE;
if (dli_csr[ln] & CSR_IE)
dli_set_int (ln, DLI_RCI);
dli_buf[ln] = c;
}
}
else if (dlo_unit[ln].flags & DLX_MDM) { /* discpnn & modem? */
if (dli_csr[ln] & DLICSR_CDT) { /* carrier detect? */
dli_csr[ln] |= DLICSR_DSI; /* dataset change */
if (dli_csr[ln] & DLICSR_DSIE) /* if ie, */
dli_set_int (ln, DLI_DSI); /* req int */
}
dli_csr[ln] &= ~(DLICSR_CDT|DLICSR_RNG|DLICSR_CTS);
/* clr CDT,RNG,CTS */
}
}
return SCPE_OK;
}
/* Terminal output service */
t_stat ttox_svc (UNIT *uptr)
t_stat dlo_svc (UNIT *uptr)
{
int32 c;
uint32 ln = uptr - ttox_unit; /* line # */
int32 ln = uptr - dlo_unit; /* line # */
if (ttx_ldsc[ln].conn) { /* connected? */
if (ttx_ldsc[ln].xmte) { /* tx enabled? */
TMLN *lp = &ttx_ldsc[ln]; /* get line */
c = sim_tt_outcvt (ttox_buf[ln], TT_GET_MODE (ttox_unit[ln].flags));
if (dlx_ldsc[ln].conn) { /* connected? */
if (dlx_ldsc[ln].xmte) { /* tx enabled? */
TMLN *lp = &dlx_ldsc[ln]; /* get line */
c = sim_tt_outcvt (dlo_buf[ln], TT_GET_MODE (dlo_unit[ln].flags));
if (c >= 0) tmxr_putc_ln (lp, c); /* output char */
tmxr_poll_tx (&ttx_desc); /* poll xmt */
tmxr_poll_tx (&dlx_desc); /* poll xmt */
}
else {
tmxr_poll_tx (&ttx_desc); /* poll xmt */
sim_activate (uptr, ttox_unit[ln].wait); /* wait */
tmxr_poll_tx (&dlx_desc); /* poll xmt */
sim_activate (uptr, dlo_unit[ln].wait); /* wait */
return SCPE_OK;
}
}
ttox_csr[ln] |= CSR_DONE; /* set done */
if (ttox_csr[ln] & CSR_IE) ttox_set_int (ln);
dlo_csr[ln] |= CSR_DONE; /* set done */
if (dlo_csr[ln] & CSR_IE)
dlo_set_int (ln);
return SCPE_OK;
}
/* Interrupt routines */
void ttix_clr_int (uint32 ln)
void dli_clr_int (int32 ln, uint32 wd)
{
ttix_ireq &= ~(1 << ln); /* clr mux rcv int */
if (ttix_ireq == 0) CLR_INT (TTIX); /* all clr? */
else SET_INT (TTIX); /* no, set intr */
dli_ireq[wd] &= ~(1 << ln); /* clr rcv/dset int */
if ((dli_ireq[DLI_RCI] | dli_ireq[DLI_DSI]) == 0) /* all clr? */
CLR_INT (DLI); /* all clr? */
else SET_INT (DLI); /* no, set intr */
return;
}
void ttix_set_int (int32 ln)
void dli_set_int (int32 ln, uint32 wd)
{
ttix_ireq |= (1 << ln); /* clr mux rcv int */
SET_INT (TTIX); /* set master intr */
dli_ireq[wd] |= (1 << ln); /* set rcv/dset int */
SET_INT (DLI); /* set master intr */
return;
}
int32 ttix_iack (void)
int32 dli_iack (void)
{
int32 ln;
for (ln = 0; ln < TTX_LINES; ln++) { /* find 1st line */
if (ttix_ireq & (1 << ln)) {
ttix_clr_int (ln); /* clear intr */
return (ttix_dib.vec + (ln * 010)); /* return vector */
for (ln = 0; ln < DLX_LINES; ln++) { /* find 1st line */
if ((dli_ireq[DLI_RCI] | dli_ireq[DLI_DSI]) & (1 << ln)) {
dli_clr_int (ln, DLI_RCI); /* clr both req */
dli_clr_int (ln, DLI_DSI);
return (dli_dib.vec + (ln * 010)); /* return vector */
}
}
return 0;
}
void ttox_clr_int (int32 ln)
void dlo_clr_int (int32 ln)
{
ttox_ireq &= ~(1 << ln); /* clr mux rcv int */
if (ttox_ireq == 0) CLR_INT (TTOX); /* all clr? */
else SET_INT (TTOX); /* no, set intr */
dlo_ireq &= ~(1 << ln); /* clr xmit int */
if (dlo_ireq == 0) CLR_INT (DLO); /* all clr? */
else SET_INT (DLO); /* no, set intr */
return;
}
void ttox_set_int (int32 ln)
void dlo_set_int (int32 ln)
{
ttox_ireq |= (1 << ln); /* clr mux rcv int */
SET_INT (TTOX); /* set master intr */
dlo_ireq |= (1 << ln); /* set xmit int */
SET_INT (DLO); /* set master intr */
return;
}
int32 ttox_iack (void)
int32 dlo_iack (void)
{
int32 ln;
for (ln = 0; ln < TTX_LINES; ln++) { /* find 1st line */
if (ttox_ireq & (1 << ln)) {
ttox_clr_int (ln); /* clear intr */
return (ttix_dib.vec + (ln * 010) + 4); /* return vector */
for (ln = 0; ln < DLX_LINES; ln++) { /* find 1st line */
if (dlo_ireq & (1 << ln)) {
dlo_clr_int (ln); /* clear intr */
return (dli_dib.vec + (ln * 010) + 4); /* return vector */
}
}
return 0;
@@ -372,40 +453,43 @@ return 0;
/* Reset */
t_stat ttx_reset (DEVICE *dptr)
t_stat dlx_reset (DEVICE *dptr)
{
int32 ln;
ttx_enbdis (dptr->flags & DEV_DIS); /* sync enables */
sim_cancel (&ttix_unit); /* assume stop */
if (ttix_unit.flags & UNIT_ATT) /* if attached, */
sim_activate (&ttix_unit, tmxr_poll); /* activate */
for (ln = 0; ln < TTX_LINES; ln++) /* for all lines */
ttx_reset_ln (ln);
return auto_config (ttix_dev.name, ttx_desc.lines); /* auto config */
dlx_enbdis (dptr->flags & DEV_DIS); /* sync enables */
sim_cancel (&dli_unit); /* assume stop */
if (dli_unit.flags & UNIT_ATT) /* if attached, */
sim_activate (&dli_unit, tmxr_poll); /* activate */
for (ln = 0; ln < DLX_LINES; ln++) /* for all lines */
dlx_reset_ln (ln);
return auto_config (dli_dev.name, dlx_desc.lines); /* auto config */
}
/* Reset individual line */
void ttx_reset_ln (uint32 ln)
void dlx_reset_ln (int32 ln)
{
ttix_buf[ln] = 0; /* clear buf, */
ttix_csr[ln] = CSR_DONE;
ttox_buf[ln] = 0; /* clear buf */
ttox_csr[ln] = CSR_DONE;
sim_cancel (&ttox_unit[ln]); /* deactivate */
ttix_clr_int (ln);
ttox_clr_int (ln);
dli_buf[ln] = 0; /* clear buf */
if (dlo_unit[ln].flags & DLX_MDM) /* modem */
dli_csr[ln] &= DLICSR_DTR; /* dont clr DTR */
else dli_csr[ln] = 0;
dlo_buf[ln] = 0; /* clear buf */
dlo_csr[ln] = CSR_DONE;
sim_cancel (&dlo_unit[ln]); /* deactivate */
dli_clr_int (ln, DLI_RCI);
dli_clr_int (ln, DLI_DSI);
dlo_clr_int (ln);
return;
}
/* Attach master unit */
t_stat ttx_attach (UNIT *uptr, char *cptr)
t_stat dlx_attach (UNIT *uptr, char *cptr)
{
t_stat r;
r = tmxr_attach (&ttx_desc, uptr, cptr); /* attach */
r = tmxr_attach (&dlx_desc, uptr, cptr); /* attach */
if (r != SCPE_OK) return r; /* error */
sim_activate (uptr, tmxr_poll); /* start poll */
return SCPE_OK;
@@ -413,25 +497,25 @@ return SCPE_OK;
/* Detach master unit */
t_stat ttx_detach (UNIT *uptr)
t_stat dlx_detach (UNIT *uptr)
{
int32 i;
t_stat r;
r = tmxr_detach (&ttx_desc, uptr); /* detach */
for (i = 0; i < TTX_LINES; i++) /* all lines, */
ttx_ldsc[i].rcve = 0; /* disable rcv */
r = tmxr_detach (&dlx_desc, uptr); /* detach */
for (i = 0; i < DLX_LINES; i++) /* all lines, */
dlx_ldsc[i].rcve = 0; /* disable rcv */
sim_cancel (uptr); /* stop poll */
return r;
}
/* Show summary processor */
t_stat ttx_summ (FILE *st, UNIT *uptr, int32 val, void *desc)
t_stat dlx_summ (FILE *st, UNIT *uptr, int32 val, void *desc)
{
int32 i, t;
for (i = t = 0; i < TTX_LINES; i++) t = t + (ttx_ldsc[i].conn != 0);
for (i = t = 0; i < DLX_LINES; i++) t = t + (dlx_ldsc[i].conn != 0);
if (t == 1) fprintf (st, "1 connection");
else fprintf (st, "%d connections", t);
return SCPE_OK;
@@ -439,16 +523,16 @@ return SCPE_OK;
/* SHOW CONN/STAT processor */
t_stat ttx_show (FILE *st, UNIT *uptr, int32 val, void *desc)
t_stat dlx_show (FILE *st, UNIT *uptr, int32 val, void *desc)
{
int32 i, t;
for (i = t = 0; i < TTX_LINES; i++) t = t + (ttx_ldsc[i].conn != 0);
for (i = t = 0; i < DLX_LINES; i++) t = t + (dlx_ldsc[i].conn != 0);
if (t) {
for (i = 0; i < TTX_LINES; i++) {
if (ttx_ldsc[i].conn) {
if (val) tmxr_fconns (st, &ttx_ldsc[i], i);
else tmxr_fstats (st, &ttx_ldsc[i], i);
for (i = 0; i < DLX_LINES; i++) {
if (dlx_ldsc[i].conn) {
if (val) tmxr_fconns (st, &dlx_ldsc[i], i);
else tmxr_fstats (st, &dlx_ldsc[i], i);
}
}
}
@@ -458,64 +542,65 @@ return SCPE_OK;
/* Enable/disable device */
void ttx_enbdis (int32 dis)
void dlx_enbdis (int32 dis)
{
if (dis) {
ttix_dev.flags = ttox_dev.flags | DEV_DIS;
ttox_dev.flags = ttox_dev.flags | DEV_DIS;
dli_dev.flags = dlo_dev.flags | DEV_DIS;
dlo_dev.flags = dlo_dev.flags | DEV_DIS;
}
else {
ttix_dev.flags = ttix_dev.flags & ~DEV_DIS;
ttox_dev.flags = ttox_dev.flags & ~DEV_DIS;
dli_dev.flags = dli_dev.flags & ~DEV_DIS;
dlo_dev.flags = dlo_dev.flags & ~DEV_DIS;
}
return;
}
/* SHOW VECTOR processor */
t_stat ttx_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc)
t_stat dlx_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc)
{
return show_vec (st, uptr, ttx_desc.lines * 2, desc);
return show_vec (st, uptr, dlx_desc.lines * 2, desc);
}
/* Change number of lines */
t_stat ttx_set_lines (UNIT *uptr, int32 val, char *cptr, void *desc)
t_stat dlx_set_lines (UNIT *uptr, int32 val, char *cptr, void *desc)
{
int32 newln, i, t;
t_stat r;
if (cptr == NULL) return SCPE_ARG;
newln = get_uint (cptr, 10, TTX_LINES, &r);
if ((r != SCPE_OK) || (newln == ttx_desc.lines)) return r;
newln = get_uint (cptr, 10, DLX_LINES, &r);
if ((r != SCPE_OK) || (newln == dlx_desc.lines)) return r;
if (newln == 0) return SCPE_ARG;
if (newln < ttx_desc.lines) {
for (i = newln, t = 0; i < ttx_desc.lines; i++) t = t | ttx_ldsc[i].conn;
if (newln < dlx_desc.lines) {
for (i = newln, t = 0; i < dlx_desc.lines; i++) t = t | dlx_ldsc[i].conn;
if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE))
return SCPE_OK;
for (i = newln; i < ttx_desc.lines; i++) {
if (ttx_ldsc[i].conn) {
tmxr_linemsg (&ttx_ldsc[i], "\r\nOperator disconnected line\r\n");
tmxr_reset_ln (&ttx_ldsc[i]); /* reset line */
for (i = newln; i < dlx_desc.lines; i++) {
if (dlx_ldsc[i].conn) {
tmxr_linemsg (&dlx_ldsc[i], "\r\nOperator disconnected line\r\n");
tmxr_reset_ln (&dlx_ldsc[i]); /* reset line */
}
ttox_unit[i].flags |= UNIT_DIS;
ttx_reset_ln (i);
dlo_unit[i].flags |= UNIT_DIS;
dlx_reset_ln (i);
}
}
else {
for (i = ttx_desc.lines; i < newln; i++) {
ttox_unit[i].flags &= ~UNIT_DIS;
ttx_reset_ln (i);
for (i = dlx_desc.lines; i < newln; i++) {
dlo_unit[i].flags &= ~UNIT_DIS;
dlx_reset_ln (i);
}
}
ttx_desc.lines = newln;
return auto_config (ttix_dev.name, newln); /* auto config */
dlx_desc.lines = newln;
dli_dib.lnt = newln * 010; /* upd IO page lnt */
return auto_config (dli_dev.name, newln); /* auto config */
}
/* Show number of lines */
t_stat ttx_show_lines (FILE *st, UNIT *uptr, int32 val, void *desc)
t_stat dlx_show_lines (FILE *st, UNIT *uptr, int32 val, void *desc)
{
fprintf (st, "lines=%d", ttx_desc.lines);
fprintf (st, "lines=%d", dlx_desc.lines);
return SCPE_OK;
}

View File

@@ -1,6 +1,6 @@
/* pdp11_io.c: PDP-11 I/O simulator
Copyright (c) 1993-2006, Robert M Supnik
Copyright (c) 1993-2008, 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"),
@@ -23,6 +23,9 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
16-May-08 RMS Added multiple DC11 support
Renamed DL11 in autoconfigure
02-Feb-08 RMS Fixed DMA memory address limit test (found by John Dundas)
06-Jul-06 RMS Added multiple KL11/DL11 support
15-Oct-05 RMS Fixed bug in autoconfiguration (missing XU)
25-Jul-05 RMS Revised autoconfiguration algorithm and interface
@@ -54,7 +57,7 @@ extern int32 autcon_enb;
extern int32 uba_last;
extern FILE *sim_log;
extern DEVICE *sim_devices[], cpu_dev;
extern UNIT cpu_unit;
extern t_addr cpu_memsize;
int32 calc_ints (int32 nipl, int32 trq);
@@ -239,7 +242,7 @@ if (cpu_bme) { /* map enabled? */
}
else { /* physical */
if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */
else if (ADDR_IS_MEM (ba)) alim = MEMSIZE; /* no, strt ok? */
else if (ADDR_IS_MEM (ba)) alim = cpu_memsize; /* no, strt ok? */
else return bc; /* no, err */
for ( ; ba < alim; ba++) { /* by bytes */
if (ba & 1) *buf++ = (M[ba >> 1] >> 8) & 0377; /* get byte */
@@ -265,7 +268,7 @@ if (cpu_bme) { /* map enabled? */
}
else { /* physical */
if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */
else if (ADDR_IS_MEM (ba)) alim = MEMSIZE; /* no, strt ok? */
else if (ADDR_IS_MEM (ba)) alim = cpu_memsize; /* no, strt ok? */
else return bc; /* no, err */
for ( ; ba < alim; ba = ba + 2) { /* by words */
*buf++ = M[ba >> 1];
@@ -292,7 +295,7 @@ if (cpu_bme) { /* map enabled? */
}
else { /* physical */
if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */
else if (ADDR_IS_MEM (ba)) alim = MEMSIZE; /* no, strt ok? */
else if (ADDR_IS_MEM (ba)) alim = cpu_memsize; /* no, strt ok? */
else return bc; /* no, err */
for ( ; ba < alim; ba++) { /* by bytes */
if (ba & 1) M[ba >> 1] = (M[ba >> 1] & 0377) |
@@ -319,7 +322,7 @@ if (cpu_bme) { /* map enabled? */
}
else { /* physical */
if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */
else if (ADDR_IS_MEM (ba)) alim = MEMSIZE; /* no, strt ok? */
else if (ADDR_IS_MEM (ba)) alim = cpu_memsize; /* no, strt ok? */
else return bc; /* no, err */
for ( ; ba < alim; ba = ba + 2) { /* by words */
M[ba >> 1] = *buf++;
@@ -600,7 +603,8 @@ typedef struct {
} AUTO_CON;
AUTO_CON auto_tab[] = {
{ { "TTIX" }, TTX_LINES, 2, 0, 8, { 0 } }, /* KL11/DL11/DLV11 - fx CSRs */
{ { "DCI" }, DCX_LINES, 2, 0, 8, { 0 } }, /* DC11 - fx CSRs */
{ { "DLI" }, DLX_LINES, 2, 0, 8, { 0 } }, /* KL11/DL11/DLV11 - fx CSRs */
{ { NULL }, 1, 2, 8, 8 }, /* DJ11 */
{ { NULL }, 1, 2, 16, 8 }, /* DH11 */
{ { NULL }, 1, 2, 8, 8 }, /* DQ11 */

348
PDP11/pdp11_ke.c Normal file
View File

@@ -0,0 +1,348 @@
/* pdp11_ke.c: PDP-11/20 extended arithmetic element
Copyright (c) 1993-2008, 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 ke_ACTION OF CONTRke_ACT, 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 code draws on prior work by Tim Shoppa and Brad Parker. My thanks for
to them for letting me use their work.
EAE PDP-11/20 extended arithmetic element
*/
#include "pdp11_defs.h"
#define GET_SIGN_L(v) (((v) >> 31) & 1)
#define GET_SIGN_W(v) (((v) >> 15) & 1)
#define GET_SIGN_B(v) (((v) >> 7) & 1)
/* KE11A I/O address offsets 0177300 - 0177316 */
#define KE_DIV 000 /* divide */
#define KE_AC 002 /* accumulator */
#define KE_MQ 004 /* MQ */
#define KE_MUL 006 /* multiply */
#define KE_SC 010 /* step counter */
#define KE_NOR 012 /* normalize */
#define KE_LSH 014 /* logical shift */
#define KE_ASH 016 /* arithmetic shift */
/* Status register */
#define KE_SR_C 0001 /* carry */
#define KE_SR_SXT 0002 /* AC<15:0> = MQ<15> */
#define KE_SR_Z 0004 /* AC = MQ = 0 */
#define KE_SR_MQZ 0010 /* MQ = 0 */
#define KE_SR_ACZ 0020 /* AC = 0 */
#define KE_SR_ACM1 0040 /* AC = 177777 */
#define KE_SR_N 0100 /* last op negative */
#define KE_SR_NXV 0200 /* last op ovf XOR N */
#define KE_SR_DYN (KE_SR_SXT|KE_SR_Z|KE_SR_MQZ|KE_SR_ACZ|KE_SR_ACM1)
/* Visible state */
uint32 ke_AC = 0;
uint32 ke_MQ = 0;
uint32 ke_SC = 0;
uint32 ke_SR = 0;
DEVICE ke_dev;
t_stat ke_rd (int32 *data, int32 PA, int32 access);
t_stat ke_wr (int32 data, int32 PA, int32 access);
t_stat ke_reset (DEVICE *dptr);
uint32 ke_set_SR (void);
DIB ke_dib = { IOBA_KE, IOLN_KE, &ke_rd, &ke_wr, 0 };
UNIT ke_unit = {
UDATA (NULL, UNIT_DISABLE, 0)
};
REG ke_reg[] = {
{ ORDATA (AC, ke_AC, 16) },
{ ORDATA (MQ, ke_MQ, 16) },
{ ORDATA (SC, ke_SC, 6) },
{ ORDATA (SR, ke_SR, 8) },
{ NULL }
};
MTAB ke_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL,
NULL, &show_addr, NULL },
{ 0 }
};
DEVICE ke_dev = {
"KE", &ke_unit, ke_reg, ke_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ke_reset,
NULL, NULL, NULL,
&ke_dib, DEV_DISABLE | DEV_DIS | DEV_UBUS
};
/* KE read - reads are always 16b, to even addresses */
t_stat ke_rd (int32 *data, int32 PA, int32 access)
{
switch (PA & 016) { /* decode PA<3:1> */
case KE_AC: /* AC */
*data = ke_AC;
break;
case KE_MQ: /* MQ */
*data = ke_MQ;
break;
case KE_NOR: /* norm (SC) */
*data = ke_SC;
break;
case KE_SC: /* SR/SC */
*data = (ke_set_SR () << 8) | ke_SC;
break;
default:
*data = 0;
break;
}
return SCPE_OK;
}
/* KE write - writes trigger actual arithmetic */
t_stat ke_wr (int32 data, int32 PA, int32 access)
{
int32 quo, t32, sout, sign;
uint32 absd, absr;
switch (PA & 017) { /* decode PA<3:0> */
case KE_DIV: /* divide */
if ((access == WRITEB) && GET_SIGN_B (data)) /* byte write? */
data |= 0177400; /* sext data to 16b */
ke_SR = 0; /* N = V = C = 0 */
t32 = (ke_AC << 16) | ke_MQ; /* 32b divd */
if (GET_SIGN_W (ke_AC)) /* sext (divd) */
t32 = t32 | ~017777777777;
if (GET_SIGN_W (data)) /* sext (divr) */
data = data | ~077777;
absd = abs (t32);
absr = abs (data);
if ((absd >> 16) >= absr) { /* divide fails? */
/* Based on the documentation, here's what has happened:
SC = 16.
SR<c> = (AC<15> == data<15>)
AC'MQ = (AC'MQ << 1) | SR<c>
AC = SR<c>? AC - data: AC + data
SR<c> = (AC<15> == data<15>)
SC = SC - 1
stop
*/
sign = GET_SIGN_W (ke_AC ^ data) ^ 1; /* 1 if signs match */
ke_AC = (ke_AC << 1) | (ke_MQ >> 15);
ke_AC = (sign? ke_AC - data: ke_AC + data) & DMASK;
ke_MQ = ((ke_MQ << 1) | sign) & DMASK;
if (GET_SIGN_W (ke_AC ^ data) == 0) /* 0 if signs match */
ke_SR |= KE_SR_C;
ke_SC = 15; /* SC clocked once */
ke_SR |= KE_SR_NXV; /* set overflow */
}
else {
ke_SC = 0;
quo = t32 / data;
ke_MQ = quo & DMASK; /* MQ has quo */
ke_AC = (t32 % data) & DMASK; /* AC has rem */
if ((quo > 32767) || (quo < -32768)) /* quo overflow? */
ke_SR |= KE_SR_NXV; /* set overflow */
}
if (GET_SIGN_W (ke_MQ)) /* result negative? */
ke_SR ^= (KE_SR_N | KE_SR_NXV); /* N = 1, compl NXV */
break;
case KE_AC: /* AC */
if ((access == WRITEB) && GET_SIGN_B (data)) /* byte write? */
data |= 0177400; /* sext data to 16b */
ke_AC = data;
break;
case KE_AC + 1: /* AC odd byte */
ke_AC = (ke_AC & 0377) | (data << 8);
break;
case KE_MQ: /* MQ */
if ((access == WRITEB) && GET_SIGN_B (data)) /* byte write? */
data |= 0177400; /* sext data to 16b */
ke_MQ = data;
if (GET_SIGN_W (ke_MQ)) /* sext MQ to AC */
ke_AC = 0177777;
else ke_AC = 0;
break;
case KE_MQ + 1: /* MQ odd byte */
ke_MQ = (ke_MQ & 0377) | (data << 8);
if (GET_SIGN_W (ke_MQ)) /* sext MQ to AC */
ke_AC = 0177777;
else ke_AC = 0;
break;
case KE_MUL: /* multiply */
if ((access == WRITEB) && GET_SIGN_B (data)) /* byte write? */
data |= 0177400; /* sext data to 16b */
ke_SC = 0;
if (GET_SIGN_W (data)) /* sext operands */
data |= ~077777;
t32 = ke_MQ;
if (GET_SIGN_W (t32))
t32 |= ~077777;
t32 = t32 * data;
ke_AC = (t32 >> 16) & DMASK;
ke_MQ = t32 & DMASK;
if (GET_SIGN_W (ke_AC)) /* result negative? */
ke_SR = KE_SR_N | KE_SR_NXV; /* N = 1, V = C = 0 */
else ke_SR = 0; /* N = 0, V = C = 0 */
break;
case KE_SC: /* SC */
if (access == WRITEB) /* ignore byte writes */
return SCPE_OK;
ke_SR = (data >> 8) & (KE_SR_NXV|KE_SR_N|KE_SR_C);
ke_SC = data & 077;
break;
case KE_NOR: /* normalize */
for (ke_SC = 0; ke_SC < 31; ke_SC++) { /* max 31 shifts */
if (((ke_AC == 0140000) && (ke_MQ == 0)) || /* special case? */
(GET_SIGN_W (ke_AC ^ (ke_AC << 1)))) /* AC<15> != AC<14>? */
break;
ke_AC = ((ke_AC << 1) | (ke_MQ >> 15)) & DMASK;
ke_MQ = (ke_MQ << 1) & DMASK;
}
if (GET_SIGN_W (ke_AC)) /* result negative? */
ke_SR = KE_SR_N | KE_SR_NXV; /* N = 1, V = C = 0 */
else ke_SR = 0; /* N = 0, V = C = 0 */
break;
case KE_LSH: /* logical shift */
ke_SC = 0;
ke_SR = 0; /* N = V = C = 0 */
data = data & 077; /* 6b shift count */
if (data != 0) {
t32 = (ke_AC << 16) | ke_MQ; /* 32b operand */
if (sign = GET_SIGN_W (ke_AC)) /* sext operand */
t32 = t32 | ~017777777777;
if (data < 32) { /* [1,31] - left */
sout = (t32 >> (32 - data)) | (-sign << data);
t32 = ((uint32) t32) << data; /* do shift (zext) */
if (sout != (GET_SIGN_L (t32)? -1: 0)) /* bits lost = sext? */
ke_SR |= KE_SR_NXV; /* no, V = 1 */
if (sout & 1) /* last bit lost = 1? */
ke_SR |= KE_SR_C; /* yes, C = 1 */
}
else { /* [32,63] = -32,-1 */
if ((t32 >> (63 - data)) & 1) /* last bit lost = 1? */
ke_SR |= KE_SR_C; /* yes, C = 1*/
t32 = (data != 32)? ((uint32) t32) >> (64 - data): 0;
}
ke_AC = (t32 >> 16) & DMASK;
ke_MQ = t32 & DMASK;
}
if (GET_SIGN_W (ke_AC)) /* result negative? */
ke_SR ^= (KE_SR_N | KE_SR_NXV); /* N = 1, compl NXV */
break;
/* EAE ASH differs from EIS ASH and cannot use the same overflow test */
case KE_ASH: /* arithmetic shift */
ke_SC = 0;
ke_SR = 0; /* N = V = C = 0 */
data = data & 077; /* 6b shift count */
if (data != 0) {
t32 = (ke_AC << 16) | ke_MQ; /* 32b operand */
if (sign = GET_SIGN_W (ke_AC)) /* sext operand */
t32 = t32 | ~017777777777;
if (data < 32) { /* [1,31] - left */
sout = (t32 >> (31 - data)) | (-sign << data);
t32 = (t32 & 020000000000) | ((t32 << data) & 017777777777);
if (sout != (GET_SIGN_L (t32)? -1: 0)) /* bits lost = sext? */
ke_SR |= KE_SR_NXV; /* no, V = 1 */
if (sout & 1) /* last bit lost = 1? */
ke_SR |= KE_SR_C; /* yes, C = 1 */
}
else { /* [32,63] = -32,-1 */
if ((t32 >> (63 - data)) & 1) /* last bit lost = 1? */
ke_SR |= KE_SR_C; /* yes, C = 1 */
t32 = (data != 32)? /* special case 32 */
(((uint32) t32) >> (64 - data)) | (-sign << (data - 32)):
-sign;
}
ke_AC = (t32 >> 16) & DMASK;
ke_MQ = t32 & DMASK;
}
if (GET_SIGN_W (ke_AC)) /* result negative? */
ke_SR ^= (KE_SR_N | KE_SR_NXV); /* N = 1, compl NXV */
break;
default: /* all others ignored */
return SCPE_OK;
} /* end switch PA */
ke_set_SR ();
return SCPE_OK;
}
/* Update status register based on current AC, MQ */
uint32 ke_set_SR (void)
{
ke_SR &= ~KE_SR_DYN; /* clr dynamic bits */
if (ke_MQ == 0) /* MQ == 0? */
ke_SR |= KE_SR_MQZ;
if (ke_AC == 0) { /* AC == 0? */
ke_SR |= KE_SR_ACZ;
if (GET_SIGN_W (ke_MQ) == 0) /* MQ positive? */
ke_SR |= KE_SR_SXT;
if (ke_MQ == 0) /* MQ zero? */
ke_SR |= KE_SR_Z;
}
if (ke_AC == 0177777) { /* AC == 177777? */
ke_SR |= KE_SR_ACM1;
if (GET_SIGN_W (ke_MQ) == 1) /* MQ negative? */
ke_SR |= KE_SR_SXT;
}
return ke_SR;
}
/* Reset routine */
t_stat ke_reset (DEVICE *dptr)
{
ke_SR = 0;
ke_SC = 0;
ke_AC = 0;
ke_MQ = 0;
return SCPE_OK;
}

477
PDP11/pdp11_kg.c Normal file
View File

@@ -0,0 +1,477 @@
/* pdp11_kg.c - Communications Arithmetic Option KG11-A
Copyright (c) 2007-2008, John A. Dundas III
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 the author shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the author.
kg KG11-A Communications Arithmetic Option (M7251)
08-Jan-08 JAD First public release integrated with SIMH V3.7-3.
09-Dec-07 JAD SIMH-style debugging.
Finished validating against real hardware.
Support for up to 8 units, the maximum.
Keep all module data in the UNIT structure.
Clean up bit and mask definitions.
01-Dec-07 JAD Now work on the corner cases that the
diagnostic does not check.
CLR does not clear the QUO bit.
Correct SR write logic.
29-Nov-07 JAD Original implementation and testing based on
an idea from 07-Jul-03. Passes the ZKGAB0
diagnostic.
Information necessary to create this simulation was gathered from
a number of sources including:
KG11-A Exclusive-OR and CRC block check manual, DEC-11-HKGAA-B-D
<http://www.computer.museum.uq.edu.au/pdf/DEC-11-HKGAA-B-D%20KG11-A%20Exclusive-OR%20and%20CRC%20Block%20Check%20Manual.pdf>
Maintenance print set
<http://bitsavers.org/pdf/dec/unibus/KG11A_EngrDrws.pdf>
A Painless Guide to CRC Error Detection Algorithms, Ross N. Williams
<http://www.ross.net/crc/download/crc_v3.txt">
The original PDP-11 instruction set, as implemented in the /20,
/15, /10, and /5, did not include XOR. [One of the differences
tables incorrectly indicates the /04 does not implement this
instruction.] This device implements XOR, XORB, and a variety of
CRCs.
The maintenance prints indicate that the device was probably available
starting in late 1971. May need to check further. The first edition
of the manual was May 1972.
The device was still sold at least as late as mid-1982 according
to the PDP-11 Systems and Options Summary. RSTS/E included support
for up to 8 units in support of the 2780 emulation or for use with
DP11, DU11, or DUP11. The device appears to have been retired by
1983-03, and possibly earlier.
I/O Page Registers
SR 7707x0 (read-write) status
BCC 7707x2 (read-only) BCC (block check character)
DR 7707x4 (write-only) data
Vector: none
Priority: none
The KG11-A is a programmed-I/O, non-interrupting device. Therefore
no vector or bus request level are necessary. It is a Unibus device
but since it does not address memory itself (it only presents
registers in the I/O page) it is compatible with extended Unibus
machines (22-bit) as well as traditional Unibus.
Implements 5 error detection codes:
LRC-8
LRC-16
CRC-12
CRC-16
CRC-CCITT
*/
#if !defined (VM_PDP11)
#error "KG11 is not supported!"
#endif
#include "pdp11_defs.h"
extern FILE *sim_deb;
extern REG cpu_reg[];
extern int32 R[];
#ifndef KG_UNITS
#define KG_UNITS (8)
#endif
/* Control and Status Register */
#define KGSR_V_QUO (8) /* RO */
#define KGSR_V_DONE (7) /* RO */
#define KGSR_V_SEN (6) /* R/W shift enable */
#define KGSR_V_STEP (5) /* W */
#define KGSR_V_CLR (4) /* W */
#define KGSR_V_DDB (3) /* R/W double data byte */
#define KGSR_V_CRCIC (2) /* R/W */
#define KGSR_V_LRC (1) /* R/W */
#define KGSR_V_16 (0) /* R/W */
#define KGSR_M_QUO (1u << KGSR_V_QUO)
#define KGSR_M_DONE (1u << KGSR_V_DONE)
#define KGSR_M_SEN (1u << KGSR_V_SEN)
#define KGSR_M_STEP (1u << KGSR_V_STEP)
#define KGSR_M_CLR (1u << KGSR_V_CLR)
#define KGSR_M_DDB (1u << KGSR_V_DDB)
#define KGSR_M_CRCIC (1u << KGSR_V_CRCIC)
#define KGSR_M_LRC (1u << KGSR_V_LRC)
#define KGSR_M_16 (1u << KGSR_V_16)
#define KG_SR_RDMASK (KGSR_M_QUO | KGSR_M_DONE | KGSR_M_SEN | KGSR_M_DDB | \
KGSR_M_CRCIC | KGSR_M_LRC | KGSR_M_16)
#define KG_SR_WRMASK (KGSR_M_SEN | KGSR_M_DDB | KGSR_M_CRCIC | \
KGSR_M_LRC | KGSR_M_16)
#define KG_SR_POLYMASK (KGSR_M_CRCIC|KGSR_M_LRC|KGSR_M_16)
/* Unit structure redefinitions */
#define SR u3
#define BCC u4
#define DR u5
#define PULSCNT u6
#define POLY_LRC8 (0x0008)
#define POLY_LRC16 (0x0080)
#define POLY_CRC12 (0x0f01)
#define POLY_CRC16 (0xa001)
#define POLY_CCITT (0x8408)
static const struct {
uint16 poly;
uint16 pulses;
const char * const name;
} config[] = {
/* DDB=0 */
{ POLY_CRC12, 6, "CRC-12" },
{ POLY_CRC16, 8, "CRC-16" },
{ POLY_LRC8, 8, "LRC-8" },
{ POLY_LRC16, 8, "LRC-16" },
{ 0, 0, "undefined" },
{ POLY_CCITT, 8, "CRC-CCITT" },
{ 0, 0, "undefined" },
{ 0, 0, "undefined" },
/* DDB=1 */
{ POLY_CRC12, 12, "CRC-12" },
{ POLY_CRC16, 16, "CRC-16" },
{ POLY_LRC8, 16, "LRC-8" },
{ POLY_LRC16, 16, "LRC-16" },
{ 0, 0, "undefined" },
{ POLY_CCITT, 16, "CRC-CCITT" },
{ 0, 0, "undefined" },
{ 0, 0, "undefined" }
};
/* Forward declarations */
static t_stat kg_rd (int32 *, int32, int32);
static t_stat kg_wr (int32, int32, int32);
static t_stat kg_reset (DEVICE *);
static void do_poly (int, t_bool);
static t_stat set_units (UNIT *, int32, char *, void *);
/* 16-bit rotate right */
#define ROR(n,v) (((v >> n) & DMASK) | (v << (16 - n)) & DMASK)
/* 8-bit rotate right */
#define RORB(n,v) (((v & 0377) >> n) | ((v << (8 - n)) & 0377))
/* KG data structures
kg_dib KG PDP-11 device information block
kg_unit KG unit descriptor
kg_reg KG register list
kg_mod KG modifiers table
kg_debug KG debug names table
kg_dev KG device descriptor
*/
static DIB kg_dib = {
IOBA_KG,
(IOLN_KG + 2) * KG_UNITS,
&kg_rd,
&kg_wr,
0, 0, 0, { NULL }
};
static UNIT kg_unit[] = {
{ UDATA (NULL, 0, 0) },
{ UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) },
{ UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) },
{ UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) },
{ UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) },
{ UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) },
{ UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) },
{ UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) },
};
static const REG kg_reg[] = {
{ ORDATA (SR0, kg_unit[0].SR, 16) },
{ ORDATA (SR1, kg_unit[1].SR, 16) },
{ ORDATA (SR2, kg_unit[2].SR, 16) },
{ ORDATA (SR3, kg_unit[3].SR, 16) },
{ ORDATA (SR4, kg_unit[4].SR, 16) },
{ ORDATA (SR5, kg_unit[5].SR, 16) },
{ ORDATA (SR6, kg_unit[6].SR, 16) },
{ ORDATA (SR7, kg_unit[7].SR, 16) },
{ ORDATA (BCC0, kg_unit[0].BCC, 16) },
{ ORDATA (BCC1, kg_unit[1].BCC, 16) },
{ ORDATA (BCC2, kg_unit[2].BCC, 16) },
{ ORDATA (BCC3, kg_unit[3].BCC, 16) },
{ ORDATA (BCC4, kg_unit[4].BCC, 16) },
{ ORDATA (BCC5, kg_unit[5].BCC, 16) },
{ ORDATA (BCC6, kg_unit[6].BCC, 16) },
{ ORDATA (BCC7, kg_unit[7].BCC, 16) },
{ ORDATA (DR0, kg_unit[0].DR, 16) },
{ ORDATA (DR1, kg_unit[1].DR, 16) },
{ ORDATA (DR2, kg_unit[2].DR, 16) },
{ ORDATA (DR3, kg_unit[3].DR, 16) },
{ ORDATA (DR4, kg_unit[4].DR, 16) },
{ ORDATA (DR5, kg_unit[5].DR, 16) },
{ ORDATA (DR6, kg_unit[6].DR, 16) },
{ ORDATA (DR7, kg_unit[7].DR, 16) },
{ ORDATA (PULSCNT0, kg_unit[0].PULSCNT, 16) },
{ ORDATA (PULSCNT1, kg_unit[1].PULSCNT, 16) },
{ ORDATA (PULSCNT2, kg_unit[2].PULSCNT, 16) },
{ ORDATA (PULSCNT3, kg_unit[3].PULSCNT, 16) },
{ ORDATA (PULSCNT4, kg_unit[4].PULSCNT, 16) },
{ ORDATA (PULSCNT5, kg_unit[5].PULSCNT, 16) },
{ ORDATA (PULSCNT6, kg_unit[6].PULSCNT, 16) },
{ ORDATA (PULSCNT7, kg_unit[7].PULSCNT, 16) },
{ ORDATA (DEVADDR, kg_dib.ba, 32), REG_HRO },
{ NULL }
};
static const MTAB kg_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, NULL, &show_addr, NULL },
{ MTAB_XTD|MTAB_VDV, 0, NULL, "UNITS=0..8", &set_units, NULL, NULL },
{ 0 }
};
#define DBG_REG (01)
#define DBG_POLY (02)
#define DBG_CYCLE (04)
static const DEBTAB kg_debug[] = {
{"REG", DBG_REG},
{"POLY", DBG_POLY},
{"CYCLE", DBG_CYCLE},
{0},
};
DEVICE kg_dev = {
"KG", (UNIT *) &kg_unit, (REG *) kg_reg, (MTAB *) kg_mod,
KG_UNITS, 8, 16, 2, 8, 16,
NULL, /* examine */
NULL, /* deposit */
&kg_reset, /* reset */
NULL, /* boot */
NULL, /* attach */
NULL, /* detach */
&kg_dib,
DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG,
0, /* debug control */
(DEBTAB *) &kg_debug, /* debug flags */
NULL, /* memory size chage */
NULL /* logical name */
};
/* KG I/O address routines */
static t_stat kg_rd (int32 *data, int32 PA, int32 access)
{
int unit = (PA >> 3) & 07;
if ((unit >= KG_UNITS) || (kg_unit[unit].flags & UNIT_DIS))
return (SCPE_NXM);
switch ((PA >> 1) & 03) {
case 00: /* SR */
if (DEBUG_PRI(kg_dev, DBG_REG))
fprintf (sim_deb, ">>KG%d: rd SR %06o, PC %06o\n",
unit, kg_unit[unit].SR, PC);
*data = kg_unit[unit].SR & KG_SR_RDMASK;
break;
case 01: /* BCC */
if (DEBUG_PRI(kg_dev, DBG_REG))
fprintf (sim_deb, ">>KG%d rd BCC %06o, PC %06o\n",
unit, kg_unit[unit].BCC, PC);
*data = kg_unit[unit].BCC & DMASK;
break;
case 02: /* DR */
break;
default:
break;
}
return (SCPE_OK);
}
static t_stat kg_wr (int32 data, int32 PA, int32 access)
{
int setup;
int unit = (PA >> 3) & 07;
if ((unit >= KG_UNITS) || (kg_unit[unit].flags & UNIT_DIS))
return (SCPE_NXM);
switch ((PA >> 1) & 03) {
case 00: /* SR */
if (access == WRITEB)
data = (PA & 1) ?
(kg_unit[unit].SR & 0377) | (data << 8) :
(kg_unit[unit].SR & ~0377) | data;
if (DEBUG_PRI(kg_dev, DBG_REG))
fprintf (sim_deb, ">>KG%d: wr SR %06o, PC %06o\n",
unit, data, PC);
if (data & KGSR_M_CLR) {
kg_unit[unit].PULSCNT = 0; /* not sure about this */
kg_unit[unit].BCC = 0;
kg_unit[unit].SR |= KGSR_M_DONE;
}
setup = (kg_unit[unit].SR & 017) ^ (data & 017);
kg_unit[unit].SR = (kg_unit[unit].SR & ~KG_SR_WRMASK) |
(data & KG_SR_WRMASK);
/* if low 4b changed, reset C1 & C2 */
if (setup) {
kg_unit[unit].PULSCNT = 0;
if (DEBUG_PRI(kg_dev, DBG_POLY))
fprintf (sim_deb, ">>KG%d poly %s %d\n",
unit, config[data & 017].name, config[data & 017].pulses);
}
if (data & KGSR_M_SEN)
break;
if (data & KGSR_M_STEP) {
do_poly (unit, TRUE);
break;
}
break;
case 01: /* BCC */
break; /* ignored */
case 02: /* DR */
if (access == WRITEB)
data = (PA & 1) ?
(kg_unit[unit].DR & 0377) | (data << 8) :
(kg_unit[unit].DR & ~0377) | data;
kg_unit[unit].DR = data & DMASK;
if (DEBUG_PRI(kg_dev, DBG_REG))
fprintf (sim_deb, ">>KG%d: wr DR %06o, data %06o, PC %06o\n",
unit, kg_unit[unit].DR, data, PC);
kg_unit[unit].SR &= ~KGSR_M_DONE;
/* In a typical device, this is normally where we would use sim_activate()
to initiate an I/O to be completed later. The KG is a little
different. When it was first introduced, it's computation operation
completed before another instruction could execute (on early PDP-11s),
and software often took "advantage" of this fact by not bothering
to check the status of the DONE bit. In reality, the execution
time of the polynomial is dependent upon the width of the poly; if
8 bits 1us, if 16 bits, 2us. Since known existing software will
break if we actually defer the computation, it is performed immediately
instead. However this could easily be made into a run-time option,
if there were software to validate correct operation. */
if (kg_unit[unit].SR & KGSR_M_SEN)
do_poly (unit, FALSE);
break;
default:
break;
}
return (SCPE_OK);
}
/* KG reset */
static t_stat kg_reset (DEVICE *dptr)
{
int i;
if (DEBUG_PRI(kg_dev, DBG_REG))
fprintf (sim_deb, ">>KG: reset PC %06o\n", PC);
for (i = 0; i < KG_UNITS; i++) {
kg_unit[i].SR = KGSR_M_DONE;
kg_unit[i].BCC = 0;
kg_unit[i].PULSCNT = 0;
}
return (SCPE_OK);
}
static void cycleOneBit (int unit)
{
int quo;
if (DEBUG_PRI(kg_dev, DBG_CYCLE))
fprintf (sim_deb, ">>KG%d: cycle s BCC %06o DR %06o\n",
unit, kg_unit[unit].BCC, kg_unit[unit].DR);
if (kg_unit[unit].SR & KGSR_M_DONE)
return;
if ((kg_unit[unit].SR & KG_SR_POLYMASK) == 0)
kg_unit[unit].BCC = (kg_unit[unit].BCC & 077) |
((kg_unit[unit].BCC >> 2) & 07700);
kg_unit[unit].SR &= ~KGSR_M_QUO;
quo = (kg_unit[unit].BCC & 01) ^ (kg_unit[unit].DR & 01);
kg_unit[unit].BCC = (kg_unit[unit].BCC & ~01) | quo;
if (kg_unit[unit].SR & KGSR_M_LRC)
kg_unit[unit].BCC = (kg_unit[unit].SR & KGSR_M_16) ?
ROR(1, kg_unit[unit].BCC) :
RORB(1, kg_unit[unit].BCC);
else
kg_unit[unit].BCC = (kg_unit[unit].BCC & 01) ?
(kg_unit[unit].BCC >> 1) ^ config[kg_unit[unit].SR & 07].poly :
kg_unit[unit].BCC >> 1;
kg_unit[unit].DR >>= 1;
kg_unit[unit].SR |= quo << KGSR_V_QUO;
if ((kg_unit[unit].SR & KG_SR_POLYMASK) == 0)
kg_unit[unit].BCC = (kg_unit[unit].BCC & 077) |
((kg_unit[unit].BCC & 07700) << 2);
kg_unit[unit].PULSCNT++;
if (kg_unit[unit].PULSCNT >= config[kg_unit[unit].SR & 017].pulses)
kg_unit[unit].SR |= KGSR_M_DONE;
if (DEBUG_PRI(kg_dev, DBG_CYCLE))
fprintf (sim_deb, ">>KG%d: cycle e BCC %06o DR %06o\n",
unit, kg_unit[unit].BCC, kg_unit[unit].DR);
}
static void do_poly (int unit, t_bool step)
{
if (kg_unit[unit].SR & KGSR_M_DONE)
return;
if (step)
cycleOneBit (unit);
else {
while (!(kg_unit[unit].SR & KGSR_M_DONE))
cycleOneBit (unit);
}
}
static t_stat set_units (UNIT *u, int32 val, char *s, void *desc)
{
int32 i, units;
t_stat stat;
if (s == NULL)
return (SCPE_ARG);
units = get_uint (s, 10, KG_UNITS, &stat);
if (stat != SCPE_OK)
return (stat);
for (i = 0; i < KG_UNITS; i++) {
if (i < units)
kg_unit[i].flags &= ~UNIT_DIS;
else
kg_unit[i].flags |= UNIT_DIS;
}
kg_dev.numunits = units;
return (SCPE_OK);
}

View File

@@ -1,6 +1,6 @@
/* pdp11_pclk.c: KW11P programmable clock simulator
Copyright (c) 1993-2007, Robert M Supnik
Copyright (c) 1993-2008, Robert M Supnik
Written by John Dundas, used with his gracious permission
Permission is hereby granted, free of charge, to any person obtaining a
@@ -26,6 +26,7 @@
pclk KW11P line frequency clock
20-May-08 RMS Standardized clock delay at 1mips
18-Jun-07 RMS Added UNIT_IDLE flag
07-Jul-05 RMS Removed extraneous externs
@@ -133,7 +134,7 @@ uint32 pclk_csr = 0; /* control/status */
uint32 pclk_csb = 0; /* count set buffer */
uint32 pclk_ctr = 0; /* counter */
static uint32 rate[4] = { 100000, 10000, 60, 10 }; /* ticks per second */
static uint32 xtim[4] = { 10, 100, 16000, 100000 }; /* nominal time delay */
static uint32 xtim[4] = { 10, 100, 16667, 100000 }; /* nominal time delay */
DEVICE pclk_dev;
t_stat pclk_rd (int32 *data, int32 PA, int32 access);

583
PDP11/pdp11_rc.c Normal file
View File

@@ -0,0 +1,583 @@
/* pdp11_rc.c: RC11/RS64 fixed head disk simulator
Copyright (c) 2007-2008, John A. Dundas III
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 the author shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the author.
rc RC11/RS64 fixed head disk
28-Dec-07 JAD Correct extraction of unit number from da in rc_svc.
Clear _all_ error bits when a new operation starts.
Passes all diagnostics in all configurations.
25-Dec-07 JAD Compute the CRC-16 of the last sector read via
a READ or WCHK.
20-Dec-07 JAD Correctly simulate rotation over the selected
track for RCLA. Also update the register
correctly during I/O operations.
Insure function activation time is non-zero.
Handle unit number wrap correctly.
19-Dec-07 JAD Iterate over a full sector regardless of the
actual word count so that RCDA ends correctly.
Honor the read-only vs. read-write status of the
attached file.
16-Dec-07 JAD The RCDA must be checked for validity when it is
written to, not just when GO is received.
15-Dec-07 JAD Better handling of disk address errors and the RCLA
register.
Add more registers to the visible device state.
07-Jan-07 JAD Initial creation and testing. Adapted from pdp11_rf.c.
The RS64 is a head-per-track disk. To minimize overhead, the entire RC11
is buffered in memory. Up to 4 RS64 "platters" may be controlled by one
RC11 for a total of 262,144 words (65536kW/platter). [Later in time the
RK611 was assigned the same CSR address.]
Diagnostic routines:
ZRCAB0.BIC - passes w/1-4 platters
ZRCBB0.BIC - passes w/1-4 platters
ZRCCB0.BIC - passes w/1-4 platters
Note that the diagnostics require R/W disks (i.e., will destroy any
existing data).
For regression, must pass all three diagnostics configured for 1-4
platters for a total of 12 tests.
Information necessary to create this simulation was gathered from the
PDP11 Peripherals Handbook, 1973-74 edition.
One timing parameter is provided:
rc_time Minimum I/O operation time, must be non-zero
*/
#if !defined (VM_PDP11)
#error "RC11 is not supported!"
#endif
#include "pdp11_defs.h"
#include <math.h>
#define UNIT_V_AUTO (UNIT_V_UF + 0) /* autosize */
#define UNIT_V_PLAT (UNIT_V_UF + 1) /* #platters - 1 */
#define UNIT_M_PLAT 03
#define UNIT_GETP(x) ((((x) >> UNIT_V_PLAT) & UNIT_M_PLAT) + 1)
#define UNIT_AUTO (1 << UNIT_V_AUTO)
#define UNIT_PLAT (UNIT_M_PLAT << UNIT_V_PLAT)
/* Constants */
#define RC_NUMWD (32*64) /* words/track */
#define RC_NUMTR 32 /* tracks/disk */
#define RC_DKSIZE (RC_NUMTR * RC_NUMWD) /* words/disk */
#define RC_NUMDK 4 /* disks/controller */
#define RC_WMASK (RC_NUMWD - 1) /* word mask */
/* Parameters in the unit descriptor */
#define FUNC u4 /* function */
/* Control and status register (RCCS) */
#define RCCS_ERR (CSR_ERR) /* error */
#define RCCS_DATA 0040000 /* data error */
#define RCCS_ADDR 0020000 /* address error */
#define RCCS_WLK 0010000 /* write lock */
#define RCCS_NED 0004000 /* nx disk */
#define RCCS_WCHK 0002000 /* write check */
#define RCCS_INH 0001000 /* inhibit CA incr */
#define RCCS_ABO 0000400 /* abort */
#define RCCS_DONE (CSR_DONE)
#define RCCS_IE (CSR_IE)
#define RCCS_M_MEX 0000003 /* memory extension */
#define RCCS_V_MEX 4
#define RCCS_MEX (RCCS_M_MEX << RCCS_V_MEX)
#define RCCS_MAINT 0000010 /* maint */
#define RCCS_M_FUNC 0000003 /* function */
#define RFNC_LAH 0
#define RFNC_WRITE 1
#define RFNC_READ 2
#define RFNC_WCHK 3
#define RCCS_V_FUNC 1
#define RCCS_FUNC (RCCS_M_FUNC << RCCS_V_FUNC)
#define RCCS_GO 0000001
#define RCCS_ALLERR (RCCS_DATA|RCCS_ADDR|RCCS_WLK|RCCS_NED|RCCS_WCHK)
#define RCCS_W (RCCS_INH | RCCS_ABO |RCCS_IE | RCCS_MEX | RCCS_MAINT | \
RCCS_FUNC | RCCS_GO)
/* Disk error status register (RCER) */
#define RCER_DLT 0100000 /* data late */
#define RCER_CHK 0040000 /* block check */
#define RCER_SYNC 0020000 /* data sync */
#define RCER_NXM 0010000 /* nonexistant memory */
#define RCER_TRK 0001000 /* track error */
#define RCER_APAR 0000200 /* address parity */
#define RCER_SADDR 0000100 /* sync address */
#define RCER_OVFL 0000040 /* disk overflow */
#define RCER_MIS 0000020 /* missed transfer */
/* Lood Ahead Register (RCLA) */
#define RCLA_BADD 0100000 /* bad address */
/* extract device operation code */
#define GET_FUNC(x) (((x) >> RCCS_V_FUNC) & RCCS_M_FUNC)
/* extract memory extension address (bits 17,18) */
#define GET_MEX(x) (((x) & RCCS_MEX) << (16 - RCCS_V_MEX))
#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \
((double) RC_NUMWD)))
extern int32 int_req[IPL_HLVL];
extern FILE *sim_deb;
extern int32 R[];
static uint32 rc_la = 0; /* look-ahead */
static uint32 rc_da = 0; /* disk address */
static uint32 rc_er = 0; /* error status */
static uint32 rc_cs = 0; /* command and status */
static uint32 rc_wc = 0; /* word count */
static uint32 rc_ca = 0; /* current address */
static uint32 rc_maint = 0; /* maintenance */
static uint32 rc_db = 0; /* data buffer */
static uint32 rc_wlk = 0; /* write lock */
static uint32 rc_time = 16; /* inter-word time: 16us */
static uint32 rc_stopioe = 1; /* stop on error */
/* forward references */
DEVICE rc_dev;
static t_stat rc_rd (int32 *, int32, int32);
static t_stat rc_wr (int32, int32, int32);
static t_stat rc_svc (UNIT *);
static t_stat rc_reset (DEVICE *);
static t_stat rc_attach (UNIT *, char *);
static t_stat rc_set_size (UNIT *, int32, char *, void *);
static uint32 update_rccs (uint32, uint32);
/* RC11 data structures
rc_dev RC device descriptor
rc_unit RC unit descriptor
rc_reg RC register list
*/
static DIB rc_dib = {
IOBA_RC,
IOLN_RC,
&rc_rd,
&rc_wr,
1, IVCL (RC), VEC_RC, { NULL }
};
static UNIT rc_unit = {
UDATA (&rc_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_BUFABLE +
UNIT_MUSTBUF + UNIT_ROABLE + UNIT_BINK, RC_DKSIZE)
};
static const REG rc_reg[] = {
{ ORDATA (RCLA, rc_la, 16) },
{ ORDATA (RCDA, rc_da, 16) },
{ ORDATA (RCER, rc_er, 16) },
{ ORDATA (RCCS, rc_cs, 16) },
{ ORDATA (RCWC, rc_wc, 16) },
{ ORDATA (RCCA, rc_ca, 16) },
{ ORDATA (RCMN, rc_maint, 16) },
{ ORDATA (RCDB, rc_db, 16) },
{ ORDATA (RCWLK, rc_wlk, 32) },
{ FLDATA (INT, IREQ (RC), INT_V_RC) },
{ FLDATA (ERR, rc_cs, CSR_V_ERR) },
{ FLDATA (DONE, rc_cs, CSR_V_DONE) },
{ FLDATA (IE, rc_cs, CSR_V_IE) },
{ DRDATA (TIME, rc_time, 24), REG_NZ + PV_LEFT },
{ FLDATA (STOP_IOE, rc_stopioe, 0) },
{ ORDATA (DEVADDR, rc_dib.ba, 32), REG_HRO },
{ ORDATA (DEVVEC, rc_dib.vec, 16), REG_HRO },
{ NULL }
};
static const MTAB rc_mod[] = {
{ UNIT_PLAT, (0 << UNIT_V_PLAT), NULL, "1P", &rc_set_size },
{ UNIT_PLAT, (1 << UNIT_V_PLAT), NULL, "2P", &rc_set_size },
{ UNIT_PLAT, (2 << UNIT_V_PLAT), NULL, "3P", &rc_set_size },
{ UNIT_PLAT, (3 << UNIT_V_PLAT), NULL, "4P", &rc_set_size },
{ UNIT_AUTO, UNIT_AUTO, "autosize", "AUTOSIZE", NULL },
{ MTAB_XTD|MTAB_VDV, 020, "ADDRESS", "ADDRESS",
&set_addr, &show_addr, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",
&set_vec, &show_vec, NULL },
{ 0 }
};
DEVICE rc_dev = {
"RC", &rc_unit, (REG *) rc_reg, (MTAB *) rc_mod,
1, 8, 21, 1, 8, 16,
NULL, /* examine */
NULL, /* deposit */
&rc_reset, /* reset */
NULL, /* boot */
&rc_attach, /* attach */
NULL, /* detach */
&rc_dib,
DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG
};
/* I/O dispatch routine, I/O addresses 17777440 - 17777456 */
static t_stat rc_rd (int32 *data, int32 PA, int32 access)
{
uint32 t;
switch ((PA >> 1) & 07) { /* decode PA<3:1> */
case 0: /* RCLA */
t = rc_la & 017777;
if ((rc_cs & RCCS_NED) || (rc_er & RCER_OVFL))
t |= RCLA_BADD;
*data = t;
/* simulate sequential rotation about the current track */
rc_la = (rc_la & ~077) | ((rc_la + 1) & 077);
if (DEBUG_PRS (rc_dev))
fprintf (sim_deb, ">>RC rd: RCLA %06o\n", rc_la);
break;
case 1: /* RCDA */
*data = rc_da;
if (DEBUG_PRS (rc_dev))
fprintf (sim_deb, ">>RC rd: RCDA %06o, PC %06o\n",
rc_da, PC);
break;
case 2: /* RCER */
*data = rc_er;
if (DEBUG_PRS (rc_dev))
fprintf (sim_deb, ">>RC rd: RCER %06o\n", rc_er);
break;
case 3: /* RCCS */
*data = update_rccs (0, 0) & ~(RCCS_ABO | RCCS_GO);
if (DEBUG_PRS (rc_dev))
fprintf (sim_deb, ">>RC rd: RCCS %06o\n", *data);
break;
case 4: /* RCWC */
*data = rc_wc;
if (DEBUG_PRS (rc_dev))
fprintf (sim_deb, ">>RC rd: RCWC %06o\n", rc_wc);
break;
case 5: /* RCCA */
*data = rc_ca;
if (DEBUG_PRS (rc_dev))
fprintf (sim_deb, ">>RC rd: RCCA %06o\n", rc_ca);
break;
case 6: /* RCMN */
*data = rc_maint;
if (DEBUG_PRS (rc_dev))
fprintf (sim_deb, ">>RC rd: RCMN %06o\n", rc_maint);
break;
case 7: /* RCDB */
*data = rc_db;
if (DEBUG_PRS (rc_dev))
fprintf (sim_deb, ">>RC rd: RCDB %06o\n", rc_db);
break;
default:
return (SCPE_NXM); /* can't happen */
} /* end switch */
return (SCPE_OK);
}
static t_stat rc_wr (int32 data, int32 PA, int32 access)
{
int32 t;
switch ((PA >> 1) & 07) { /* decode PA<3:1> */
case 0: /* RCLA */
if (DEBUG_PRS (rc_dev))
fprintf (sim_deb, ">>RC wr: RCLA\n");
break; /* read only */
case 1: /* RCDA */
if (access == WRITEB)
data = (PA & 1) ?
(rc_da & 0377) | (data << 8) :
(rc_da & ~0377) | data;
rc_da = data & 017777;
rc_cs &= ~RCCS_NED;
update_rccs (0, 0);
/* perform unit select */
if (((rc_da >> 11) & 03) >= UNIT_GETP(rc_unit.flags))
update_rccs (RCCS_NED, 0);
else
rc_la = rc_da;
if (DEBUG_PRS (rc_dev))
fprintf (sim_deb, ">>RC wr: RCDA %06o, PC %06o\n",
rc_da, PC);
break;
case 2: /* RCER */
if (DEBUG_PRS (rc_dev))
fprintf (sim_deb, ">>RC wr: RCER\n");
break; /* read only */
case 3: /* RCCS */
if (access == WRITEB)
data = (PA & 1) ?
(rc_cs & 0377) | (data << 8) :
(rc_cs & ~0377) | data;
if (data & RCCS_ABO) {
update_rccs (RCCS_DONE, 0);
sim_cancel (&rc_unit);
}
if ((data & RCCS_IE) == 0) /* int disable? */
CLR_INT (RC); /* clr int request */
else if ((rc_cs & (RCCS_DONE | RCCS_IE)) == RCCS_DONE)
SET_INT (RC); /* set int request */
rc_cs = (rc_cs & ~RCCS_W) | (data & RCCS_W); /* merge */
if ((rc_cs & RCCS_DONE) && (data & RCCS_GO)) { /* new function? */
rc_unit.FUNC = GET_FUNC (data); /* save function */
t = (rc_da & RC_WMASK) - GET_POS (rc_time); /* delta to new loc */
if (t <= 0) /* wrap around? */
t = t + RC_NUMWD;
sim_activate (&rc_unit, t * rc_time); /* schedule op */
/* clear error indicators for new operation */
rc_cs &= ~(RCCS_ALLERR | RCCS_ERR | RCCS_DONE);
rc_er = 0;
CLR_INT (RC);
if (DEBUG_PRS (rc_dev))
fprintf (sim_deb, ">>RC start: cs = %o, da = %o, ma = %o, wc = %o\n",
update_rccs (0, 0), rc_da,
GET_MEX (rc_cs) | rc_ca, rc_wc);
}
break;
case 4: /* RCWC */
if (access == WRITEB)
data = (PA & 1) ?
(rc_wc & 0377) | (data << 8) :
(rc_wc & ~0377) | data;
rc_wc = data & DMASK;
if (DEBUG_PRS (rc_dev))
fprintf (sim_deb, ">>RC wr: RCWC %06o, PC %06o\n",
rc_wc, PC);
break;
case 5: /* RCCA */
/* TBD: write byte fixup? */
rc_ca = data & 0177776;
if (DEBUG_PRS (rc_dev))
fprintf (sim_deb, ">>RC wr: RCCA %06o\n", rc_ca);
break;
case 6: /* RCMN */
/* TBD: write byte fixup? */
rc_maint = data & 0177700;
if (DEBUG_PRS (rc_dev))
fprintf (sim_deb, ">>RC wr: RCMN %06o\n", rc_maint);
break;
case 7: /* RCDB */
if (DEBUG_PRS (rc_dev))
fprintf (sim_deb, ">>RC wr: RCDB\n");
break; /* read only */
default: /* can't happen */
return (SCPE_NXM);
} /* end switch */
update_rccs (0, 0);
return (SCPE_OK);
}
/* sector (32W) CRC-16 */
static uint32 sectorCRC (const uint16 *data)
{
uint32 crc, i, j, d;
crc = 0;
for (i = 0; i < 32; i++) {
d = *data++;
/* cribbed from KG11-A */
for (j = 0; j < 16; j++) {
crc = (crc & ~01) | ((crc & 01) ^ (d & 01));
crc = (crc & 01) ? (crc >> 1) ^ 0120001 : crc >> 1;
d >>= 1;
}
}
return (crc);
}
/* Unit service
Note that for reads and writes, memory addresses wrap around in the
current field. This code assumes the entire disk is buffered.
*/
static t_stat rc_svc (UNIT *uptr)
{
uint32 ma, da, t, u_old, u_new, last_da;
uint16 dat;
uint16 *fbuf = uptr->filebuf;
if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */
update_rccs (RCCS_NED | RCCS_DONE, 0); /* nx disk */
return (IORETURN (rc_stopioe, SCPE_UNATT));
}
ma = GET_MEX (rc_cs) | rc_ca; /* 18b mem addr */
da = rc_da * RC_NUMTR; /* sector->word offset */
u_old = (da >> 16) & 03; /* save starting unit# */
do {
u_new = (da >> 16) & 03;
if (u_new < u_old) { /* unit # overflow? */
update_rccs (RCCS_NED, RCER_OVFL);
break;
}
if (u_new >= UNIT_GETP(uptr->flags)) { /* disk overflow? */
update_rccs (RCCS_NED, 0);
break;
}
if (uptr->FUNC == RFNC_READ) { /* read? */
last_da = da & ~037;
dat = fbuf[da]; /* get disk data */
rc_db = dat;
if (Map_WriteW (ma, 2, &dat)) { /* store mem, nxm? */
update_rccs (0, RCER_NXM);
break;
}
} else if (uptr->FUNC == RFNC_WCHK) { /* write check? */
last_da = da & ~037;
rc_db = fbuf[da]; /* get disk data */
if (Map_ReadW (ma, 2, &dat)) { /* read mem, nxm? */
update_rccs (0, RCER_NXM);
break;
}
if (rc_db != dat) { /* miscompare? */
update_rccs (RCCS_WCHK, 0);
break;
}
} else if (uptr->FUNC == RFNC_WRITE) { /* write */
t = (da >> 15) & 037;
if (((rc_wlk >> t) & 1) ||
(uptr->flags & UNIT_RO)) { /* write locked? */
update_rccs (RCCS_WLK, 0);
break;
}
/* not locked */
if (Map_ReadW (ma, 2, &dat)) { /* read mem, nxm? */
update_rccs (0, RCER_NXM);
break;
}
fbuf[da] = dat; /* write word */
rc_db = dat;
if (da >= uptr->hwmark)
uptr->hwmark = da + 1;
} else { /* look ahead */
break; /* no op for now */
}
rc_wc = (rc_wc + 1) & DMASK; /* incr word count */
da = (da + 1) & 0777777; /* incr disk addr */
if ((rc_cs & RCCS_INH) == 0) /* inhibit clear? */
ma = (ma + 2) & UNIMASK; /* incr mem addr */
} while (rc_wc != 0); /* brk if wc */
rc_ca = ma & DMASK; /* split ma */
rc_cs = (rc_cs & ~RCCS_MEX) | ((ma >> (16 - RCCS_V_MEX)) & RCCS_MEX);
da += 31;
rc_da = (da >> 5) & 017777;
/* CRC of last 32W, if necessary */
if ((uptr->FUNC == RFNC_READ) || (uptr->FUNC == RFNC_WCHK))
rc_db = sectorCRC (&fbuf[last_da]);
if (uptr->FUNC != RFNC_LAH)
rc_la = rc_da;
update_rccs (RCCS_DONE, 0);
if (DEBUG_PRS (rc_dev))
fprintf (sim_deb, ">>RC done: cs = %o, da = %o, ma = %o, wc = %o\n",
rc_cs, rc_da, rc_ca, rc_wc);
return (SCPE_OK);
}
/* Update CS register */
static uint32 update_rccs (uint32 newcs, uint32 newer)
{
uint32 oldcs = rc_cs;
rc_er |= newer; /* update RCER */
rc_cs |= newcs; /* update CS */
if ((rc_cs & RCCS_ALLERR) || (rc_er != 0)) /* update CS<err> */
rc_cs |= RCCS_ERR;
else
rc_cs &= ~RCCS_ERR;
if ((rc_cs & RCCS_IE) && /* IE and */
(rc_cs & RCCS_DONE) && !(oldcs & RCCS_DONE)) /* done 0->1? */
SET_INT (RC);
return (rc_cs);
}
/* Reset routine */
static t_stat rc_reset (DEVICE *dptr)
{
rc_cs = RCCS_DONE;
rc_la = rc_da = 0;
rc_er = 0;
rc_wc = 0;
rc_ca = 0;
rc_maint = 0;
rc_db = 0;
CLR_INT (RC);
sim_cancel (&rc_unit);
return (SCPE_OK);
}
/* Attach routine */
static t_stat rc_attach (UNIT *uptr, char *cptr)
{
uint32 sz, p;
static const uint32 ds_bytes = RC_DKSIZE * sizeof (int16);
if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize_name (cptr))) {
p = (sz + ds_bytes - 1) / ds_bytes;
if (p >= RC_NUMDK)
p = RC_NUMDK - 1;
uptr->flags = (uptr->flags & ~UNIT_PLAT) | (p << UNIT_V_PLAT);
}
uptr->capac = UNIT_GETP (uptr->flags) * RC_DKSIZE;
return (attach_unit (uptr, cptr));
}
/* Change disk size */
static t_stat rc_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
if (val < 0)
return (SCPE_IERR);
if (uptr->flags & UNIT_ATT)
return (SCPE_ALATT);
uptr->capac = UNIT_GETP (val) * RC_DKSIZE;
uptr->flags = uptr->flags & ~UNIT_AUTO;
return (SCPE_OK);
}

View File

@@ -1,6 +1,6 @@
/* pdp11_rh.c: PDP-11 Massbus adapter simulator
Copyright (c) 2005-2007, Robert M Supnik
Copyright (c) 2005-2008, 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"),
@@ -25,6 +25,7 @@
rha, rhb RH11/RH70 Massbus adapter
02-Feb-08 RMS Fixed DMA memory address limit test (found by John Dundas)
17-May-07 RMS Moved CS1 drive enable to devices
21-Nov-05 RMS Added enable/disable routine
07-Jul-05 RMS Removed extraneous externs
@@ -160,7 +161,7 @@ MBACTX massbus[MBA_NUM];
extern int32 cpu_opt, cpu_bme;
extern uint16 *M;
extern int32 int_req[IPL_HLVL];
extern UNIT cpu_unit;
extern t_addr cpu_memsize;
extern FILE *sim_deb;
extern FILE *sim_log;
extern int32 sim_switches;

View File

@@ -1,6 +1,6 @@
/* pdp11_stddev.c: PDP-11 standard I/O devices simulator
Copyright (c) 1993-2007, Robert M Supnik
Copyright (c) 1993-2008, 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"),
@@ -26,6 +26,7 @@
tti,tto DL11 terminal input/output
clk KW11L (and other) line frequency clock
20-May-08 RMS Standardized clock delay at 1mips
18-Jun-07 RMS Added UNIT_IDLE flag to console input, clock
29-Oct-06 RMS Synced keyboard and clock
Added clock coscheduling support
@@ -66,7 +67,7 @@
#define TTOCSR_RW (CSR_IE)
#define CLKCSR_IMP (CSR_DONE + CSR_IE) /* real-time clock */
#define CLKCSR_RW (CSR_IE)
#define CLK_DELAY 8000
#define CLK_DELAY 16667
extern int32 int_req[IPL_HLVL];
extern uint32 cpu_type;
@@ -202,7 +203,7 @@ DIB clk_dib = {
1, IVCL (CLK), VEC_CLK, { &clk_inta }
};
UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE, 0), 8000 };
UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE, 0), CLK_DELAY };
REG clk_reg[] = {
{ ORDATA (CSR, clk_csr, 16) },

View File

@@ -1,6 +1,6 @@
/* pdp11_sys.c: PDP-11 simulator interface
Copyright (c) 1993-2006, Robert M Supnik
Copyright (c) 1993-2008, 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"),
@@ -23,6 +23,11 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
15-May-08 RMS Added KE11-A, DC11 support
Renamed DL11
04-Feb-08 RMS Modified to allow -A, -B use with 8b devices
25-Jan-08 RMS Added RC11, KG11A support from John Dundas
10-Sep-07 RMS Cleaned up binary loader
20-Dec-06 RMS Added TA11 support
12-Nov-06 RMS Fixed operand order in EIS instructions (found by W.F.J. Mueller)
14-Jul-06 RMS Reordered device list
@@ -69,11 +74,14 @@ extern DEVICE lpt_dev;
extern DEVICE cr_dev;
extern DEVICE clk_dev;
extern DEVICE pclk_dev;
extern DEVICE ttix_dev;
extern DEVICE ttox_dev;
extern DEVICE dli_dev;
extern DEVICE dlo_dev;
extern DEVICE dci_dev;
extern DEVICE dco_dev;
extern DEVICE dz_dev;
extern DEVICE vh_dev;
extern DEVICE dt_dev;
extern DEVICE rc_dev;
extern DEVICE rf_dev;
extern DEVICE rk_dev;
extern DEVICE rl_dev;
@@ -90,6 +98,8 @@ extern DEVICE tu_dev;
extern DEVICE ta_dev;
extern DEVICE xq_dev, xqb_dev;
extern DEVICE xu_dev, xub_dev;
extern DEVICE ke_dev;
extern DEVICE kg_dev;
extern UNIT cpu_unit;
extern REG cpu_reg[];
extern uint16 *M;
@@ -124,10 +134,13 @@ DEVICE *sim_devices[] = {
&tto_dev,
&cr_dev,
&lpt_dev,
&ttix_dev,
&ttox_dev,
&dli_dev,
&dlo_dev,
&dci_dev,
&dco_dev,
&dz_dev,
&vh_dev,
&rc_dev,
&rf_dev,
&rk_dev,
&rl_dev,
@@ -149,6 +162,8 @@ DEVICE *sim_devices[] = {
&xqb_dev,
&xu_dev,
&xub_dev,
&ke_dev,
&kg_dev,
NULL
};
@@ -202,66 +217,44 @@ const char *sim_stop_messages[] = {
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
{
int32 csum, count, state, i;
uint32 origin;
int32 c[6], d, i, cnt, csum;
uint32 org;
if ((*cptr != 0) || (flag != 0)) return SCPE_ARG;
state = csum = 0;
while ((i = getc (fileref)) != EOF) {
csum = csum + i; /* add into chksum */
switch (state) {
case 0: /* leader */
if (i == 1) state = 1;
else csum = 0;
break;
case 1: /* ignore after 001 */
state = 2;
break;
case 2: /* low count */
count = i;
state = 3;
break;
case 3: /* high count */
count = (i << 8) | count;
state = 4;
break;
case 4: /* low origin */
origin = i;
state = 5;
break;
case 5: /* high origin */
origin = (i << 8) | origin;
if (count == 6) {
if (origin != 1) saved_PC = origin & 0177776;
return SCPE_OK;
}
count = count - 6;
state = 6;
break;
case 6: /* data */
if (origin >= MEMSIZE) return SCPE_NXM;
M[origin >> 1] = (origin & 1)?
(M[origin >> 1] & 0377) | (i << 8):
(M[origin >> 1] & 0177400) | i;
origin = origin + 1;
count = count - 1;
state = state + (count == 0);
break;
case 7: /* checksum */
if (csum & 0377) return SCPE_CSUM;
csum = state = 0;
break;
} /* end switch */
} /* end while */
return SCPE_FMT; /* unexpected eof */
if ((*cptr != 0) || (flag != 0))
return SCPE_ARG;
do { /* block loop */
csum = 0; /* init checksum */
for (i = 0; i < 6; ) { /* 6 char header */
if ((c[i] = getc (fileref)) == EOF)
return SCPE_FMT;
if ((i != 0) || (c[i] == 1)) /* 1st must be 1 */
csum = csum + c[i++]; /* add into csum */
}
cnt = (c[3] << 8) | c[2]; /* count */
org = (c[5] << 8) | c[4]; /* origin */
if (cnt < 6) /* invalid? */
return SCPE_FMT;
if (cnt == 6) { /* end block? */
if (org != 1) /* set PC? */
saved_PC = org & 0177776;
return SCPE_OK;
}
for (i = 6; i < cnt; i++) { /* exclude hdr */
if ((d = getc (fileref)) == EOF) /* data char */
return SCPE_FMT;
csum = csum + d; /* add into csum */
if (org >= MEMSIZE) /* invalid addr? */
return SCPE_NXM;
M[org >> 1] = (org & 1)? /* store data */
(M[org >> 1] & 0377) | (d << 8):
(M[org >> 1] & 0177400) | d;
org = (org + 1) & 0177777; /* inc origin */
}
if ((d = getc (fileref)) == EOF) /* get csum */
return SCPE_FMT;
csum = csum + d; /* add in */
} while ((csum & 0377) == 0); /* result mbz */
return SCPE_CSUM;
}
/* Factory bad block table creation routine
@@ -288,20 +281,27 @@ t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds)
int32 i, da;
uint16 *buf;
if ((sec < 2) || (wds < 16)) return SCPE_ARG;
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT;
if (uptr->flags & UNIT_RO) return SCPE_RO;
if (!get_yn ("Create bad block table on last track? [N]", FALSE)) return SCPE_OK;
da = (uptr->capac - (sec * wds)) * sizeof (int16);
if (fseek (uptr->fileref, da, SEEK_SET)) return SCPE_IOERR;
if ((buf = (uint16 *) malloc (wds * sizeof (uint16))) == NULL) return SCPE_MEM;
if ((sec < 2) || (wds < 16))
return SCPE_ARG;
if ((uptr->flags & UNIT_ATT) == 0)
return SCPE_UNATT;
if (uptr->flags & UNIT_RO)
return SCPE_RO;
if (!get_yn ("Create bad block table on last track? [N]", FALSE))
return SCPE_OK;
da = (uptr->capac - (sec * wds)) * sizeof (uint16);
if (fseek (uptr->fileref, da, SEEK_SET))
return SCPE_IOERR;
if ((buf = (uint16 *) malloc (wds * sizeof (uint16))) == NULL)
return SCPE_MEM;
buf[0] = buf[1] = 012345u;
buf[2] = buf[3] = 0;
for (i = 4; i < wds; i++) buf[i] = 0177777u;
for (i = 0; (i < sec) && (i < 10); i++)
fxwrite (buf, sizeof (uint16), wds, uptr->fileref);
free (buf);
if (ferror (uptr->fileref)) return SCPE_IOERR;
if (ferror (uptr->fileref))
return SCPE_IOERR;
return SCPE_OK;
}
@@ -532,7 +532,8 @@ mode = ((spec >> 3) & 07);
switch (mode) {
case 0:
if (iflag) fprintf (of, "%s", rname[reg]);
if (iflag)
fprintf (of, "%s", rname[reg]);
else fprintf (of, "%s", fname[reg]);
break;
@@ -541,12 +542,14 @@ switch (mode) {
break;
case 2:
if (reg != 7) fprintf (of, "(%s)+", rname[reg]);
if (reg != 7)
fprintf (of, "(%s)+", rname[reg]);
else fprintf (of, "#%-o", nval);
break;
case 3:
if (reg != 7) fprintf (of, "@(%s)+", rname[reg]);
if (reg != 7)
fprintf (of, "@(%s)+", rname[reg]);
else fprintf (of, "@#%-o", nval);
break;
@@ -559,12 +562,14 @@ switch (mode) {
break;
case 6:
if ((reg != 7) || !flag) fprintf (of, "%-o(%s)", nval, rname[reg]);
if ((reg != 7) || !flag)
fprintf (of, "%-o(%s)", nval, rname[reg]);
else fprintf (of, "%-o", (nval + addr + 4) & 0177777);
break;
case 7:
if ((reg != 7) || !flag) fprintf (of, "@%-o(%s)", nval, rname[reg]);
if ((reg != 7) || !flag)
fprintf (of, "@%-o(%s)", nval, rname[reg]);
else fprintf (of, "@%-o", (nval + addr + 4) & 0177777);
break;
} /* end case */
@@ -589,20 +594,35 @@ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
UNIT *uptr, int32 sw)
{
int32 cflag, i, j, c1, c2, c3, inst, fac, srcm, srcr, dstm, dstr;
int32 l8b, brdisp, wd1, wd2;
int32 bflag, l8b, brdisp, wd1, wd2;
extern int32 FPS;
cflag = (uptr == NULL) || (uptr == &cpu_unit);
bflag = 0; /* assume 16b */
cflag = (uptr == NULL) || (uptr == &cpu_unit); /* cpu? */
if (!cflag) { /* not cpu? */
DEVICE *dptr = find_dev_from_unit (uptr);
if (dptr == NULL)
return SCPE_IERR;
if (dptr->dwidth < 16)
bflag = 1;
}
if (sw & SWMASK ('A')) { /* ASCII? */
c1 = (val[0] >> ((addr & 1)? 8: 0)) & 0177;
if (bflag)
c1 = val[0] & 0177;
else c1 = (val[0] >> ((addr & 1)? 8: 0)) & 0177;
fprintf (of, (c1 < 040)? "<%03o>": "%c", c1);
return 0;
}
if (sw & SWMASK ('B')) { /* byte? */
c1 = (val[0] >> ((addr & 1)? 8: 0)) & 0377;
if (bflag)
c1 = val[0] & 0177;
else c1 = (val[0] >> ((addr & 1)? 8: 0)) & 0377;
fprintf (of, "%o", c1);
return 0;
}
if (bflag) return SCPE_ARG; /* 16b only */
if (sw & SWMASK ('C')) { /* character? */
c1 = val[0] & 0177;
c2 = (val[0] >> 8) & 0177;
@@ -669,8 +689,10 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
case I_V_BR: /* cond branch */
fprintf (of, "%s ", opcode[i]);
brdisp = (l8b + l8b + ((l8b & 0200)? 0177002: 2)) & 0177777;
if (cflag) fprintf (of, "%-o", (addr + brdisp) & 0177777);
else if (brdisp < 01000) fprintf (of, ".+%-o", brdisp);
if (cflag)
fprintf (of, "%-o", (addr + brdisp) & 0177777);
else if (brdisp < 01000)
fprintf (of, ".+%-o", brdisp);
else fprintf (of, ".-%-o", 0200000 - brdisp);
break;
@@ -681,8 +703,10 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
case I_V_SOB: /* sob */
fprintf (of, "%s %s,", opcode[i], rname[srcr]);
brdisp = (dstm * 2) - 2;
if (cflag) fprintf (of, "%-o", (addr - brdisp) & 0177777);
else if (brdisp <= 0) fprintf (of, ".+%-o", -brdisp);
if (cflag)
fprintf (of, "%-o", (addr - brdisp) & 0177777);
else if (brdisp <= 0)
fprintf (of, ".+%-o", -brdisp);
else fprintf (of, ".-%-o", brdisp);
break;
@@ -741,7 +765,8 @@ int32 i;
if (*(cptr + 2) != mchar) return -1;
for (i = 0; i < 8; i++) {
if (strncmp (cptr, strings[i], 2) == 0) return i;
if (strncmp (cptr, strings[i], 2) == 0)
return i;
}
return -1;
}
@@ -782,11 +807,13 @@ if (*cptr == '-') { /* -? */
errno = 0;
val = strtoul (cptr, &tptr, 8);
if (cptr == tptr) { /* no number? */
if (*pflag == (A_REL + A_NUM)) return NULL; /* .+, .-? */
if (*pflag == (A_REL + A_NUM)) /* .+, .-? */
return NULL;
*dptr = 0;
return cptr;
}
if (errno || (*pflag == A_REL)) return NULL; /* .n? */
if (errno || (*pflag == A_REL)) /* .n? */
return NULL;
*dptr = (minus? -val: val) & 0177777;
*pflag = *pflag | A_NUM;
return tptr;
@@ -832,7 +859,8 @@ if (strncmp (cptr, "-(", 2) == 0) { /* autodecrement? */
else if ((cptr = get_addr (cptr, &disp, &pflag)) == NULL) return 1;
if (*cptr == '(') { /* register index? */
pflag = pflag | A_PAR;
if ((reg = get_reg (cptr + 1, rname, ')')) < 0) return 1;
if ((reg = get_reg (cptr + 1, rname, ')')) < 0)
return 1;
cptr = cptr + 4;
if (*cptr == '+') { /* autoincrement? */
pflag = pflag | A_PLS;
@@ -843,7 +871,8 @@ else if ((reg = get_reg (cptr, iflag? rname: fname, 0)) >= 0) {
pflag = pflag | A_REG;
cptr = cptr + 2;
}
if (*cptr != 0) return 1; /* all done? */
if (*cptr != 0) /* all done? */
return 1;
switch (pflag) { /* case on syntax */
case A_REG: /* Rn, @Rn */
@@ -873,7 +902,8 @@ switch (pflag) { /* case on syntax */
return -1;
case A_PND+A_REL: case A_PND+A_REL+A_NUM: /* #.+n, @#.+n */
if (!cflag) return 1;
if (!cflag)
return 1;
disp = (disp + addr) & 0177777; /* fall through */
case A_PND+A_NUM: /* #n, @#n */
*sptr = 027 + indir;
@@ -917,37 +947,59 @@ switch (pflag) { /* case on syntax */
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
{
int32 cflag, d, i, j, reg, spec, n1, n2, disp, pflag;
int32 bflag, cflag, d, i, j, reg, spec, n1, n2, disp, pflag;
t_value by;
t_stat r;
char *tptr, gbuf[CBUFSIZE];
cflag = (uptr == NULL) || (uptr == &cpu_unit);
bflag = 0; /* assume 16b */
cflag = (uptr == NULL) || (uptr == &cpu_unit); /* cpu? */
if (!cflag) { /* not cpu? */
DEVICE *dptr = find_dev_from_unit (uptr);
if (dptr == NULL)
return SCPE_IERR;
if (dptr->dwidth < 16)
bflag = 1;
}
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 */
if (addr & 1) val[0] = (val[0] & 0377) | (((t_value) cptr[0]) << 8);
else val[0] = (val[0] & ~0377) | ((t_value) cptr[0]);
if (cptr[0] == 0) /* must have 1 char */
return SCPE_ARG;
if (bflag)
val[0] = (t_value) cptr[0];
else val[0] = (addr & 1)?
(val[0] & 0377) | (((t_value) cptr[0]) << 8):
(val[0] & ~0377) | ((t_value) cptr[0]);
return 0;
}
if (sw & SWMASK ('B')) { /* byte? */
by = get_uint (cptr, 8, 0377, &r); /* get byte */
if (r != SCPE_OK) return SCPE_ARG;
if (addr & 1) val[0] = (val[0] & 0377) | (by << 8);
else val[0] = (val[0] & ~0377) | by;
if (r != SCPE_OK)
return SCPE_ARG;
if (bflag)
val[0] = by;
else val[0] = (addr & 1)?
(val[0] & 0377) | (by << 8):
(val[0] & ~0377) | by;
return 0;
}
if (bflag) return SCPE_ARG;
if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
if (cptr[0] == 0) /* must have 1 char */
return SCPE_ARG;
val[0] = ((t_value) cptr[1] << 8) | (t_value) cptr[0];
return -1;
}
if (sw & SWMASK ('R')) return SCPE_ARG; /* radix 50 */
if (sw & SWMASK ('R')) /* radix 50 */
return SCPE_ARG;
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
n1 = n2 = pflag = 0;
for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
if (opcode[i] == NULL) return SCPE_ARG;
if (opcode[i] == NULL)
return SCPE_ARG;
val[0] = opc_val[i] & 0177777; /* get value */
j = (opc_val[i] >> I_V_CL) & I_M_CL; /* get class */
@@ -958,26 +1010,30 @@ switch (j) { /* case on class */
case I_V_REG: /* register */
cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
if ((reg = get_reg (gbuf, rname, 0)) < 0) return SCPE_ARG;
if ((reg = get_reg (gbuf, rname, 0)) < 0)
return SCPE_ARG;
val[0] = val[0] | reg;
break;
case I_V_3B: case I_V_6B: case I_V_8B: /* xb literal */
cptr = get_glyph (cptr, gbuf, 0); /* get literal */
d = get_uint (gbuf, 8, (1 << j) - 1, &r);
if (r != SCPE_OK) return SCPE_ARG;
if (r != SCPE_OK)
return SCPE_ARG;
val[0] = val[0] | d; /* put in place */
break;
case I_V_BR: /* cond br */
cptr = get_glyph (cptr, gbuf, 0); /* get address */
tptr = get_addr (gbuf, &disp, &pflag); /* parse */
if ((tptr == NULL) || (*tptr != 0)) return SCPE_ARG;
if ((tptr == NULL) || (*tptr != 0))
return SCPE_ARG;
if ((pflag & A_REL) == 0) {
if (cflag) disp = (disp - addr) & 0177777;
else return SCPE_ARG;
}
if ((disp & 1) || (disp > 0400) && (disp < 0177402)) return SCPE_ARG;
if ((disp & 1) || (disp > 0400) && (disp < 0177402))
return SCPE_ARG;
val[0] = val[0] | (((disp - 2) >> 1) & 0377);
break;
@@ -987,18 +1043,21 @@ switch (j) { /* case on class */
val[0] = val[0] | (reg << 6);
cptr = get_glyph (cptr, gbuf, 0); /* get address */
tptr = get_addr (gbuf, &disp, &pflag); /* parse */
if ((tptr == NULL) || (*tptr != 0)) return SCPE_ARG;
if ((tptr == NULL) || (*tptr != 0))
return SCPE_ARG;
if ((pflag & A_REL) == 0) {
if (cflag) disp = (disp - addr) & 0177777;
else return SCPE_ARG;
}
if ((disp & 1) || ((disp > 2) && (disp < 0177604))) return SCPE_ARG;
if ((disp & 1) || ((disp > 2) && (disp < 0177604)))
return SCPE_ARG;
val[0] = val[0] | (((2 - disp) >> 1) & 077);
break;
case I_V_RSOP: /* reg, sop */
cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
if ((reg = get_reg (gbuf, rname, 0)) < 0) return SCPE_ARG;
if ((reg = get_reg (gbuf, rname, 0)) < 0)
return SCPE_ARG;
val[0] = val[0] | (reg << 6); /* fall through */
case I_V_SOP: /* sop */
cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
@@ -1013,19 +1072,23 @@ switch (j) { /* case on class */
return SCPE_ARG;
val[0] = val[0] | spec;
cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
if ((reg = get_reg (gbuf, rname, 0)) < 0) return SCPE_ARG;
if ((reg = get_reg (gbuf, rname, 0)) < 0)
return SCPE_ARG;
val[0] = val[0] | (reg << 6);
break;
case I_V_AFOP: case I_V_ASOP: case I_V_ASMD: /* fac, (s)fop */
cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
if ((reg = get_reg (gbuf, fname, 0)) < 0) return SCPE_ARG;
if (reg > 3) return SCPE_ARG;
if ((reg = get_reg (gbuf, fname, 0)) < 0)
return SCPE_ARG;
if (reg > 3)
return SCPE_ARG;
val[0] = val[0] | (reg << 6); /* fall through */
case I_V_FOP: /* fop */
cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
if ((n1 = get_spec (gbuf, addr, 0, &spec, &val[1], cflag,
(j == I_V_ASOP) || (j == I_V_ASMD))) > 0) return SCPE_ARG;
(j == I_V_ASOP) || (j == I_V_ASMD))) > 0)
return SCPE_ARG;
val[0] = val[0] | spec;
break;
@@ -1036,7 +1099,8 @@ switch (j) { /* case on class */
val[0] = val[0] | (spec << 6);
cptr = get_glyph (cptr, gbuf, 0); /* get glyph */
if ((n2 = get_spec (gbuf, addr, n1, &spec, &val[1 - n1],
cflag, TRUE)) > 0) return SCPE_ARG;
cflag, TRUE)) > 0)
return SCPE_ARG;
val[0] = val[0] | spec;
break;
@@ -1046,7 +1110,8 @@ switch (j) { /* case on class */
for (i = 0; (opcode[i] != NULL) &&
(strcmp (opcode[i], gbuf) != 0) ; i++) ;
if ((((opc_val[i] >> I_V_CL) & I_M_CL) != j) ||
(opcode[i] == NULL)) return SCPE_ARG;
(opcode[i] == NULL))
return SCPE_ARG;
val[0] = val[0] | (opc_val[i] & 0177777);
}
break;
@@ -1055,6 +1120,7 @@ switch (j) { /* case on class */
return SCPE_ARG;
}
if (*cptr != 0) return SCPE_ARG; /* junk at end? */
if (*cptr != 0) /* junk at end? */
return SCPE_ARG;
return ((n1 + n2) * 2) - 1;
}