RESTRICTION: The PDP-15 FPP is only partially debugged. Do NOT enable this feature for normal operations. WARNING: The core simulator files (scp.c, sim_*.c) have been reorganized. Unzip V3.2-0 to an empty directory before attempting to compile the source. IMPORTANT: If you are compiling for UNIX, please read the notes for Ethernet very carefully. You may need to download a new version of the pcap library, or make changes to the makefile, to get Ethernet support to work. 1. New Features in 3.2-0 1.1 SCP and libraries - Added SHOW <device> RADIX command. - Added SHOW <device> MODIFIERS command. - Added SHOW <device> NAMES command. - Added SET/SHOW <device> DEBUG command. - Added sim_vm_parse_addr and sim_vm_fprint_addr optional interfaces. - Added REG_VMAD flag. - Split SCP into separate libraries for easier modification. - Added more room to the device and unit flag fields. - Changed terminal multiplexor library to support unlimited. number of async lines. 1.2 All DECtapes - Added STOP_EOR flag to enable end-of-reel error stop - Added device debug support. 1.3 Nova and Eclipse - Added QTY and ALM multiplexors (Bruce Ray). 1.4 LGP-30 - Added LGP-30/LGP-21 simulator. 1.5 PDP-11 - Added format, address increment inhibit, transfer overrun detection to RK. - Added device debug support to HK, RP, TM, TQ, TS. - Added DEUNA/DELUA (XU) support (Dave Hittner). - Add DZ per-line logging. 1.6 18b PDP's - Added support for 1-4 (PDP-9)/1-16 (PDP-15) additional terminals. 1.7 PDP-10 - Added DEUNA/DELUA (XU) support (Dave Hittner). 1.8 VAX - Added extended memory to 512MB (Mark Pizzolato). - Added RXV21 support. 2. Bugs Fixed in 3.2-0 2.1 SCP - Fixed double logging of SHOW BREAK (found by Mark Pizzolato). - Fixed implementation of REG_VMIO. 2.2 Nova and Eclipse - Fixed device enable/disable support (found by Bruce Ray). 2.3 PDP-1 - Fixed bug in LOAD (found by Mark Crispin). 2.4 PDP-10 - Fixed bug in floating point unpack. - Fixed bug in FIXR (found by Phil Stone, fixed by Chris Smith). 2.6 PDP-11 - Fixed bug in RQ interrupt control (found by Tom Evans). 2.6 PDP-18B - Fixed bug in PDP-15 XVM g_mode implementation. - Fixed bug in PDP-15 indexed address calculation. - Fixed bug in PDP-15 autoindexed address calculation. - Fixed bugs in FPP-15 instruction decode. - Fixed clock response to CAF. - Fixed bug in hardware read-in mode bootstrap. - Fixed PDP-15 XVM instruction decoding errors. 2.7 VAX - Fixed PC read fault in EXTxV. - Fixed PC write fault in INSV.
567 lines
18 KiB
C
567 lines
18 KiB
C
/* id_io.c: Interdata CPU-independent I/O routines
|
||
|
||
Copyright (c) 2001-2004, 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.
|
||
|
||
21-Jun-03 RMS Changed subroutine argument for ARM compiler conflict
|
||
|
||
Interdata I/O devices are defined by a device information block:
|
||
|
||
dno base device number
|
||
sch selector channel, -1 if none
|
||
irq interrupt request flag
|
||
tplte device number template, NULL if one device number
|
||
iot I/O processing routine
|
||
ini initialization routine
|
||
|
||
Interdata I/O uses the following interconnected tables:
|
||
|
||
dev_tab[dev] Indexed by device number, points to the I/O instruction
|
||
processing routine for the device.
|
||
|
||
sch_tab[dev] Indexed by device number, if non-zero, the number + 1
|
||
of the selector channel used by the device.
|
||
|
||
int_req[level] Indexed by interrupt level, device interrupt flags.
|
||
|
||
int_enb[level] Indexed by interrupt level, device interrupt enable flags.
|
||
|
||
int_tab[idx] Indexed by ((interrupt level * 32) + interrupt number),
|
||
maps bit positions in int_req to device numbers.
|
||
*/
|
||
|
||
#include "id_defs.h"
|
||
|
||
/* Selector channel */
|
||
|
||
#define SCHC_EXA 0x40 /* read ext addr */
|
||
#define SCHC_RD 0x20 /* read */
|
||
#define SCHC_GO 0x10 /* go */
|
||
#define SCHC_STOP 0x08 /* stop */
|
||
#define SCHC_SSTA 0x04 /* sel ch status */
|
||
#define SCHC_EXM 0x03 /* ext mem */
|
||
|
||
extern uint32 int_req[INTSZ], int_enb[INTSZ];
|
||
extern uint32 (*dev_tab[DEVNO])(uint32 dev, uint32 op, uint32 datout);
|
||
extern uint32 pawidth;
|
||
extern UNIT cpu_unit;
|
||
extern FILE *sim_log;
|
||
extern DEVICE *sim_devices[];
|
||
|
||
uint32 sch_max = 2; /* sch count */
|
||
uint32 sch_sa[SCH_NUMCH] = { 0 }; /* start addr */
|
||
uint32 sch_ea[SCH_NUMCH] = { 0 }; /* end addr */
|
||
uint8 sch_sdv[SCH_NUMCH] = { 0 }; /* device */
|
||
uint8 sch_cmd[SCH_NUMCH] = { 0 }; /* command */
|
||
uint8 sch_rdp[SCH_NUMCH] = { 0 }; /* read ptr */
|
||
uint8 sch_wdc[SCH_NUMCH] = { 0 }; /* write ctr */
|
||
uint32 sch_tab[DEVNO] = { 0 }; /* dev to sch map */
|
||
uint32 int_tab[INTSZ * 32] = { 0 }; /* int to dev map */
|
||
uint8 sch_tplte[SCH_NUMCH + 1]; /* dnum template */
|
||
|
||
uint32 sch (uint32 dev, uint32 op, uint32 dat);
|
||
void sch_ini (t_bool dtpl);
|
||
t_stat sch_reset (DEVICE *dptr);
|
||
t_stat sch_set_nchan (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||
t_stat sch_show_reg (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||
|
||
/* Selector channel data structures
|
||
|
||
sch_dev channel device descriptor
|
||
sch_unit channel unit descriptor
|
||
sch_mod channel modifiers list
|
||
sch_reg channel register list
|
||
*/
|
||
|
||
DIB sch_dib = { d_SCH, -1, v_SCH, sch_tplte, &sch, &sch_ini };
|
||
|
||
UNIT sch_unit = { UDATA (NULL, 0, 0) };
|
||
|
||
REG sch_reg[] = {
|
||
{ HRDATA (CHAN, sch_max, 3), REG_HRO },
|
||
{ BRDATA (SA, sch_sa, 16, 20, SCH_NUMCH) },
|
||
{ BRDATA (EA, sch_ea, 16, 20, SCH_NUMCH) },
|
||
{ BRDATA (CMD, sch_cmd, 16, 8, SCH_NUMCH) },
|
||
{ BRDATA (DEV, sch_sdv, 16, 8, SCH_NUMCH) },
|
||
{ BRDATA (RDP, sch_rdp, 16, 2, SCH_NUMCH) },
|
||
{ BRDATA (WDC, sch_wdc, 16, 3, SCH_NUMCH) },
|
||
{ GRDATA (IREQ, int_req[l_SCH], 16, SCH_NUMCH, i_SCH) },
|
||
{ GRDATA (IENB, int_enb[l_SCH], 16, SCH_NUMCH, i_SCH) },
|
||
{ HRDATA (DEVNO, sch_dib.dno, 8), REG_HRO },
|
||
{ NULL } };
|
||
|
||
MTAB sch_mod[] = {
|
||
{ MTAB_XTD|MTAB_VDV|MTAB_VAL, 0, "channels", "CHANNELS",
|
||
&sch_set_nchan, NULL, &sch_reg[0] },
|
||
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "0", NULL,
|
||
NULL, &sch_show_reg, NULL },
|
||
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "1", NULL,
|
||
NULL, &sch_show_reg, NULL },
|
||
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 2, "2", NULL,
|
||
NULL, &sch_show_reg, NULL },
|
||
{ MTAB_XTD | MTAB_VDV | MTAB_NMO, 3, "3", NULL,
|
||
NULL, &sch_show_reg, NULL },
|
||
{ MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",
|
||
&set_dev, &show_dev, &sch_dib },
|
||
{ 0 } };
|
||
|
||
DEVICE sch_dev = {
|
||
"SELCH", &sch_unit, sch_reg, sch_mod,
|
||
1, 16, 8, 1, 16, 8,
|
||
NULL, NULL, &sch_reset,
|
||
NULL, NULL, NULL,
|
||
&sch_dib, 0 };
|
||
|
||
/* (Extended) selector channel
|
||
|
||
There are really three different selector channels:
|
||
- 16b selector channel (max 4B of data)
|
||
- 18b selector channel (max 4B of data)
|
||
- 20b selector channel (max 6B of data)
|
||
The algorithm for loading the start and end addresses is taken
|
||
from the maintenance manual for the Extended Selector Channel.
|
||
*/
|
||
|
||
#define SCH_EXR(ch) ((sch_cmd[ch] & SCHC_EXA) && (pawidth == PAWIDTH32))
|
||
|
||
uint32 sch (uint32 dev, uint32 op, uint32 dat)
|
||
{
|
||
uint32 t, bank, sdv, ch = dev - sch_dib.dno;
|
||
|
||
switch (op) { /* case IO op */
|
||
case IO_ADR: /* select */
|
||
return BY; /* byte only */
|
||
case IO_RD: /* read data */
|
||
t = (sch_sa[ch] >> (sch_rdp[ch] * 8)) & DMASK8; /* get sa byte */
|
||
if (sch_rdp[ch] == 0) sch_rdp[ch] = /* wrap? */
|
||
SCH_EXR (ch)? 2: 1;
|
||
else sch_rdp[ch] = sch_rdp[ch] - 1; /* dec byte ptr */
|
||
return t;
|
||
case IO_WD: /* write data */
|
||
if (pawidth != PAWIDTH32) { /* 16b? max 4 */
|
||
if (sch_wdc[ch] >= 4) break; /* stop at 4 */
|
||
sch_sa[ch] = ((sch_sa[ch] << 8) | /* ripple ea to sa */
|
||
(sch_ea[ch] >> 8)) & DMASK16;
|
||
sch_ea[ch] = ((sch_ea[ch] << 8) | /* ripple ea low */
|
||
dat) & DMASK16; } /* insert byte */
|
||
else { /* 32b? max 6 */
|
||
if (sch_wdc[ch] >= 6) break; /* stop at 6 */
|
||
if (sch_wdc[ch] != 5) { /* if not last */
|
||
sch_sa[ch] = ((sch_sa[ch] << 8) | /* ripple ea<15:8> to sa */
|
||
((sch_ea[ch] >> 8) & DMASK8)) & PAMASK32;
|
||
sch_ea[ch] = /* ripple ea<7:0> */
|
||
(((sch_ea[ch] & DMASK8) << 8) | dat) & PAMASK32; }
|
||
else sch_ea[ch] = ((sch_ea[ch] << 8) | dat) & PAMASK32; }
|
||
sch_wdc[ch] = sch_wdc[ch] + 1; /* adv sequencer */
|
||
break;
|
||
case IO_SS: /* status */
|
||
if (sch_cmd[ch] & SCHC_GO) return STA_BSY; /* test busy */
|
||
if (sch_cmd[ch] & SCHC_SSTA) return 0; /* test sch sta */
|
||
else {
|
||
sdv = sch_sdv[ch]; /* get dev */
|
||
if (dev_tab[sdv] == 0) return CC_V; /* not there? */
|
||
dev_tab[sdv] (sdv, IO_ADR, 0); /* select dev */
|
||
t = dev_tab[sdv] (sdv, IO_SS, 0); /* get status */
|
||
return t & ~STA_BSY; } /* clr busy */
|
||
case IO_OC: /* command */
|
||
bank = 0; /* assume no bank */
|
||
if (pawidth != PAWIDTH32) { /* 16b/18b proc? */
|
||
dat = dat & ~(SCHC_EXA | SCHC_SSTA); /* clr ext func */
|
||
if (pawidth == PAWIDTH16E) /* 18b proc? */
|
||
bank = (dat & SCHC_EXM) << 16; }
|
||
if (dat & SCHC_STOP) { /* stop? */
|
||
sch_cmd[ch] = dat & (SCHC_EXA | SCHC_SSTA); /* clr go */
|
||
CLR_INT (v_SCH + ch); /* clr intr */
|
||
sch_rdp[ch] = SCH_EXR (ch)? 2: 1; /* init sequencers */
|
||
sch_wdc[ch] = 0; }
|
||
else if (dat & SCHC_GO) { /* go? */
|
||
sch_cmd[ch] = dat & (SCHC_GO | SCHC_RD);
|
||
if (sch_wdc[ch] <= 4) { /* 4 bytes? */
|
||
sch_sa[ch] = (sch_sa[ch] & PAMASK16) | bank; /* 16b addr */
|
||
sch_ea[ch] = (sch_ea[ch] & PAMASK16) | bank; }
|
||
sch_sa[ch] = sch_sa[ch] & ~1;
|
||
if (sch_ea[ch] <= sch_sa[ch]) /* wrap? */
|
||
sch_ea[ch] = sch_ea[ch] | /* modify end addr */
|
||
((pawidth == PAWIDTH32)? PAMASK32: PAMASK16); }
|
||
break; }
|
||
return 0;
|
||
}
|
||
|
||
/* CPU call to test if channel blocks access to device */
|
||
|
||
t_bool sch_blk (uint32 dev)
|
||
{
|
||
uint32 ch = sch_tab[dev] - 1;
|
||
|
||
if ((ch < sch_max) && (sch_cmd[ch] & SCHC_GO)) return TRUE;
|
||
return FALSE;
|
||
}
|
||
|
||
/* Device call to 'remember' last dev on channel */
|
||
|
||
void sch_adr (uint32 ch, uint32 dev)
|
||
{
|
||
if (ch < sch_max) sch_sdv[ch] = dev;
|
||
return;
|
||
}
|
||
|
||
/* Device call to see if selector channel is active for device */
|
||
|
||
t_bool sch_actv (uint32 ch, uint32 dev)
|
||
{
|
||
if ((ch < sch_max) && /* chan valid, */
|
||
(sch_cmd[ch] & SCHC_GO) && /* on, and */
|
||
(sch_sdv[ch] == dev)) return TRUE; /* set for dev? */
|
||
return FALSE; /* no */
|
||
}
|
||
|
||
/* Device call to read a block of memory */
|
||
|
||
uint32 sch_rdmem (uint32 ch, uint8 *buf, uint32 cnt)
|
||
{
|
||
uint32 addr, end, xfr, inc;
|
||
|
||
if ((ch >= sch_max) || ((sch_cmd[ch] & SCHC_GO) == 0)) return 0;
|
||
addr = sch_sa[ch]; /* start */
|
||
end = sch_ea[ch]; /* end */
|
||
xfr = MIN (cnt, end - addr + 1); /* sch xfr cnt */
|
||
inc = IOReadBlk (addr, xfr, buf); /* read mem */
|
||
if ((addr + inc) > end) { /* end? */
|
||
SET_INT (v_SCH + ch); /* interrupt */
|
||
sch_cmd[ch] &= ~(SCHC_GO | SCHC_RD); /* clear GO */
|
||
sch_sa[ch] = sch_sa[ch] + inc - 1; } /* end addr */
|
||
else sch_sa[ch] = sch_sa[ch] + inc; /* next addr */
|
||
return inc;
|
||
}
|
||
|
||
/* Device call to write a block of memory */
|
||
|
||
uint32 sch_wrmem (uint32 ch, uint8 *buf, uint32 cnt)
|
||
{
|
||
uint32 addr, end, xfr, inc;
|
||
|
||
if ((ch >= sch_max) || ((sch_cmd[ch] & SCHC_GO) == 0)) return 0;
|
||
addr = sch_sa[ch]; /* start */
|
||
end = sch_ea[ch]; /* end */
|
||
xfr = MIN (cnt, end - addr + 1); /* sch xfr cnt */
|
||
inc = IOWriteBlk (addr, xfr, buf); /* write mem */
|
||
if ((addr + inc) > end) { /* end? */
|
||
SET_INT (v_SCH + ch); /* interrupt */
|
||
sch_cmd[ch] &= ~(SCHC_GO | SCHC_RD); /* clear GO */
|
||
sch_sa[ch] = sch_sa[ch] + inc - 1; } /* end addr */
|
||
else sch_sa[ch] = sch_sa[ch] + inc; /* next addr */
|
||
return inc;
|
||
}
|
||
|
||
/* Device call to stop a selector channel */
|
||
|
||
void sch_stop (uint32 ch)
|
||
{
|
||
if (ch < sch_max) {
|
||
SET_INT (v_SCH + ch); /* interrupt */
|
||
sch_cmd[ch] &= ~(SCHC_GO | SCHC_RD); } /* clear GO */
|
||
return;
|
||
}
|
||
|
||
/* Reset */
|
||
|
||
void sch_reset_ch (uint32 rst_lim)
|
||
{
|
||
uint32 ch;
|
||
|
||
for (ch = 0; ch < SCH_NUMCH; ch++) {
|
||
if (ch >= rst_lim) {
|
||
CLR_INT (v_SCH + ch);
|
||
SET_ENB (v_SCH + ch);
|
||
sch_sa[ch] = sch_ea[ch] = 0;
|
||
sch_cmd[ch] = sch_sdv[ch] = 0;
|
||
sch_wdc[ch] = 0;
|
||
sch_rdp[ch] = 1; } }
|
||
return;
|
||
}
|
||
|
||
t_stat sch_reset (DEVICE *dptr)
|
||
{
|
||
sch_reset_ch (0); /* reset all chan */
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Set number of channels */
|
||
|
||
t_stat sch_set_nchan (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||
{
|
||
DEVICE *dptr;
|
||
DIB *dibp;
|
||
uint32 i, newmax;
|
||
t_stat r;
|
||
|
||
if (cptr == NULL) return SCPE_ARG;
|
||
newmax = get_uint (cptr, 10, SCH_NUMCH, &r); /* get new max */
|
||
if ((r != SCPE_OK) || (newmax == sch_max)) return r; /* err or no chg? */
|
||
if (newmax == 0) return SCPE_ARG; /* must be > 0 */
|
||
if (newmax < sch_max) { /* reducing? */
|
||
for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru dev */
|
||
dibp = (DIB *) dptr->ctxt; /* get DIB */
|
||
if (dibp && (dibp->sch >= (int32) newmax)) {/* dev using chan? */
|
||
printf ("Device %02X uses channel %d\n",
|
||
dibp->dno, dibp->sch);
|
||
if (sim_log) fprintf (sim_log, "Device %02X uses channel %d\n",
|
||
dibp->dno, dibp->sch);
|
||
return SCPE_OK; } } }
|
||
sch_max = newmax; /* set new max */
|
||
sch_reset_ch (sch_max); /* reset chan */
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Show channel registers */
|
||
|
||
t_stat sch_show_reg (FILE *st, UNIT *uptr, int32 val, void *desc)
|
||
{
|
||
if (val < 0) return SCPE_IERR;
|
||
if (val >= (int32) sch_max) fprintf (st, "Channel %d disabled\n", val);
|
||
else { fprintf (st, "SA: %05X\n", sch_sa[val]);
|
||
fprintf (st, "EA: %05X\n", sch_ea[val]);
|
||
fprintf (st, "CMD: %02X\n", sch_cmd[val]);
|
||
fprintf (st, "DEV: %02X\n", sch_sdv[val]);
|
||
fprintf (st, "RDP: %X\n", sch_rdp[val]);
|
||
fprintf (st, "WDC: %X\n", sch_wdc[val]); }
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Initialize template */
|
||
|
||
void sch_ini (t_bool dtpl)
|
||
{
|
||
uint32 i;
|
||
|
||
for (i = 0; i < sch_max; i++) sch_tplte[i] = i;
|
||
sch_tplte[sch_max] = TPL_END;
|
||
return;
|
||
}
|
||
|
||
/* Evaluate interrupt */
|
||
|
||
void int_eval (void)
|
||
{
|
||
int i;
|
||
extern uint32 qevent;
|
||
|
||
for (i = 0; i < INTSZ; i++)
|
||
if (int_req[i] & int_enb[i]) {
|
||
qevent = qevent | EV_INT;
|
||
return; }
|
||
qevent = qevent & ~EV_INT;
|
||
return;
|
||
}
|
||
|
||
/* Return interrupting device */
|
||
|
||
uint32 int_getdev (void)
|
||
{
|
||
int32 i, j, t;
|
||
uint32 r;
|
||
|
||
for (i = t = 0; i < INTSZ; i++) { /* loop thru array */
|
||
if (r = int_req[i] & int_enb[i]) { /* find nz int wd */
|
||
for (j = 0; j < 32; t++, j++) {
|
||
if (r & (1u << j)) {
|
||
int_req[i] = int_req[i] & ~(1u << j); /* clr request */
|
||
return int_tab[t]; } } }
|
||
else t = t + 32; }
|
||
return 0;
|
||
}
|
||
|
||
/* Update device interrupt status */
|
||
|
||
int32 int_chg (uint32 irq, int32 dat, int32 armdis)
|
||
{
|
||
int32 t = CMD_GETINT (dat); /* get int ctrl */
|
||
|
||
if (t == CMD_IENB) { /* enable? */
|
||
SET_ENB (irq);
|
||
return 1; }
|
||
else if (t == CMD_IDIS) { /* disable? */
|
||
CLR_ENB (irq);
|
||
return 1; }
|
||
if (t == CMD_IDSA) { /* disarm? */
|
||
CLR_ENB (irq);
|
||
CLR_INT (irq);
|
||
return 0; }
|
||
return armdis;
|
||
}
|
||
|
||
/* Process a 2b field and return unchanged, set, clear, complement */
|
||
|
||
int32 io_2b (int32 val, int32 pos, int32 old)
|
||
{
|
||
int32 t = (val >> pos) & 3;
|
||
if (t == 0) return old;
|
||
if (t == 1) return 1;
|
||
if (t == 2) return 0;
|
||
return old ^1;
|
||
}
|
||
|
||
/* Block transfer routines */
|
||
|
||
uint32 IOReadBlk (uint32 loc, uint32 cnt, uint8 *buf)
|
||
{
|
||
uint32 i;
|
||
|
||
if (!MEM_ADDR_OK (loc) || (cnt == 0)) return 0;
|
||
if (!MEM_ADDR_OK (loc + cnt - 1)) cnt = MEMSIZE - loc;
|
||
for (i = 0; i < cnt; i++) buf[i] = IOReadB (loc + i);
|
||
return cnt;
|
||
}
|
||
|
||
uint32 IOWriteBlk (uint32 loc, uint32 cnt, uint8 *buf)
|
||
{
|
||
uint32 i;
|
||
|
||
if (!MEM_ADDR_OK (loc) || (cnt == 0)) return 0;
|
||
if (!MEM_ADDR_OK (loc + cnt - 1)) cnt = MEMSIZE - loc;
|
||
for (i = 0; i < cnt; i++) IOWriteB (loc + i, buf[i]);
|
||
return cnt;
|
||
}
|
||
|
||
/* Change selector channel for a device */
|
||
|
||
t_stat set_sch (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||
{
|
||
DEVICE *dptr;
|
||
DIB *dibp;
|
||
uint32 newch;
|
||
t_stat r;
|
||
|
||
if (cptr == NULL) return SCPE_ARG;
|
||
if (uptr == NULL) return SCPE_IERR;
|
||
dptr = find_dev_from_unit (uptr);
|
||
if (dptr == NULL) return SCPE_IERR;
|
||
dibp = (DIB *) dptr->ctxt;
|
||
if ((dibp == NULL) || (dibp->sch < 0)) return SCPE_IERR;
|
||
newch = get_uint (cptr, 16, sch_max - 1, &r); /* get new */
|
||
if (r != SCPE_OK) return r;
|
||
dibp->sch = newch; /* store */
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Show selector channel for a device */
|
||
|
||
t_stat show_sch (FILE *st, UNIT *uptr, int32 val, void *desc)
|
||
{
|
||
DEVICE *dptr;
|
||
DIB *dibp;
|
||
|
||
if (uptr == NULL) return SCPE_IERR;
|
||
dptr = find_dev_from_unit (uptr);
|
||
if (dptr == NULL) return SCPE_IERR;
|
||
dibp = (DIB *) dptr->ctxt;
|
||
if ((dibp == NULL) || (dibp->sch < 0)) return SCPE_IERR;
|
||
fprintf (st, "selch=%X", dibp->sch);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Change device number for a device */
|
||
|
||
t_stat set_dev (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||
{
|
||
DEVICE *dptr;
|
||
DIB *dibp;
|
||
uint32 newdev;
|
||
t_stat r;
|
||
|
||
if (cptr == NULL) return SCPE_ARG;
|
||
if (uptr == NULL) return SCPE_IERR;
|
||
dptr = find_dev_from_unit (uptr);
|
||
if (dptr == NULL) return SCPE_IERR;
|
||
dibp = (DIB *) dptr->ctxt;
|
||
if (dibp == NULL) return SCPE_IERR;
|
||
newdev = get_uint (cptr, 16, DEV_MAX, &r); /* get new */
|
||
if ((r != SCPE_OK) || (newdev == dibp->dno)) return r;
|
||
if (newdev == 0) return SCPE_ARG; /* must be > 0 */
|
||
dibp->dno = newdev; /* store */
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Show device number for a device */
|
||
|
||
t_stat show_dev (FILE *st, UNIT *uptr, int32 val, void *desc)
|
||
{
|
||
DEVICE *dptr;
|
||
DIB *dibp;
|
||
|
||
if (uptr == NULL) return SCPE_IERR;
|
||
dptr = find_dev_from_unit (uptr);
|
||
if (dptr == NULL) return SCPE_IERR;
|
||
dibp = (DIB *) dptr->ctxt;
|
||
if ((dibp == NULL) || (dibp->dno == 0)) return SCPE_IERR;
|
||
fprintf (st, "devno=%02X", dibp->dno);
|
||
return SCPE_OK;
|
||
}
|
||
|
||
/* Init device tables */
|
||
|
||
t_bool devtab_init (void)
|
||
{
|
||
DEVICE *dptr;
|
||
DIB *dibp;
|
||
uint32 i, j, dno, dmsk, doff, t, dmap[DEVNO / 32];
|
||
uint8 *tplte, dflt_tplte[] = { 0, TPL_END };
|
||
|
||
/* Clear tables, device map */
|
||
|
||
for (i = 0; i < DEVNO; i++) {
|
||
dev_tab[i] = NULL;
|
||
sch_tab[i] = 0; }
|
||
for (i = 0; i < (INTSZ * 32); i++) int_tab[i] = 0;
|
||
for (i = 0; i < (DEVNO / 32); i++) dmap[i] = 0;
|
||
|
||
/* Test each device for conflict; add to map; init tables */
|
||
|
||
for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru devices */
|
||
dibp = (DIB *) dptr->ctxt; /* get DIB */
|
||
if ((dibp == NULL) || (dptr->flags & DEV_DIS)) continue; /* exist, enabled? */
|
||
dno = dibp->dno; /* get device num */
|
||
if (dibp->ini) dibp->ini (TRUE); /* gen dno template */
|
||
tplte = dibp->tplte; /* get template */
|
||
if (tplte == NULL) tplte = dflt_tplte; /* none? use default */
|
||
for ( ; *tplte != TPL_END; tplte++) { /* loop thru template */
|
||
t = (dno + *tplte) & DEV_MAX; /* loop thru template */
|
||
dmsk = 1u << (t & 0x1F); /* bit to test */
|
||
doff = t / 32; /* word to test */
|
||
if (dmap[doff] & dmsk) { /* in use? */
|
||
printf ("Device number conflict, devno = %02X\n", t);
|
||
if (sim_log) fprintf (sim_log,
|
||
"Device number conflict, devno = %02X\n", t);
|
||
return TRUE; }
|
||
dmap[doff] = dmap[doff] | dmsk;
|
||
if (dibp->sch >= 0) sch_tab[t] = dibp->sch + 1;
|
||
dev_tab[t] = dibp->iot; }
|
||
|
||
if (dibp->ini) dibp->ini (FALSE); /* gen int template */
|
||
tplte = dibp->tplte; /* get template */
|
||
if (tplte == NULL) tplte = dflt_tplte; /* none? use default */
|
||
for (j = dibp->irq; *tplte != TPL_END; j++, tplte++) {
|
||
int_tab[j] = (dno + *tplte) & DEV_MAX; }
|
||
} /* end for i */
|
||
return FALSE;
|
||
}
|