mirror of
https://github.com/simh/simh.git
synced 2026-02-22 07:08:21 +00:00
PDP11, PDP15, UC15: Merge simh v3.10 functionality from Supnik-Current branch
This commit is contained in:
@@ -650,12 +650,8 @@ MTAB cpu_mod[] = {
|
||||
{ MTAB_XTD|MTAB_VDV, 0, NULL, "NOAUTOCONFIG",
|
||||
&set_autocon, NULL },
|
||||
#else
|
||||
{ MTAB_XTD|MTAB_VDV, MOD_1104, NULL, "11/04", &cpu_set_model },
|
||||
{ MTAB_XTD|MTAB_VDV, MOD_1105, NULL, "11/05", &cpu_set_model },
|
||||
{ MTAB_XTD|MTAB_VDV, MOD_1120, NULL, "11/20", &cpu_set_model },
|
||||
{ UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size},
|
||||
{ UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size},
|
||||
{ UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size},
|
||||
#endif
|
||||
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "IOSPACE", NULL,
|
||||
NULL, &show_iospace },
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* pdp11_sys.c: PDP-11 simulator interface
|
||||
|
||||
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"),
|
||||
@@ -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.
|
||||
|
||||
23-May-18 RMS Changed UC15 simulator name
|
||||
14-Mar-16 RMS Added UC15 support
|
||||
02-Sep-13 RMS Added third Massbus, RS03/RS04
|
||||
29-Apr-12 RMS Fixed compiler warning (Mark Pizzolato)
|
||||
@@ -128,7 +129,11 @@ extern int32 saved_PC;
|
||||
sim_load binary loader
|
||||
*/
|
||||
|
||||
#if !defined (UC15)
|
||||
char sim_name[] = "PDP-11";
|
||||
#else
|
||||
char sim_name[] = "UC-15";
|
||||
#endif
|
||||
|
||||
REG *sim_PC = &cpu_reg[0];
|
||||
|
||||
|
||||
542
PDP11/pdp11_uc15.c
Normal file
542
PDP11/pdp11_uc15.c
Normal file
@@ -0,0 +1,542 @@
|
||||
/* pdp11_uc15.c: UC15 interface 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.
|
||||
|
||||
uca DR11 #1
|
||||
ucb DR11 #2
|
||||
|
||||
The DR11Cs provide control communications with the DR15C in the PDP15.
|
||||
|
||||
The PDP15 and UC15 use a master/slave 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, which is
|
||||
not wired to interrupt on the PDP15. Note that TCBP has been
|
||||
converted from a word address to a byte address by the way
|
||||
the two systems are wired together.
|
||||
- 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 UC15 must "call out" to the PDP15 to signal two conditions:
|
||||
- the TCB pointer has been read
|
||||
- an API interrupt is requested
|
||||
|
||||
The DR15 must "call in" to the UC15 for two reasons:
|
||||
- the TCBP has been written
|
||||
- API interrupt status has changed
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "pdp11_defs.h"
|
||||
|
||||
#include "sim_fio.h"
|
||||
#include "uc15_defs.h"
|
||||
|
||||
/* Constants */
|
||||
|
||||
/* DR11 #1 */
|
||||
|
||||
#define UCAC_APID (CSR_DONE)
|
||||
#define UCAB_V_TCBHI 0
|
||||
#define UCAB_M_TCBHI 03
|
||||
#define UCAB_API2 0000100
|
||||
#define UCAB_API0 0000200
|
||||
#define UCAB_V_LOCAL 8
|
||||
#define UCAB_M_LOCAL 07
|
||||
#define UCAB_API3 0040000
|
||||
#define UCAB_API1 0100000
|
||||
|
||||
/* DR11 #2 */
|
||||
|
||||
#define UCBC_NTCB (CSR_DONE)
|
||||
|
||||
/* Declarations */
|
||||
|
||||
extern int32 int_req[IPL_HLVL];
|
||||
extern UNIT cpu_unit;
|
||||
extern uint16 *M;
|
||||
|
||||
int32 uca_csr = 0; /* DR11C #1 CSR */
|
||||
int32 uca_buf = 0; /* DR11C #1 input buffer */
|
||||
int32 ucb_csr = 0;
|
||||
int32 ucb_buf = 0;
|
||||
int32 uc15_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 */
|
||||
int32 *pdp15_mem = NULL;
|
||||
uint32 uc15_memsize = 0;
|
||||
|
||||
t_stat uca_rd (int32 *data, int32 PA, int32 access);
|
||||
t_stat uca_wr (int32 data, int32 PA, int32 access);
|
||||
t_stat ucb_rd (int32 *data, int32 PA, int32 access);
|
||||
t_stat ucb_wr (int32 data, int32 PA, int32 access);
|
||||
t_stat uc15_reset (DEVICE *dptr);
|
||||
t_stat uc15_svc (UNIT *uptr);
|
||||
t_stat uc15_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
|
||||
t_stat uc15_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
|
||||
t_stat uc15_attach (UNIT *uptr, CONST char *cptr);
|
||||
t_stat uc15_detach (UNIT *uptr);
|
||||
|
||||
void uc15_set_memsize (void);
|
||||
int32 uc15_get_uca_buf (void);
|
||||
t_stat uc15_api_req (int32 lvl, int32 vec);
|
||||
|
||||
/* UC15 data structures
|
||||
|
||||
uca_dev, ucb_dev UC15 device descriptor
|
||||
uca_unit, ucb_unit UC15 unit descriptor
|
||||
uca_reg, ucb reg UC15 register list
|
||||
|
||||
The two DR11Cs must be separate devices because they interrupt at
|
||||
different IPLs and must have different DIBs!
|
||||
*/
|
||||
|
||||
DIB uca_dib = {
|
||||
IOBA_UCA, IOLN_UCA, &uca_rd, &uca_wr,
|
||||
1, IVCL (UCA), VEC_UCA, { NULL }
|
||||
};
|
||||
|
||||
UNIT uca_unit = { UDATA (&uc15_svc, 0, UNIT_ATTABLE) };
|
||||
|
||||
REG uca_reg[] = {
|
||||
{ ORDATA (CSR, uca_csr, 16) },
|
||||
{ ORDATA (BUF, uca_buf, 16) },
|
||||
{ FLDATA (APID, uca_csr, CSR_V_DONE) },
|
||||
{ FLDATA (IE, uca_csr, CSR_V_IE) },
|
||||
{ DRDATA (POLL, uc15_poll, 10), REG_NZ },
|
||||
{ DRDATA (UCMEMSIZE, uc15_memsize, 18), REG_HRO },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
MTAB uc15_mod[] = {
|
||||
{ MTAB_XTD|MTAB_VDV, 006, "ADDRESS", "ADDRESS",
|
||||
NULL, &show_addr, NULL },
|
||||
{ MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",
|
||||
NULL, &show_vec, NULL },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
DEVICE uca_dev = {
|
||||
"UCA", &uca_unit, uca_reg, uc15_mod,
|
||||
1, 8, 10, 1, 8, 32,
|
||||
&uc15_ex, &uc15_dep, &uc15_reset,
|
||||
NULL, &uc15_attach, &uc15_detach,
|
||||
&uca_dib, DEV_DISABLE | DEV_DEBUG
|
||||
};
|
||||
|
||||
DIB ucb_dib = {
|
||||
IOBA_UCB, IOLN_UCB, &ucb_rd, &ucb_wr,
|
||||
1, IVCL (UCB), VEC_UCB, { NULL }
|
||||
};
|
||||
|
||||
UNIT ucb_unit = { UDATA (NULL, 0, 0) };
|
||||
|
||||
REG ucb_reg[] = {
|
||||
{ ORDATA (CSR, ucb_csr, 16) },
|
||||
{ ORDATA (BUF, ucb_buf, 16) },
|
||||
{ FLDATA (NTCB, ucb_csr, CSR_V_DONE) },
|
||||
{ FLDATA (IE, ucb_csr, CSR_V_IE) },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
DEVICE ucb_dev = {
|
||||
"UCB", &ucb_unit, ucb_reg, uc15_mod,
|
||||
1, 8, 18, 1, 8, 18,
|
||||
NULL, NULL, NULL,
|
||||
NULL, NULL, NULL,
|
||||
&ucb_dib, DEV_DISABLE
|
||||
};
|
||||
|
||||
/* IO routines */
|
||||
|
||||
/* DR11 #1 */
|
||||
|
||||
t_stat uca_rd (int32 *data, int32 PA, int32 access)
|
||||
{
|
||||
switch ((PA >> 1) & 03) { /* case on PA<2:1> */
|
||||
|
||||
case 0: /* CSR */
|
||||
*data = uca_csr;
|
||||
return SCPE_OK;
|
||||
|
||||
case 1: /* output buffers */
|
||||
return SCPE_OK;
|
||||
|
||||
case 2: /* input buffer */
|
||||
*data = uc15_get_uca_buf (); /* assemble buffer */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
return SCPE_NXM;
|
||||
}
|
||||
|
||||
t_stat uca_wr (int32 data, int32 PA, int32 access)
|
||||
{
|
||||
switch ((PA >> 1) & 03) { /* case on PA<2:1> */
|
||||
|
||||
case 0: /* CSR */
|
||||
if (PA & 1)
|
||||
return SCPE_OK;
|
||||
if ((data & CSR_IE) == 0)
|
||||
CLR_INT (UCA);
|
||||
else if ((uca_csr & (UCAC_APID + CSR_IE)) == UCAC_APID)
|
||||
SET_INT (UCA);
|
||||
uca_csr = (uca_csr & ~CSR_IE) | (data & CSR_IE);
|
||||
return SCPE_OK;
|
||||
|
||||
case 1: /* output buffer */
|
||||
if (PA & 1) /* odd byte? API 1 */
|
||||
uc15_api_req (1, data & 0377);
|
||||
else {
|
||||
if (access == WRITE) /* full word? API 1 */
|
||||
uc15_api_req (1, (data >> 8) & 0377);
|
||||
uc15_api_req (0, data & 0377); /* API 0 */
|
||||
}
|
||||
return SCPE_OK;
|
||||
|
||||
case 2:
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
return SCPE_NXM;
|
||||
}
|
||||
|
||||
t_stat ucb_rd (int32 *data, int32 PA, int32 access)
|
||||
{
|
||||
switch ((PA >> 1) & 03) { /* case on PA<2:1> */
|
||||
|
||||
case 0: /* CSR */
|
||||
*data = ucb_csr;
|
||||
return SCPE_OK;
|
||||
|
||||
case 1: /* output buffers */
|
||||
return SCPE_OK;
|
||||
|
||||
case 2: /* input buffer */
|
||||
*data = ucb_buf = (UC15_SHARED_RD (UC15_TCBP) << 1) & 0177777;
|
||||
ucb_csr &= ~UCBC_NTCB; /* clear TCBP rdy */
|
||||
CLR_INT (UCB); /* clear int */
|
||||
UC15_ATOMIC_CAS (UC15_TCBP_RD, 0, 1); /* send ACK */
|
||||
if (DEBUG_PRS (uca_dev)) {
|
||||
uint32 apiv, apil, fnc, tsk, pa;
|
||||
t_bool spl;
|
||||
|
||||
pa = ucb_buf + MEMSIZE;
|
||||
apiv = RdMemB (pa);
|
||||
apil = RdMemB (pa + 1);
|
||||
fnc = RdMemB (pa + 2);
|
||||
spl = (RdMemB (pa + 3) & 0200) != 0;
|
||||
tsk = RdMemB (pa + 3) & 0177;
|
||||
fprintf (sim_deb, ">> UC15: TCB rcvd, API = %o/%d, fnc = %o, %s task = %o, eventvar = %o\n",
|
||||
apiv, apil, fnc, spl? "Spooled": "Unspooled", tsk, RdMemW (pa + 4));
|
||||
fprintf (sim_deb, "Additional parameters = %o %o %o %o %o\n",
|
||||
RdMemW (pa + 6), RdMemW (pa + 8), RdMemW (pa + 10), RdMemW (pa + 12), RdMemW (pa + 14));
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
return SCPE_NXM;
|
||||
}
|
||||
|
||||
t_stat ucb_wr (int32 data, int32 PA, int32 access)
|
||||
{
|
||||
switch ((PA >> 1) & 03) { /* case on PA<2:1> */
|
||||
|
||||
case 0: /* CSR */
|
||||
if (PA & 1)
|
||||
return SCPE_OK;
|
||||
if ((data & CSR_IE) == 0) /* IE = 0? */
|
||||
CLR_INT (UCB);
|
||||
else if ((ucb_csr & (UCBC_NTCB + CSR_IE)) == UCBC_NTCB)
|
||||
SET_INT (UCB);
|
||||
ucb_csr = (ucb_csr & ~CSR_IE) | (data & CSR_IE);
|
||||
return SCPE_OK;
|
||||
|
||||
case 1: /* output buffer */
|
||||
if (PA & 1) /* odd byte? API 3*/
|
||||
uc15_api_req (3, data & 0377);
|
||||
else {
|
||||
if (access == WRITE) /* full word? API 3 */
|
||||
uc15_api_req (3, (data >> 8) & 0377);
|
||||
uc15_api_req (2, data & 0377); /* API 2 */
|
||||
}
|
||||
return SCPE_OK;
|
||||
|
||||
case 2:
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
return SCPE_NXM;
|
||||
}
|
||||
|
||||
/* Request PDP15 to take an API interrupt */
|
||||
|
||||
t_stat uc15_api_req (int32 lvl, int32 vec)
|
||||
{
|
||||
UC15_SHARED_WR (UC15_API_VEC + (lvl * UC15_API_VEC_MUL), vec);
|
||||
UC15_ATOMIC_CAS (UC15_API_REQ + (lvl * UC15_API_VEC_MUL), 0, 1);
|
||||
if (DEBUG_PRS (uca_dev))
|
||||
fprintf (sim_deb, ">>UC15: API request sent, API = %o/%d\n",
|
||||
vec, lvl);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Routine to poll for state changes from PDP15 */
|
||||
|
||||
t_stat uc15_svc (UNIT *uptr)
|
||||
{
|
||||
uint32 t;
|
||||
|
||||
t = UC15_SHARED_RD (UC15_TCBP_WR); /* TCBP written? */
|
||||
if ((t != 0) && UC15_ATOMIC_CAS (UC15_TCBP_WR, 1, 0)) { /* for real? */
|
||||
ucb_csr |= UCBC_NTCB; /* set new TCB flag */
|
||||
if (ucb_csr & CSR_IE)
|
||||
SET_INT (UCB);
|
||||
uc15_set_memsize (); /* update mem size */
|
||||
}
|
||||
t = UC15_SHARED_RD (UC15_API_UPD); /* API update? */
|
||||
if ((t != 0) && UC15_ATOMIC_CAS (UC15_API_UPD, 1, 0)) { /* for real? */
|
||||
uc15_get_uca_buf (); /* update UCA buf */
|
||||
}
|
||||
sim_activate (uptr, uc15_poll); /* next poll */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Routine to assemble/update uca_buf
|
||||
|
||||
Note that the PDP-15 and PDP-11 have opposite interpretations of
|
||||
API requests. On the PDP-15, a "1" indicates an active request.
|
||||
On the PDP-11, a "1" indicates request done (API inactive).
|
||||
*/
|
||||
|
||||
int32 uc15_get_uca_buf (void)
|
||||
{
|
||||
int32 i, t;
|
||||
static int32 ucab_api[4] =
|
||||
{ UCAB_API0, UCAB_API1, UCAB_API2, UCAB_API3 };
|
||||
|
||||
t = UC15_SHARED_RD (UC15_TCBP); /* get TCB ptr */
|
||||
uca_buf = (t >> 15) & UCAB_M_TCBHI; /* PDP15 bits<1:2> */
|
||||
t = cpu_unit.capac >> 13; /* local mem in 4KW */
|
||||
uca_buf |= ((t & UCAB_M_LOCAL) << UCAB_V_LOCAL);
|
||||
t = UC15_SHARED_RD (UC15_API_SUMM); /* get API summary */
|
||||
for (i = 0; i < 4; i++) { /* check 0..3 */
|
||||
if (((t >> i) & 1) == 0) /* level inactive? */
|
||||
uca_buf |= ucab_api[i]; /* set status bit */
|
||||
}
|
||||
if ((t == 0) && ((uca_csr & UCAC_APID) == 0)) { /* API req now 0? */
|
||||
uca_csr |= UCAC_APID; /* set flag */
|
||||
if ((uca_csr & CSR_IE) != 0) /* if ie, req int */
|
||||
SET_INT (UCA);
|
||||
}
|
||||
return uca_buf;
|
||||
}
|
||||
|
||||
/* Routine to set overall memory limit for UC15 checking */
|
||||
|
||||
void uc15_set_memsize (void)
|
||||
{
|
||||
uint32 t = UC15_SHARED_RD (UC15_PDP15MEM); /* get PDP15 memory size */
|
||||
if (t == 0) /* PDP15 not running? */
|
||||
t = PDP15_MAXMEM * 2; /* max mem in bytes */
|
||||
uc15_memsize = t + MEMSIZE; /* shared + local mem */
|
||||
if (uc15_memsize > (UNIMEMSIZE - IOPAGESIZE)) /* more than 18b? */
|
||||
uc15_memsize = UNIMEMSIZE - IOPAGESIZE; /* limit */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Reset routine
|
||||
|
||||
Aside from performing a device reset, this routine sets up shared
|
||||
UC15 state and shared PDP15 main memory. It also reads the size
|
||||
of PDP15 main memory (in PDP11 bytes) from the shared state region.
|
||||
*/
|
||||
|
||||
t_stat uc15_reset (DEVICE *dptr)
|
||||
{
|
||||
t_stat r;
|
||||
void *basead;
|
||||
|
||||
uca_csr = 0;
|
||||
uca_buf = 0;
|
||||
ucb_csr = 0;
|
||||
ucb_buf = 0;
|
||||
CLR_INT (UCA);
|
||||
CLR_INT (UCB);
|
||||
if (uc15_shmem == NULL) { /* allocate shared state */
|
||||
r = sim_shmem_open ("UC15SharedState", UC15_STATE_SIZE, &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", PDP15_MAXMEM * sizeof (int32), &pdp15_shmem, &basead);
|
||||
if (r != SCPE_OK)
|
||||
return r;
|
||||
pdp15_mem = (int32 *) basead;
|
||||
}
|
||||
uc15_set_memsize ();
|
||||
sim_activate (dptr->units, uc15_poll); /* start polling */
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Shared state ex/mod routines for debug */
|
||||
|
||||
t_stat uc15_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
|
||||
{
|
||||
if (addr >= UC15_STATE_SIZE)
|
||||
return SCPE_NXM;
|
||||
if (vptr != NULL)
|
||||
*vptr = UC15_SHARED_RD ((int32) addr);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat uc15_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
|
||||
{
|
||||
if (addr >= UC15_STATE_SIZE)
|
||||
return SCPE_NXM;
|
||||
UC15_SHARED_WR ((int32) addr, (int32) val);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* Fake attach routine to kill attach attempts */
|
||||
|
||||
t_stat uc15_attach (UNIT *uptr, CONST char *cptr)
|
||||
{
|
||||
return SCPE_NOFNC;
|
||||
}
|
||||
|
||||
/* Shutdown detach routine to release shared memories */
|
||||
|
||||
t_stat uc15_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;
|
||||
}
|
||||
|
||||
/* Physical read/write memory routines
|
||||
Used by CPU and IO devices
|
||||
Physical address is known to be legal
|
||||
We can use MEMSIZE rather than cpu_memsize because configurations
|
||||
were limited to 16KW of local memory
|
||||
8b and 16b writes clear the upper 2b of PDP-15 memory
|
||||
*/
|
||||
|
||||
int32 uc15_RdMemW (int32 pa)
|
||||
{
|
||||
if (((uint32) pa) < MEMSIZE)
|
||||
return M[pa >> 1];
|
||||
else {
|
||||
pa = pa - MEMSIZE;
|
||||
return (pdp15_mem[pa >> 1] & DMASK);
|
||||
}
|
||||
}
|
||||
|
||||
int32 uc15_RdMemB (int32 pa)
|
||||
{
|
||||
if (((uint32) pa) < MEMSIZE)
|
||||
return ((pa & 1)? (M[pa >> 1] >> 8): (M[pa >> 1] & 0377));
|
||||
else {
|
||||
pa = pa - MEMSIZE;
|
||||
return ((pa & 1)? (pdp15_mem[pa >> 1] >> 8): (pdp15_mem[pa >> 1] & 0377));
|
||||
}
|
||||
}
|
||||
|
||||
void uc15_WrMemW (int32 pa, int32 d)
|
||||
{
|
||||
if (((uint32) pa) < MEMSIZE)
|
||||
M[pa >> 1] = d;
|
||||
else {
|
||||
pa = pa - MEMSIZE;
|
||||
pdp15_mem[pa >> 1] = d & DMASK;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void uc15_WrMemB (int32 pa, int32 d)
|
||||
{
|
||||
if (((uint32) pa) < MEMSIZE)
|
||||
M[pa >> 1] = (pa & 1)?
|
||||
((M[pa >> 1] & 0377) | ((d & 0377) << 8)): \
|
||||
((M[pa >> 1] & ~0377) | (d & 0377));
|
||||
else {
|
||||
pa = pa - MEMSIZE;
|
||||
pdp15_mem[pa >> 1] = (pa & 1)?
|
||||
((pdp15_mem[pa >> 1] & 0377) | ((d & 0377) << 8)): \
|
||||
((pdp15_mem[pa >> 1] & ~0377) | (d & 0377));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* 18b DMA routines - physical only */
|
||||
|
||||
int32 Map_Read18 (uint32 ba, int32 bc, uint32 *buf)
|
||||
{
|
||||
uint32 alim, lim;
|
||||
|
||||
ba = (ba & UNIMASK) & ~01; /* trim, align addr */
|
||||
lim = ba + (bc & ~01);
|
||||
if (lim < uc15_memsize) /* end ok? */
|
||||
alim = lim;
|
||||
else if (ba < uc15_memsize) /* no, strt ok? */
|
||||
alim = uc15_memsize;
|
||||
else return bc; /* no, err */
|
||||
for ( ; ba < alim; ba = ba + 2) { /* by 18b words */
|
||||
if (ba < MEMSIZE)
|
||||
*buf++ = M[ba >> 1];
|
||||
else *buf++ = pdp15_mem[(ba - MEMSIZE) >> 1] & 0777777;
|
||||
}
|
||||
return (lim - alim);
|
||||
}
|
||||
|
||||
int32 Map_Write18 (uint32 ba, int32 bc, uint32 *buf)
|
||||
{
|
||||
uint32 alim, lim;
|
||||
|
||||
ba = (ba & UNIMASK) & ~01; /* trim, align addr */
|
||||
lim = ba + (bc & ~01);
|
||||
if (lim < uc15_memsize) /* end ok? */
|
||||
alim = lim;
|
||||
else if (ba < uc15_memsize) /* no, strt ok? */
|
||||
alim = uc15_memsize;
|
||||
else return bc; /* no, err */
|
||||
for ( ; ba < alim; ba = ba + 2) { /* by 18 bit words */
|
||||
if (ba < MEMSIZE)
|
||||
M[ba >> 1] = *buf++ & DMASK;
|
||||
else pdp15_mem[(ba - MEMSIZE) >> 1] = *buf++ & 0777777;
|
||||
}
|
||||
return (lim - alim);
|
||||
}
|
||||
Reference in New Issue
Block a user