542 lines
18 KiB
C
542 lines
18 KiB
C
/* 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|MTAB_VALR, 006, "ADDRESS", NULL,
|
|
NULL, &show_addr, NULL },
|
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "VECTOR", NULL,
|
|
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 * 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", 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);
|
|
}
|