mirror of
https://github.com/simh/simh.git
synced 2026-01-25 19:56:25 +00:00
simh 3.10-RC1a
3.10 is mostly an attempt to get aligned with the current head of the GitHub 4.0 sources. While the core libraries and SCP have diverged too far for real forward and backward compatibility, enough 4.0 workalikes have been added to allow much closer convergence of the two streams. 3.10 will provide the basis for my future simulation work.
This commit is contained in:
committed by
Mark Pizzolato
parent
140ab5b350
commit
3fada8da5a
@@ -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.
|
||||
|
||||
17-Mar-16 PLB Added GRAPHICS-2 support for PDP-7 UNIX
|
||||
10-Mar-16 RMS Added 3-cycle databreak set/show routines
|
||||
26-Feb-16 RMS Added RB09 to PDP-7 for Unix "v0" and RM09 to PDP-9
|
||||
13-Sep-15 RMS Added DR15C
|
||||
@@ -82,6 +83,7 @@
|
||||
Type 550/555 DECtape
|
||||
Type 24 serial drum
|
||||
RB09 fixed head disk (Unix V0 only)
|
||||
Bell Labs GRAPHICS-2 (Unix V0 only)
|
||||
|
||||
PDP9 32K KE09A EAE KSR-33 Teletype
|
||||
KF09A auto pri intr PC09A paper tape reader and punch
|
||||
@@ -105,7 +107,7 @@
|
||||
TC59D magnetic tape
|
||||
TC15/TU56 DECtape
|
||||
LT15/LT19 additional Teletypes
|
||||
DR15C parallel interface to UC15
|
||||
DR15C parallel interface to UC15
|
||||
|
||||
??Indicates not implemented. The PDP-4 manual refers to a memory
|
||||
??extension control; there is no documentation on it.
|
||||
@@ -142,6 +144,7 @@
|
||||
#define TYPE550 0 /* DECtape */
|
||||
#define DRM 0 /* drum */
|
||||
#define RB 0 /* fixed head disk */
|
||||
#define GRAPHICS2 0 /* BTL display */
|
||||
#elif defined (PDP9)
|
||||
#define ADDRSIZE 15
|
||||
#define TYPE647 0 /* sixbit printer */
|
||||
@@ -162,6 +165,7 @@
|
||||
#define MTA 0 /* magtape */
|
||||
#define TC02 0 /* DECtape */
|
||||
#define TTY1 16 /* second Teletype(s) */
|
||||
#define UC15 0 /* UC15 */
|
||||
#define BRMASK 0377400 /* bounds mask */
|
||||
#define BRMASK_XVM 0777400 /* bounds mask, XVM */
|
||||
#endif
|
||||
@@ -287,6 +291,29 @@ typedef struct {
|
||||
#define DEV_MT 073 /* magtape */
|
||||
#define DEV_DTA 075 /* dectape */
|
||||
|
||||
#ifdef GRAPHICS2
|
||||
/* Bell Telephone Labs GRAPHICS-2 Display System ("as large as the PDP-7")
|
||||
* Used by PDP-7 UNIX as a "Glass TTY"
|
||||
*/
|
||||
#define DEV_G2D1 005 /* Display Ctrl 1 */
|
||||
#define DEV_G2D 006 /* (Display Ctrl 2) */
|
||||
#define DEV_G2LP 007 /* (Light Pen) */
|
||||
#define DEV_G2DS 010 /* (Display Status) */
|
||||
#define DEV_G2D3 014 /* (Display Ctrl 3) */
|
||||
#define DEV_G2D4 034 /* (Display Ctrl 4) */
|
||||
|
||||
#define DEV_G2UNK 042 /* (???) */
|
||||
#define DEV_G2KB 043 /* Keyboard */
|
||||
#define DEV_G2BB 044 /* Button Box */
|
||||
#define DEV_G2IM 045 /* (PDP7 int. mask) */
|
||||
|
||||
/* PDP-7/9 to 201A Data Phone Interface
|
||||
* (status bits retrieved with G2DS IOT)
|
||||
* used for UNIX to GCOS Remote Job Entry
|
||||
*/
|
||||
#define DEV_DP 047 /* (Data Phone) */
|
||||
#endif
|
||||
|
||||
/* Interrupt system
|
||||
|
||||
The interrupt system can be modelled on either the flag driven system
|
||||
@@ -433,6 +460,7 @@ typedef struct {
|
||||
#define INT_V_TTI 0 /* console keyboard */
|
||||
#define INT_V_TTO 1 /* console output */
|
||||
#define INT_V_PTP 2 /* paper tape punch */
|
||||
#define INT_V_G2 3 /* BTL GRAPHICS-2 */
|
||||
|
||||
#define INT_TTI (1 << INT_V_TTI)
|
||||
#define INT_TTO (1 << INT_V_TTO)
|
||||
@@ -442,6 +470,15 @@ typedef struct {
|
||||
#define API_TTO 4
|
||||
#define API_PTP 4
|
||||
|
||||
#ifdef GRAPHICS2
|
||||
/*
|
||||
* A PDP-9 version existed,
|
||||
* but we're only interested simulating a PDP-7 without API
|
||||
*/
|
||||
#define INT_G2 (1 << INT_V_G2)
|
||||
#define API_G2 4
|
||||
#endif
|
||||
|
||||
/* Interrupt macros */
|
||||
|
||||
#define SET_INT(dv) int_hwre[API_##dv] = int_hwre[API_##dv] | INT_##dv
|
||||
@@ -452,7 +489,7 @@ typedef struct {
|
||||
This allows software to have a single definition for the interrupt bit position,
|
||||
regardless of level. The standard macros cannot be used. */
|
||||
|
||||
#define INT_V_DR 7 /* to left of all */
|
||||
#define INT_V_DR 9 /* to left of all */
|
||||
#define INT_DR (1 << INT_V_DR)
|
||||
#define API_DR0 0
|
||||
#define API_DR1 1
|
||||
@@ -522,4 +559,10 @@ t_stat show_3cyc_reg (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
|
||||
int32 clk_cosched (int32 wait);
|
||||
|
||||
/* Translation tables */
|
||||
|
||||
extern const int32 asc_to_baud[128];
|
||||
extern const char baud_to_asc[64];
|
||||
extern const char fio_to_asc[64];
|
||||
|
||||
#endif
|
||||
|
||||
339
PDP18B/pdp18b_dr15.c
Normal file
339
PDP18B/pdp18b_dr15.c
Normal file
@@ -0,0 +1,339 @@
|
||||
/* pdp18b_dr15.c: DR15C simulator
|
||||
|
||||
Copyright (c) 2016, 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.
|
||||
|
||||
dr PDP-15 DR15C interface for UC15 system
|
||||
|
||||
The DR15C provides control communications with the DR11Cs in the UC15.
|
||||
Its state consists of an 18b register (the Task Control Block Pointer),
|
||||
a one bit flag (TCBP acknowledge, not wired to interrupt), four interrupt
|
||||
requests wired to API, four interrupt vectors for the API levels, and an
|
||||
API interrupt enable/disable flag.
|
||||
|
||||
The PDP15 and UC15 use a master/save communications protocol.
|
||||
- The PDP15 initiates a request to the PDP11 by writing TCBP and
|
||||
clearing TCBP acknowledge. This alerts/interrupts the PDP11.
|
||||
- The PDP11 reads TCBP. This sets TCBP acknowledge.
|
||||
- The PDP11 processes the request.
|
||||
- The PDP11 signals completion by writing a vector into one of
|
||||
four API request levels.
|
||||
- The PDP15 is interrupted, and the request is considered complete.
|
||||
|
||||
The DR15 must "call out" to the UC15 to signal two conditions:
|
||||
- a new TCBP has been written
|
||||
- API requests have been updated
|
||||
|
||||
The UC15 must "call in" to the DR15 for two reasons:
|
||||
- the TCBP has been read
|
||||
- an API interrupt is requested
|
||||
|
||||
The DR15 and UC15 use a shared memory section and ATOMIC operations
|
||||
to communicate. Shared state is maintained in shared memory, with one
|
||||
side having read/write access, the other read-only. Actions are
|
||||
implemented by setting signals with an atomic compare-and-swap.
|
||||
The signals may be polled with non-atomic operations but must be
|
||||
verified with an atomic compare-and-swap.
|
||||
|
||||
Debug hooks - when DEBUG is turned on, the simulator will print
|
||||
information relating to PIREX operation.
|
||||
*/
|
||||
|
||||
#include "pdp18b_defs.h"
|
||||
#include "sim_shmem.h"
|
||||
#include "uc15_defs.h"
|
||||
|
||||
/* Declarations */
|
||||
|
||||
extern int32 int_hwre[API_HLVL+1];
|
||||
extern int32 api_vec[API_HLVL][32];
|
||||
extern int32 *M;
|
||||
extern UNIT cpu_unit;
|
||||
|
||||
uint32 dr15_tcbp = 0; /* buffer = TCB ptr */
|
||||
int32 dr15_tcb_ack = 0; /* TCBP write ack */
|
||||
int32 dr15_ie = 0; /* int enable */
|
||||
uint32 dr15_int_req = 0; /* int req 0-3 */
|
||||
int32 dr15_poll = 3; /* polling interval */
|
||||
SHMEM *uc15_shmem = NULL; /* shared state identifier */
|
||||
int32 *uc15_shstate = NULL; /* shared state base */
|
||||
SHMEM *pdp15_shmem = NULL; /* PDP15 mem identifier */
|
||||
|
||||
DEVICE dr15_dev;
|
||||
int32 dr60 (int32 dev, int32 pulse, int32 AC);
|
||||
int32 dr61 (int32 dev, int32 pulse, int32 AC);
|
||||
t_stat dr15_reset (DEVICE *dptr);
|
||||
void dr15_set_clr_ie (int32 val);
|
||||
t_stat dr15_svc (UNIT *uptr);
|
||||
t_stat dr15_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
|
||||
t_stat dr15_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
|
||||
t_stat dr15_attach (UNIT *uptr, char *cptr);
|
||||
t_stat dr15_detach (UNIT *uptr);
|
||||
|
||||
t_stat uc15_new_api (int32 val); /* callouts */
|
||||
t_stat uc15_tcbp_wr (int32 val);
|
||||
|
||||
/* DR15 data structures
|
||||
|
||||
dr15_dev DR15 device descriptor
|
||||
dr15_unit DR15 unit descriptor
|
||||
dr15_reg DR15 register list
|
||||
*/
|
||||
|
||||
DIB dr15_dib = { DEV_DR, 2 ,NULL, { &dr60, &dr61 } };
|
||||
|
||||
UNIT dr15_unit = {
|
||||
UDATA (&dr15_svc, UNIT_FIX+UNIT_BINK+UNIT_ATTABLE, UC15_STATE_SIZE)
|
||||
};
|
||||
|
||||
REG dr15_reg[] = {
|
||||
{ ORDATA (TCBP, dr15_tcbp, ADDRSIZE) },
|
||||
{ FLDATA (TCBACK, dr15_tcb_ack, 0) },
|
||||
{ FLDATA (IE, dr15_ie, 0) },
|
||||
{ ORDATA (REQ, dr15_int_req, 4) },
|
||||
{ FLDATA (API0, int_hwre[API_DR0], INT_V_DR) },
|
||||
{ FLDATA (API1, int_hwre[API_DR1], INT_V_DR) },
|
||||
{ FLDATA (API2, int_hwre[API_DR2], INT_V_DR) },
|
||||
{ FLDATA (API3, int_hwre[API_DR3], INT_V_DR) },
|
||||
{ ORDATA (APIVEC0, api_vec[API_DR0][INT_V_DR], 7) },
|
||||
{ ORDATA (APIVEC1, api_vec[API_DR1][INT_V_DR], 7) },
|
||||
{ ORDATA (APIVEC2, api_vec[API_DR2][INT_V_DR], 7) },
|
||||
{ ORDATA (APIVEC3, api_vec[API_DR3][INT_V_DR], 7) },
|
||||
{ DRDATA (POLL, dr15_poll, 10), REG_NZ },
|
||||
{ ORDATA (DEVNO, dr15_dib.dev, 6), REG_HRO },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
MTAB dr15_mod[] = {
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", NULL, &show_devno },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
DEVICE dr15_dev = {
|
||||
"DR", &dr15_unit, dr15_reg, dr15_mod,
|
||||
1, 8, 10, 1, 8, 32,
|
||||
&dr15_ex, &dr15_dep, &dr15_reset,
|
||||
NULL, &dr15_attach, &dr15_detach,
|
||||
&dr15_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG
|
||||
};
|
||||
|
||||
/* IOT routines */
|
||||
|
||||
int32 dr60 (int32 dev, int32 pulse, int32 AC)
|
||||
{
|
||||
int32 subdev = (pulse >> 4) & 03;
|
||||
|
||||
if (((pulse & 01) != 0) && (dr15_tcb_ack != 0)) /* SIOA */
|
||||
AC |= IOT_SKP;
|
||||
if ((pulse & 02) != 0) /* CIOP */
|
||||
dr15_tcb_ack = 0;
|
||||
if ((pulse & 04) != 0) { /* LIOR */
|
||||
dr15_tcbp = AC & AMASK; /* top bit zero */
|
||||
uc15_tcbp_wr (dr15_tcbp); /* inform UC15 */
|
||||
}
|
||||
return AC;
|
||||
}
|
||||
|
||||
int32 dr61 (int32 dev, int32 pulse, int32 AC)
|
||||
{
|
||||
int32 subdev = (pulse >> 4) & 03;
|
||||
|
||||
if (pulse & 01) { /* SAPIn */
|
||||
if (((dr15_int_req >> subdev) & 01) != 0)
|
||||
AC = AC | IOT_SKP;
|
||||
}
|
||||
if (pulse & 02) {
|
||||
if (subdev == 0) /* RDRS */
|
||||
AC |= dr15_ie;
|
||||
else if (subdev == 1)
|
||||
dr15_set_clr_ie (AC & 1);
|
||||
}
|
||||
if (pulse & 04) { /* CAPI */
|
||||
int32 old_int_req = dr15_int_req;
|
||||
dr15_int_req &= ~(1 << subdev); /* clear local req */
|
||||
int_hwre[subdev] &= ~INT_DR; /* clear hwre req */
|
||||
if (dr15_int_req != old_int_req) /* state change? */
|
||||
uc15_new_api (dr15_int_req); /* inform UC15 */
|
||||
}
|
||||
return AC;
|
||||
}
|
||||
|
||||
/* Set/clear interrupt enable */
|
||||
|
||||
void dr15_set_clr_ie (int32 val)
|
||||
{
|
||||
int32 i;
|
||||
|
||||
dr15_ie = val;
|
||||
for (i = 0; i < 4; i++) {
|
||||
if ((dr15_ie != 0) && (((dr15_int_req >> i) & 01) != 0))
|
||||
int_hwre[i] |= INT_DR;
|
||||
else int_hwre[i] &= ~INT_DR;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Routines to inform UC15 of state changes */
|
||||
|
||||
t_stat uc15_new_api (int32 req)
|
||||
{
|
||||
UC15_SHARED_WR (UC15_API_SUMM, req); /* new value */
|
||||
UC15_ATOMIC_CAS (UC15_API_UPD, 0, 1); /* signal UC15 */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat uc15_tcbp_wr (int32 tcbp)
|
||||
{
|
||||
UC15_SHARED_WR (UC15_TCBP, tcbp); /* new value */
|
||||
UC15_ATOMIC_CAS (UC15_TCBP_WR, 0, 1); /* signal UC15 */
|
||||
if (DEBUG_PRS (dr15_dev)) {
|
||||
uint32 apiv, apil, fnc, tsk;
|
||||
t_bool spl;
|
||||
|
||||
apiv = (M[tcbp] >> 8) & 0377;
|
||||
apil = M[tcbp] & 0377;
|
||||
fnc = (M[tcbp + 1] >> 8) & 0377;
|
||||
spl = (M[tcbp + 1] & 0200) != 0;
|
||||
tsk = (M[tcbp + 1] & 0177);
|
||||
fprintf (sim_deb, ">> DR15: TCB write, API = %o/%d, fnc = %o, %s task = %o, eventvar = %o\n",
|
||||
apiv, apil, fnc, spl? "Spooled": "Unspooled", tsk, M[tcbp + 2]);
|
||||
fprintf (sim_deb, "Additional parameters = %o %o %o %o %o\n",
|
||||
M[tcbp + 3], M[tcbp + 4], M[tcbp + 5], M[tcbp + 6], M[tcbp + 7]);
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Routine to poll for state changes from UC15 */
|
||||
|
||||
t_stat dr15_svc (UNIT *uptr)
|
||||
{
|
||||
int32 i, t;
|
||||
uint32 old_int_req = dr15_int_req;
|
||||
|
||||
t = UC15_SHARED_RD (UC15_TCBP_RD); /* TCBP read? */
|
||||
if ((t != 0) && UC15_ATOMIC_CAS (UC15_TCBP_RD, 1, 0)) /* for real? clear */
|
||||
dr15_tcb_ack = 1; /* set ack */
|
||||
for (i = 0; i < 4; i++) { /* API req */
|
||||
t = UC15_SHARED_RD (UC15_API_REQ + (i * UC15_API_VEC_MUL));
|
||||
if ((t != 0) && /* API req? for real? */
|
||||
UC15_ATOMIC_CAS (UC15_API_REQ + (i * UC15_API_VEC_MUL), 1, 0)) {
|
||||
api_vec[i][INT_V_DR] = UC15_SHARED_RD (UC15_API_VEC + (i * UC15_API_VEC_MUL)) & 0177;
|
||||
dr15_int_req |= (1u << i);
|
||||
if (dr15_ie != 0)
|
||||
int_hwre[i] |= INT_DR;
|
||||
if (DEBUG_PRS (dr15_dev))
|
||||
fprintf (sim_deb, ">>DR15: API request, API = %o/%d\n",
|
||||
api_vec[i][INT_V_DR], i);
|
||||
} /* end if changed */
|
||||
} /* end for */
|
||||
if (dr15_int_req != old_int_req) /* changes? */
|
||||
uc15_new_api (dr15_int_req); /* inform UC15 */
|
||||
sim_activate (uptr, dr15_poll); /* next poll */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Reset routine
|
||||
|
||||
Aside from performing a device reset, this routine sets up shared
|
||||
UC15 state and shared PDP15 main memory. It also writes the size
|
||||
of PDP15 main memory (in PDP11 bytes) into the shared state region.
|
||||
*/
|
||||
|
||||
t_stat dr15_reset (DEVICE *dptr)
|
||||
{
|
||||
int32 i;
|
||||
t_stat r;
|
||||
void *basead;
|
||||
|
||||
dr15_int_req = 0; /* clear API req */
|
||||
dr15_ie = 1; /* IE inits to 1 */
|
||||
dr15_tcb_ack = 1; /* TCBP ack inits to 1 */
|
||||
dr15_int_req = 0;
|
||||
for (i = 0; i < 4; i++) { /* clear intr and vectors */
|
||||
int_hwre[i] &= ~INT_DR;
|
||||
api_vec[i][INT_V_DR] = 0;
|
||||
}
|
||||
sim_cancel (dptr->units);
|
||||
if ((dptr->flags & DEV_DIS) != 0) /* disabled? */
|
||||
return SCPE_OK;
|
||||
|
||||
if (uc15_shmem == NULL) { /* allocate shared state */
|
||||
r = sim_shmem_open ("UC15SharedState", UC15_STATE_SIZE * sizeof (int32), &uc15_shmem, &basead);
|
||||
if (r != SCPE_OK)
|
||||
return r;
|
||||
uc15_shstate = (int32 *) basead;
|
||||
}
|
||||
if (pdp15_shmem == NULL) { /* allocate shared memory */
|
||||
r = sim_shmem_open ("PDP15MainMemory", MAXMEMSIZE * sizeof (int32), &pdp15_shmem, &basead);
|
||||
if (r != SCPE_OK)
|
||||
return r;
|
||||
free (M); /* release normal memory */
|
||||
M = (int32 *) basead;
|
||||
}
|
||||
UC15_SHARED_WR (UC15_PDP15MEM, cpu_unit.capac << 1); /* write mem size to shared state */
|
||||
uc15_new_api (dr15_int_req); /* inform UC15 of new API (and mem) */
|
||||
sim_activate (dptr->units, dr15_poll); /* start polling */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Shared state ex/mod routines for debug */
|
||||
|
||||
t_stat dr15_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
|
||||
{
|
||||
if (addr >= UC15_STATE_SIZE)
|
||||
return SCPE_NXM;
|
||||
if (vptr != NULL) {
|
||||
if (uc15_shmem != NULL)
|
||||
*vptr = UC15_SHARED_RD ((int32) addr);
|
||||
else *vptr = 0;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat dr15_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
|
||||
{
|
||||
if (addr >= UC15_STATE_SIZE)
|
||||
return SCPE_NXM;
|
||||
if (uc15_shmem != NULL)
|
||||
UC15_SHARED_WR ((int32) addr, (int32) val);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Fake attach routine to kill attach attempts */
|
||||
|
||||
t_stat dr15_attach (UNIT *uptr, char *cptr)
|
||||
{
|
||||
return SCPE_NOFNC;
|
||||
}
|
||||
|
||||
/* Shutdown detach routine to release shared memories */
|
||||
|
||||
t_stat dr15_detach (UNIT *uptr)
|
||||
{
|
||||
if ((sim_switches & SIM_SW_SHUT) == 0) /* only if shutdown */
|
||||
return SCPE_NOFNC;
|
||||
sim_shmem_close (uc15_shmem); /* release shared state */
|
||||
sim_shmem_close (pdp15_shmem); /* release shared mem */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@@ -1154,7 +1154,7 @@ switch (fnc) { /* at speed, check fnc *
|
||||
if (ba >= uptr->hwmark)
|
||||
uptr->hwmark = ba + 1;
|
||||
}
|
||||
/* /* ignore hdr */
|
||||
/* ignore hdr */
|
||||
sim_activate (uptr, DT_WSIZE * dt_ltime);
|
||||
if (M[DT_WC] == 0)
|
||||
dt_substate = DTO_WCO;
|
||||
|
||||
603
PDP18B/pdp18b_g2tty.c
Normal file
603
PDP18B/pdp18b_g2tty.c
Normal file
@@ -0,0 +1,603 @@
|
||||
/* pdp18b_g2tty.c: PDP-7/9 Bell Labs "GRAPHIC-2" subsystem as a TTY via TELNET
|
||||
from 13-Sep-15 version of pdp18b_tt1.c
|
||||
|
||||
Copyright (c) 1993-2015, Robert M Supnik
|
||||
Copyright (c) 2016, Philip L Budne
|
||||
|
||||
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.
|
||||
|
||||
Doug McIlroy had this to say about the Bell Labs PDP-7 Ken Thompson
|
||||
created UNIX on:
|
||||
|
||||
The pdp7 was cast off by the visual and acoustics research department.
|
||||
Bill Ninke et al. built graphic II on it -- a graphics attachment as big
|
||||
as the pdp7 itself. The disk was an amazing thing about 2' in diameter,
|
||||
mounted on a horizontal axis. Mystery crashes bedeviled it until somebody
|
||||
realized that the axis was perpendicular to the loading dock 4 floors
|
||||
below. A 90-degree turn solved the problem.
|
||||
|
||||
GRAPHICS-2 was a command list based graphics display system,
|
||||
and included a light pen, a "button box" and status bits
|
||||
for a "dataphone" interface to speak to a GECOS system.
|
||||
|
||||
The UNIX-7 system driver only uses text display, and reserves 269
|
||||
words (holding two characters each; the buffer is 273 words, but
|
||||
three contain display "setup" commands, and the final word in the
|
||||
buffer must be a display "TRAP" instruction that ends the display
|
||||
list).
|
||||
|
||||
The UNIX system code triggers a refresh every 10 60Hz "ticks" of
|
||||
the real time clock. This driver attempts to do detect new text
|
||||
and send it to a user who has TELNETed in.
|
||||
|
||||
Thoughts on implementing a web interface:
|
||||
|
||||
538 characters redisplaying at 6Hz (every 10 "ticks") gives a
|
||||
bandwith requirement of only 26Kbit, and most refreshes won't
|
||||
change the screen and could be suppressed. So it seems like it
|
||||
would be reasonable to create a web interface.
|
||||
|
||||
Make a SIMH TCP server port which implements a tiny HTTP server.
|
||||
The base URL serves up a skeletal page with (lighted) buttons,
|
||||
and a "display window".
|
||||
|
||||
And either:
|
||||
|
||||
1) Use "AJAX": an (invisible) <iframe> on in the HTML served by the
|
||||
"base URL" keeps a never-ending connection that is sent "script"
|
||||
tags to alter the "screen" (div) contents, and light push buttons.
|
||||
Keypresses and buttons could be implemented using "onclick"
|
||||
actions which trigger a GET (or a POST) on a URLs which
|
||||
open new (temporary) HTTP connections to SIMH. The key/button
|
||||
press URL could contain a session UUID which has to match
|
||||
a value sent in the initial page.
|
||||
|
||||
2) Have the "home" page HTML establish a bi-directional WebSocket
|
||||
connection to Encapsulate all the traffic (screen contents,
|
||||
button lighting, key & button presses).
|
||||
|
||||
The graphics system responds as ten PDP-7 "devices";
|
||||
UNIX only uses six, and only three of the six are simulated here
|
||||
(and *JUST* enough of those to figure out the text being displayed),
|
||||
as two SIMH DEVICES, G2OUT and G2IN:
|
||||
|
||||
G2OUT:
|
||||
G2D1 005 GRAPHICS-2 display output
|
||||
G2IN:
|
||||
G2KB 043 GRAPHICS-2 keyboard
|
||||
G2BB 044 GRAPHICS-2 button box (lighted bush buttons)
|
||||
|
||||
20-Mar-16 PLB Works, mostly
|
||||
19-Mar-16 PLB Working (up to a screen full)
|
||||
17-Mar-16 PLB Cloned from 13-Sep-15 version of pdp18b_tt1.c
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
* GRAPHICS-2 was vector graphics hardware, UNIX-7 uses it as a
|
||||
* "Glass TTY" for a "second seat".
|
||||
*
|
||||
* This simulation ONLY handles text display; the one program
|
||||
* found that uses the "capt" (capture?) call to set a user
|
||||
* supplied display list will not work here.
|
||||
*
|
||||
* When the display buffer or screen is filled, the UNIX "display"
|
||||
* driver lights "push button 7" (PB7), and waits for the user to
|
||||
* press the button. UNIX then clears the screen, and output
|
||||
* continues. If the program outputs a "Form Feed" character the
|
||||
* display is also cleared.
|
||||
*
|
||||
* This simulation automatically presses PB7 when lit, without
|
||||
* bothering the user (a more accurate simulation might prompt
|
||||
* the user to press any key)!
|
||||
*/
|
||||
|
||||
#include "pdp18b_defs.h"
|
||||
#ifdef GRAPHICS2
|
||||
#include "sim_tmxr.h"
|
||||
|
||||
int debug = 0;
|
||||
|
||||
/* hardware registers */
|
||||
uint8 g2kb_done = 0; /* keyboard flag */
|
||||
uint32 g2kb_buf = 0; /* keyboard buffer */
|
||||
uint8 g2bb_flag = 0; /* button flag */
|
||||
uint32 g2bb_bbuf = 0; /* button buffer */
|
||||
uint32 g2bb_lbuf = 0; /* button lights buffer */
|
||||
uint32 g2out_addr = 0; /* display address */
|
||||
#define PB7 02000
|
||||
|
||||
/* not hardware registers: */
|
||||
uint32 g2out_count = 0;
|
||||
uint8 g2out_stuffcr = 0; /* need to stuff a CR */
|
||||
|
||||
|
||||
/* keep old and new version of characters to display
|
||||
* a count & checksum of the "old" screen contents might suffice,
|
||||
* time will tell....
|
||||
*/
|
||||
uint8 g2out_which = 0;
|
||||
#define OLD g2out_which
|
||||
#define NEW (g2out_which ^ 1)
|
||||
|
||||
#define MAXBUFCHARS 700 /* larger than kernel display list */
|
||||
static struct dspbuf {
|
||||
uint16 count;
|
||||
char buffer[MAXBUFCHARS]; /* 7-bit ASCII */
|
||||
} g2out_dspbufs[2];
|
||||
|
||||
/* terminal mux data */
|
||||
TMLN g2_ldsc = { 0 }; /* line descriptor */
|
||||
TMXR g2_desc = { 1, 0, 0, &g2_ldsc }; /* mux descriptor */
|
||||
|
||||
/* kernel display lists always start like this: */
|
||||
static const int32 g2_expect[3] = {
|
||||
0065057, /* PARAM: clear blink, clear light pen, scale=1, intensity=3 */
|
||||
0147740, /* X-Y: invisible, no delay, Y=01740 (992) */
|
||||
0160000 /* X-Y: invisible, settling delay, X=0 */
|
||||
};
|
||||
|
||||
extern int32 *M;
|
||||
extern int32 int_hwre[API_HLVL+1];
|
||||
extern int32 api_vec[API_HLVL][32];
|
||||
extern int32 tmxr_poll;
|
||||
extern int32 stop_inst;
|
||||
|
||||
/* SIMH G2IN DEVICE */
|
||||
t_bool g2kb_test_done ();
|
||||
void g2kb_set_done ();
|
||||
void g2kb_clr_done ();
|
||||
int32 g2kb_iot (int32 dev, int32 pulse, int32 dat); /* device 043 */
|
||||
|
||||
t_bool g2bb_test_flag ();
|
||||
void g2bb_set_flag ();
|
||||
void g2bb_clr_flag ();
|
||||
int32 g2bb_iot (int32 dev, int32 pulse, int32 dat); /* device 044 */
|
||||
|
||||
t_stat g2in_svc (UNIT *uptr);
|
||||
|
||||
/* SIMH G2OUT DEVICE */
|
||||
int32 g2d1_iot (int32 dev, int32 pulse, int32 dat); /* device 05 */
|
||||
static void g2out_clear ();
|
||||
static void g2out_process_display_list ();
|
||||
static int g2out_send_new ();
|
||||
|
||||
/* both G2IN/G2OUT: */
|
||||
t_stat g2_attach (UNIT *uptr, CONST char *cptr);
|
||||
t_stat g2_detach (UNIT *uptr);
|
||||
t_stat g2_reset (DEVICE *dptr);
|
||||
|
||||
/****************************************************************
|
||||
* SIMH G2IN (keyboard/buttons) DEVICE data structures
|
||||
*
|
||||
* g2in_dev G2IN device descriptor
|
||||
* g2in_unit G2IN unit descriptor
|
||||
* g2in_reg G2IN register list
|
||||
* g2in_mod G2IN modifiers list
|
||||
*/
|
||||
|
||||
DIB g2in_dib = { DEV_G2KB, 2, NULL, { &g2kb_iot, &g2bb_iot } };
|
||||
|
||||
UNIT g2in_unit = {
|
||||
UDATA (&g2in_svc, UNIT_IDLE|UNIT_ATTABLE, 0), KBD_POLL_WAIT
|
||||
};
|
||||
|
||||
REG g2in_reg[] = {
|
||||
{ ORDATA (KBBUF, g2kb_buf, 1) },
|
||||
{ ORDATA (KBDONE, g2kb_done, 1) },
|
||||
{ FLDATA (INT, int_hwre[API_G2], INT_V_G2) },
|
||||
{ DRDATA (TIME, g2in_unit.wait, 24), REG_NZ + PV_LEFT },
|
||||
{ ORDATA (BBBBUF, g2bb_bbuf, 1) }, /* button box button buffer */
|
||||
{ ORDATA (BBFLAG, g2bb_flag, 1) }, /* button box IRQ */
|
||||
{ ORDATA (BBLBUF, g2bb_lbuf, 1) }, /* button box lights buffer */
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
MTAB g2in_mod[] = {
|
||||
{ UNIT_ATT, UNIT_ATT, "summary", NULL,
|
||||
NULL, &tmxr_show_summ, (void *) &g2_desc },
|
||||
{ MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT",
|
||||
&tmxr_dscln, NULL, (void *) &g2_desc },
|
||||
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL,
|
||||
NULL, &tmxr_show_cstat, (void *) &g2_desc },
|
||||
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL,
|
||||
NULL, &tmxr_show_cstat, (void *) &g2_desc },
|
||||
{ MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG",
|
||||
&tmxr_set_log, &tmxr_show_log, &g2_desc },
|
||||
{ MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG",
|
||||
&tmxr_set_nolog, NULL, &g2_desc },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
NULL, &show_devno, NULL },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
/* SIMH G2IN device descriptor (GRAPHICS-2 keyboard & button box) */
|
||||
DEVICE g2in_dev = {
|
||||
"G2IN", /* name */
|
||||
&g2in_unit, /* units */
|
||||
g2in_reg, g2in_mod, /* registers, modifiers */
|
||||
1, /* numunits */
|
||||
10, 31, /* aradix, awidth */
|
||||
1, 8, 8, /* aincr, dradix, dwidth */
|
||||
&tmxr_ex, &tmxr_dep, &g2_reset, /* examine, deposit, reset */
|
||||
NULL, &g2_attach, &g2_detach, /* boot, attach, detach */
|
||||
&g2in_dib, DEV_MUX|DEV_DISABLE|DEV_DIS /* ctxt, flags */
|
||||
};
|
||||
|
||||
/****************************************************************
|
||||
* SIMH G2OUT (display output) DEVICE data structures
|
||||
* Only needed to hold "iot" routine, since DIB's can't represent
|
||||
* devices with register sets as sparse as GRAPHICS-2
|
||||
*
|
||||
* g2out_dev G2OUT device descriptor
|
||||
* g2out_unit G2OUT unit descriptor
|
||||
* g2out_reg G2OUT register list
|
||||
* g2out_mod G2OUT modifiers list
|
||||
*/
|
||||
|
||||
DIB g2out_dib = { DEV_G2D1, 1, NULL, { &g2d1_iot } };
|
||||
|
||||
UNIT g2out_unit = { UDATA (NULL, 0, 0) };
|
||||
|
||||
REG g2out_reg[] = {
|
||||
{ ORDATA (DPYADDR, g2out_addr, 1) },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
MTAB g2out_mod[] = {
|
||||
{ MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT",
|
||||
&tmxr_dscln, NULL, &g2_desc },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||||
NULL, &show_devno, NULL },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
/* SIMH G2OUT device descriptor (simulates just one of many display IOTs!) */
|
||||
DEVICE g2out_dev = {
|
||||
"G2OUT", /* name */
|
||||
&g2out_unit, /* units */
|
||||
g2out_reg, g2out_mod, /* registers, modifiers */
|
||||
1, /* numunits */
|
||||
10, 31, /* aradix, awidth */
|
||||
1, 8, 8, /* aincr, dradix, dwidth */
|
||||
NULL, NULL, &g2_reset, /* examine, deposit, reset */
|
||||
NULL, NULL, NULL, /* boot, attach, detach */
|
||||
&g2out_dib, DEV_DISABLE|DEV_DIS /* ctxt, flags */
|
||||
};
|
||||
|
||||
/****************************************************************
|
||||
* IOT routines
|
||||
*/
|
||||
|
||||
/* Keyboard input IOT routine */
|
||||
/* real device could have done bitwise decode?! */
|
||||
int32 g2kb_iot (int32 dev, int32 pulse, int32 dat)
|
||||
{
|
||||
if (pulse == 001) { /* sck */
|
||||
if (g2kb_done) {
|
||||
dat = dat | IOT_SKP;
|
||||
}
|
||||
}
|
||||
else if (pulse == 002) { /* lck */
|
||||
dat = dat | g2kb_buf; /* return buffer */
|
||||
}
|
||||
else if (pulse == 004) { /* cck */
|
||||
g2kb_clr_done (); /* clear flag */
|
||||
}
|
||||
return dat;
|
||||
}
|
||||
|
||||
/* Button Box IOT routine */
|
||||
int32 g2bb_iot (int32 dev, int32 pulse, int32 dat)
|
||||
{
|
||||
if (pulse == 001) { /* "spb" -- skip on push button flag */
|
||||
if (g2bb_flag)
|
||||
dat = dat | IOT_SKP;
|
||||
}
|
||||
else if (pulse == 002) /* "lpb"/"opb" -- or push buttons */
|
||||
dat = dat | g2bb_bbuf; /* return buttons */
|
||||
else if (pulse == 004) { /* "cpb" -- clear push button flag */
|
||||
g2bb_clr_flag (); /* clear flag */
|
||||
}
|
||||
else if (pulse == 024) { /* "wbl" -- write buttons lights */
|
||||
if (dat == 0)
|
||||
g2out_clear(); /* UNIX has ack'ed button press */
|
||||
g2bb_lbuf = dat;
|
||||
}
|
||||
return dat;
|
||||
}
|
||||
|
||||
/* Input side Unit service */
|
||||
t_stat g2in_svc (UNIT *uptr)
|
||||
{
|
||||
int32 ln, c;
|
||||
|
||||
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
|
||||
return SCPE_OK;
|
||||
|
||||
if (g2bb_lbuf & PB7) { /* button 7 lit? */
|
||||
/* yes: try sending anything new */
|
||||
g2out_process_display_list();
|
||||
g2out_send_new();
|
||||
|
||||
g2bb_bbuf |= PB7; /* press it to clear screen! */
|
||||
g2bb_set_flag ();
|
||||
}
|
||||
sim_activate (uptr, clk_cosched (tmxr_poll)); /* continue poll */
|
||||
ln = tmxr_poll_conn (&g2_desc); /* look for connect */
|
||||
if (ln >= 0) /* got one? rcv enab */
|
||||
g2_ldsc.rcve = 1;
|
||||
tmxr_poll_rx (&g2_desc); /* poll for input */
|
||||
if (g2_ldsc.conn) { /* connected? */
|
||||
tmxr_poll_tx (&g2_desc); /* PLB: poll xmt */
|
||||
if ((c = tmxr_getc_ln (&g2_ldsc))) { /* get char */
|
||||
if (c & SCPE_BREAK) /* break? */
|
||||
c = 0;
|
||||
else {
|
||||
c &= 0177;
|
||||
if (c == '\r') /* translate CR but not ESC! */
|
||||
c = '\n';
|
||||
else if ((c & 0155) == 055) /* kernel swaps around -?/= */
|
||||
c ^= 020; /* pre-swap!! */
|
||||
}
|
||||
g2kb_buf = c;
|
||||
g2kb_set_done ();
|
||||
}
|
||||
} /* connected */
|
||||
else {
|
||||
/* not connected; next connection sees entire "screen" */
|
||||
g2out_stuffcr = 0;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Interrupt handling routines */
|
||||
|
||||
t_bool g2kb_test_done ()
|
||||
{
|
||||
return g2kb_done != 0;
|
||||
}
|
||||
|
||||
void g2kb_set_done ()
|
||||
{
|
||||
g2kb_done = 1;
|
||||
SET_INT (G2);
|
||||
return;
|
||||
}
|
||||
|
||||
void g2kb_clr_done ()
|
||||
{
|
||||
g2kb_done = 0;
|
||||
CLR_INT (G2);
|
||||
return;
|
||||
}
|
||||
|
||||
t_bool g2bb_test_flag ()
|
||||
{
|
||||
return g2bb_flag != 0;
|
||||
}
|
||||
|
||||
void g2bb_set_flag ()
|
||||
{
|
||||
g2bb_flag = 1;
|
||||
SET_INT (G2);
|
||||
return;
|
||||
}
|
||||
|
||||
void g2bb_clr_flag ()
|
||||
{
|
||||
g2bb_flag = 0;
|
||||
CLR_INT (G2);
|
||||
return;
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* SIMH G2OUT (Display Output) DEVICE routines
|
||||
*/
|
||||
|
||||
/* helper to put 7-bit display character */
|
||||
static void g2pc(char c) {
|
||||
//if (debug) putchar(c);
|
||||
tmxr_putc_ln (&g2_ldsc, c);
|
||||
}
|
||||
|
||||
/* send a character from the display. adds CR after LF */
|
||||
/* returns 1 if "c" was sent; 0 means try again later */
|
||||
static int g2out_putchar(char c)
|
||||
{
|
||||
if (!g2_ldsc.conn || !g2_ldsc.xmte) /* connected, tx enabled? */
|
||||
return 0;
|
||||
|
||||
if (g2out_stuffcr) { /* need to stuff a CR? */
|
||||
g2pc ('\r');
|
||||
g2out_stuffcr = 0;
|
||||
if (!g2_ldsc.xmte) /* full? */
|
||||
return 0; /* yes: wait until next time */
|
||||
}
|
||||
|
||||
g2pc (c);
|
||||
|
||||
if (c == '\n') { /* was it a NL? */
|
||||
if (g2_ldsc.xmte) /* transmitter enabled? */
|
||||
g2pc ('\r'); /* send CR now */
|
||||
else
|
||||
g2out_stuffcr = 1; /* wait until next time */
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Device 05 IOT routine */
|
||||
int32 g2d1_iot (int32 dev, int32 pulse, int32 dat)
|
||||
{
|
||||
/*
|
||||
* UNIX text display command lists always end with a TRAP
|
||||
* and display output is restarted periodicly in timer PI service code
|
||||
*/
|
||||
if (g2_ldsc.conn && g2_ldsc.xmte && pulse == 047) { /* conn&ready, "beg" */
|
||||
g2out_addr = dat & 017777;
|
||||
g2out_process_display_list();
|
||||
g2out_send_new();
|
||||
g2out_which ^= 1; /* swap buffers */
|
||||
} /* beg IOT */
|
||||
return dat;
|
||||
}
|
||||
|
||||
/****************
|
||||
* display buffer management/process
|
||||
* we're informed when UNIX wants to clear the screen (PB7 lit)
|
||||
* we then press the button
|
||||
* UNIX does a "cpb" to ACK/clear the interrupt.
|
||||
*
|
||||
* *BUT* UNIX clears the screen when a FF (014) char is output,
|
||||
* which just resets the buffer (and not issuing any IOTs)
|
||||
*/
|
||||
|
||||
static void g2out_clear() {
|
||||
g2out_stuffcr = 0;
|
||||
g2out_which = 0;
|
||||
g2out_count = 0;
|
||||
g2out_dspbufs[0].count = g2out_dspbufs[1].count = 0;
|
||||
}
|
||||
|
||||
/* interpret display list; save characters into "new" dspbuf
|
||||
* quits early if display list doesn't conform to what's expected
|
||||
*/
|
||||
static void g2out_process_display_list() {
|
||||
uint32 i;
|
||||
struct dspbuf *dp = g2out_dspbufs + NEW;
|
||||
|
||||
dp->count = 0;
|
||||
for (i = g2out_addr; i < 020000; i++) {
|
||||
uint32 w = M[i] & 0777777;
|
||||
int offset = i - g2out_addr;
|
||||
char c;
|
||||
|
||||
if (w & 0400000) /* TRAP (end of display list) */
|
||||
return;
|
||||
|
||||
/* check first three words for expected setup commands */
|
||||
if (offset < sizeof(g2_expect)/sizeof(g2_expect[0])) {
|
||||
if (w != g2_expect[offset])
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
if (w & 0300000) /* not characters? */
|
||||
return;
|
||||
|
||||
c = (w >> 7) & 0177;
|
||||
if (c)
|
||||
dp->buffer[dp->count++] = c;
|
||||
c = w & 0177;
|
||||
if (c)
|
||||
dp->buffer[dp->count++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
/* figure out what to send on TELNET connection
|
||||
* truncates new->count to the number sent so far
|
||||
* returns number of new characters sent
|
||||
*/
|
||||
static int g2out_send_new() {
|
||||
struct dspbuf *old = g2out_dspbufs + OLD;
|
||||
struct dspbuf *New = g2out_dspbufs + NEW;
|
||||
char *cp = New->buffer;
|
||||
int cur = 0;
|
||||
int start;
|
||||
|
||||
/* nothing in newest refresh?
|
||||
* COULD have had undisplayed stuff on last screen before it was cleared??
|
||||
* would need to have a transmit queue??
|
||||
*/
|
||||
if (New->count == 0)
|
||||
return 0;
|
||||
|
||||
if (old->count && /* have old chars */
|
||||
memcmp(old->buffer, New->buffer, old->count) == 0) { /* and a prefix */
|
||||
cur = old->count;
|
||||
cp += cur;
|
||||
}
|
||||
/* loop for chars while connected & tx enabled */
|
||||
start = cur;
|
||||
while (cur < New->count && g2_ldsc.conn && g2_ldsc.xmte) {
|
||||
if (g2out_putchar(*cp)) {
|
||||
cp++;
|
||||
cur++;
|
||||
}
|
||||
}
|
||||
New->count = cur; /* only remember what's been sent */
|
||||
return cur - start; /* remember number sent */
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* subsystem common routines (used by both G2IN and G2OUT SIMH DEVICEs)
|
||||
*/
|
||||
|
||||
/* Reset routine */
|
||||
t_stat g2_reset (DEVICE *dptr)
|
||||
{
|
||||
if (dptr->flags & DEV_DIS) { /* sync enables */
|
||||
g2in_dev.flags = g2in_dev.flags | DEV_DIS;
|
||||
g2out_dev.flags = g2out_dev.flags | DEV_DIS;
|
||||
}
|
||||
else {
|
||||
g2in_dev.flags = g2in_dev.flags & ~DEV_DIS;
|
||||
g2out_dev.flags = g2out_dev.flags & ~DEV_DIS;
|
||||
}
|
||||
if (g2in_unit.flags & UNIT_ATT) /* if attached, */
|
||||
sim_activate (&g2in_unit, tmxr_poll); /* activate */
|
||||
else sim_cancel (&g2in_unit); /* else stop */
|
||||
|
||||
g2kb_buf = 0; /* clear buf */
|
||||
g2kb_clr_done (); /* clear done */
|
||||
|
||||
g2bb_bbuf = 0; /* clear buttons */
|
||||
g2bb_lbuf = 0; /* clear lights */
|
||||
g2bb_clr_flag ();
|
||||
|
||||
g2out_addr = 0;
|
||||
g2out_clear();
|
||||
sim_cancel (&g2out_unit); /* stop poll */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Attach master unit */
|
||||
t_stat g2_attach (UNIT *uptr, CONST char *cptr)
|
||||
{
|
||||
t_stat r;
|
||||
|
||||
r = tmxr_attach (&g2_desc, uptr, cptr); /* attach */
|
||||
if (r != SCPE_OK) /* error */
|
||||
return r;
|
||||
sim_activate (uptr, 0); /* start poll at once */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Detach master unit */
|
||||
|
||||
t_stat g2_detach (UNIT *uptr)
|
||||
{
|
||||
t_stat r = tmxr_detach (&g2_desc, uptr); /* detach */
|
||||
sim_cancel (uptr); /* stop poll */
|
||||
g2_ldsc.rcve = 0;
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
@@ -130,7 +130,7 @@ int32 rf72 (int32 dev, int32 pulse, int32 dat);
|
||||
int32 rf_iors (void);
|
||||
t_stat rf_svc (UNIT *uptr);
|
||||
t_stat rf_reset (DEVICE *dptr);
|
||||
int32 rf_updsta (int32 new);
|
||||
int32 rf_updsta (int32 newst);
|
||||
t_stat rf_attach (UNIT *uptr, char *cptr);
|
||||
t_stat rf_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
|
||||
@@ -316,9 +316,9 @@ return SCPE_OK;
|
||||
|
||||
/* Update status */
|
||||
|
||||
int32 rf_updsta (int32 news)
|
||||
int32 rf_updsta (int32 newst)
|
||||
{
|
||||
rf_sta = (rf_sta | news) & ~(RFS_ERR | RFS_CLR);
|
||||
rf_sta = (rf_sta | newst) & ~(RFS_ERR | RFS_CLR);
|
||||
if (rf_sta & RFS_EFLGS)
|
||||
rf_sta = rf_sta | RFS_ERR;
|
||||
if ((rf_sta & (RFS_ERR | RFS_DON)) && (rf_sta & RFS_IE))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* pdp18b_rp.c: RP15/RP02 disk pack simulator
|
||||
|
||||
Copyright (c) 1993-2016, Robert M Supnik
|
||||
Copyright (c) 1993-2018, 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 @@
|
||||
|
||||
rp RP15/RP02/RP03 disk pack
|
||||
|
||||
30-May-18 RMS Extra address bit only recognized on RP03 units
|
||||
15-Mar-16 RMS Added RP03 support
|
||||
Fixed handling of done flag
|
||||
07-Mar-16 RMS Revised for dynamically allocated memory
|
||||
@@ -135,9 +136,10 @@
|
||||
#define DA_M_CYL 0377
|
||||
#define GET_SECT(x) (((x) >> DA_V_SECT) & DA_M_SECT)
|
||||
#define GET_SURF(x) (((x) >> DA_V_SURF) & DA_M_SURF)
|
||||
#define GET_CYL(x) ((((x) >> DA_V_CYL) & DA_M_CYL) + \
|
||||
(((x) & DA_C256)? 256: 0))
|
||||
#define GET_DA(x) ((((GET_CYL (x) * RP_NUMSF) + GET_SURF (x)) * \
|
||||
#define GET_CYL(x,f) ((((x) >> DA_V_CYL) & DA_M_CYL) + \
|
||||
(((((x) & DA_C256) != 0) && \
|
||||
(((f) & UNIT_RP03) != 0))? 256: 0))
|
||||
#define GET_DA(x,f) ((((GET_CYL (x,f) * RP_NUMSF) + GET_SURF (x)) * \
|
||||
RP_NUMSC) + GET_SECT (x))
|
||||
|
||||
/* Current cylinder */
|
||||
@@ -263,7 +265,8 @@ if (pulse & 04) {
|
||||
rp_updsta (STA_NXS, 0);
|
||||
if (GET_SURF (rp_da) >= RP_NUMSF)
|
||||
rp_updsta (STA_NXF, 0);
|
||||
if (GET_CYL (rp_da) >= RP_QCYL (rp_unit[u].flags))
|
||||
if (GET_CYL(rp_da, rp_unit[u].flags) >=
|
||||
RP_QCYL(rp_unit[u].flags))
|
||||
rp_updsta (STA_NXC, 0);
|
||||
}
|
||||
else if (sb == 020) { /* DPCS */
|
||||
@@ -332,7 +335,7 @@ if (pulse & 04) {
|
||||
(f == FN_SEEK) || (f == FN_RECAL))
|
||||
sim_activate (uptr, RP_MIN); /* short delay */
|
||||
else {
|
||||
c = GET_CYL (rp_da);
|
||||
c = GET_CYL (rp_da, uptr->flags);
|
||||
c = abs (c - uptr->CYL) * rp_swait; /* seek time */
|
||||
sim_activate (uptr, MAX (RP_MIN, c + rp_rwait));
|
||||
rp_sta = rp_sta & ~STA_DON; /* clear done */
|
||||
@@ -371,7 +374,7 @@ if (f == FN_IDLE) { /* idle? */
|
||||
|
||||
if ((f == FN_SEEK) || (f == FN_RECAL)) { /* seek or recal? */
|
||||
rp_busy = 0; /* not busy */
|
||||
cyl = (f == FN_SEEK)? GET_CYL (rp_da): 0; /* get cylinder */
|
||||
cyl = (f == FN_SEEK)? GET_CYL (rp_da, uptr->flags): 0; /* get cylinder */
|
||||
sim_activate (uptr, MAX (RP_MIN, abs (cyl - uptr->CYL) * rp_swait));
|
||||
uptr->CYL = cyl; /* on cylinder */
|
||||
uptr->FUNC = FN_SEEK | FN_2ND; /* set second state */
|
||||
@@ -398,16 +401,16 @@ if (GET_SECT (rp_da) >= RP_NUMSC)
|
||||
rp_updsta (STA_NXS, 0);
|
||||
if (GET_SURF (rp_da) >= RP_NUMSF)
|
||||
rp_updsta (STA_NXF, 0);
|
||||
if (GET_CYL (rp_da) >= RP_QCYL (uptr->flags))
|
||||
if (GET_CYL (rp_da, uptr->flags) >= RP_QCYL (uptr->flags))
|
||||
rp_updsta (STA_NXC, 0);
|
||||
if (rp_sta & (STA_NXS | STA_NXF | STA_NXC)) { /* or bad disk addr? */
|
||||
rp_updsta (STA_DON, STB_SUFU); /* done, unsafe */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
uptr->CYL = GET_CYL (rp_da); /* on cylinder */
|
||||
uptr->CYL = GET_CYL (rp_da, uptr->flags); /* on cylinder */
|
||||
pa = rp_ma & AMASK; /* get mem addr */
|
||||
da = GET_DA (rp_da) * RP_NUMWD; /* get disk addr */
|
||||
da = GET_DA (rp_da, uptr->flags) * RP_NUMWD; /* get disk addr */
|
||||
wc = 01000000 - rp_wc; /* get true wc */
|
||||
if (((uint32) (pa + wc)) > MEMSIZE) { /* memory overrun? */
|
||||
nexm = 1; /* set nexm flag */
|
||||
@@ -456,7 +459,7 @@ if (cyl >= RP_QCYL (uptr->flags)) /* cyl ovflo wraps */
|
||||
surf = (da % (RP_NUMSC * RP_NUMSF)) / RP_NUMSC; /* get surface */
|
||||
sect = (da % (RP_NUMSC * RP_NUMSF)) % RP_NUMSC; /* get sector */
|
||||
rp_da = ((cyl & DA_M_CYL) << DA_V_CYL) | (surf << DA_V_SURF) | (sect << DA_V_SECT);
|
||||
if (cyl >= 256) /* cyl >= 8 bits? */
|
||||
if ((cyl >= 256) && ((uptr->flags & UNIT_RP03) != 0)) /* cyl >= 8 bits && RP03 */
|
||||
rp_da = rp_da | DA_C256;
|
||||
rp_busy = 0; /* clear busy */
|
||||
rp_updsta (STA_DON, 0); /* set done */
|
||||
|
||||
@@ -99,6 +99,9 @@ extern DEVICE mt_dev;
|
||||
extern DEVICE tti1_dev, tto1_dev;
|
||||
extern UNIT tti1_unit, tto1_unit;
|
||||
#endif
|
||||
#if defined (GRAPHICS2)
|
||||
extern DEVICE g2out_dev, g2in_dev;
|
||||
#endif
|
||||
#if defined (UC15)
|
||||
extern DEVICE dr15_dev;
|
||||
#endif
|
||||
@@ -107,9 +110,6 @@ extern REG cpu_reg[];
|
||||
extern int32 *M;
|
||||
extern int32 memm;
|
||||
extern int32 PC;
|
||||
extern const char asc_to_baud[128];
|
||||
extern const char baud_to_asc[64];
|
||||
extern const char fio_to_asc[64];
|
||||
|
||||
/* SCP data structures and interface routines
|
||||
|
||||
@@ -178,6 +178,9 @@ DEVICE *sim_devices[] = {
|
||||
#endif
|
||||
#if defined (UC15)
|
||||
&dr15_dev,
|
||||
#endif
|
||||
#if defined (GRAPHICS2)
|
||||
&g2out_dev, &g2in_dev,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
59
PDP18B/uc15_defs.h
Normal file
59
PDP18B/uc15_defs.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* uc15_defs.h: PDP15/UC15 shared state definitions
|
||||
|
||||
Copyright (c) 2016, 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.
|
||||
*/
|
||||
|
||||
#ifndef UC15_DEFS_H_
|
||||
#define UC15_DEFS_H_ 0
|
||||
|
||||
#define UC15_STATE_SIZE 1024 /* size (int32's) */
|
||||
|
||||
/* The shared state region is divided into four quadrants
|
||||
|
||||
000-255 PDP-15 read/write, PDP-11 read only, data
|
||||
255-511 PDP-11 read/write, PDP-15 read only, data
|
||||
768-1023 Event signals (locks), read/write
|
||||
*/
|
||||
|
||||
#define PDP15_MAXMEM 0400000 /* PDP15 max mem, words */
|
||||
|
||||
#define UC15_PDP15MEM 0040 /* PDP15 mem size, bytes */
|
||||
#define UC15_TCBP 0100 /* TCB pointer */
|
||||
#define UC15_API_SUMM 0140 /* API summary */
|
||||
|
||||
#define UC15_API_VEC 0600 /* vectors[4] */
|
||||
#define UC15_API_VEC_MUL 010 /* vector spread factor */
|
||||
|
||||
#define UC15_TCBP_WR 01000 /* TCBP write signal */
|
||||
#define UC15_TCBP_RD 01040 /* TCBP read signal */
|
||||
#define UC15_API_UPD 01100 /* API summ update */
|
||||
#define UC15_API_REQ 01200 /* +1 for API req[4] */
|
||||
|
||||
#define UC15_SHARED_RD(p) (*(uc15_shstate + (p)))
|
||||
#define UC15_SHARED_WR(p,d) *(uc15_shstate + (p)) = (d)
|
||||
|
||||
#define UC15_ATOMIC_CAS(p,o,n) sim_shmem_atomic_cas ((uc15_shstate + (p)), o, n)
|
||||
#define UC15_ATOMIC_ADD(p,a) sim_shmem_atomic_add ((uc15_shstate + (p)), (a))
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user