1
0
mirror of https://github.com/simh/simh.git synced 2026-01-25 11:46:37 +00:00

Notes For V3.5-0

The source set has been extensively overhauled.  For correct
viewing, set Visual C++ or Emacs to have tab stops every 4
characters.

1. New Features in 3.4-1

1.1 All Ethernet devices

- Added Windows user-defined adapter names (from Timothe Litt)

1.2 Interdata, SDS, HP, PDP-8, PDP-18b terminal multiplexors

- Added support for SET <unit>n DISCONNECT

1.3 VAX

- Added latent QDSS support
- Revised autoconfigure to handle QDSS

1.4 PDP-11

- Revised autoconfigure to handle more casees

2. Bugs Fixed in 3.4-1

2.1 SCP and libraries

- Trim trailing spaces on all input (for example, attach file names)
- Fixed sim_sock spurious SIGPIPE error in Unix/Linux
- Fixed sim_tape misallocation of TPC map array for 64b simulators

2.2 1401

- Fixed bug, CPU reset was clearing SSB through SSG

2.3 PDP-11

- Fixed bug in VH vector display routine
- Fixed XU runt packet processing (found by Tim Chapman)

2.4 Interdata

- Fixed bug in SHOW PAS CONN/STATS
- Fixed potential integer overflow exception in divide

2.5 SDS

- Fixed bug in SHOW MUX CONN/STATS

2.6 HP

- Fixed bug in SHOW MUX CONN/STATS

2.7 PDP-8

- Fixed bug in SHOW TTIX CONN/STATS
- Fixed bug in SET/SHOW TTOXn LOG

2.8 PDP-18b

- Fixed bug in SHOW TTIX CONN/STATS
- Fixed bug in SET/SHOW TTOXn LOG

2.9 Nova, Eclipse

- Fixed potential integer overflow exception in divide
This commit is contained in:
Bob Supnik
2005-09-09 18:09:00 -07:00
committed by Mark Pizzolato
parent ec60bbf329
commit b7c1eae41f
257 changed files with 107140 additions and 97195 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,14 @@
To: Users
From: Bob Supnik
Subj: PDP-10 Simulator Usage
Date: 15-Nov-2004
Date: 01-Jul-2005
COPYRIGHT NOTICE
The following copyright notice applies to both the SIMH source and binary:
Original code published in 1993-2004, written by Robert M Supnik
Copyright (c) 1993-2004, Robert M Supnik
Original code published in 1993-2005, written by Robert M Supnik
Copyright (c) 1993-2005, 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"),
@@ -27,8 +27,8 @@ The following copyright notice applies to both the SIMH source and binary:
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
Except as contained in this notice, the name of Robert M Supnik shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
This memorandum documents the PDP-10 simulator.
@@ -383,7 +383,7 @@ DISCONNECT command, or a DETACH DZ command.
The SHOW DZ CONNECTIONS command displays the current connections to the DZ.
The SHOW DZ STATISTICS command displays statistics for active connections.
The SET DZ DISCONNECT=linenumber disconnects the specified line.
The SET DZ DISCONNECT=linenumber command disconnects the specified line.
The DZ11 implements these registers:

View File

@@ -19,24 +19,24 @@
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
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.
fe KS10 console front end
fe KS10 console front end
28-May-04 RMS Removed SET FE CTRL-C
29-Dec-03 RMS Added console backpressure support
25-Apr-03 RMS Revised for extended file support
22-Dec-02 RMS Added break support
30-May-02 RMS Widened COUNT to 32b
30-Nov-01 RMS Added extended SET/SHOW support
23-Oct-01 RMS New IO page address constants
07-Sep-01 RMS Moved function prototypes
28-May-04 RMS Removed SET FE CTRL-C
29-Dec-03 RMS Added console backpressure support
25-Apr-03 RMS Revised for extended file support
22-Dec-02 RMS Added break support
30-May-02 RMS Widened COUNT to 32b
30-Nov-01 RMS Added extended SET/SHOW support
23-Oct-01 RMS New IO page address constants
07-Sep-01 RMS Moved function prototypes
*/
#include "pdp10_defs.h"
#define UNIT_DUMMY (1 << UNIT_V_UF)
#define UNIT_DUMMY (1 << UNIT_V_UF)
extern d10 *M;
extern int32 apr_flg;
@@ -47,37 +47,41 @@ t_stat fe_stop_os (UNIT *uptr, int32 val, char *cptr, void *desc);
/* FE data structures
fe_dev FE device descriptor
fe_unit FE unit descriptor
fe_reg FE register list
fe_dev FE device descriptor
fe_unit FE unit descriptor
fe_reg FE register list
*/
#define fei_unit fe_unit[0]
#define feo_unit fe_unit[1]
#define fei_unit fe_unit[0]
#define feo_unit fe_unit[1]
UNIT fe_unit[] = {
{ UDATA (&fei_svc, 0, 0), KBD_POLL_WAIT },
{ UDATA (&feo_svc, 0, 0), SERIAL_OUT_WAIT } };
{ UDATA (&fei_svc, 0, 0), KBD_POLL_WAIT },
{ UDATA (&feo_svc, 0, 0), SERIAL_OUT_WAIT }
};
REG fe_reg[] = {
{ ORDATA (IBUF, fei_unit.buf, 8) },
{ DRDATA (ICOUNT, fei_unit.pos, T_ADDR_W), REG_RO + PV_LEFT },
{ DRDATA (ITIME, fei_unit.wait, 24), REG_NZ + PV_LEFT },
{ ORDATA (OBUF, feo_unit.buf, 8) },
{ DRDATA (OCOUNT, feo_unit.pos, T_ADDR_W), REG_RO + PV_LEFT },
{ DRDATA (OTIME, feo_unit.wait, 24), REG_NZ + PV_LEFT },
{ NULL } };
{ ORDATA (IBUF, fei_unit.buf, 8) },
{ DRDATA (ICOUNT, fei_unit.pos, T_ADDR_W), REG_RO + PV_LEFT },
{ DRDATA (ITIME, fei_unit.wait, 24), REG_NZ + PV_LEFT },
{ ORDATA (OBUF, feo_unit.buf, 8) },
{ DRDATA (OCOUNT, feo_unit.pos, T_ADDR_W), REG_RO + PV_LEFT },
{ DRDATA (OTIME, feo_unit.wait, 24), REG_NZ + PV_LEFT },
{ NULL }
};
MTAB fe_mod[] = {
{ UNIT_DUMMY, 0, NULL, "STOP", &fe_stop_os },
{ 0 } };
{ UNIT_DUMMY, 0, NULL, "STOP", &fe_stop_os },
{ 0 }
};
DEVICE fe_dev = {
"FE", fe_unit, fe_reg, fe_mod,
2, 10, 31, 1, 8, 8,
NULL, NULL, &fe_reset,
NULL, NULL, NULL };
"FE", fe_unit, fe_reg, fe_mod,
2, 10, 31, 1, 8, 8,
NULL, NULL, &fe_reset,
NULL, NULL, NULL
};
/* Front end processor (console terminal)
Communications between the KS10 and its front end is based on an in-memory
@@ -106,13 +110,15 @@ DEVICE fe_dev = {
void fe_intr (void)
{
if (M[FE_CTYOUT] & FE_CVALID) { /* char to print? */
feo_unit.buf = (int32) M[FE_CTYOUT] & 0177; /* pick it up */
feo_unit.pos = feo_unit.pos + 1;
sim_activate (&feo_unit, feo_unit.wait); } /* sched completion */
else if ((M[FE_CTYIN] & FE_CVALID) == 0) { /* input char taken? */
sim_cancel (&fei_unit); /* sched immediate */
sim_activate (&fei_unit, 0); }; /* keyboard poll */
if (M[FE_CTYOUT] & FE_CVALID) { /* char to print? */
feo_unit.buf = (int32) M[FE_CTYOUT] & 0177; /* pick it up */
feo_unit.pos = feo_unit.pos + 1;
sim_activate (&feo_unit, feo_unit.wait); /* sched completion */
}
else if ((M[FE_CTYIN] & FE_CVALID) == 0) { /* input char taken? */
sim_cancel (&fei_unit); /* sched immediate */
sim_activate (&fei_unit, 0); /* keyboard poll */
}
return;
}
@@ -120,11 +126,12 @@ t_stat feo_svc (UNIT *uptr)
{
t_stat r;
if ((r = sim_putchar_s (uptr->buf)) != SCPE_OK) { /* output; error? */
sim_activate (uptr, uptr->wait); /* try again */
return ((r == SCPE_STALL)? SCPE_OK: r); } /* !stall? report */
M[FE_CTYOUT] = 0; /* clear char */
apr_flg = apr_flg | APRF_CON; /* interrupt KS10 */
if ((r = sim_putchar_s (uptr->buf)) != SCPE_OK) { /* output; error? */
sim_activate (uptr, uptr->wait); /* try again */
return ((r == SCPE_STALL)? SCPE_OK: r); /* !stall? report */
}
M[FE_CTYOUT] = 0; /* clear char */
apr_flg = apr_flg | APRF_CON; /* interrupt KS10 */
return SCPE_OK;
}
@@ -132,16 +139,16 @@ t_stat fei_svc (UNIT *uptr)
{
int32 temp;
sim_activate (&fei_unit, fei_unit.wait); /* continue poll */
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */
if (temp & SCPE_BREAK) return SCPE_OK; /* ignore break */
sim_activate (&fei_unit, fei_unit.wait); /* continue poll */
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */
if (temp & SCPE_BREAK) return SCPE_OK; /* ignore break */
fei_unit.buf = temp & 0177;
fei_unit.pos = fei_unit.pos + 1;
M[FE_CTYIN] = fei_unit.buf | FE_CVALID; /* put char in mem */
apr_flg = apr_flg | APRF_CON; /* interrupt KS10 */
M[FE_CTYIN] = fei_unit.buf | FE_CVALID; /* put char in mem */
apr_flg = apr_flg | APRF_CON; /* interrupt KS10 */
return SCPE_OK;
}
/* Reset */
t_stat fe_reset (DEVICE *dptr)
@@ -149,7 +156,7 @@ t_stat fe_reset (DEVICE *dptr)
fei_unit.buf = feo_unit.buf = 0;
M[FE_CTYIN] = M[FE_CTYOUT] = 0;
apr_flg = apr_flg & ~(APRF_ITC | APRF_CON);
sim_activate (&fei_unit, fei_unit.wait); /* start input poll */
sim_activate (&fei_unit, fei_unit.wait); /* start input poll */
return SCPE_OK;
}
@@ -157,6 +164,6 @@ return SCPE_OK;
t_stat fe_stop_os (UNIT *uptr, int32 val, char *cptr, void *desc)
{
M[FE_SWITCH] = IOBA_RP; /* tell OS to stop */
M[FE_SWITCH] = IOBA_RP; /* tell OS to stop */
return SCPE_OK;
}

View File

@@ -1,6 +1,6 @@
/* pdp10_ksio.c: PDP-10 KS10 I/O subsystem simulator
Copyright (c) 1993-2004, Robert M Supnik
Copyright (c) 1993-2005, 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"),
@@ -19,25 +19,25 @@
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
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.
uba Unibus adapters
uba Unibus adapters
25-Jan-04 RMS Added stub floating address routine
12-Mar-03 RMS Added logical name support
10-Oct-02 RMS Revised for dynamic table generation
Added SHOW IOSPACE routine
29-Sep-02 RMS Added variable vector, central map support
25-Jan-02 RMS Revised for multiple DZ11's
06-Jan-02 RMS Revised enable/disable support
23-Sep-01 RMS New IO page address constants
07-Sep-01 RMS Revised device disable mechanism
25-Aug-01 RMS Enabled DZ11
21-Aug-01 RMS Updated DZ11 disable
01-Jun-01 RMS Updated DZ11 vectors
12-May-01 RMS Fixed typo
25-Jan-04 RMS Added stub floating address routine
12-Mar-03 RMS Added logical name support
10-Oct-02 RMS Revised for dynamic table generation
Added SHOW IOSPACE routine
29-Sep-02 RMS Added variable vector, central map support
25-Jan-02 RMS Revised for multiple DZ11's
06-Jan-02 RMS Revised enable/disable support
23-Sep-01 RMS New IO page address constants
07-Sep-01 RMS Revised device disable mechanism
25-Aug-01 RMS Enabled DZ11
21-Aug-01 RMS Updated DZ11 disable
01-Jun-01 RMS Updated DZ11 vectors
12-May-01 RMS Fixed typo
The KS10 uses the PDP-11 Unibus for its I/O, via adapters. While
nominally four adapters are supported, in practice only 1 and 3
@@ -67,39 +67,42 @@
Unibus adapter 3) which insert the Unibus adapter number into the
effective address.
*/
#include "pdp10_defs.h"
#include <setjmp.h>
#define XBA_MBZ 0400000 /* ba mbz */
#define eaRB (ea & ~1)
#define GETBYTE(ea,x) ((((ea) & 1)? (x) >> 8: (x)) & 0377)
#define XBA_MBZ 0400000 /* ba mbz */
#define eaRB (ea & ~1)
#define GETBYTE(ea,x) ((((ea) & 1)? (x) >> 8: (x)) & 0377)
#define UBNXM_FAIL(pa,op) \
n = iocmap[GET_IOUBA (pa)]; \
if (n >= 0) ubcs[n] = ubcs[n] | UBCS_TMO | UBCS_NXD; \
pager_word = PF_HARD | PF_VIRT | PF_IO | \
((op == WRITEB)? PF_BYTE: 0) | \
(TSTF (F_USR)? PF_USER: 0) | (pa); \
ABORT (PAGE_FAIL)
n = iocmap[GET_IOUBA (pa)]; \
if (n >= 0) ubcs[n] = ubcs[n] | UBCS_TMO | UBCS_NXD; \
pager_word = PF_HARD | PF_VIRT | PF_IO | \
((op == WRITEB)? PF_BYTE: 0) | \
(TSTF (F_USR)? PF_USER: 0) | (pa); \
ABORT (PAGE_FAIL)
/* Unibus adapter data */
int32 ubcs[UBANUM] = { 0 }; /* status registers */
int32 ubmap[UBANUM][UMAP_MEMSIZE] = { 0 }; /* Unibus maps */
int32 int_req = 0; /* interrupt requests */
int32 ubcs[UBANUM] = { 0 }; /* status registers */
int32 ubmap[UBANUM][UMAP_MEMSIZE] = { 0 }; /* Unibus maps */
int32 int_req = 0; /* interrupt requests */
/* Map IO controller numbers to Unibus adapters: -1 = non-existent */
static int iocmap[IO_N_UBA] = { /* map I/O ext to UBA # */
-1, 0, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
static int iocmap[IO_N_UBA] = { /* map I/O ext to UBA # */
-1, 0, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
static const int32 ubabr76[UBANUM] = {
INT_UB1 & (INT_IPL7 | INT_IPL6), INT_UB3 & (INT_IPL7 | INT_IPL6) };
INT_UB1 & (INT_IPL7 | INT_IPL6), INT_UB3 & (INT_IPL7 | INT_IPL6)
};
static const int32 ubabr54[UBANUM] = {
INT_UB1 & (INT_IPL5 | INT_IPL4), INT_UB3 & (INT_IPL5 | INT_IPL4) };
INT_UB1 & (INT_IPL5 | INT_IPL4), INT_UB3 & (INT_IPL5 | INT_IPL4)
};
static const int32 ubashf[4] = { 18, 26, 0, 8 };
extern d10 *M; /* main memory */
extern d10 *M; /* main memory */
extern d10 *ac_cur;
extern d10 pager_word;
extern int32 flags, pi_l2bit[8];
@@ -127,12 +130,12 @@ t_stat uba_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat uba_reset (DEVICE *dptr);
d10 ReadIO (a10 ea);
void WriteIO (a10 ea, d10 val, int32 mode);
/* Unibus adapter data structures
uba_dev UBA device descriptor
uba_unit UBA units
uba_reg UBA register list
uba_dev UBA device descriptor
uba_unit UBA units
uba_reg UBA register list
*/
DIB ubmp1_dib = { IOBA_UBMAP1, IOLN_UBMAP1, &ubmap_rd, &ubmap_wr, 0 };
@@ -144,93 +147,99 @@ DIB ubmn3_dib = { IOBA_UBMNT3, IOLN_UBMNT3, &rd_zro, &wr_nop, 0 };
DIB msys_dib = { 00100000, 1, &rd_zro, &wr_nop, 0 };
UNIT uba_unit[] = {
{ UDATA (NULL, UNIT_FIX, UMAP_MEMSIZE) },
{ UDATA (NULL, UNIT_FIX, UMAP_MEMSIZE) } };
{ UDATA (NULL, UNIT_FIX, UMAP_MEMSIZE) },
{ UDATA (NULL, UNIT_FIX, UMAP_MEMSIZE) }
};
REG uba_reg[] = {
{ ORDATA (INTREQ, int_req, 32), REG_RO },
{ ORDATA (UB1CS, ubcs[0], 18) },
{ ORDATA (UB3CS, ubcs[1], 18) },
{ NULL } };
{ ORDATA (INTREQ, int_req, 32), REG_RO },
{ ORDATA (UB1CS, ubcs[0], 18) },
{ ORDATA (UB3CS, ubcs[1], 18) },
{ NULL }
};
DEVICE uba_dev = {
"UBA", uba_unit, uba_reg, NULL,
UBANUM, 8, UMAP_ASIZE, 1, 8, 32,
&uba_ex, &uba_dep, &uba_reset,
NULL, NULL, NULL,
NULL, 0 };
"UBA", uba_unit, uba_reg, NULL,
UBANUM, 8, UMAP_ASIZE, 1, 8, 32,
&uba_ex, &uba_dep, &uba_reset,
NULL, NULL, NULL,
NULL, 0
};
/* PDP-11 I/O structures */
DIB *dib_tab[DIB_MAX]; /* run-time DIBs */
DIB *dib_tab[DIB_MAX]; /* run-time DIBs */
int32 (*int_ack[32])(void); /* int ack routines */
int32 (*int_ack[32])(void); /* int ack routines */
int32 int_vec[32]; /* int vectors */
int32 int_vec[32]; /* int vectors */
DIB *std_dib[] = { /* standard DIBs */
&ubmp1_dib,
&ubmp3_dib,
&ubcs1_dib,
&ubcs3_dib,
&ubmn1_dib,
&ubmn3_dib,
&msys_dib,
NULL };
/* IO 710 (DEC) TIOE - test I/O word, skip if zero
(ITS) IORDI - read word from Unibus 3
returns TRUE if skip, FALSE otherwise
DIB *std_dib[] = { /* standard DIBs */
&ubmp1_dib,
&ubmp3_dib,
&ubcs1_dib,
&ubcs3_dib,
&ubmn1_dib,
&ubmn3_dib,
&msys_dib,
NULL
};
/* IO 710 (DEC) TIOE - test I/O word, skip if zero
(ITS) IORDI - read word from Unibus 3
returns TRUE if skip, FALSE otherwise
*/
t_bool io710 (int32 ac, a10 ea)
{
d10 val;
if (ITS) AC(ac) = ReadIO (IO_UBA3 | ea); /* IORDI */
else { /* TIOE */
val = ReadIO (ea); /* read word */
if ((AC(ac) & val) == 0) return TRUE; }
if (ITS) AC(ac) = ReadIO (IO_UBA3 | ea); /* IORDI */
else { /* TIOE */
val = ReadIO (ea); /* read word */
if ((AC(ac) & val) == 0) return TRUE;
}
return FALSE;
}
/* IO 711 (DEC) TION - test I/O word, skip if non-zero
(ITS) IORDQ - read word from Unibus 1
returns TRUE if skip, FALSE otherwise
/* IO 711 (DEC) TION - test I/O word, skip if non-zero
(ITS) IORDQ - read word from Unibus 1
returns TRUE if skip, FALSE otherwise
*/
t_bool io711 (int32 ac, a10 ea)
{
d10 val;
if (ITS) AC(ac) = ReadIO (IO_UBA1 | ea); /* IORDQ */
else { /* TION */
val = ReadIO (ea); /* read word */
if ((AC(ac) & val) != 0) return TRUE; }
if (ITS) AC(ac) = ReadIO (IO_UBA1 | ea); /* IORDQ */
else { /* TION */
val = ReadIO (ea); /* read word */
if ((AC(ac) & val) != 0) return TRUE;
}
return FALSE;
}
/* IO 712 (DEC) RDIO - read I/O word, addr in ea
(ITS) IORD - read I/O word, addr in M[ea]
/* IO 712 (DEC) RDIO - read I/O word, addr in ea
(ITS) IORD - read I/O word, addr in M[ea]
*/
d10 io712 (a10 ea)
{
return ReadIO (ea); /* RDIO, IORD */
return ReadIO (ea); /* RDIO, IORD */
}
/* IO 713 (DEC) WRIO - write I/O word, addr in ea
(ITS) IOWR - write I/O word, addr in M[ea]
/* IO 713 (DEC) WRIO - write I/O word, addr in ea
(ITS) IOWR - write I/O word, addr in M[ea]
*/
void io713 (d10 val, a10 ea)
{
WriteIO (ea, val & 0177777, WRITE); /* WRIO, IOWR */
WriteIO (ea, val & 0177777, WRITE); /* WRIO, IOWR */
return;
}
/* IO 714 (DEC) BSIO - set bit in I/O address
(ITS) IOWRI - write word to Unibus 3
/* IO 714 (DEC) BSIO - set bit in I/O address
(ITS) IOWRI - write word to Unibus 3
*/
void io714 (d10 val, a10 ea)
@@ -238,16 +247,17 @@ void io714 (d10 val, a10 ea)
d10 temp;
val = val & 0177777;
if (ITS) WriteIO (IO_UBA3 | ea, val, WRITE); /* IOWRI */
if (ITS) WriteIO (IO_UBA3 | ea, val, WRITE); /* IOWRI */
else {
temp = ReadIO (ea); /* BSIO */
temp = temp | val;
WriteIO (ea, temp, WRITE); }
temp = ReadIO (ea); /* BSIO */
temp = temp | val;
WriteIO (ea, temp, WRITE);
}
return;
}
/* IO 715 (DEC) BCIO - clear bit in I/O address
(ITS) IOWRQ - write word to Unibus 1
/* IO 715 (DEC) BCIO - clear bit in I/O address
(ITS) IOWRQ - write word to Unibus 1
*/
void io715 (d10 val, a10 ea)
@@ -255,76 +265,81 @@ void io715 (d10 val, a10 ea)
d10 temp;
val = val & 0177777;
if (ITS) WriteIO (IO_UBA1 | ea, val, WRITE); /* IOWRQ */
if (ITS) WriteIO (IO_UBA1 | ea, val, WRITE); /* IOWRQ */
else {
temp = ReadIO (ea); /* BCIO */
temp = temp & ~val;
WriteIO (ea, temp, WRITE); }
temp = ReadIO (ea); /* BCIO */
temp = temp & ~val;
WriteIO (ea, temp, WRITE);
}
return;
}
/* IO 720 (DEC) TIOEB - test I/O byte, skip if zero
(ITS) IORDBI - read byte from Unibus 3
returns TRUE if skip, FALSE otherwise
/* IO 720 (DEC) TIOEB - test I/O byte, skip if zero
(ITS) IORDBI - read byte from Unibus 3
returns TRUE if skip, FALSE otherwise
*/
t_bool io720 (int32 ac, a10 ea)
{
d10 val;
if (ITS) { /* IORDBI */
val = ReadIO (IO_UBA3 | eaRB);
AC(ac) = GETBYTE (ea, val); }
else { /* TIOEB */
val = ReadIO (eaRB);
val = GETBYTE (ea, val);
if ((AC(ac) & val) == 0) return TRUE; }
if (ITS) { /* IORDBI */
val = ReadIO (IO_UBA3 | eaRB);
AC(ac) = GETBYTE (ea, val);
}
else { /* TIOEB */
val = ReadIO (eaRB);
val = GETBYTE (ea, val);
if ((AC(ac) & val) == 0) return TRUE;
}
return FALSE;
}
/* IO 721 (DEC) TIONB - test I/O word, skip if non-zero
(ITS) IORDBQ - read word from Unibus 1
returns TRUE if skip, FALSE otherwise
/* IO 721 (DEC) TIONB - test I/O word, skip if non-zero
(ITS) IORDBQ - read word from Unibus 1
returns TRUE if skip, FALSE otherwise
*/
t_bool io721 (int32 ac, a10 ea)
{
d10 val;
if (ITS) { /* IORDBQ */
val = ReadIO (IO_UBA1 | eaRB);
AC(ac) = GETBYTE (ea, val); }
else { /* TIONB */
val = ReadIO (eaRB);
val = GETBYTE (ea, val);
if ((AC(ac) & val) != 0) return TRUE; }
if (ITS) { /* IORDBQ */
val = ReadIO (IO_UBA1 | eaRB);
AC(ac) = GETBYTE (ea, val);
}
else { /* TIONB */
val = ReadIO (eaRB);
val = GETBYTE (ea, val);
if ((AC(ac) & val) != 0) return TRUE;
}
return FALSE;
}
/* IO 722 (DEC) RDIOB - read I/O byte, addr in ea
(ITS) IORDB - read I/O byte, addr in M[ea]
/* IO 722 (DEC) RDIOB - read I/O byte, addr in ea
(ITS) IORDB - read I/O byte, addr in M[ea]
*/
d10 io722 (a10 ea)
{
d10 val;
val = ReadIO (eaRB); /* RDIOB, IORDB */
val = ReadIO (eaRB); /* RDIOB, IORDB */
return GETBYTE (ea, val);
}
/* IO 723 (DEC) WRIOB - write I/O byte, addr in ea
(ITS) IOWRB - write I/O byte, addr in M[ea]
/* IO 723 (DEC) WRIOB - write I/O byte, addr in ea
(ITS) IOWRB - write I/O byte, addr in M[ea]
*/
void io723 (d10 val, a10 ea)
{
WriteIO (ea, val & 0377, WRITEB); /* WRIOB, IOWRB */
WriteIO (ea, val & 0377, WRITEB); /* WRIOB, IOWRB */
return;
}
/* IO 724 (DEC) BSIOB - set bit in I/O byte address
(ITS) IOWRBI - write byte to Unibus 3
/* IO 724 (DEC) BSIOB - set bit in I/O byte address
(ITS) IOWRBI - write byte to Unibus 3
*/
void io724 (d10 val, a10 ea)
@@ -332,17 +347,18 @@ void io724 (d10 val, a10 ea)
d10 temp;
val = val & 0377;
if (ITS) WriteIO (IO_UBA3 | ea, val, WRITEB); /* IOWRBI */
if (ITS) WriteIO (IO_UBA3 | ea, val, WRITEB); /* IOWRBI */
else {
temp = ReadIO (eaRB); /* BSIOB */
temp = GETBYTE (ea, temp);
temp = temp | val;
WriteIO (ea, temp, WRITEB); }
temp = ReadIO (eaRB); /* BSIOB */
temp = GETBYTE (ea, temp);
temp = temp | val;
WriteIO (ea, temp, WRITEB);
}
return;
}
/* IO 725 (DEC) BCIOB - clear bit in I/O byte address
(ITS) IOWRBQ - write byte to Unibus 1
/* IO 725 (DEC) BCIOB - clear bit in I/O byte address
(ITS) IOWRBQ - write byte to Unibus 1
*/
void io725 (d10 val, a10 ea)
@@ -350,15 +366,16 @@ void io725 (d10 val, a10 ea)
d10 temp;
val = val & 0377;
if (ITS) WriteIO (IO_UBA1 | ea, val, WRITEB); /* IOWRBQ */
if (ITS) WriteIO (IO_UBA1 | ea, val, WRITEB); /* IOWRBQ */
else {
temp = ReadIO (eaRB); /* BCIOB */
temp = GETBYTE (ea, temp);
temp = temp & ~val;
WriteIO (ea, temp, WRITEB); }
temp = ReadIO (eaRB); /* BCIOB */
temp = GETBYTE (ea, temp);
temp = temp & ~val;
WriteIO (ea, temp, WRITEB);
}
return;
}
/* Read and write I/O devices.
These routines are the linkage between the 64b world of the main
simulator and the 32b world of the device simulators.
@@ -371,11 +388,13 @@ int32 i, n, val;
DIB *dibp;
for (i = 0; dibp = dib_tab[i]; i++ ) {
if ((pa >= dibp->ba) &&
(pa < (dibp->ba + dibp->lnt))) {
dibp->rd (&val, pa, READ);
pi_eval ();
return ((d10) val); } }
if ((pa >= dibp->ba) &&
(pa < (dibp->ba + dibp->lnt))) {
dibp->rd (&val, pa, READ);
pi_eval ();
return ((d10) val);
}
}
UBNXM_FAIL (pa, READ);
}
@@ -386,23 +405,25 @@ int32 i, n;
DIB *dibp;
for (i = 0; dibp = dib_tab[i]; i++ ) {
if ((pa >= dibp->ba) &&
(pa < (dibp->ba + dibp->lnt))) {
dibp->wr ((int32) val, pa, mode);
pi_eval ();
return; } }
if ((pa >= dibp->ba) &&
(pa < (dibp->ba + dibp->lnt))) {
dibp->wr ((int32) val, pa, mode);
pi_eval ();
return;
}
}
UBNXM_FAIL (pa, mode);
}
/* Mapped read and write routines - used by standard Unibus devices on Unibus 1 */
a10 Map_Addr10 (a10 ba, int32 ub)
{
a10 pa10;
int32 vpn = PAG_GETVPN (ba >> 2); /* get PDP-10 page number */
int32 vpn = PAG_GETVPN (ba >> 2); /* get PDP-10 page number */
if ((vpn >= UMAP_MEMSIZE) || (ba & XBA_MBZ) ||
((ubmap[ub][vpn] & UMAP_VLD) == 0)) return -1; /* invalid map? */
((ubmap[ub][vpn] & UMAP_VLD) == 0)) return -1; /* invalid map? */
pa10 = (ubmap[ub][vpn] + PAG_GETOFF (ba >> 2)) & PAMASK;
return pa10;
}
@@ -413,13 +434,14 @@ uint32 lim;
a10 pa10;
lim = ba + bc;
for ( ; ba < lim; ba++) { /* by bytes */
pa10 = Map_Addr10 (ba, 1); /* map addr */
if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
return (lim - ba); } /* return bc */
*buf++ = (uint8) ((M[pa10] >> ubashf[ba & 3]) & 0377);
}
for ( ; ba < lim; ba++) { /* by bytes */
pa10 = Map_Addr10 (ba, 1); /* map addr */
if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
return (lim - ba); /* return bc */
}
*buf++ = (uint8) ((M[pa10] >> ubashf[ba & 3]) & 0377);
}
return 0;
}
@@ -428,15 +450,16 @@ int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf)
uint32 lim;
a10 pa10;
ba = ba & ~01; /* align start */
ba = ba & ~01; /* align start */
lim = ba + (bc & ~01);
for ( ; ba < lim; ba = ba + 2) { /* by words */
pa10 = Map_Addr10 (ba, 1); /* map addr */
if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
return (lim - ba); } /* return bc */
*buf++ = (uint16) ((M[pa10] >> ((ba & 2)? 0: 18)) & 0177777);
}
for ( ; ba < lim; ba = ba + 2) { /* by words */
pa10 = Map_Addr10 (ba, 1); /* map addr */
if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
return (lim - ba); /* return bc */
}
*buf++ = (uint16) ((M[pa10] >> ((ba & 2)? 0: 18)) & 0177777);
}
return 0;
}
@@ -444,16 +467,19 @@ int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf)
{
uint32 lim;
a10 pa10;
static d10 mask = 0377;
d10 mask;
lim = ba + bc;
for ( ; ba < lim; ba++) { /* by bytes */
pa10 = Map_Addr10 (ba, 1); /* map addr */
if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
return (lim - ba); } /* return bc */
M[pa10] = (M[pa10] & ~(mask << ubashf[ba & 3])) |
(((d10) *buf++) << ubashf[ba & 3]); }
for ( ; ba < lim; ba++) { /* by bytes */
pa10 = Map_Addr10 (ba, 1); /* map addr */
if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
return (lim - ba); /* return bc */
}
mask = 0377;
M[pa10] = (M[pa10] & ~(mask << ubashf[ba & 3])) |
(((d10) *buf++) << ubashf[ba & 3]);
}
return 0;
}
@@ -463,20 +489,21 @@ uint32 lim;
a10 pa10;
d10 val;
ba = ba & ~01; /* align start */
ba = ba & ~01; /* align start */
lim = ba + (bc & ~01);
for ( ; ba < lim; ba++) { /* by bytes */
pa10 = Map_Addr10 (ba, 1); /* map addr */
if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
return (lim - ba); } /* return bc */
val = *buf++; /* get data */
if (ba & 2) M[pa10] = (M[pa10] & 0777777600000) | val;
else M[pa10] = (M[pa10] & 0600000777777) | (val << 18);
}
for ( ; ba < lim; ba++) { /* by bytes */
pa10 = Map_Addr10 (ba, 1); /* map addr */
if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */
ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */
return (lim - ba); /* return bc */
}
val = *buf++; /* get data */
if (ba & 2) M[pa10] = (M[pa10] & 0777777600000) | val;
else M[pa10] = (M[pa10] & 0600000777777) | (val << 18);
}
return 0;
}
/* Evaluate Unibus priority interrupts */
int32 pi_ub_eval ()
@@ -484,10 +511,11 @@ int32 pi_ub_eval ()
int32 i, lvl;
for (i = lvl = 0; i < UBANUM; i++) {
if (int_req & ubabr76[i])
lvl = lvl | pi_l2bit[UBCS_GET_HI (ubcs[i])];
if (int_req & ubabr54[i])
lvl = lvl | pi_l2bit[UBCS_GET_LO (ubcs[i])]; }
if (int_req & ubabr76[i])
lvl = lvl | pi_l2bit[UBCS_GET_HI (ubcs[i])];
if (int_req & ubabr54[i])
lvl = lvl | pi_l2bit[UBCS_GET_LO (ubcs[i])];
}
return lvl;
}
@@ -495,7 +523,7 @@ return lvl;
Takes as input the request level calculated by pi_eval
If there is an interrupting Unibus device at that level, return its vector,
otherwise, returns 0
otherwise, returns 0
*/
int32 pi_ub_vec (int32 rlvl, int32 *uba)
@@ -503,19 +531,22 @@ int32 pi_ub_vec (int32 rlvl, int32 *uba)
int32 i, masked_irq;
for (i = masked_irq = 0; i < UBANUM; i++) {
if ((rlvl == UBCS_GET_HI (ubcs[i])) && /* req on hi level? */
(masked_irq = int_req & ubabr76[i])) break;
if ((rlvl == UBCS_GET_LO (ubcs[i])) && /* req on lo level? */
(masked_irq = int_req & ubabr54[i])) break; }
*uba = (i << 1) + 1; /* store uba # */
for (i = 0; (i < 32) && masked_irq; i++) { /* find hi pri req */
if ((masked_irq >> i) & 1) {
int_req = int_req & ~(1u << i); /* clear req */
if (int_ack[i]) return int_ack[i]();
return int_vec[i]; } } /* return vector */
if ((rlvl == UBCS_GET_HI (ubcs[i])) && /* req on hi level? */
(masked_irq = int_req & ubabr76[i])) break;
if ((rlvl == UBCS_GET_LO (ubcs[i])) && /* req on lo level? */
(masked_irq = int_req & ubabr54[i])) break;
}
*uba = (i << 1) + 1; /* store uba # */
for (i = 0; (i < 32) && masked_irq; i++) { /* find hi pri req */
if ((masked_irq >> i) & 1) {
int_req = int_req & ~(1u << i); /* clear req */
if (int_ack[i]) return int_ack[i]();
return int_vec[i]; /* return vector */
}
}
return 0;
}
/* Unibus adapter map routines */
t_stat ubmap_rd (int32 *val, int32 pa, int32 mode)
@@ -555,8 +586,9 @@ int32 n = iocmap[GET_IOUBA (pa)];
if (n < 0) ABORT (STOP_ILLIOC);
if (val & UBCS_INI) {
reset_all (5); /* start after UBA */
ubcs[n] = val & UBCS_DXF; }
reset_all (5); /* start after UBA */
ubcs[n] = val & UBCS_DXF;
}
else ubcs[n] = val & UBCS_RDW;
if (int_req & ubabr76[n]) ubcs[n] = ubcs[n] | UBCS_HI;
if (int_req & ubabr54[n]) ubcs[n] = ubcs[n] | UBCS_LO;
@@ -575,7 +607,9 @@ t_stat wr_nop (int32 val, int32 pa, int32 mode)
{
return SCPE_OK;
}
/* Simulator interface routines */
t_stat uba_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
{
int32 uba = uptr - uba_unit;
@@ -600,12 +634,13 @@ int32 i, uba;
int_req = 0;
for (uba = 0; uba < UBANUM; uba++) {
ubcs[uba] = 0;
for (i = 0; i < UMAP_MEMSIZE; i++) ubmap[uba][i] = 0; }
ubcs[uba] = 0;
for (i = 0; i < UMAP_MEMSIZE; i++) ubmap[uba][i] = 0;
}
pi_eval ();
return SCPE_OK;
}
/* Change device address */
t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc)
@@ -621,12 +656,12 @@ dptr = find_dev_from_unit (uptr);
if (dptr == NULL) return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL) return SCPE_IERR;
newba = (uint32) get_uint (cptr, 8, PAMASK, &r); /* get new */
newba = (uint32) get_uint (cptr, 8, PAMASK, &r); /* get new */
if ((r != SCPE_OK) || (newba == dibp->ba)) return r;
if (GET_IOUBA (newba) != GET_IOUBA (dibp->ba)) return SCPE_ARG;
if (newba % ((uint32) val)) return SCPE_ARG; /* check modulus */
if (newba % ((uint32) val)) return SCPE_ARG; /* check modulus */
if (GET_IOUBA (newba) != GET_IOUBA (dibp->ba)) return SCPE_ARG;
dibp->ba = newba; /* store */
dibp->ba = newba; /* store */
return SCPE_OK;
}
@@ -644,7 +679,7 @@ dibp = (DIB *) dptr->ctxt;
if ((dibp == NULL) || (dibp->ba <= IOPAGEBASE)) return SCPE_IERR;
fprintf (st, "address=%07o", dibp->ba);
if (dibp->lnt > 1)
fprintf (st, "-%07o", dibp->ba + dibp->lnt - 1);
fprintf (st, "-%07o", dibp->ba + dibp->lnt - 1);
return SCPE_OK;
}
@@ -688,11 +723,13 @@ vec = dibp->vec;
if (arg) numvec = arg;
else numvec = dibp->vnum;
if (vec == 0) fprintf (st, "no vector");
else { fprintf (st, "vector=%o", vec);
if (numvec > 1) fprintf (st, "-%o", vec + (4 * (numvec - 1))); }
else {
fprintf (st, "vector=%o", vec);
if (numvec > 1) fprintf (st, "-%o", vec + (4 * (numvec - 1)));
}
return SCPE_OK;
}
/* Test for conflict in device addresses */
t_bool dev_conflict (DIB *curr)
@@ -701,21 +738,23 @@ uint32 i, end;
DEVICE *dptr;
DIB *dibp;
end = curr->ba + curr->lnt - 1; /* get end */
for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */
dibp = (DIB *) dptr->ctxt; /* get DIB */
if ((dibp == NULL) || (dibp == curr) ||
(dptr->flags & DEV_DIS)) continue;
if (((curr->ba >= dibp->ba) && /* overlap start? */
(curr->ba < (dibp->ba + dibp->lnt))) ||
((end >= dibp->ba) && /* overlap end? */
(end < (dibp->ba + dibp->lnt)))) {
printf ("Device %s address conflict at %08o\n",
sim_dname (dptr), dibp->ba);
if (sim_log) fprintf (sim_log,
"Device %s address conflict at %08o\n",
sim_dname (dptr), dibp->ba);
return TRUE; } }
end = curr->ba + curr->lnt - 1; /* get end */
for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */
dibp = (DIB *) dptr->ctxt; /* get DIB */
if ((dibp == NULL) || (dibp == curr) ||
(dptr->flags & DEV_DIS)) continue;
if (((curr->ba >= dibp->ba) && /* overlap start? */
(curr->ba < (dibp->ba + dibp->lnt))) ||
((end >= dibp->ba) && /* overlap end? */
(end < (dibp->ba + dibp->lnt)))) {
printf ("Device %s address conflict at %08o\n",
sim_dname (dptr), dibp->ba);
if (sim_log) fprintf (sim_log,
"Device %s address conflict at %08o\n",
sim_dname (dptr), dibp->ba);
return TRUE;
}
}
return FALSE;
}
@@ -736,27 +775,31 @@ int32 i, j, k;
DEVICE *dptr;
DIB *dibp;
for (i = 0; i < 32; i++) { /* clear intr tables */
int_vec[i] = 0;
int_ack[i] = NULL; }
for (i = j = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */
dibp = (DIB *) dptr->ctxt; /* get DIB */
if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */
if (dibp->vnum > VEC_DEVMAX) return SCPE_IERR;
for (k = 0; k < dibp->vnum; k++) /* loop thru vec */
build_int_vec (dibp->vloc + k, /* add vector */
dibp->vec + (k * 4), dibp->ack[k]);
if (dibp->lnt != 0) { /* I/O addresses? */
dib_tab[j++] = dibp; /* add DIB to dib_tab */
if (j >= DIB_MAX) return SCPE_IERR; } /* too many? */
} /* end if enabled */
} /* end for */
for (i = 0; (dibp = std_dib[i]) != NULL; i++) { /* loop thru std */
dib_tab[j++] = dibp; /* add to dib_tab */
if (j >= DIB_MAX) return SCPE_IERR; } /* too many? */
dib_tab[j] = NULL; /* end with NULL */
for (i = 0; (dibp = dib_tab[i]) != NULL; i++) { /* test built dib_tab */
if (dev_conflict (dibp)) return SCPE_STOP; } /* for conflicts */
for (i = 0; i < 32; i++) { /* clear intr tables */
int_vec[i] = 0;
int_ack[i] = NULL;
}
for (i = j = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */
dibp = (DIB *) dptr->ctxt; /* get DIB */
if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */
if (dibp->vnum > VEC_DEVMAX) return SCPE_IERR;
for (k = 0; k < dibp->vnum; k++) /* loop thru vec */
build_int_vec (dibp->vloc + k, /* add vector */
dibp->vec + (k * 4), dibp->ack[k]);
if (dibp->lnt != 0) { /* I/O addresses? */
dib_tab[j++] = dibp; /* add DIB to dib_tab */
if (j >= DIB_MAX) return SCPE_IERR; /* too many? */
}
} /* end if enabled */
} /* end for */
for (i = 0; (dibp = std_dib[i]) != NULL; i++) { /* loop thru std */
dib_tab[j++] = dibp; /* add to dib_tab */
if (j >= DIB_MAX) return SCPE_IERR; /* too many? */
}
dib_tab[j] = NULL; /* end with NULL */
for (i = 0; (dibp = dib_tab[i]) != NULL; i++) { /* test built dib_tab */
if (dev_conflict (dibp)) return SCPE_STOP; /* for conflicts */
}
return SCPE_OK;
}
@@ -768,31 +811,35 @@ int32 i, j, done = 0;
DEVICE *dptr;
DIB *dibt;
build_dib_tab (); /* build table */
while (done == 0) { /* sort ascending */
done = 1; /* assume done */
for (i = 0; dib_tab[i + 1] != NULL; i++) { /* check table */
if (dib_tab[i]->ba > dib_tab[i + 1]->ba) { /* out of order? */
dibt = dib_tab[i]; /* interchange */
dib_tab[i] = dib_tab[i + 1];
dib_tab[i + 1] = dibt;
done = 0; } } /* not done */
} /* end while */
for (i = 0; dib_tab[i] != NULL; i++) { /* print table */
for (j = 0, dptr = NULL; sim_devices[j] != NULL; j++) {
if (((DIB*) sim_devices[j]->ctxt) == dib_tab[i]) {
dptr = sim_devices[j];
break; } }
fprintf (st, "%07o - %07o\t%s\n", dib_tab[i]->ba,
dib_tab[i]->ba + dib_tab[i]->lnt - 1,
dptr? sim_dname (dptr): "CPU");
}
build_dib_tab (); /* build table */
while (done == 0) { /* sort ascending */
done = 1; /* assume done */
for (i = 0; dib_tab[i + 1] != NULL; i++) { /* check table */
if (dib_tab[i]->ba > dib_tab[i + 1]->ba) { /* out of order? */
dibt = dib_tab[i]; /* interchange */
dib_tab[i] = dib_tab[i + 1];
dib_tab[i + 1] = dibt;
done = 0; /* not done */
}
}
} /* end while */
for (i = 0; dib_tab[i] != NULL; i++) { /* print table */
for (j = 0, dptr = NULL; sim_devices[j] != NULL; j++) {
if (((DIB*) sim_devices[j]->ctxt) == dib_tab[i]) {
dptr = sim_devices[j];
break;
}
}
fprintf (st, "%07o - %07o\t%s\n", dib_tab[i]->ba,
dib_tab[i]->ba + dib_tab[i]->lnt - 1,
dptr? sim_dname (dptr): "CPU");
}
return SCPE_OK;
}
/* Stub auto-configure */
t_stat auto_config (uint32 rank, uint32 num)
t_stat auto_config (char *name, int32 num)
{
return SCPE_OK;
}

View File

@@ -19,145 +19,144 @@
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
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.
lp20 line printer
lp20 line printer
18-Mar-05 RMS Added attached test to detach routine
29-Dec-03 RMS Fixed bug in scheduling
25-Apr-03 RMS Revised for extended file support
29-Sep-02 RMS Added variable vector support
Modified to use common Unibus routines
New data structures
30-May-02 RMS Widened POS to 32b
06-Jan-02 RMS Added enable/disable support
30-Nov-01 RMS Added extended SET/SHOW support
04-Sep-05 RMS Fixed missing return (found by Peter Schorn)
07-Jul-05 RMS Removed extraneous externs
18-Mar-05 RMS Added attached test to detach routine
29-Dec-03 RMS Fixed bug in scheduling
25-Apr-03 RMS Revised for extended file support
29-Sep-02 RMS Added variable vector support
Modified to use common Unibus routines
New data structures
30-May-02 RMS Widened POS to 32b
06-Jan-02 RMS Added enable/disable support
30-Nov-01 RMS Added extended SET/SHOW support
*/
#include "pdp10_defs.h"
#define UNIT_DUMMY (1 << UNIT_V_UF)
#define LP_WIDTH 132 /* printer width */
#define UNIT_DUMMY (1 << UNIT_V_UF)
#define LP_WIDTH 132 /* printer width */
/* DAVFU RAM */
#define DV_SIZE 143 /* DAVFU size */
#define DV_DMASK 077 /* data mask per byte */
#define DV_TOF 0 /* top of form channel */
#define DV_MAX 11 /* max channel number */
#define DV_SIZE 143 /* DAVFU size */
#define DV_DMASK 077 /* data mask per byte */
#define DV_TOF 0 /* top of form channel */
#define DV_MAX 11 /* max channel number */
/* Translation RAM */
#define TX_SIZE 256 /* translation RAM */
#define TX_AMASK (TX_SIZE - 1)
#define TX_DMASK 07777
#define TX_V_FL 8 /* flags */
#define TX_M_FL 017
/* define TX_INTR 04000 /* interrupt */
#define TX_DELH 02000 /* delimiter */
/* define TX_XLAT 01000 /* translate */
/* define TX_DVFU 00400 /* DAVFU */
#define TX_SLEW 00020 /* chan vs slew */
#define TX_VMASK 00017 /* spacing mask */
#define TX_CHR 0 /* states: pr char */
#define TX_RAM 1 /* pr translation */
#define TX_DVU 2 /* DAVFU action */
#define TX_INT 3 /* interrupt */
#define TX_GETFL(x) (((x) >> TX_V_FL) & TX_M_FL)
#define TX_SIZE 256 /* translation RAM */
#define TX_AMASK (TX_SIZE - 1)
#define TX_DMASK 07777
#define TX_V_FL 8 /* flags */
#define TX_M_FL 017
/* define TX_INTR 04000 /* interrupt */
#define TX_DELH 02000 /* delimiter */
/* define TX_XLAT 01000 /* translate */
/* define TX_DVFU 00400 /* DAVFU */
#define TX_SLEW 00020 /* chan vs slew */
#define TX_VMASK 00017 /* spacing mask */
#define TX_CHR 0 /* states: pr char */
#define TX_RAM 1 /* pr translation */
#define TX_DVU 2 /* DAVFU action */
#define TX_INT 3 /* interrupt */
#define TX_GETFL(x) (((x) >> TX_V_FL) & TX_M_FL)
/* LPCSRA (765400) */
#define CSA_GO 0000001 /* go */
#define CSA_PAR 0000002 /* parity enable NI */
#define CSA_V_FNC 2 /* function */
#define CSA_M_FNC 03
#define FNC_PR 0 /* print */
#define FNC_TST 1 /* test */
#define FNC_DVU 2 /* load DAVFU */
#define FNC_RAM 3 /* load translation RAM */
#define FNC_INTERNAL 1 /* internal function */
#define CSA_FNC (CSA_M_FNC << CSA_V_FNC)
#define CSA_V_UAE 4 /* Unibus addr extension */
#define CSA_UAE (03 << CSA_V_UAE)
#define CSA_IE 0000100 /* interrupt enable */
#define CSA_DONE 0000200 /* done */
#define CSA_INIT 0000400 /* init */
#define CSA_ECLR 0001000 /* clear errors */
#define CSA_DELH 0002000 /* delimiter hold */
#define CSA_ONL 0004000 /* online */
#define CSA_DVON 0010000 /* DAVFU online */
#define CSA_UNDF 0020000 /* undefined char */
#define CSA_PZRO 0040000 /* page counter zero */
#define CSA_ERR 0100000 /* error */
#define CSA_RW (CSA_DELH | CSA_IE | CSA_UAE | CSA_FNC | CSA_PAR | CSA_GO)
#define CSA_MBZ (CSA_ECLR | CSA_INIT)
#define CSA_GETUAE(x) (((x) & CSA_UAE) << (16 - CSA_V_UAE))
#define CSA_GETFNC(x) (((x) >> CSA_V_FNC) & CSA_M_FNC)
#define CSA_GO 0000001 /* go */
#define CSA_PAR 0000002 /* parity enable NI */
#define CSA_V_FNC 2 /* function */
#define CSA_M_FNC 03
#define FNC_PR 0 /* print */
#define FNC_TST 1 /* test */
#define FNC_DVU 2 /* load DAVFU */
#define FNC_RAM 3 /* load translation RAM */
#define FNC_INTERNAL 1 /* internal function */
#define CSA_FNC (CSA_M_FNC << CSA_V_FNC)
#define CSA_V_UAE 4 /* Unibus addr extension */
#define CSA_UAE (03 << CSA_V_UAE)
#define CSA_IE 0000100 /* interrupt enable */
#define CSA_DONE 0000200 /* done */
#define CSA_INIT 0000400 /* init */
#define CSA_ECLR 0001000 /* clear errors */
#define CSA_DELH 0002000 /* delimiter hold */
#define CSA_ONL 0004000 /* online */
#define CSA_DVON 0010000 /* DAVFU online */
#define CSA_UNDF 0020000 /* undefined char */
#define CSA_PZRO 0040000 /* page counter zero */
#define CSA_ERR 0100000 /* error */
#define CSA_RW (CSA_DELH | CSA_IE | CSA_UAE | CSA_FNC | CSA_PAR | CSA_GO)
#define CSA_MBZ (CSA_ECLR | CSA_INIT)
#define CSA_GETUAE(x) (((x) & CSA_UAE) << (16 - CSA_V_UAE))
#define CSA_GETFNC(x) (((x) >> CSA_V_FNC) & CSA_M_FNC)
/* LPCSRB (765402) */
#define CSB_GOE 0000001 /* go error */
#define CSB_DTE 0000002 /* DEM timing error NI */
#define CSB_MTE 0000004 /* MSYN error (Ubus timeout) */
#define CSB_RPE 0000010 /* RAM parity error NI */
#define CSB_MPE 0000020 /* MEM parity error NI */
#define CSB_LPE 0000040 /* LPT parity error NI */
#define CSB_DVOF 0000100 /* DAVFU not ready */
#define CSB_OFFL 0000200 /* offline */
#define CSB_TEST 0003400 /* test mode */
#define CSB_OVFU 0004000 /* optical VFU NI */
#define CSB_PBIT 0010000 /* data parity bit NI */
#define CSB_NRDY 0020000 /* printer error NI */
#define CSB_LA180 0040000 /* LA180 printer NI */
#define CSB_VLD 0100000 /* valid data NI */
#define CSB_ECLR (CSB_GOE | CSB_DTE | CSB_MTE | CSB_RPE | CSB_MPE | CSB_LPE)
#define CSB_ERR (CSB_ECLR | CSB_DVOF | CSB_OFFL)
#define CSB_RW CSB_TEST
#define CSB_MBZ (CSB_DTE | CSB_RPE | CSB_MPE | CSB_LPE | CSB_OVFU |\
CSB_PBIT | CSB_NRDY | CSB_LA180 | CSB_VLD)
#define CSB_GOE 0000001 /* go error */
#define CSB_DTE 0000002 /* DEM timing error NI */
#define CSB_MTE 0000004 /* MSYN error (Ubus timeout) */
#define CSB_RPE 0000010 /* RAM parity error NI */
#define CSB_MPE 0000020 /* MEM parity error NI */
#define CSB_LPE 0000040 /* LPT parity error NI */
#define CSB_DVOF 0000100 /* DAVFU not ready */
#define CSB_OFFL 0000200 /* offline */
#define CSB_TEST 0003400 /* test mode */
#define CSB_OVFU 0004000 /* optical VFU NI */
#define CSB_PBIT 0010000 /* data parity bit NI */
#define CSB_NRDY 0020000 /* printer error NI */
#define CSB_LA180 0040000 /* LA180 printer NI */
#define CSB_VLD 0100000 /* valid data NI */
#define CSB_ECLR (CSB_GOE | CSB_DTE | CSB_MTE | CSB_RPE | CSB_MPE | CSB_LPE)
#define CSB_ERR (CSB_ECLR | CSB_DVOF | CSB_OFFL)
#define CSB_RW CSB_TEST
#define CSB_MBZ (CSB_DTE | CSB_RPE | CSB_MPE | CSB_LPE | CSB_OVFU |\
CSB_PBIT | CSB_NRDY | CSB_LA180 | CSB_VLD)
/* LPBA (765404) */
/* LPBC (765506) */
#define BC_MASK 0007777 /* <15:12> MBZ */
#define BC_MASK 0007777 /* <15:12> MBZ */
/* LPPAGC (765510) */
#define PAGC_MASK 0007777 /* <15:12> MBZ */
#define PAGC_MASK 0007777 /* <15:12> MBZ */
/* LPRDAT (765512) */
#define RDAT_MASK 0007777 /* <15:12> MBZ */
#define RDAT_MASK 0007777 /* <15:12> MBZ */
/* LPCOLC/LPCBUF (765514) */
/* LPCSUM/LPPDAT (765516) */
extern d10 *M; /* main memory */
extern int32 int_req;
extern int32 int_vec[32];
extern int32 ubcs[UBANUM]; /* UBA csr */
extern int32 ubmap[UBANUM][UMAP_MEMSIZE]; /* UBA map */
int32 lpcsa = 0; /* control/status A */
int32 lpcsb = 0; /* control/status B */
int32 lpba = 0; /* bus address */
int32 lpbc = 0; /* byte count */
int32 lppagc = 0; /* page count */
int32 lprdat = 0; /* RAM data */
int32 lpcbuf = 0; /* character buffer */
int32 lpcolc = 0; /* column count */
int32 lppdat = 0; /* printer data */
int32 lpcsum = 0; /* checksum */
int32 dvptr = 0; /* davfu pointer */
int32 dvlnt = 0; /* davfu length */
int32 lp20_irq = 0; /* int request */
int32 lp20_stopioe = 0; /* stop on error */
int16 txram[TX_SIZE] = { 0 }; /* translation RAM */
int16 davfu[DV_SIZE] = { 0 }; /* DAVFU */
extern d10 *M; /* main memory */
extern int32 int_req;
int32 lpcsa = 0; /* control/status A */
int32 lpcsb = 0; /* control/status B */
int32 lpba = 0; /* bus address */
int32 lpbc = 0; /* byte count */
int32 lppagc = 0; /* page count */
int32 lprdat = 0; /* RAM data */
int32 lpcbuf = 0; /* character buffer */
int32 lpcolc = 0; /* column count */
int32 lppdat = 0; /* printer data */
int32 lpcsum = 0; /* checksum */
int32 dvptr = 0; /* davfu pointer */
int32 dvlnt = 0; /* davfu length */
int32 lp20_irq = 0; /* int request */
int32 lp20_stopioe = 0; /* stop on error */
int16 txram[TX_SIZE] = { 0 }; /* translation RAM */
int16 davfu[DV_SIZE] = { 0 }; /* DAVFU */
DEVICE lp20_dev;
t_stat lp20_rd (int32 *data, int32 pa, int32 access);
@@ -175,285 +174,332 @@ void update_lpcs (int32 flg);
/* LP data structures
lp20_dev LPT device descriptor
lp20_unit LPT unit descriptor
lp20_reg LPT register list
lp20_dev LPT device descriptor
lp20_unit LPT unit descriptor
lp20_reg LPT register list
*/
DIB lp20_dib = { IOBA_LP20, IOLN_LP20, &lp20_rd, &lp20_wr,
1, IVCL (LP20), VEC_LP20, { &lp20_inta } };
DIB lp20_dib = {
IOBA_LP20, IOLN_LP20, &lp20_rd, &lp20_wr,
1, IVCL (LP20), VEC_LP20, { &lp20_inta }
};
UNIT lp20_unit = {
UDATA (&lp20_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT };
UDATA (&lp20_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT
};
REG lp20_reg[] = {
{ ORDATA (LPCSA, lpcsa, 16) },
{ ORDATA (LPCSB, lpcsb, 16) },
{ ORDATA (LPBA, lpba, 16) },
{ ORDATA (LPBC, lpbc, 12) },
{ ORDATA (LPPAGC, lppagc, 12) },
{ ORDATA (LPRDAT, lprdat, 12) },
{ ORDATA (LPCBUF, lpcbuf, 8) },
{ ORDATA (LPCOLC, lpcolc, 8) },
{ ORDATA (LPPDAT, lppdat, 8) },
{ ORDATA (LPCSUM, lpcsum, 8) },
{ ORDATA (DVPTR, dvptr, 7) },
{ ORDATA (DVLNT, dvlnt, 7), REG_RO + REG_NZ },
{ FLDATA (INT, int_req, INT_V_LP20) },
{ FLDATA (IRQ, lp20_irq, 0) },
{ FLDATA (ERR, lpcsa, CSR_V_ERR) },
{ FLDATA (DONE, lpcsa, CSR_V_DONE) },
{ FLDATA (IE, lpcsa, CSR_V_IE) },
{ DRDATA (POS, lp20_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, lp20_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, lp20_stopioe, 0) },
{ BRDATA (TXRAM, txram, 8, 12, TX_SIZE) },
{ BRDATA (DAVFU, davfu, 8, 12, DV_SIZE) },
{ ORDATA (DEVADDR, lp20_dib.ba, 32), REG_HRO },
{ ORDATA (DEVVEC, lp20_dib.vec, 16), REG_HRO },
{ NULL } };
{ ORDATA (LPCSA, lpcsa, 16) },
{ ORDATA (LPCSB, lpcsb, 16) },
{ ORDATA (LPBA, lpba, 16) },
{ ORDATA (LPBC, lpbc, 12) },
{ ORDATA (LPPAGC, lppagc, 12) },
{ ORDATA (LPRDAT, lprdat, 12) },
{ ORDATA (LPCBUF, lpcbuf, 8) },
{ ORDATA (LPCOLC, lpcolc, 8) },
{ ORDATA (LPPDAT, lppdat, 8) },
{ ORDATA (LPCSUM, lpcsum, 8) },
{ ORDATA (DVPTR, dvptr, 7) },
{ ORDATA (DVLNT, dvlnt, 7), REG_RO + REG_NZ },
{ FLDATA (INT, int_req, INT_V_LP20) },
{ FLDATA (IRQ, lp20_irq, 0) },
{ FLDATA (ERR, lpcsa, CSR_V_ERR) },
{ FLDATA (DONE, lpcsa, CSR_V_DONE) },
{ FLDATA (IE, lpcsa, CSR_V_IE) },
{ DRDATA (POS, lp20_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, lp20_unit.wait, 24), PV_LEFT },
{ FLDATA (STOP_IOE, lp20_stopioe, 0) },
{ BRDATA (TXRAM, txram, 8, 12, TX_SIZE) },
{ BRDATA (DAVFU, davfu, 8, 12, DV_SIZE) },
{ ORDATA (DEVADDR, lp20_dib.ba, 32), REG_HRO },
{ ORDATA (DEVVEC, lp20_dib.vec, 16), REG_HRO },
{ NULL }
};
MTAB lp20_mod[] = {
{ UNIT_DUMMY, 0, NULL, "VFUCLEAR", &lp20_clear_vfu },
{ MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS",
&set_addr, &show_addr, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",
&set_vec, &show_vec, NULL },
{ 0 } };
{ UNIT_DUMMY, 0, NULL, "VFUCLEAR", &lp20_clear_vfu },
{ MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS",
&set_addr, &show_addr, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR",
&set_vec, &show_vec, NULL },
{ 0 }
};
DEVICE lp20_dev = {
"LP20", &lp20_unit, lp20_reg, lp20_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &lp20_reset,
NULL, &lp20_attach, &lp20_detach,
&lp20_dib, DEV_DISABLE | DEV_UBUS };
"LP20", &lp20_unit, lp20_reg, lp20_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &lp20_reset,
NULL, &lp20_attach, &lp20_detach,
&lp20_dib, DEV_DISABLE | DEV_UBUS
};
/* Line printer routines
lp20_rd I/O page read
lp20_wr I/O page write
lp20_svc process event (printer ready)
lp20_reset process reset
lp20_attach process attach
lp20_detach process detach
lp20_rd I/O page read
lp20_wr I/O page write
lp20_svc process event (printer ready)
lp20_reset process reset
lp20_attach process attach
lp20_detach process detach
*/
t_stat lp20_rd (int32 *data, int32 pa, int32 access)
{
update_lpcs (0); /* update csr's */
switch ((pa >> 1) & 07) { /* case on PA<3:1> */
case 00: /* LPCSA */
*data = lpcsa = lpcsa & ~CSA_MBZ;
break;
case 01: /* LPCSB */
*data = lpcsb = lpcsb & ~CSB_MBZ;
break;
case 02: /* LPBA */
*data = lpba;
break;
case 03: /* LPBC */
*data = lpbc = lpbc & BC_MASK;
break;
case 04: /* LPPAGC */
*data = lppagc = lppagc & PAGC_MASK;
break;
case 05: /* LPRDAT */
*data = lprdat = lprdat & RDAT_MASK;
break;
case 06: /* LPCOLC/LPCBUF */
*data = (lpcolc << 8) | lpcbuf;
break;
case 07: /* LPCSUM/LPPDAT */
*data = (lpcsum << 8) | lppdat;
break; } /* end case PA */
update_lpcs (0); /* update csr's */
switch ((pa >> 1) & 07) { /* case on PA<3:1> */
case 00: /* LPCSA */
*data = lpcsa = lpcsa & ~CSA_MBZ;
break;
case 01: /* LPCSB */
*data = lpcsb = lpcsb & ~CSB_MBZ;
break;
case 02: /* LPBA */
*data = lpba;
break;
case 03: /* LPBC */
*data = lpbc = lpbc & BC_MASK;
break;
case 04: /* LPPAGC */
*data = lppagc = lppagc & PAGC_MASK;
break;
case 05: /* LPRDAT */
*data = lprdat = lprdat & RDAT_MASK;
break;
case 06: /* LPCOLC/LPCBUF */
*data = (lpcolc << 8) | lpcbuf;
break;
case 07: /* LPCSUM/LPPDAT */
*data = (lpcsum << 8) | lppdat;
break;
} /* end case PA */
return SCPE_OK;
}
t_stat lp20_wr (int32 data, int32 pa, int32 access)
{
update_lpcs (0); /* update csr's */
switch ((pa >> 1) & 07) { /* case on PA<3:1> */
case 00: /* LPCSA */
if (access == WRITEB) data = (pa & 1)?
(lpcsa & 0377) | (data << 8): (lpcsa & ~0377) | data;
if (data & CSA_ECLR) { /* error clear? */
lpcsa = (lpcsa | CSA_DONE) & ~CSA_GO; /* set done, clr go */
lpcsb = lpcsb & ~CSB_ECLR; /* clear err */
sim_cancel (&lp20_unit); } /* cancel I/O */
if (data & CSA_INIT) lp20_reset (&lp20_dev); /* init? */
if (data & CSA_GO) { /* go set? */
if ((lpcsa & CSA_GO) == 0) { /* not set before? */
if (lpcsb & CSB_ERR) lpcsb = lpcsb | CSB_GOE;
lpcsum = 0; /* clear checksum */
sim_activate (&lp20_unit, lp20_unit.wait); } }
else sim_cancel (&lp20_unit); /* go clr, stop DMA */
lpcsa = (lpcsa & ~CSA_RW) | (data & CSA_RW);
break;
case 01: /* LPCSB */
break; /* ignore writes to TEST */
case 02: /* LPBA */
if (access == WRITEB) data = (pa & 1)?
(lpba & 0377) | (data << 8): (lpba & ~0377) | data;
lpba = data;
break;
case 03: /* LPBC */
if (access == WRITEB) data = (pa & 1)?
(lpbc & 0377) | (data << 8): (lpbc & ~0377) | data;
lpbc = data & BC_MASK;
lpcsa = lpcsa & ~CSA_DONE;
break;
case 04: /* LPPAGC */
if (access == WRITEB) data = (pa & 1)?
(lppagc & 0377) | (data << 8): (lppagc & ~0377) | data;
lppagc = data & PAGC_MASK;
break;
case 05: /* LPRDAT */
if (access == WRITEB) data = (pa & 1)?
(lprdat & 0377) | (data << 8): (lprdat & ~0377) | data;
lprdat = data & RDAT_MASK;
txram[lpcbuf & TX_AMASK] = lprdat; /* load RAM */
break;
case 06: /* LPCOLC/LPCBUF */
if ((access == WRITEB) && (pa & 1)) /* odd byte */
lpcolc = data & 0377;
else {
lpcbuf = data & 0377; /* even byte, word */
if (access == WRITE) lpcolc = (data >> 8) & 0377; }
break;
case 07: /* LPCSUM/LPPDAT */
break; } /* read only */
update_lpcs (0); /* update csr's */
switch ((pa >> 1) & 07) { /* case on PA<3:1> */
case 00: /* LPCSA */
if (access == WRITEB) data = (pa & 1)?
(lpcsa & 0377) | (data << 8): (lpcsa & ~0377) | data;
if (data & CSA_ECLR) { /* error clear? */
lpcsa = (lpcsa | CSA_DONE) & ~CSA_GO; /* set done, clr go */
lpcsb = lpcsb & ~CSB_ECLR; /* clear err */
sim_cancel (&lp20_unit); /* cancel I/O */
}
if (data & CSA_INIT) lp20_reset (&lp20_dev); /* init? */
if (data & CSA_GO) { /* go set? */
if ((lpcsa & CSA_GO) == 0) { /* not set before? */
if (lpcsb & CSB_ERR) lpcsb = lpcsb | CSB_GOE;
lpcsum = 0; /* clear checksum */
sim_activate (&lp20_unit, lp20_unit.wait);
}
}
else sim_cancel (&lp20_unit); /* go clr, stop DMA */
lpcsa = (lpcsa & ~CSA_RW) | (data & CSA_RW);
break;
case 01: /* LPCSB */
break; /* ignore writes to TEST */
case 02: /* LPBA */
if (access == WRITEB) data = (pa & 1)?
(lpba & 0377) | (data << 8): (lpba & ~0377) | data;
lpba = data;
break;
case 03: /* LPBC */
if (access == WRITEB) data = (pa & 1)?
(lpbc & 0377) | (data << 8): (lpbc & ~0377) | data;
lpbc = data & BC_MASK;
lpcsa = lpcsa & ~CSA_DONE;
break;
case 04: /* LPPAGC */
if (access == WRITEB) data = (pa & 1)?
(lppagc & 0377) | (data << 8): (lppagc & ~0377) | data;
lppagc = data & PAGC_MASK;
break;
case 05: /* LPRDAT */
if (access == WRITEB) data = (pa & 1)?
(lprdat & 0377) | (data << 8): (lprdat & ~0377) | data;
lprdat = data & RDAT_MASK;
txram[lpcbuf & TX_AMASK] = lprdat; /* load RAM */
break;
case 06: /* LPCOLC/LPCBUF */
if ((access == WRITEB) && (pa & 1)) /* odd byte */
lpcolc = data & 0377;
else {
lpcbuf = data & 0377; /* even byte, word */
if (access == WRITE) lpcolc = (data >> 8) & 0377;
}
break;
case 07: /* LPCSUM/LPPDAT */
break; /* read only */
} /* end case PA */
update_lpcs (0);
return SCPE_OK;
}
/* Line printer service
The translation RAM case table is derived from the LP20 spec and
verified against the LP20 RAM simulator in TOPS10 7.04 LPTSPL.
The equations are:
flags := inter, delim, xlate, paper, delim_hold (from CSRA)
actions : = print_input, print_xlate, davfu_action, interrupt
flags := inter, delim, xlate, paper, delim_hold (from CSRA)
actions : = print_input, print_xlate, davfu_action, interrupt
if (inter) {
if (!xlate || delim || delim_hold) interrupt;
else if (paper) davfu_action;
else print_xlate; }
else if (paper) {
if (xlate || delim || delim_hold) davfu_action;
else print_input; }
else {
if (xlate || delim || delim_hold) print_xlate;
else print_input; }
if (inter) {
if (!xlate || delim || delim_hold) interrupt;
else if (paper) davfu_action;
else print_xlate;
}
else if (paper) {
if (xlate || delim || delim_hold) davfu_action;
else print_input;
}
else {
if (xlate || delim || delim_hold) print_xlate;
else print_input;
}
*/
t_stat lp20_svc (UNIT *uptr)
{
int32 fnc, i, tbc, temp, txst;
int32 dvld = -2; /* must be even */
int32 err = 0;
int32 dvld = -2; /* must be even */
uint16 wd10;
t_bool cont;
a10 ba;
static const uint32 txcase[32] = {
TX_CHR, TX_RAM, TX_CHR, TX_DVU, TX_RAM, TX_RAM, TX_DVU, TX_DVU,
TX_RAM, TX_RAM, TX_DVU, TX_DVU, TX_RAM, TX_RAM, TX_DVU, TX_DVU,
TX_INT, TX_INT, TX_INT, TX_INT, TX_RAM, TX_INT, TX_DVU, TX_INT,
TX_INT, TX_INT, TX_INT, TX_INT, TX_INT, TX_INT, TX_INT, TX_INT };
TX_CHR, TX_RAM, TX_CHR, TX_DVU, TX_RAM, TX_RAM, TX_DVU, TX_DVU,
TX_RAM, TX_RAM, TX_DVU, TX_DVU, TX_RAM, TX_RAM, TX_DVU, TX_DVU,
TX_INT, TX_INT, TX_INT, TX_INT, TX_RAM, TX_INT, TX_DVU, TX_INT,
TX_INT, TX_INT, TX_INT, TX_INT, TX_INT, TX_INT, TX_INT, TX_INT
};
lpcsa = lpcsa & ~CSA_GO;
ba = CSA_GETUAE (lpcsa) | lpba;
fnc = CSA_GETFNC (lpcsa);
tbc = 010000 - lpbc;
if (((fnc & FNC_INTERNAL) == 0) && ((lp20_unit.flags & UNIT_ATT) == 0)) {
update_lpcs (CSA_ERR);
IORETURN (lp20_stopioe, SCPE_UNATT); }
update_lpcs (CSA_ERR);
return IORETURN (lp20_stopioe, SCPE_UNATT);
}
if ((fnc == FNC_PR) && (dvlnt == 0)) {
update_lpcs (CSA_ERR);
return SCPE_OK; }
update_lpcs (CSA_ERR);
return SCPE_OK;
}
for (i = 0, cont = TRUE; (i < tbc) && cont; ba++, i++) {
if (Map_ReadW (ba, 2, &wd10)) { /* get word, err? */
lpcsb = lpcsb | CSB_MTE; /* set NXM error */
update_lpcs (CSA_ERR); /* set done */
break; }
lpcbuf = (wd10 >> ((ba & 1)? 8: 0)) & 0377; /* get character */
lpcsum = (lpcsum + lpcbuf) & 0377; /* add into checksum */
switch (fnc) { /* switch on function */
if (Map_ReadW (ba, 2, &wd10)) { /* get word, err? */
lpcsb = lpcsb | CSB_MTE; /* set NXM error */
update_lpcs (CSA_ERR); /* set done */
break;
}
lpcbuf = (wd10 >> ((ba & 1)? 8: 0)) & 0377; /* get character */
lpcsum = (lpcsum + lpcbuf) & 0377; /* add into checksum */
switch (fnc) { /* switch on function */
/* Translation RAM load */
case FNC_RAM: /* RAM load */
txram[(i >> 1) & TX_AMASK] = wd10 & TX_DMASK;
break;
case FNC_RAM: /* RAM load */
txram[(i >> 1) & TX_AMASK] = wd10 & TX_DMASK;
break;
/* DAVFU RAM load. The DAVFU RAM is actually loaded in bytes, delimited by
a start (354 to 356) and stop (357) byte pair. If the number of bytes
loaded is odd, or no bytes are loaded, the DAVFU is invalid.
*/
case FNC_DVU: /* DVU load */
if ((lpcbuf >= 0354) && (lpcbuf <= 0356)) /* start DVU load? */
dvld = dvlnt = 0; /* reset lnt */
else if (lpcbuf == 0357) { /* stop DVU load? */
dvptr = 0; /* reset ptr */
if (dvld & 1) dvlnt = 0; } /* if odd, invalid */
else if (dvld == 0) { /* even state? */
temp = lpcbuf & DV_DMASK;
dvld = 1; }
else if (dvld == 1) { /* odd state? */
if (dvlnt < DV_SIZE) davfu[dvlnt++] =
temp | ((lpcbuf & DV_DMASK) << 6);
dvld = 0; }
break;
case FNC_DVU: /* DVU load */
if ((lpcbuf >= 0354) && (lpcbuf <= 0356)) /* start DVU load? */
dvld = dvlnt = 0; /* reset lnt */
else if (lpcbuf == 0357) { /* stop DVU load? */
dvptr = 0; /* reset ptr */
if (dvld & 1) dvlnt = 0; /* if odd, invalid */
}
else if (dvld == 0) { /* even state? */
temp = lpcbuf & DV_DMASK;
dvld = 1;
}
else if (dvld == 1) { /* odd state? */
if (dvlnt < DV_SIZE) davfu[dvlnt++] =
temp | ((lpcbuf & DV_DMASK) << 6);
dvld = 0;
}
break;
/* Print characters */
case FNC_PR: /* print */
lprdat = txram[lpcbuf]; /* get RAM char */
txst = (TX_GETFL (lprdat) << 1) | /* get state */
((lpcsa & CSA_DELH)? 1: 0); /* plus delim hold */
if (lprdat & TX_DELH) lpcsa = lpcsa | CSA_DELH;
else lpcsa = lpcsa & ~CSA_DELH;
lpcsa = lpcsa & ~CSA_UNDF; /* assume char ok */
switch (txcase[txst]) { /* case on state */
case TX_CHR: /* take char */
cont = lp20_print (lpcbuf);
break;
case TX_RAM: /* take translation */
cont = lp20_print (lprdat);
break;
case TX_DVU: /* DAVFU action */
if (lprdat & TX_SLEW)
cont = lp20_adv (lprdat & TX_VMASK, TRUE);
else cont = lp20_davfu (lprdat & TX_VMASK);
break;
case TX_INT: /* interrupt */
lpcsa = lpcsa | CSA_UNDF; /* set flag */
cont = FALSE; /* force stop */
break; } /* end case char state */
break;
case FNC_TST: /* test */
break; } /* end case function */
} /* end for */
case FNC_PR: /* print */
lprdat = txram[lpcbuf]; /* get RAM char */
txst = (TX_GETFL (lprdat) << 1) | /* get state */
((lpcsa & CSA_DELH)? 1: 0); /* plus delim hold */
if (lprdat & TX_DELH) lpcsa = lpcsa | CSA_DELH;
else lpcsa = lpcsa & ~CSA_DELH;
lpcsa = lpcsa & ~CSA_UNDF; /* assume char ok */
switch (txcase[txst]) { /* case on state */
case TX_CHR: /* take char */
cont = lp20_print (lpcbuf);
break;
case TX_RAM: /* take translation */
cont = lp20_print (lprdat);
break;
case TX_DVU: /* DAVFU action */
if (lprdat & TX_SLEW)
cont = lp20_adv (lprdat & TX_VMASK, TRUE);
else cont = lp20_davfu (lprdat & TX_VMASK);
break;
case TX_INT: /* interrupt */
lpcsa = lpcsa | CSA_UNDF; /* set flag */
cont = FALSE; /* force stop */
break;
} /* end case char state */
break;
case FNC_TST: /* test */
break;
} /* end case function */
} /* end for */
lpba = ba & 0177777;
lpcsa = (lpcsa & ~CSA_UAE) | ((ba >> (16 - CSA_V_UAE)) & CSA_UAE);
lpbc = (lpbc + i) & BC_MASK;
if (lpbc) update_lpcs (CSA_MBZ); /* intr, but not done */
else update_lpcs (CSA_DONE); /* intr and done */
if (lpbc) update_lpcs (CSA_MBZ); /* intr, but not done */
else update_lpcs (CSA_DONE); /* intr and done */
if ((fnc == FNC_PR) && ferror (lp20_unit.fileref)) {
perror ("LP I/O error");
clearerr (uptr->fileref);
return SCPE_IOERR; }
perror ("LP I/O error");
clearerr (uptr->fileref);
return SCPE_IOERR;
}
return SCPE_OK;
}
/* Print routines
lp20_print print a character
lp20_adv advance n lines
lp20_davfu advance to channel on VFU
lp20_print print a character
lp20_adv advance n lines
lp20_davfu advance to channel on VFU
Return TRUE to continue printing, FALSE to stop
*/
@@ -463,20 +509,24 @@ t_bool lp20_print (int32 c)
t_bool r = TRUE;
int32 i, rpt = 1;
lppdat = c & 0177; /* mask char to 7b */
if (lppdat == 000) return TRUE; /* NUL? no op */
if (lppdat == 012) return lp20_adv (1, TRUE); /* LF? adv carriage */
if (lppdat == 014) return lp20_davfu (DV_TOF); /* FF? top of form */
if (lppdat == 015) lpcolc = 0; /* CR? reset col cntr */
else if (lppdat == 011) { /* TAB? simulate */
lppdat = ' '; /* with spaces */
if (lpcolc >= 128) {
r = lp20_adv (1, TRUE); /* eol? adv carriage */
rpt = 8; } /* adv to col 9 */
else rpt = 8 - (lpcolc & 07); } /* else adv 1 to 8 */
else { if (lppdat < 040) lppdat = ' '; /* cvt non-prnt to spc */
if (lpcolc >= LP_WIDTH) /* line full? */
r = lp20_adv (1, TRUE); } /* adv carriage */
lppdat = c & 0177; /* mask char to 7b */
if (lppdat == 000) return TRUE; /* NUL? no op */
if (lppdat == 012) return lp20_adv (1, TRUE); /* LF? adv carriage */
if (lppdat == 014) return lp20_davfu (DV_TOF); /* FF? top of form */
if (lppdat == 015) lpcolc = 0; /* CR? reset col cntr */
else if (lppdat == 011) { /* TAB? simulate */
lppdat = ' '; /* with spaces */
if (lpcolc >= 128) {
r = lp20_adv (1, TRUE); /* eol? adv carriage */
rpt = 8; /* adv to col 9 */
}
else rpt = 8 - (lpcolc & 07); /* else adv 1 to 8 */
}
else {
if (lppdat < 040) lppdat = ' '; /* cvt non-prnt to spc */
if (lpcolc >= LP_WIDTH) /* line full? */
r = lp20_adv (1, TRUE); /* adv carriage */
}
for (i = 0; i < rpt; i++) putc (lppdat, lp20_unit.fileref);
lp20_unit.pos = lp20_unit.pos + rpt;
lpcolc = lpcolc + rpt;
@@ -488,17 +538,20 @@ t_bool lp20_adv (int32 cnt, t_bool dvuadv)
int32 i;
if (cnt == 0) return TRUE;
lpcolc = 0; /* reset col cntr */
lpcolc = 0; /* reset col cntr */
for (i = 0; i < cnt; i++) putc ('\n', lp20_unit.fileref);
lp20_unit.pos = lp20_unit.pos + cnt; /* print 'n' newlines */
if (dvuadv) dvptr = (dvptr + cnt) % dvlnt; /* update DAVFU ptr */
if (davfu[dvptr] & (1 << DV_TOF)) { /* at top of form? */
if (lppagc = (lppagc - 1) & PAGC_MASK) { /* decr page cntr */
lpcsa = lpcsa & ~CSA_PZRO; /* update status */
return TRUE; }
else {
lpcsa = lpcsa | CSA_PZRO; /* stop if zero */
return FALSE; } }
lp20_unit.pos = lp20_unit.pos + cnt; /* print 'n' newlines */
if (dvuadv) dvptr = (dvptr + cnt) % dvlnt; /* update DAVFU ptr */
if (davfu[dvptr] & (1 << DV_TOF)) { /* at top of form? */
if (lppagc = (lppagc - 1) & PAGC_MASK) { /* decr page cntr */
lpcsa = lpcsa & ~CSA_PZRO; /* update status */
return TRUE;
}
else {
lpcsa = lpcsa | CSA_PZRO; /* stop if zero */
return FALSE;
}
}
return TRUE;
}
@@ -506,40 +559,45 @@ t_bool lp20_davfu (int32 cnt)
{
int i;
if (cnt > DV_MAX) cnt = 7; /* inval chan? */
for (i = 0; i < dvlnt; i++) { /* search DAVFU */
dvptr = dvptr + 1; /* adv DAVFU ptr */
if (dvptr >= dvlnt) dvptr = 0; /* wrap at end */
if (davfu[dvptr] & (1 << cnt)) { /* channel stop set? */
if (cnt) return lp20_adv (i + 1, FALSE); /* ~TOF, adv */
if (lpcolc) lp20_adv (1, FALSE); /* TOF, need newline? */
putc ('\f', lp20_unit.fileref); /* print form feed */
lp20_unit.pos = lp20_unit.pos + 1;
if (lppagc = (lppagc - 1) & PAGC_MASK) { /* decr page cntr */
lpcsa = lpcsa & ~CSA_PZRO; /* update status */
return TRUE; }
else {
lpcsa = lpcsa | CSA_PZRO; /* stop if zero */
return FALSE; } }
} /* end for */
dvlnt = 0; /* DAVFU error */
if (cnt > DV_MAX) cnt = 7; /* inval chan? */
for (i = 0; i < dvlnt; i++) { /* search DAVFU */
dvptr = dvptr + 1; /* adv DAVFU ptr */
if (dvptr >= dvlnt) dvptr = 0; /* wrap at end */
if (davfu[dvptr] & (1 << cnt)) { /* channel stop set? */
if (cnt) return lp20_adv (i + 1, FALSE); /* ~TOF, adv */
if (lpcolc) lp20_adv (1, FALSE); /* TOF, need newline? */
putc ('\f', lp20_unit.fileref); /* print form feed */
lp20_unit.pos = lp20_unit.pos + 1;
if (lppagc = (lppagc - 1) & PAGC_MASK) { /* decr page cntr */
lpcsa = lpcsa & ~CSA_PZRO; /* update status */
return TRUE;
}
else {
lpcsa = lpcsa | CSA_PZRO; /* stop if zero */
return FALSE;
}
}
} /* end for */
dvlnt = 0; /* DAVFU error */
return FALSE;
}
/* Update LPCSA, optionally request interrupt */
void update_lpcs (int32 flg)
{
if (flg) lp20_irq = 1; /* set int req */
if (flg) lp20_irq = 1; /* set int req */
lpcsa = (lpcsa | flg) & ~(CSA_MBZ | CSA_ERR | CSA_ONL | CSA_DVON);
lpcsb = (lpcsb | CSB_OFFL | CSB_DVOF) & ~CSB_MBZ;
if (lp20_unit.flags & UNIT_ATT) {
lpcsa = lpcsa | CSA_ONL;
lpcsb = lpcsb & ~CSB_OFFL; }
lpcsa = lpcsa | CSA_ONL;
lpcsb = lpcsb & ~CSB_OFFL;
}
else lpcsa = lpcsa & ~CSA_DONE;
if (dvlnt) {
lpcsa = lpcsa | CSA_DVON;
lpcsb = lpcsb & ~CSB_DVOF; }
lpcsa = lpcsa | CSA_DVON;
lpcsb = lpcsb & ~CSB_DVOF;
}
if (lpcsb & CSB_ERR) lpcsa = lpcsa | CSA_ERR;
if ((lpcsa & CSA_IE) && lp20_irq) int_req = int_req | INT_LP20;
else int_req = int_req & ~INT_LP20;
@@ -550,31 +608,31 @@ return;
int32 lp20_inta (void)
{
lp20_irq = 0; /* clear int req */
lp20_irq = 0; /* clear int req */
return lp20_dib.vec;
}
t_stat lp20_reset (DEVICE *dptr)
{
lpcsa = CSA_DONE;
lpcsb = 0;
lpba = lpbc = lppagc = lpcolc = 0; /* clear registers */
lpba = lpbc = lppagc = lpcolc = 0; /* clear registers */
lprdat = lppdat = lpcbuf = lpcsum = 0;
lp20_irq = 0; /* clear int req */
dvptr = 0; /* reset davfu ptr */
sim_cancel (&lp20_unit); /* deactivate unit */
update_lpcs (0); /* update status */
lp20_irq = 0; /* clear int req */
dvptr = 0; /* reset davfu ptr */
sim_cancel (&lp20_unit); /* deactivate unit */
update_lpcs (0); /* update status */
return SCPE_OK;
}
t_stat lp20_attach (UNIT *uptr, char *cptr)
{
t_stat reason;
reason = attach_unit (uptr, cptr); /* attach file */
if (lpcsa & CSA_ONL) return reason; /* just file chg? */
if (sim_is_active (&lp20_unit)) update_lpcs (0); /* busy? no int */
else update_lpcs (CSA_MBZ); /* interrupt */
reason = attach_unit (uptr, cptr); /* attach file */
if (lpcsa & CSA_ONL) return reason; /* just file chg? */
if (sim_is_active (&lp20_unit)) update_lpcs (0); /* busy? no int */
else update_lpcs (CSA_MBZ); /* interrupt */
return reason;
}
@@ -582,7 +640,7 @@ t_stat lp20_detach (UNIT *uptr)
{
t_stat reason;
if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */
if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; /* attached? */
reason = detach_unit (uptr);
sim_cancel (&lp20_unit);
lpcsa = lpcsa & ~CSA_GO;

View File

@@ -1,6 +1,6 @@
/* pdp10_mdfp.c: PDP-10 multiply/divide and floating point simulator
Copyright (c) 1993-2004, Robert M Supnik
Copyright (c) 1993-2005, 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"),
@@ -19,31 +19,33 @@
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
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.
2-Apr-04 RMS Fixed bug in floating point unpack
Fixed bug in FIXR (found by Phil Stone, fixed by
Chris Smith)
2-Apr-04 RMS Fixed bug in floating point unpack
Fixed bug in FIXR (found by Phil Stone, fixed by
Chris Smith)
31-Aug-01 RMS Changed int64 to t_int64 for Windoze
10-Aug-01 RMS Removed register in declarations
Instructions handled in this module:
imul integer multiply
idiv integer divide
mul multiply
div divide
dmul double precision multiply
ddiv double precision divide
fad(r) floating add (and round)
fsb(r) floating subtract (and round)
fmp(r) floating multiply (and round)
fdv(r) floating divide and round
fsc floating scale
fix(r) floating to fixed (and round)
fltr fixed to floating and round
dfad double precision floating add/subtract
dfmp double precision floating multiply
dfdv double precision floating divide
imul integer multiply
idiv integer divide
mul multiply
div divide
dmul double precision multiply
ddiv double precision divide
fad(r) floating add (and round)
fsb(r) floating subtract (and round)
fmp(r) floating multiply (and round)
fdv(r) floating divide and round
fsc floating scale
fix(r) floating to fixed (and round)
fltr fixed to floating and round
dfad double precision floating add/subtract
dfmp double precision floating multiply
dfdv double precision floating divide
The PDP-10 stores double (quad) precision integers in sequential
AC's or memory locations. Integers are stored in 2's complement
@@ -94,87 +96,85 @@
The KL10 added extended precision (11-bit exponent) floating point
format (so-called G floating). These instructions were not
implemented in the KS10 and are treated as MUUO's.
31-Aug-01 RMS Changed int64 to t_int64 for Windoze
10-Aug-01 RMS Removed register in declarations
*/
#include "pdp10_defs.h"
#include <setjmp.h>
struct ufp { /* unpacked fp number */
int32 sign; /* sign */
int32 exp; /* exponent */
t_uint64 fhi; /* fraction high */
t_uint64 flo; }; /* for double prec */
typedef struct { /* unpacked fp number */
int32 sign; /* sign */
int32 exp; /* exponent */
t_uint64 fhi; /* fraction high */
t_uint64 flo; /* for double prec */
} UFP;
typedef struct ufp UFP;
#define MSK32 0xFFFFFFFF
#define FIT27 (DMASK - 0x07FFFFFF)
#define FIT32 (DMASK - MSK32)
#define SFRC TRUE /* frac 2's comp */
#define AFRC FALSE /* frac abs value */
#define MSK32 0xFFFFFFFF
#define FIT27 (DMASK - 0x07FFFFFF)
#define FIT32 (DMASK - MSK32)
#define SFRC TRUE /* frac 2's comp */
#define AFRC FALSE /* frac abs value */
/* In packed floating point number */
#define FP_BIAS 0200 /* exponent bias */
#define FP_N_FHI 27 /* # of hi frac bits */
#define FP_V_FHI 0 /* must be zero */
#define FP_M_FHI 0000777777777
#define FP_N_EXP 8 /* # of exp bits */
#define FP_V_EXP (FP_V_FHI + FP_N_FHI)
#define FP_M_EXP 0377
#define FP_V_SIGN (FP_V_EXP + FP_N_EXP) /* sign */
#define FP_N_FLO 35 /* # of lo frac bits */
#define FP_V_FLO 0 /* must be zero */
#define FP_M_FLO 0377777777777
#define GET_FPSIGN(x) ((int32) (((x) >> FP_V_SIGN) & 1))
#define GET_FPEXP(x) ((int32) (((x) >> FP_V_EXP) & FP_M_EXP))
#define GET_FPHI(x) ((x) & FP_M_FHI)
#define GET_FPLO(x) ((x) & FP_M_FLO)
#define FP_BIAS 0200 /* exponent bias */
#define FP_N_FHI 27 /* # of hi frac bits */
#define FP_V_FHI 0 /* must be zero */
#define FP_M_FHI 0000777777777
#define FP_N_EXP 8 /* # of exp bits */
#define FP_V_EXP (FP_V_FHI + FP_N_FHI)
#define FP_M_EXP 0377
#define FP_V_SIGN (FP_V_EXP + FP_N_EXP) /* sign */
#define FP_N_FLO 35 /* # of lo frac bits */
#define FP_V_FLO 0 /* must be zero */
#define FP_M_FLO 0377777777777
#define GET_FPSIGN(x) ((int32) (((x) >> FP_V_SIGN) & 1))
#define GET_FPEXP(x) ((int32) (((x) >> FP_V_EXP) & FP_M_EXP))
#define GET_FPHI(x) ((x) & FP_M_FHI)
#define GET_FPLO(x) ((x) & FP_M_FLO)
/* In unpacked floating point number */
#define FP_N_GUARD 1 /* # of guard bits */
#define FP_V_UFLO FP_N_GUARD /* <35:1> */
#define FP_V_URNDD (FP_V_UFLO - 1) /* dp round bit */
#define FP_V_UFHI (FP_V_UFLO + FP_N_FLO) /* <62:36> */
#define FP_V_URNDS (FP_V_UFHI - 1) /* sp round bit */
#define FP_V_UCRY (FP_V_UFHI + FP_N_FHI) /* <63> */
#define FP_V_UNORM (FP_V_UCRY - 1) /* normalized bit */
#define FP_UFHI 0x7FFFFFF000000000
#define FP_UFLO 0x0000000FFFFFFFFE
#define FP_UFRAC 0x7FFFFFFFFFFFFFFE
#define FP_URNDD 0x0000000000000001
#define FP_URNDS 0x0000000800000000
#define FP_UNORM 0x4000000000000000
#define FP_UCRY 0x8000000000000000
#define FP_ONES 0xFFFFFFFFFFFFFFFF
#define FP_N_GUARD 1 /* # of guard bits */
#define FP_V_UFLO FP_N_GUARD /* <35:1> */
#define FP_V_URNDD (FP_V_UFLO - 1) /* dp round bit */
#define FP_V_UFHI (FP_V_UFLO + FP_N_FLO) /* <62:36> */
#define FP_V_URNDS (FP_V_UFHI - 1) /* sp round bit */
#define FP_V_UCRY (FP_V_UFHI + FP_N_FHI) /* <63> */
#define FP_V_UNORM (FP_V_UCRY - 1) /* normalized bit */
#define FP_UFHI 0x7FFFFFF000000000
#define FP_UFLO 0x0000000FFFFFFFFE
#define FP_UFRAC 0x7FFFFFFFFFFFFFFE
#define FP_URNDD 0x0000000000000001
#define FP_URNDS 0x0000000800000000
#define FP_UNORM 0x4000000000000000
#define FP_UCRY 0x8000000000000000
#define FP_ONES 0xFFFFFFFFFFFFFFFF
#define UNEG(x) ((~x) + 1)
#define DUNEG(x) x.flo = UNEG (x.flo); x.fhi = ~x.fhi + (x.flo == 0)
#define UNEG(x) ((~x) + 1)
#define DUNEG(x) x.flo = UNEG (x.flo); x.fhi = ~x.fhi + (x.flo == 0)
extern d10 *ac_cur; /* current AC block */
extern int32 flags; /* flags */
extern d10 *ac_cur; /* current AC block */
extern int32 flags; /* flags */
void mul (d10 a, d10 b, d10 *rs);
void funpack (d10 h, d10 l, UFP *r, t_bool sgn);
void fnorm (UFP *r, t_int64 rnd);
d10 fpack (UFP *r, d10 *lo, t_bool fdvneg);
/* Integer multiply - checked against KS-10 ucode */
d10 imul (d10 a, d10 b)
{
d10 rs[2];
if ((a == SIGN) && (b == SIGN)) { /* KS10 hack */
SETF (F_AOV | F_T1); /* -2**35 squared */
return SIGN; }
mul (a, b, rs); /* mpy, dprec result */
if (rs[0] && (rs[0] != ONES)) { /* high not all sign? */
rs[1] = TSTS (a ^ b)? SETS (rs[1]): CLRS (rs[1]); /* set sign */
SETF (F_AOV | F_T1); } /* overflow */
if ((a == SIGN) && (b == SIGN)) { /* KS10 hack */
SETF (F_AOV | F_T1); /* -2**35 squared */
return SIGN;
}
mul (a, b, rs); /* mpy, dprec result */
if (rs[0] && (rs[0] != ONES)) { /* high not all sign? */
rs[1] = TSTS (a ^ b)? SETS (rs[1]): CLRS (rs[1]); /* set sign */
SETF (F_AOV | F_T1); /* overflow */
}
return rs[1];
}
@@ -185,16 +185,17 @@ return rs[1];
t_bool idiv (d10 a, d10 b, d10 *rs)
{
d10 dvd = ABS (a); /* make ops positive */
d10 dvd = ABS (a); /* make ops positive */
d10 dvr = ABS (b);
if (dvr == 0) { /* divide by 0? */
SETF (F_DCK | F_AOV | F_T1); /* set flags, return */
return FALSE; }
rs[0] = dvd / dvr; /* get quotient */
rs[1] = dvd % dvr; /* get remainder */
if (TSTS (a ^ b)) rs[0] = NEG (rs[0]); /* sign of result */
if (TSTS (a)) rs[1] = NEG (rs[1]); /* sign of remainder */
if (dvr == 0) { /* divide by 0? */
SETF (F_DCK | F_AOV | F_T1); /* set flags, return */
return FALSE;
}
rs[0] = dvd / dvr; /* get quotient */
rs[1] = dvd % dvr; /* get remainder */
if (TSTS (a ^ b)) rs[0] = NEG (rs[0]); /* sign of result */
if (TSTS (a)) rs[1] = NEG (rs[1]); /* sign of remainder */
return TRUE;
}
@@ -206,25 +207,30 @@ t_uint64 a = ABS (s1);
t_uint64 b = ABS (s2);
t_uint64 t, u, r;
if ((a == 0) || (b == 0)) { /* operand = 0? */
rs[0] = rs[1] = 0; /* result 0 */
return; }
if ((a & FIT32) || (b & FIT32)) { /* fit in 64b? */
t = a >> 18; /* no, split in half */
a = a & RMASK; /* "dp" multiply */
u = b >> 18;
b = b & RMASK;
r = (a * b) + (((a * u) + (b * t)) << 18); /* low is only 35b */
rs[0] = ((t * u) << 1) + (r >> 35); /* so lsh hi 1 */
rs[1] = r & MMASK; }
else { r = a * b; /* fits, native mpy */
rs[0] = r >> 35; /* split at bit 35 */
rs[1] = r & MMASK; }
if ((a == 0) || (b == 0)) { /* operand = 0? */
rs[0] = rs[1] = 0; /* result 0 */
return;
}
if ((a & FIT32) || (b & FIT32)) { /* fit in 64b? */
t = a >> 18; /* no, split in half */
a = a & RMASK; /* "dp" multiply */
u = b >> 18;
b = b & RMASK;
r = (a * b) + (((a * u) + (b * t)) << 18); /* low is only 35b */
rs[0] = ((t * u) << 1) + (r >> 35); /* so lsh hi 1 */
rs[1] = r & MMASK;
}
else {
r = a * b; /* fits, native mpy */
rs[0] = r >> 35; /* split at bit 35 */
rs[1] = r & MMASK;
}
if (TSTS (s1 ^ s2)) { MKDNEG (rs); } /* result -? */
else if (TSTS (rs[0])) { /* result +, 2**70? */
SETF (F_AOV | F_T1); /* overflow */
rs[1] = SETS (rs[1]); } /* consistent - */
if (TSTS (s1 ^ s2)) { MKDNEG (rs); } /* result -? */
else if (TSTS (rs[0])) { /* result +, 2**70? */
SETF (F_AOV | F_T1); /* overflow */
rs[1] = SETS (rs[1]); /* consistent - */
}
return;
}
@@ -236,31 +242,37 @@ return;
t_bool divi (int32 ac, d10 b, d10 *rs)
{
int32 p1 = ADDAC (ac, 1);
d10 dvr = ABS (b); /* make divr positive */
d10 dvr = ABS (b); /* make divr positive */
t_int64 t;
int32 i;
d10 dvd[2];
dvd[0] = AC(ac); /* divd high */
dvd[1] = CLRS (AC(p1)); /* divd lo, clr sgn */
if (TSTS (AC(ac))) { DMOVN (dvd); } /* make divd positive */
if (dvd[0] >= dvr) { /* divide fail? */
SETF (F_AOV | F_DCK | F_T1); /* set flags, return */
return FALSE; }
if (dvd[0] & FIT27) { /* fit in 63b? */
for (i = 0, rs[0] = 0; i < 35; i++) { /* 35 quotient bits */
dvd[0] = (dvd[0] << 1) | ((dvd[1] >> 34) & 1);
dvd[1] = (dvd[1] << 1) & MMASK; /* shift dividend */
rs[0] = rs[0] << 1; /* shift quotient */
if (dvd[0] >= dvr) { /* subtract work? */
dvd[0] = dvd[0] - dvr; /* quo bit is 1 */
rs[0] = rs[0] + 1; } }
rs[1] = dvd[0]; } /* store remainder */
else { t = (dvd[0] << 35) | dvd[1]; /* concatenate */
rs[0] = t / dvr; /* quotient */
rs[1] = t % dvr; } /* remainder */
if (TSTS (AC(ac) ^ b)) rs[0] = NEG (rs[0]); /* sign of result */
if (TSTS (AC(ac))) rs[1] = NEG (rs[1]); /* sign of remainder */
dvd[0] = AC(ac); /* divd high */
dvd[1] = CLRS (AC(p1)); /* divd lo, clr sgn */
if (TSTS (AC(ac))) { DMOVN (dvd); } /* make divd positive */
if (dvd[0] >= dvr) { /* divide fail? */
SETF (F_AOV | F_DCK | F_T1); /* set flags, return */
return FALSE;
}
if (dvd[0] & FIT27) { /* fit in 63b? */
for (i = 0, rs[0] = 0; i < 35; i++) { /* 35 quotient bits */
dvd[0] = (dvd[0] << 1) | ((dvd[1] >> 34) & 1);
dvd[1] = (dvd[1] << 1) & MMASK; /* shift dividend */
rs[0] = rs[0] << 1; /* shift quotient */
if (dvd[0] >= dvr) { /* subtract work? */
dvd[0] = dvd[0] - dvr; /* quo bit is 1 */
rs[0] = rs[0] + 1;
}
}
rs[1] = dvd[0]; /* store remainder */
}
else {
t = (dvd[0] << 35) | dvd[1]; /* concatenate */
rs[0] = t / dvr; /* quotient */
rs[1] = t % dvr; /* remainder */
}
if (TSTS (AC(ac) ^ b)) rs[0] = NEG (rs[0]); /* sign of result */
if (TSTS (AC(ac))) rs[1] = NEG (rs[1]); /* sign of remainder */
return TRUE;
}
@@ -276,36 +288,41 @@ int32 p3 = ADDAC (ac, 3);
int32 i;
d10 mpc[2], sign;
mpc[0] = AC(ac); /* mplcnd hi */
mpc[1] = CLRS (AC(p1)); /* mplcnd lo, clr sgn */
sign = mpc[0] ^ mpy[0]; /* sign of result */
if (TSTS (mpc[0])) { DMOVN (mpc); } /* get abs (mpcnd) */
if (TSTS (mpy[0])) { DMOVN (mpy); } /* get abs (mpyer) */
else mpy[1] = CLRS (mpy[1]); /* clear mpy lo sign */
AC(ac) = AC(p1) = AC(p2) = AC(p3) = 0; /* clear AC's */
mpc[0] = AC(ac); /* mplcnd hi */
mpc[1] = CLRS (AC(p1)); /* mplcnd lo, clr sgn */
sign = mpc[0] ^ mpy[0]; /* sign of result */
if (TSTS (mpc[0])) { DMOVN (mpc); } /* get abs (mpcnd) */
if (TSTS (mpy[0])) { DMOVN (mpy); } /* get abs (mpyer) */
else mpy[1] = CLRS (mpy[1]); /* clear mpy lo sign */
AC(ac) = AC(p1) = AC(p2) = AC(p3) = 0; /* clear AC's */
if (((mpy[0] | mpy[1]) == 0) || ((mpc[0] | mpc[1]) == 0)) return;
for (i = 0; i < 71; i++) { /* 71 mpyer bits */
if (i) { /* shift res, mpy */
AC(p3) = (AC(p3) >> 1) | ((AC(p2) & 1) << 34);
AC(p2) = (AC(p2) >> 1) | ((AC(p1) & 1) << 34);
AC(p1) = (AC(p1) >> 1) | ((AC(ac) & 1) << 34);
AC(ac) = AC(ac) >> 1;
mpy[1] = (mpy[1] >> 1) | ((mpy[0] & 1) << 34);
mpy[0] = mpy[0] >> 1; }
if (mpy[1] & 1) { /* if mpy lo bit = 1 */
AC(p1) = AC(p1) + mpc[1];
AC(ac) = AC(ac) + mpc[0] + (TSTS (AC(p1) != 0));
AC(p1) = CLRS (AC(p1)); } }
if (TSTS (sign)) { /* result minus? */
AC(p3) = (-AC(p3)) & MMASK; /* quad negate */
AC(p2) = (~AC(p2) + (AC(p3) == 0)) & MMASK;
AC(p1) = (~AC(p1) + (AC(p2) == 0)) & MMASK;
AC(ac) = (~AC(ac) + (AC(p1) == 0)) & DMASK; }
else if (TSTS (AC(ac))) SETF (F_AOV | F_T1); /* wrong sign */
if (TSTS (AC(ac))) { /* if result - */
AC(p1) = SETS (AC(p1)); /* make signs consistent */
AC(p2) = SETS (AC(p2));
AC(p3) = SETS (AC(p3)); }
for (i = 0; i < 71; i++) { /* 71 mpyer bits */
if (i) { /* shift res, mpy */
AC(p3) = (AC(p3) >> 1) | ((AC(p2) & 1) << 34);
AC(p2) = (AC(p2) >> 1) | ((AC(p1) & 1) << 34);
AC(p1) = (AC(p1) >> 1) | ((AC(ac) & 1) << 34);
AC(ac) = AC(ac) >> 1;
mpy[1] = (mpy[1] >> 1) | ((mpy[0] & 1) << 34);
mpy[0] = mpy[0] >> 1;
}
if (mpy[1] & 1) { /* if mpy lo bit = 1 */
AC(p1) = AC(p1) + mpc[1];
AC(ac) = AC(ac) + mpc[0] + (TSTS (AC(p1) != 0));
AC(p1) = CLRS (AC(p1));
}
}
if (TSTS (sign)) { /* result minus? */
AC(p3) = (-AC(p3)) & MMASK; /* quad negate */
AC(p2) = (~AC(p2) + (AC(p3) == 0)) & MMASK;
AC(p1) = (~AC(p1) + (AC(p2) == 0)) & MMASK;
AC(ac) = (~AC(ac) + (AC(p1) == 0)) & DMASK;
}
else if (TSTS (AC(ac))) SETF (F_AOV | F_T1); /* wrong sign */
if (TSTS (AC(ac))) { /* if result - */
AC(p1) = SETS (AC(p1)); /* make signs consistent */
AC(p2) = SETS (AC(p2));
AC(p3) = SETS (AC(p3));
}
return;
}
@@ -316,40 +333,45 @@ void ddiv (int32 ac, d10 *dvr)
int32 i, cryin;
d10 sign, qu[2], dvd[4];
dvd[0] = AC(ac); /* save dividend */
dvd[0] = AC(ac); /* save dividend */
for (i = 1; i < 4; i++) dvd[i] = CLRS (AC(ADDAC (ac, i)));
sign = AC(ac) ^ dvr[0]; /* sign of result */
if (TSTS (AC(ac))) { /* get abs (dividend) */
for (i = 3, cryin = 1; i > 0; i--) { /* negate quad */
dvd[i] = (~dvd[i] + cryin) & MMASK; /* comp + carry in */
if (dvd[i]) cryin = 0; } /* next carry in */
dvd[0] = (~dvd[0] + cryin) & DMASK; }
if (TSTS (dvr[0])) { DMOVN (dvr); } /* get abs (divisor) */
sign = AC(ac) ^ dvr[0]; /* sign of result */
if (TSTS (AC(ac))) { /* get abs (dividend) */
for (i = 3, cryin = 1; i > 0; i--) { /* negate quad */
dvd[i] = (~dvd[i] + cryin) & MMASK; /* comp + carry in */
if (dvd[i]) cryin = 0; /* next carry in */
}
dvd[0] = (~dvd[0] + cryin) & DMASK;
}
if (TSTS (dvr[0])) { DMOVN (dvr); } /* get abs (divisor) */
else dvr[1] = CLRS (dvr[1]);
if (DCMPGE (dvd, dvr)) { /* will divide work? */
SETF (F_AOV | F_DCK | F_T1); /* no, set flags */
return; }
qu[0] = qu[1] = 0; /* clear quotient */
for (i = 0; i < 70; i++) { /* 70 quotient bits */
dvd[0] = ((dvd[0] << 1) | ((dvd[1] >> 34) & 1)) & DMASK;;
dvd[1] = ((dvd[1] << 1) | ((dvd[2] >> 34) & 1)) & MMASK;
dvd[2] = ((dvd[2] << 1) | ((dvd[3] >> 34) & 1)) & MMASK;
dvd[3] = (dvd[3] << 1) & MMASK; /* shift dividend */
qu[0] = (qu[0] << 1) | ((qu[1] >> 34) & 1); /* shift quotient */
qu[1] = (qu[1] << 1) & MMASK;
if (DCMPGE (dvd, dvr)) { /* subtract work? */
dvd[0] = dvd[0] - dvr[0] - (dvd[1] < dvr[1]);
dvd[1] = (dvd[1] - dvr[1]) & MMASK; /* do subtract */
qu[1] = qu[1] + 1; } } /* set quotient bit */
if (TSTS (sign) && (qu[0] | qu[1])) { MKDNEG (qu); }
if (TSTS (AC(ac)) && (dvd[0] | dvd[1])) { MKDNEG (dvd); }
AC(ac) = qu[0]; /* quotient */
if (DCMPGE (dvd, dvr)) { /* will divide work? */
SETF (F_AOV | F_DCK | F_T1); /* no, set flags */
return;
}
qu[0] = qu[1] = 0; /* clear quotient */
for (i = 0; i < 70; i++) { /* 70 quotient bits */
dvd[0] = ((dvd[0] << 1) | ((dvd[1] >> 34) & 1)) & DMASK;;
dvd[1] = ((dvd[1] << 1) | ((dvd[2] >> 34) & 1)) & MMASK;
dvd[2] = ((dvd[2] << 1) | ((dvd[3] >> 34) & 1)) & MMASK;
dvd[3] = (dvd[3] << 1) & MMASK; /* shift dividend */
qu[0] = (qu[0] << 1) | ((qu[1] >> 34) & 1); /* shift quotient */
qu[1] = (qu[1] << 1) & MMASK;
if (DCMPGE (dvd, dvr)) { /* subtract work? */
dvd[0] = dvd[0] - dvr[0] - (dvd[1] < dvr[1]);
dvd[1] = (dvd[1] - dvr[1]) & MMASK; /* do subtract */
qu[1] = qu[1] + 1; /* set quotient bit */
}
}
if (TSTS (sign) && (qu[0] | qu[1])) { MKDNEG (qu); }
if (TSTS (AC(ac)) && (dvd[0] | dvd[1])) { MKDNEG (dvd); }
AC(ac) = qu[0]; /* quotient */
AC(ADDAC(ac, 1)) = qu[1];
AC(ADDAC(ac, 2)) = dvd[0]; /* remainder */
AC(ADDAC(ac, 2)) = dvd[0]; /* remainder */
AC(ADDAC(ac, 3)) = dvd[1];
return;
}
/* Single precision floating add/subtract - checked against KS10 ucode
The KS10 shifts the smaller operand regardless of the exponent diff.
This code will not shift more than 63 places; shifts beyond that
@@ -366,31 +388,38 @@ d10 fad (d10 op1, d10 op2, t_bool rnd, int32 inv)
int32 ediff;
UFP a, b, t;
if (inv) op2 = NEG (op2); /* subtract? -b */
if (op1 == 0) funpack (op2, 0, &a, AFRC); /* a = 0? result is b */
else if (op2 == 0) funpack (op1, 0, &a, AFRC); /* b = 0? result is a */
else { funpack (op1, 0, &a, SFRC); /* unpack operands */
funpack (op2, 0, &b, SFRC); /* fracs are 2's comp */
ediff = a.exp - b.exp; /* get exp diff */
if (ediff < 0) { /* a < b? switch */
t = a;
a = b;
b = t;
ediff = -ediff; }
if (ediff > 63) ediff = 63; /* cap diff at 63 */
if (ediff) b.fhi = (t_int64) b.fhi >> ediff; /* shift b (signed) */
a.fhi = a.fhi + b.fhi; /* add fractions */
if (a.sign ^ b.sign) { /* add or subtract? */
if (a.fhi & FP_UCRY) { /* subtract, frac -? */
a.fhi = UNEG (a.fhi); /* complement result */
a.sign = 1; } /* result is - */
else a.sign = 0; } /* result is + */
else {
if (a.sign) a.fhi = UNEG (a.fhi); /* add, src -? comp */
if (a.fhi & FP_UCRY) { /* check for carry */
a.fhi = a.fhi >> 1; /* flo won't be used */
a.exp = a.exp + 1; } } }
fnorm (&a, (rnd? FP_URNDS: 0)); /* normalize, round */
if (inv) op2 = NEG (op2); /* subtract? -b */
if (op1 == 0) funpack (op2, 0, &a, AFRC); /* a = 0? result is b */
else if (op2 == 0) funpack (op1, 0, &a, AFRC); /* b = 0? result is a */
else {
funpack (op1, 0, &a, SFRC); /* unpack operands */
funpack (op2, 0, &b, SFRC); /* fracs are 2's comp */
ediff = a.exp - b.exp; /* get exp diff */
if (ediff < 0) { /* a < b? switch */
t = a;
a = b;
b = t;
ediff = -ediff;
}
if (ediff > 63) ediff = 63; /* cap diff at 63 */
if (ediff) b.fhi = (t_int64) b.fhi >> ediff; /* shift b (signed) */
a.fhi = a.fhi + b.fhi; /* add fractions */
if (a.sign ^ b.sign) { /* add or subtract? */
if (a.fhi & FP_UCRY) { /* subtract, frac -? */
a.fhi = UNEG (a.fhi); /* complement result */
a.sign = 1; /* result is - */
}
else a.sign = 0; /* result is + */
}
else {
if (a.sign) a.fhi = UNEG (a.fhi); /* add, src -? comp */
if (a.fhi & FP_UCRY) { /* check for carry */
a.fhi = a.fhi >> 1; /* flo won't be used */
a.exp = a.exp + 1;
}
}
}
fnorm (&a, (rnd? FP_URNDS: 0)); /* normalize, round */
return fpack (&a, NULL, FALSE);
}
@@ -400,18 +429,18 @@ return fpack (&a, NULL, FALSE);
The extra 0 is accounted for by biasing the result exponent.
*/
#define FP_V_SPM (FP_V_UFHI - (32 - FP_N_FHI - 1))
#define FP_V_SPM (FP_V_UFHI - (32 - FP_N_FHI - 1))
d10 fmp (d10 op1, d10 op2, t_bool rnd)
{
UFP a, b;
funpack (op1, 0, &a, AFRC); /* unpack operands */
funpack (op2, 0, &b, AFRC); /* fracs are abs val */
if ((a.fhi == 0) || (b.fhi == 0)) return 0; /* either 0? */
a.sign = a.sign ^ b.sign; /* result sign */
a.exp = a.exp + b.exp - FP_BIAS + 1; /* result exponent */
a.fhi = (a.fhi >> FP_V_SPM) * (b.fhi >> FP_V_SPM); /* high 27b of result */
fnorm (&a, (rnd? FP_URNDS: 0)); /* normalize, round */
funpack (op1, 0, &a, AFRC); /* unpack operands */
funpack (op2, 0, &b, AFRC); /* fracs are abs val */
if ((a.fhi == 0) || (b.fhi == 0)) return 0; /* either 0? */
a.sign = a.sign ^ b.sign; /* result sign */
a.exp = a.exp + b.exp - FP_BIAS + 1; /* result exponent */
a.fhi = (a.fhi >> FP_V_SPM) * (b.fhi >> FP_V_SPM); /* high 27b of result */
fnorm (&a, (rnd? FP_URNDS: 0)); /* normalize, round */
return fpack (&a, NULL, FALSE);
}
@@ -429,27 +458,30 @@ UFP a, b;
t_uint64 savhi;
t_bool rem = FALSE;
funpack (op1, 0, &a, AFRC); /* unpack operands */
funpack (op2, 0, &b, AFRC); /* fracs are abs val */
if (a.fhi >= 2 * b.fhi) { /* will divide work? */
SETF (F_AOV | F_DCK | F_FOV | F_T1);
return FALSE; }
if (savhi = a.fhi) { /* dvd = 0? quo = 0 */
a.sign = a.sign ^ b.sign; /* result sign */
a.exp = a.exp - b.exp + FP_BIAS + 1; /* result exponent */
a.fhi = a.fhi / (b.fhi >> (FP_N_FHI + 1)); /* do divide */
if (a.sign && (savhi != (a.fhi * (b.fhi >> (FP_N_FHI + 1)))))
rem = TRUE; /* KL/KS hack */
a.fhi = a.fhi << (FP_V_UNORM - FP_N_FHI - 1); /* put quo in place */
if ((a.fhi & FP_UNORM) == 0) { /* normalize 1b */
a.fhi = a.fhi << 1; /* before masking */
a.exp = a.exp - 1; }
a.fhi = a.fhi & (FP_UFHI | FP_URNDS); } /* mask quo to 28b */
fnorm (&a, (rnd? FP_URNDS: 0)); /* normalize, round */
*rs = fpack (&a, NULL, rem); /* pack result */
funpack (op1, 0, &a, AFRC); /* unpack operands */
funpack (op2, 0, &b, AFRC); /* fracs are abs val */
if (a.fhi >= 2 * b.fhi) { /* will divide work? */
SETF (F_AOV | F_DCK | F_FOV | F_T1);
return FALSE;
}
if (savhi = a.fhi) { /* dvd = 0? quo = 0 */
a.sign = a.sign ^ b.sign; /* result sign */
a.exp = a.exp - b.exp + FP_BIAS + 1; /* result exponent */
a.fhi = a.fhi / (b.fhi >> (FP_N_FHI + 1)); /* do divide */
if (a.sign && (savhi != (a.fhi * (b.fhi >> (FP_N_FHI + 1)))))
rem = TRUE; /* KL/KS hack */
a.fhi = a.fhi << (FP_V_UNORM - FP_N_FHI - 1); /* put quo in place */
if ((a.fhi & FP_UNORM) == 0) { /* normalize 1b */
a.fhi = a.fhi << 1; /* before masking */
a.exp = a.exp - 1;
}
a.fhi = a.fhi & (FP_UFHI | FP_URNDS); /* mask quo to 28b */
}
fnorm (&a, (rnd? FP_URNDS: 0)); /* normalize, round */
*rs = fpack (&a, NULL, rem); /* pack result */
return TRUE;
}
/* Single precision floating scale. */
d10 fsc (d10 val, a10 ea)
@@ -458,11 +490,11 @@ int32 sc = LIT8 (ea);
UFP a;
if (val == 0) return 0;
funpack (val, 0, &a, AFRC); /* unpack operand */
if (ea & RSIGN) a.exp = a.exp - sc; /* adjust exponent */
funpack (val, 0, &a, AFRC); /* unpack operand */
if (ea & RSIGN) a.exp = a.exp - sc; /* adjust exponent */
else a.exp = a.exp + sc;
fnorm (&a, 0); /* renormalize */
return fpack (&a, NULL, FALSE); /* pack result */
fnorm (&a, 0); /* renormalize */
return fpack (&a, NULL, FALSE); /* pack result */
}
/* Float integer operand and round */
@@ -472,12 +504,12 @@ d10 fltr (d10 mb)
UFP a;
d10 val = ABS (mb);
a.sign = GET_FPSIGN (mb); /* get sign */
a.exp = FP_BIAS + 36; /* initial exponent */
a.fhi = val << (FP_V_UNORM - 35); /* left justify op */
a.sign = GET_FPSIGN (mb); /* get sign */
a.exp = FP_BIAS + 36; /* initial exponent */
a.fhi = val << (FP_V_UNORM - 35); /* left justify op */
a.flo = 0;
fnorm (&a, FP_URNDS); /* normalize, round */
return fpack (&a, NULL, FALSE); /* pack result */
fnorm (&a, FP_URNDS); /* normalize, round */
return fpack (&a, NULL, FALSE); /* pack result */
}
/* Fix and truncate/round floating operand */
@@ -488,18 +520,21 @@ int32 sc;
t_uint64 so;
UFP a;
funpack (mb, 0, &a, AFRC); /* unpack operand */
funpack (mb, 0, &a, AFRC); /* unpack operand */
if (a.exp > (FP_BIAS + FP_N_FHI + FP_N_EXP)) SETF (F_AOV | F_T1);
else if (a.exp < FP_BIAS) AC(ac) = 0; /* < 1/2? */
else { sc = FP_V_UNORM - (a.exp - FP_BIAS) + 1;
AC(ac) = a.fhi >> sc;
if (rnd) {
so = a.fhi << (64 - sc);
if (so >= (0x8000000000000000 + a.sign)) AC(ac) = AC(ac) + 1; }
if (a.sign) AC(ac) = NEG (AC(ac)); }
else if (a.exp < FP_BIAS) AC(ac) = 0; /* < 1/2? */
else {
sc = FP_V_UNORM - (a.exp - FP_BIAS) + 1;
AC(ac) = a.fhi >> sc;
if (rnd) {
so = a.fhi << (64 - sc);
if (so >= (0x8000000000000000 + a.sign)) AC(ac) = AC(ac) + 1;
}
if (a.sign) AC(ac) = NEG (AC(ac));
}
return;
}
/* Double precision floating add/subtract
Since a.flo is 0, adding b.flo is just a copy - this is incorporated into
the denormalization step. If there's no denormalization, bflo is zero too.
@@ -511,40 +546,48 @@ int32 p1 = ADDAC (ac, 1);
int32 ediff;
UFP a, b, t;
if (inv) { DMOVN (rs); } /* subtract? -b */
if (inv) { DMOVN (rs); } /* subtract? -b */
if ((AC(ac) | AC(p1)) == 0) funpack (rs[0], rs[1], &a, AFRC);
/* a == 0? sum = b */
/* a == 0? sum = b */
else if ((rs[0] | rs[1]) == 0) funpack (AC(ac), AC(p1), &a, AFRC);
/* b == 0? sum = a */
/* b == 0? sum = a */
else {
funpack (AC(ac), AC(p1), &a, SFRC); /* unpack operands */
funpack (rs[0], rs[1], &b, SFRC);
ediff = a.exp - b.exp; /* get exp diff */
if (ediff < 0) { /* a < b? switch */
t = a;
a = b;
b = t;
ediff = -ediff; }
if (ediff > 127) ediff = 127; /* cap diff at 127 */
if (ediff > 63) { /* diff > 63? */
a.flo = (t_int64) b.fhi >> (ediff - 64); /* b hi to a lo */
b.fhi = b.sign? FP_ONES: 0; } /* hi = all sign */
else if (ediff) { /* diff <= 63 */
a.flo = (b.flo >> ediff) | (b.fhi << (64 - ediff));
b.fhi = (t_int64) b.fhi >> ediff; } /* shift b (signed) */
a.fhi = a.fhi + b.fhi; /* do add */
if (a.sign ^ b.sign) { /* add or subtract? */
if (a.fhi & FP_UCRY) { /* subtract, frac -? */
DUNEG (a); /* complement result */
a.sign = 1; } /* result is - */
else a.sign = 0; } /* result is + */
else {
if (a.sign) { DUNEG (a); }; /* add, src -? comp */
if (a.fhi & FP_UCRY) { /* check for carry */
a.fhi = a.fhi >> 1; /* flo won't be used */
a.exp = a.exp + 1; } } }
fnorm (&a, FP_URNDD); /* normalize, round */
AC(ac) = fpack (&a, &AC(p1), FALSE); /* pack result */
funpack (AC(ac), AC(p1), &a, SFRC); /* unpack operands */
funpack (rs[0], rs[1], &b, SFRC);
ediff = a.exp - b.exp; /* get exp diff */
if (ediff < 0) { /* a < b? switch */
t = a;
a = b;
b = t;
ediff = -ediff;
}
if (ediff > 127) ediff = 127; /* cap diff at 127 */
if (ediff > 63) { /* diff > 63? */
a.flo = (t_int64) b.fhi >> (ediff - 64); /* b hi to a lo */
b.fhi = b.sign? FP_ONES: 0; /* hi = all sign */
}
else if (ediff) { /* diff <= 63 */
a.flo = (b.flo >> ediff) | (b.fhi << (64 - ediff));
b.fhi = (t_int64) b.fhi >> ediff; /* shift b (signed) */
}
a.fhi = a.fhi + b.fhi; /* do add */
if (a.sign ^ b.sign) { /* add or subtract? */
if (a.fhi & FP_UCRY) { /* subtract, frac -? */
DUNEG (a); /* complement result */
a.sign = 1; /* result is - */
}
else a.sign = 0; /* result is + */
}
else {
if (a.sign) { DUNEG (a); }; /* add, src -? comp */
if (a.fhi & FP_UCRY) { /* check for carry */
a.fhi = a.fhi >> 1; /* flo won't be used */
a.exp = a.exp + 1;
}
}
}
fnorm (&a, FP_URNDD); /* normalize, round */
AC(ac) = fpack (&a, &AC(p1), FALSE); /* pack result */
return;
}
@@ -562,24 +605,25 @@ int32 p1 = ADDAC (ac, 1);
t_uint64 xh, xl, yh, yl, mid;
UFP a, b;
funpack (AC(ac), AC(p1), &a, AFRC); /* unpack operands */
funpack (AC(ac), AC(p1), &a, AFRC); /* unpack operands */
funpack (rs[0], rs[1], &b, AFRC);
if ((a.fhi == 0) || (b.fhi == 0)) { /* either 0? result 0 */
AC(ac) = AC(p1) = 0;
return; }
a.sign = a.sign ^ b.sign; /* result sign */
a.exp = a.exp + b.exp - FP_BIAS + 1; /* result exponent */
xh = a.fhi >> 32; /* split 62b fracs */
xl = a.fhi & MSK32; /* into 32b halves */
if ((a.fhi == 0) || (b.fhi == 0)) { /* either 0? result 0 */
AC(ac) = AC(p1) = 0;
return;
}
a.sign = a.sign ^ b.sign; /* result sign */
a.exp = a.exp + b.exp - FP_BIAS + 1; /* result exponent */
xh = a.fhi >> 32; /* split 62b fracs */
xl = a.fhi & MSK32; /* into 32b halves */
yh = b.fhi >> 32;
yl = b.fhi & MSK32;
a.fhi = xh * yh; /* hi xproduct */
a.flo = xl * yl; /* low xproduct */
mid = (xh * yl) + (yh * xl); /* fits in 64b */
a.flo = a.flo + (mid << 32); /* add mid lo to lo */
a.fhi = xh * yh; /* hi xproduct */
a.flo = xl * yl; /* low xproduct */
mid = (xh * yl) + (yh * xl); /* fits in 64b */
a.flo = a.flo + (mid << 32); /* add mid lo to lo */
a.fhi = a.fhi + ((mid >> 32) & MSK32) + (a.flo < (mid << 32));
fnorm (&a, FP_URNDD); /* normalize, round */
AC(ac) = fpack (&a, &AC(p1), FALSE); /* pack result */
fnorm (&a, FP_URNDD); /* normalize, round */
AC(ac) = fpack (&a, &AC(p1), FALSE); /* pack result */
return;
}
@@ -597,29 +641,34 @@ int32 i;
t_uint64 qu = 0;
UFP a, b;
funpack (AC(ac), AC(p1), &a, AFRC); /* unpack operands */
funpack (AC(ac), AC(p1), &a, AFRC); /* unpack operands */
funpack (rs[0], rs[1], &b, AFRC);
if (a.fhi >= 2 * b.fhi) { /* will divide work? */
SETF (F_AOV | F_DCK | F_FOV | F_T1);
return; }
if (a.fhi) { /* dvd = 0? quo = 0 */
a.sign = a.sign ^ b.sign; /* result sign */
a.exp = a.exp - b.exp + FP_BIAS + 1; /* result exponent */
if (a.fhi < b.fhi) { /* make sure initial */
a.fhi = a.fhi << 1; /* divide step will work */
a.exp = a.exp - 1; }
for (i = 0; i < 63; i++) { /* 63b of quotient */
qu = qu << 1; /* shift quotient */
if (a.fhi >= b.fhi) { /* will div work? */
a.fhi = a.fhi - b.fhi; /* sub, quo = 1 */
qu = qu + 1; }
a.fhi = a.fhi << 1; } /* shift dividend */
a.fhi = qu; }
fnorm (&a, FP_URNDD); /* normalize, round */
AC(ac) = fpack (&a, &AC(p1), FALSE); /* pack result */
if (a.fhi >= 2 * b.fhi) { /* will divide work? */
SETF (F_AOV | F_DCK | F_FOV | F_T1);
return;
}
if (a.fhi) { /* dvd = 0? quo = 0 */
a.sign = a.sign ^ b.sign; /* result sign */
a.exp = a.exp - b.exp + FP_BIAS + 1; /* result exponent */
if (a.fhi < b.fhi) { /* make sure initial */
a.fhi = a.fhi << 1; /* divide step will work */
a.exp = a.exp - 1;
}
for (i = 0; i < 63; i++) { /* 63b of quotient */
qu = qu << 1; /* shift quotient */
if (a.fhi >= b.fhi) { /* will div work? */
a.fhi = a.fhi - b.fhi; /* sub, quo = 1 */
qu = qu + 1;
}
a.fhi = a.fhi << 1; /* shift dividend */
}
a.fhi = qu;
}
fnorm (&a, FP_URNDD); /* normalize, round */
AC(ac) = fpack (&a, &AC(p1), FALSE); /* pack result */
return;
}
/* Unpack floating point operand */
void funpack (d10 h, d10 l, UFP *r, t_bool sgn)
@@ -633,17 +682,22 @@ fplo = GET_FPLO (l);
r->fhi = (fphi << FP_V_UFHI) | (fplo << FP_V_UFLO);
r->flo = 0;
if (r->sign) {
r->exp = r->exp ^ FP_M_EXP; /* 1s comp exp */
if (sgn) { /* signed frac? */
if (r->fhi) r->fhi = r->fhi | FP_UCRY; /* extend sign */
else {
r->exp = r->exp + 1;
r->fhi = FP_UCRY | FP_UNORM; } }
else { /* abs frac */
if (r->fhi) r->fhi = UNEG (r->fhi) & FP_UFRAC;
else {
r->exp = r->exp + 1;
r->fhi = FP_UNORM; } } }
r->exp = r->exp ^ FP_M_EXP; /* 1s comp exp */
if (sgn) { /* signed frac? */
if (r->fhi) r->fhi = r->fhi | FP_UCRY; /* extend sign */
else {
r->exp = r->exp + 1;
r->fhi = FP_UCRY | FP_UNORM;
}
}
else { /* abs frac */
if (r->fhi) r->fhi = UNEG (r->fhi) & FP_UFRAC;
else {
r->exp = r->exp + 1;
r->fhi = FP_UNORM;
}
}
}
return;
}
@@ -654,29 +708,36 @@ void fnorm (UFP *a, t_int64 rnd)
int32 i;
static t_uint64 normmask[6] = {
0x6000000000000000, 0x7800000000000000, 0x7F80000000000000,
0x7FFF800000000000, 0x7FFFFFFF80000000, 0x7FFFFFFFFFFFFFFF };
0x7FFF800000000000, 0x7FFFFFFF80000000, 0x7FFFFFFFFFFFFFFF
};
static int32 normtab[7] = { 1, 2, 4, 8, 16, 32, 63 };
extern a10 pager_PC;
if (a->fhi & FP_UCRY) { /* carry set? */
printf ("%%PDP-10 FP: carry bit set at normalization, PC = %o\n", pager_PC);
a->flo = (a->flo >> 1) | ((a->fhi & 1) << 63); /* try to recover */
a->fhi = a->fhi >> 1; /* but root cause */
a->exp = a->exp + 1; } /* should be fixed! */
if ((a->fhi | a->flo) == 0) { /* if fraction = 0 */
a->sign = a->exp = 0; /* result is 0 */
return; }
while ((a->fhi & FP_UNORM) == 0) { /* normalized? */
for (i = 0; i < 6; i++) {
if (a->fhi & normmask[i]) break; }
a->fhi = (a->fhi << normtab[i]) | (a->flo >> (64 - normtab[i]));
a->flo = a->flo << normtab[i];
a->exp = a->exp - normtab[i]; }
if (rnd) { /* rounding? */
a->fhi = a->fhi + rnd; /* add round const */
if (a->fhi & FP_UCRY) { /* if carry out, */
a->fhi = a->fhi >> 1; /* renormalize */
a->exp = a->exp + 1; } }
if (a->fhi & FP_UCRY) { /* carry set? */
printf ("%%PDP-10 FP: carry bit set at normalization, PC = %o\n", pager_PC);
a->flo = (a->flo >> 1) | ((a->fhi & 1) << 63); /* try to recover */
a->fhi = a->fhi >> 1; /* but root cause */
a->exp = a->exp + 1; /* should be fixed! */
}
if ((a->fhi | a->flo) == 0) { /* if fraction = 0 */
a->sign = a->exp = 0; /* result is 0 */
return;
}
while ((a->fhi & FP_UNORM) == 0) { /* normalized? */
for (i = 0; i < 6; i++) {
if (a->fhi & normmask[i]) break;
}
a->fhi = (a->fhi << normtab[i]) | (a->flo >> (64 - normtab[i]));
a->flo = a->flo << normtab[i];
a->exp = a->exp - normtab[i];
}
if (rnd) { /* rounding? */
a->fhi = a->fhi + rnd; /* add round const */
if (a->fhi & FP_UCRY) { /* if carry out, */
a->fhi = a->fhi >> 1; /* renormalize */
a->exp = a->exp + 1;
}
}
return;
}
@@ -689,14 +750,16 @@ d10 val[2];
if (r->exp < 0) SETF (F_AOV | F_FOV | F_FXU | F_T1);
else if (r->exp > FP_M_EXP) SETF (F_AOV | F_FOV | F_T1);
val[0] = (((((d10) r->exp) & FP_M_EXP) << FP_V_EXP) |
((r->fhi & FP_UFHI) >> FP_V_UFHI)) & DMASK;
((r->fhi & FP_UFHI) >> FP_V_UFHI)) & DMASK;
if (lo) val[1] = ((r->fhi & FP_UFLO) >> FP_V_UFLO) & MMASK;
else val[1] = 0;
if (r->sign) { /* negate? */
if (fdvneg) { /* fdvr special? */
val[1] = ~val[1] & MMASK; /* 1's comp */
val[0] = ~val[0] & DMASK; }
else { DMOVN (val); } } /* 2's comp */
if (r->sign) { /* negate? */
if (fdvneg) { /* fdvr special? */
val[1] = ~val[1] & MMASK; /* 1's comp */
val[0] = ~val[0] & DMASK;
}
else { DMOVN (val); } /* 2's comp */
}
if (lo) *lo = val[1];
return val[0];
}

View File

@@ -1,6 +1,6 @@
/* pdp10_pag.c: PDP-10 paging subsystem simulator
Copyright (c) 1993-2004, Robert M Supnik
Copyright (c) 1993-2005, 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"),
@@ -19,18 +19,18 @@
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
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.
pag KS10 pager
pag KS10 pager
02-Dec-01 RMS Fixed bug in ITS LPMR (found by Dave Conroy)
21-Aug-01 RMS Fixed bug in ITS paging (found by Miriam Lennox)
Removed register from declarations
19-May-01 RMS Added workaround for TOPS-20 V4.1 boot bug
03-May-01 RMS Fixed bug in indirect page table pointer processing
29-Apr-01 RMS Added CLRCSH for ITS, fixed LPMR
02-Dec-01 RMS Fixed bug in ITS LPMR (found by Dave Conroy)
21-Aug-01 RMS Fixed bug in ITS paging (found by Miriam Lennox)
Removed register from declarations
19-May-01 RMS Added workaround for TOPS-20 V4.1 boot bug
03-May-01 RMS Fixed bug in indirect page table pointer processing
29-Apr-01 RMS Added CLRCSH for ITS, fixed LPMR
The pager consists of a standard hardware part (the translation
tables) and an operating-system specific page table fill routine.
@@ -45,10 +45,10 @@
reads and writes. An expanded pte contains a valid bit, a writeable
bit, and the physical page number shifted left by the page size.
Expanded pte meaning
0 invalid
>0 read only
<0 read write
Expanded pte meaning
0 invalid
>0 read only
<0 read write
There is a third, physical table, which is used in place of the
executive and user tables if paging is off. Its entries are always
@@ -65,34 +65,34 @@
The page fill routine is operating system dependent. Three styles
of paging are supported:
TOPS10 known in the KS10 microcode as KI10 paging,
used by earlier versions of TOPS10
TOPS20 known in the KS10 microcode as KL10 paging,
used by later versions of TOPS10, and TOPS20
ITS used only by ITS
TOPS10 known in the KS10 microcode as KI10 paging,
used by earlier versions of TOPS10
TOPS20 known in the KS10 microcode as KL10 paging,
used by later versions of TOPS10, and TOPS20
ITS used only by ITS
TOPS10 vs TOPS20 is selected by a bit in the EBR; ITS paging is
"hardwired" (it required different microcode).
*/
#include "pdp10_defs.h"
#include <setjmp.h>
/* Page table (contains expanded pte's) */
#define PTBL_ASIZE PAG_N_VPN
#define PTBL_MEMSIZE (1 << PTBL_ASIZE) /* page table size */
#define PTBL_AMASK (PTBL_MEMSIZE - 1)
#define PTBL_M (1u << 31) /* must be sign bit */
#define PTBL_V (1u << 30)
#define PTBL_MASK (PAG_PPN | PTBL_M | PTBL_V)
#define PTBL_ASIZE PAG_N_VPN
#define PTBL_MEMSIZE (1 << PTBL_ASIZE) /* page table size */
#define PTBL_AMASK (PTBL_MEMSIZE - 1)
#define PTBL_M (1u << 31) /* must be sign bit */
#define PTBL_V (1u << 30)
#define PTBL_MASK (PAG_PPN | PTBL_M | PTBL_V)
/* NXM processing */
#define REF_V 0 /* ref is virt */
#define REF_P 1 /* ref is phys */
#define PF_OK 0 /* pfail ok */
#define PF_TR 1 /* pfail trap */
#define REF_V 0 /* ref is virt */
#define REF_P 1 /* ref is phys */
#define PF_OK 0 /* pfail ok */
#define PF_TR 1 /* pfail trap */
extern d10 *M;
extern d10 acs[AC_NBLK * AC_NUM];
@@ -111,9 +111,9 @@ extern jmp_buf save_env;
extern int32 test_int (void);
extern int32 pi_eval (void);
int32 eptbl[PTBL_MEMSIZE]; /* exec page table */
int32 uptbl[PTBL_MEMSIZE]; /* user page table */
int32 physptbl[PTBL_MEMSIZE]; /* phys page table */
int32 eptbl[PTBL_MEMSIZE]; /* exec page table */
int32 uptbl[PTBL_MEMSIZE]; /* user page table */
int32 physptbl[PTBL_MEMSIZE]; /* phys page table */
int32 *ptbl_cur, *ptbl_prv;
int32 save_ea;
@@ -122,29 +122,32 @@ t_stat pag_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
t_stat pag_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat pag_reset (DEVICE *dptr);
void pag_nxm (a10 pa, int32 phys, int32 trap);
/* Pager data structures
pag_dev pager device descriptor
pag_unit pager units
pager_reg pager register list
pag_dev pager device descriptor
pag_unit pager units
pager_reg pager register list
*/
UNIT pag_unit[] = {
{ UDATA (NULL, UNIT_FIX, PTBL_MEMSIZE) },
{ UDATA (NULL, UNIT_FIX, PTBL_MEMSIZE) } };
{ UDATA (NULL, UNIT_FIX, PTBL_MEMSIZE) },
{ UDATA (NULL, UNIT_FIX, PTBL_MEMSIZE) }
};
REG pag_reg[] = {
{ ORDATA (PANIC_EA, save_ea, PASIZE), REG_HRO },
{ NULL } };
{ ORDATA (PANIC_EA, save_ea, PASIZE), REG_HRO },
{ NULL }
};
DEVICE pag_dev = {
"PAG", pag_unit, pag_reg, NULL,
2, 8, PTBL_ASIZE, 1, 8, 32,
&pag_ex, &pag_dep, &pag_reset,
NULL, NULL, NULL,
NULL, 0 };
"PAG", pag_unit, pag_reg, NULL,
2, 8, PTBL_ASIZE, 1, 8, 32,
&pag_ex, &pag_dep, &pag_reset,
NULL, NULL, NULL,
NULL, 0
};
/* Memory read and write routines
Read - read current or previous, read checking
@@ -161,62 +164,65 @@ d10 Read (a10 ea, int32 prv)
{
int32 pa, vpn, xpte;
if (ea < AC_NUM) return (prv? ac_prv[ea]: ac_cur[ea]); /* AC request */
vpn = PAG_GETVPN (ea); /* get page num */
xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */
if (ea < AC_NUM) return (prv? ac_prv[ea]: ac_cur[ea]); /* AC request */
vpn = PAG_GETVPN (ea); /* get page num */
xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */
if (xpte == 0) xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, PTF_RD);
pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */
if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */
return M[pa]; /* return data */
pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */
if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */
return M[pa]; /* return data */
}
d10 ReadM (a10 ea, int32 prv)
{
int32 pa, vpn, xpte;
if (ea < AC_NUM) return (prv? ac_prv[ea]: ac_cur[ea]); /* AC request */
vpn = PAG_GETVPN (ea); /* get page num */
xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */
if (ea < AC_NUM) return (prv? ac_prv[ea]: ac_cur[ea]); /* AC request */
vpn = PAG_GETVPN (ea); /* get page num */
xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */
if (xpte >= 0) xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, PTF_WR);
pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */
if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */
return M[pa]; /* return data */
pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */
if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */
return M[pa]; /* return data */
}
d10 ReadE (a10 ea)
{
int32 pa, vpn, xpte;
if (ea < AC_NUM) return AC(ea); /* AC? use current */
if (!PAGING) return M[ea]; /* phys? no mapping */
vpn = PAG_GETVPN (ea); /* get page num */
xpte = eptbl[vpn]; /* get exp pte, exec tbl */
if (ea < AC_NUM) return AC(ea); /* AC? use current */
if (!PAGING) return M[ea]; /* phys? no mapping */
vpn = PAG_GETVPN (ea); /* get page num */
xpte = eptbl[vpn]; /* get exp pte, exec tbl */
if (xpte == 0) xpte = ptbl_fill (ea, eptbl, PTF_RD);
pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */
if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */
return M[pa]; /* return data */
pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */
if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */
return M[pa]; /* return data */
}
d10 ReadP (a10 ea)
{
if (ea < AC_NUM) return AC(ea); /* AC request */
if (MEM_ADDR_NXM (ea)) pag_nxm (ea, REF_P, PF_TR); /* process nxm */
return M[ea]; /* return data */
if (ea < AC_NUM) return AC(ea); /* AC request */
if (MEM_ADDR_NXM (ea)) pag_nxm (ea, REF_P, PF_TR); /* process nxm */
return M[ea]; /* return data */
}
void Write (a10 ea, d10 val, int32 prv)
{
int32 pa, vpn, xpte;
if (ea < AC_NUM) { /* AC request */
if (prv) ac_prv[ea] = val; /* write AC */
else ac_cur[ea] = val; }
else { vpn = PAG_GETVPN (ea); /* get page num */
xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */
if (xpte >= 0) xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, PTF_WR);
pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */
if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */
else M[pa] = val; } /* write data */
if (ea < AC_NUM) { /* AC request */
if (prv) ac_prv[ea] = val; /* write AC */
else ac_cur[ea] = val;
}
else {
vpn = PAG_GETVPN (ea); /* get page num */
xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */
if (xpte >= 0) xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, PTF_WR);
pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */
if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */
else M[pa] = val; /* write data */
}
return;
}
@@ -224,22 +230,26 @@ void WriteE (a10 ea, d10 val)
{
int32 pa, vpn, xpte;
if (ea < AC_NUM) AC(ea) = val; /* AC? use current */
else if (!PAGING) M[ea] = val; /* phys? no mapping */
else { vpn = PAG_GETVPN (ea); /* get page num */
xpte = eptbl[vpn]; /* get exp pte, exec tbl */
if (xpte >= 0) xpte = ptbl_fill (ea, eptbl, PTF_WR);
pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */
if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */
else M[pa] = val; } /* write data */
if (ea < AC_NUM) AC(ea) = val; /* AC? use current */
else if (!PAGING) M[ea] = val; /* phys? no mapping */
else {
vpn = PAG_GETVPN (ea); /* get page num */
xpte = eptbl[vpn]; /* get exp pte, exec tbl */
if (xpte >= 0) xpte = ptbl_fill (ea, eptbl, PTF_WR);
pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */
if (MEM_ADDR_NXM (pa)) pag_nxm (pa, REF_V, PF_TR); /* process nxm */
else M[pa] = val; /* write data */
}
return;
}
void WriteP (a10 ea, d10 val)
{
if (ea < AC_NUM) AC(ea) = val; /* AC request */
else { if (MEM_ADDR_NXM (ea)) pag_nxm (ea, REF_P, PF_TR); /* process nxm */
M[ea] = val; } /* memory */
if (ea < AC_NUM) AC(ea) = val; /* AC request */
else {
if (MEM_ADDR_NXM (ea)) pag_nxm (ea, REF_P, PF_TR); /* process nxm */
M[ea] = val; /* memory */
}
return;
}
@@ -247,25 +257,25 @@ t_bool AccViol (a10 ea, int32 prv, int32 mode)
{
int32 vpn, xpte;
if (ea < AC_NUM) return FALSE; /* AC request */
vpn = PAG_GETVPN (ea); /* get page num */
xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */
if ((xpte == 0) || ((mode & PTF_WR) && (xpte > 0))) /* not accessible? */
xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, mode | PTF_MAP);
if (xpte) return FALSE; /* accessible */
return TRUE; /* not accessible */
if (ea < AC_NUM) return FALSE; /* AC request */
vpn = PAG_GETVPN (ea); /* get page num */
xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */
if ((xpte == 0) || ((mode & PTF_WR) && (xpte > 0))) /* not accessible? */
xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, mode | PTF_MAP);
if (xpte) return FALSE; /* accessible */
return TRUE; /* not accessible */
}
void pag_nxm (a10 pa, int32 phys, int32 trap)
{
apr_flg = apr_flg | APRF_NXM; /* set APR flag */
pi_eval (); /* eval intr */
apr_flg = apr_flg | APRF_NXM; /* set APR flag */
pi_eval (); /* eval intr */
pager_word = PF_NXM | (phys? PF_NXMP: 0) |
(TSTF (F_USR)? PF_USER: 0) | ((d10) pa);
if (PAGING && trap) ABORT (PAGE_FAIL); /* trap? */
(TSTF (F_USR)? PF_USER: 0) | ((d10) pa);
if (PAGING && trap) ABORT (PAGE_FAIL); /* trap? */
return;
}
/* Page table fill
This routine is called if the page table is invalid, or on a write
@@ -274,18 +284,19 @@ return;
pte for use by the caller. Otherwise, it generates a page fail.
Notes:
- If called from the console, invalid references return a pte
of 0, and the page table entry is not filled.
- If called from MAP, invalid references return a pte of 0. The
page fail word is properly set up.
- If called from the console, invalid references return a pte
of 0, and the page table entry is not filled.
- If called from MAP, invalid references return a pte of 0. The
page fail word is properly set up.
*/
#define PAGE_FAIL_TRAP if (mode & (PTF_CON | PTF_MAP)) return 0; \
ABORT (PAGE_FAIL)
#define READPT(x,y) if (MEM_ADDR_NXM (y)) { \
pag_nxm (y, REF_P, PF_OK); \
PAGE_FAIL_TRAP; } \
x = ReadP (y)
#define PAGE_FAIL_TRAP if (mode & (PTF_CON | PTF_MAP)) return 0; \
ABORT (PAGE_FAIL)
#define READPT(x,y) if (MEM_ADDR_NXM (y)) { \
pag_nxm (y, REF_P, PF_OK); \
PAGE_FAIL_TRAP; \
} \
x = ReadP (y)
int32 ptbl_fill (a10 ea, int32 *tbl, int32 mode)
{
@@ -300,32 +311,34 @@ int32 ptbl_fill (a10 ea, int32 *tbl, int32 mode)
ITS has no MAP instruction, therefore, physical NXM traps are ok.
*/
if (ITS) { /* ITS paging */
int32 acc, decvpn, pte, vpn, ptead, xpte;
d10 ptewd;
if (ITS) { /* ITS paging */
int32 acc, decvpn, pte, vpn, ptead, xpte;
d10 ptewd;
vpn = ITS_GETVPN (ea); /* get ITS pagno */
if (tbl == uptbl)
ptead = ((ea & RSIGN)? dbr2: dbr1) + ((vpn >> 1) & 077);
else ptead = ((ea & RSIGN)? dbr3: dbr4) + ((vpn >> 1) & 077);
ptewd = ReadP (ptead); /* get PTE pair */
pte = (int32) ((ptewd >> ((vpn & 1)? 0: 18)) & RMASK);
acc = ITS_GETACC (pte); /* get access */
pager_word = PF_VIRT | ea | ((tbl == uptbl)? PF_USER: 0) |
((mode & PTF_WR)? PF_ITS_WRITE: 0) | (acc << PF_ITS_V_ACC);
if ((acc != ITS_ACC_NO) && (!(mode & PTF_WR) || (acc == ITS_ACC_RW))) {
pte = pte & ~PTE_ITS_AGE; /* clear age */
if (vpn & 1) WriteP (ptead, (ptewd & LMASK) | pte);
else WriteP (ptead, (ptewd & RMASK) | (((d10) pte) << 18));
xpte = ((pte & PTE_ITS_PPMASK) << ITS_V_PN) | PTBL_V |
((acc == ITS_ACC_RW)? PTBL_M: 0);
decvpn = PAG_GETVPN (ea); /* get tlb idx */
if (!(mode & PTF_CON)) {
tbl[decvpn & ~1] = xpte; /* map lo ITS page */
tbl[decvpn | 1] = xpte + PAG_SIZE; } /* map hi */
return (xpte + ((decvpn & 1)? PAG_SIZE: 0)); }
PAGE_FAIL_TRAP;
} /* end ITS paging */
vpn = ITS_GETVPN (ea); /* get ITS pagno */
if (tbl == uptbl)
ptead = ((ea & RSIGN)? dbr2: dbr1) + ((vpn >> 1) & 077);
else ptead = ((ea & RSIGN)? dbr3: dbr4) + ((vpn >> 1) & 077);
ptewd = ReadP (ptead); /* get PTE pair */
pte = (int32) ((ptewd >> ((vpn & 1)? 0: 18)) & RMASK);
acc = ITS_GETACC (pte); /* get access */
pager_word = PF_VIRT | ea | ((tbl == uptbl)? PF_USER: 0) |
((mode & PTF_WR)? PF_ITS_WRITE: 0) | (acc << PF_ITS_V_ACC);
if ((acc != ITS_ACC_NO) && (!(mode & PTF_WR) || (acc == ITS_ACC_RW))) {
pte = pte & ~PTE_ITS_AGE; /* clear age */
if (vpn & 1) WriteP (ptead, (ptewd & LMASK) | pte);
else WriteP (ptead, (ptewd & RMASK) | (((d10) pte) << 18));
xpte = ((pte & PTE_ITS_PPMASK) << ITS_V_PN) | PTBL_V |
((acc == ITS_ACC_RW)? PTBL_M: 0);
decvpn = PAG_GETVPN (ea); /* get tlb idx */
if (!(mode & PTF_CON)) {
tbl[decvpn & ~1] = xpte; /* map lo ITS page */
tbl[decvpn | 1] = xpte + PAG_SIZE; /* map hi */
}
return (xpte + ((decvpn & 1)? PAG_SIZE: 0));
}
PAGE_FAIL_TRAP;
} /* end ITS paging */
/* TOPS-10 paging - checked against KS10 microcode
@@ -335,61 +348,62 @@ if (ITS) { /* ITS paging */
user process tables.
*/
else if (!T20) { /* TOPS-10 paging */
int32 pte, vpn, ptead, xpte;
d10 ptewd;
else if (!T20) { /* TOPS-10 paging */
int32 pte, vpn, ptead, xpte;
d10 ptewd;
vpn = PAG_GETVPN (ea); /* get virt page num */
if (tbl == uptbl) ptead = upta + UPT_T10_UMAP + (vpn >> 1);
else if (vpn < 0340) ptead = epta + EPT_T10_X000 + (vpn >> 1);
else if (vpn < 0400) ptead = upta + UPT_T10_X340 + ((vpn - 0340) >> 1);
else ptead = epta + EPT_T10_X400 + ((vpn - 0400) >> 1);
READPT (ptewd, ptead); /* get PTE pair */
pte = (int32) ((ptewd >> ((vpn & 1)? 0: 18)) & RMASK);
pager_word = PF_VIRT | ea | ((tbl == uptbl)? PF_USER: 0) |
((mode & PTF_WR)? PF_WRITE: 0) |
((pte & PTE_T10_A)? PF_T10_A |
((pte & PTE_T10_S)? PF_T10_S: 0): 0);
if (mode & PTF_MAP) pager_word = pager_word | /* map? add to pf wd */
((pte & PTE_T10_W)? PF_T10_W: 0) | /* W, S, C bits */
((pte & PTE_T10_S)? PF_T10_S: 0) |
((pte & PTE_T10_C)? PF_C: 0);
if ((pte & PTE_T10_A) && (!(mode & PTF_WR) || (pte & PTE_T10_W))) {
xpte = ((pte & PTE_PPMASK) << PAG_V_PN) | /* calc exp pte */
PTBL_V | ((pte & PTE_T10_W)? PTBL_M: 0);
if (!(mode & PTF_CON)) tbl[vpn] = xpte; /* set tbl if ~cons */
return xpte; }
PAGE_FAIL_TRAP;
} /* end TOPS10 paging */
vpn = PAG_GETVPN (ea); /* get virt page num */
if (tbl == uptbl) ptead = upta + UPT_T10_UMAP + (vpn >> 1);
else if (vpn < 0340) ptead = epta + EPT_T10_X000 + (vpn >> 1);
else if (vpn < 0400) ptead = upta + UPT_T10_X340 + ((vpn - 0340) >> 1);
else ptead = epta + EPT_T10_X400 + ((vpn - 0400) >> 1);
READPT (ptewd, ptead); /* get PTE pair */
pte = (int32) ((ptewd >> ((vpn & 1)? 0: 18)) & RMASK);
pager_word = PF_VIRT | ea | ((tbl == uptbl)? PF_USER: 0) |
((mode & PTF_WR)? PF_WRITE: 0) |
((pte & PTE_T10_A)? PF_T10_A |
((pte & PTE_T10_S)? PF_T10_S: 0): 0);
if (mode & PTF_MAP) pager_word = pager_word | /* map? add to pf wd */
((pte & PTE_T10_W)? PF_T10_W: 0) | /* W, S, C bits */
((pte & PTE_T10_S)? PF_T10_S: 0) |
((pte & PTE_T10_C)? PF_C: 0);
if ((pte & PTE_T10_A) && (!(mode & PTF_WR) || (pte & PTE_T10_W))) {
xpte = ((pte & PTE_PPMASK) << PAG_V_PN) | /* calc exp pte */
PTBL_V | ((pte & PTE_T10_W)? PTBL_M: 0);
if (!(mode & PTF_CON)) tbl[vpn] = xpte; /* set tbl if ~cons */
return xpte;
}
PAGE_FAIL_TRAP;
} /* end TOPS10 paging */
/* TOPS-20 paging - checked against KS10 ucode.
TOPS-20 paging has three phases:
1. Starting at EPT/UPT + 540 + section number, chase section pointers to
get the pointer to the section page table. In the KS10, because there
is only one section, the microcode caches the result of this evaluation.
Also, the evaluation of indirect pointers is simplified, as the section
table index is ignored.
1. Starting at EPT/UPT + 540 + section number, chase section pointers to
get the pointer to the section page table. In the KS10, because there
is only one section, the microcode caches the result of this evaluation.
Also, the evaluation of indirect pointers is simplified, as the section
table index is ignored.
2. Starting with the page map pointer, chase page pointers to get the
pointer to the page. The KS10 allows the operating system to inhibit
updating of the CST (base address = 0).
2. Starting with the page map pointer, chase page pointers to get the
pointer to the page. The KS10 allows the operating system to inhibit
updating of the CST (base address = 0).
3. Use the page pointer to get the CST entry. If a write reference to
a writeable page, set CST_M. If CST_M is set, set M in page table.
3. Use the page pointer to get the CST entry. If a write reference to
a writeable page, set CST_M. If CST_M is set, set M in page table.
*/
else { /* TOPS-20 paging */
int32 pmi, vpn, xpte;
int32 flg, t;
t_bool stop;
a10 pa, csta;
d10 ptr, cste;
d10 acc = PTE_T20_W | PTE_T20_C; /* init access bits */
else { /* TOPS-20 paging */
int32 pmi, vpn, xpte;
int32 flg, t;
t_bool stop;
a10 pa, csta;
d10 ptr, cste;
d10 acc = PTE_T20_W | PTE_T20_C; /* init access bits */
pager_word = PF_VIRT | ea | ((tbl == uptbl)? PF_USER: 0) |
((mode & PTF_WR)? PF_WRITE: 0); /* set page fail word */
pager_word = PF_VIRT | ea | ((tbl == uptbl)? PF_USER: 0) |
((mode & PTF_WR)? PF_WRITE: 0); /* set page fail word */
/* First phase - evaluate section pointers - returns a ptr to a page map
As a single section machine, the KS10 short circuits this part of the
@@ -407,99 +421,112 @@ else { /* TOPS-20 paging */
to generate the right behavior for the diagnostic.
*/
vpn = PAG_GETVPN (ea); /* get virt page num */
pa = (tbl == uptbl)? upta + UPT_T20_SCTN: epta + EPT_T20_SCTN;
READPT (ptr, pa & PAMASK); /* get section 0 ptr */
for (stop = FALSE, flg = 0; !stop; flg++) { /* eval section ptrs */
acc = acc & ptr; /* cascade acc bits */
switch (T20_GETTYP (ptr)) { /* case on ptr type */
case T20_NOA: /* no access */
default: /* undefined type */
PAGE_FAIL_TRAP; /* page fail */
case T20_IMM: /* immediate */
stop = TRUE; /* exit */
break;
case T20_SHR: /* shared */
pa = (int32) (spt + (ptr & RMASK)); /* get SPT idx */
READPT (ptr, pa & PAMASK); /* get SPT entry */
stop = TRUE; /* exit */
break;
case T20_IND: /* indirect */
if (flg && (t = test_int ())) ABORT (t);
pmi = T20_GETPMI (ptr); /* get sect tbl idx */
pa = (int32) (spt + (ptr & RMASK)); /* get SPT idx */
if (pmi) { /* for dskec */
pag_nxm ((pmi << 18) | pa, REF_P, PF_OK);
PAGE_FAIL_TRAP; }
READPT (ptr, pa & PAMASK); /* get SPT entry */
if (ptr & PTE_T20_STM) { PAGE_FAIL_TRAP; }
pa = PAG_PTEPA (ptr, pmi); /* index off page */
READPT (ptr, pa & PAMASK); /* get pointer */
break; /* continue in loop */
} /* end case */
} /* end for */
vpn = PAG_GETVPN (ea); /* get virt page num */
pa = (tbl == uptbl)? upta + UPT_T20_SCTN: epta + EPT_T20_SCTN;
READPT (ptr, pa & PAMASK); /* get section 0 ptr */
for (stop = FALSE, flg = 0; !stop; flg++) { /* eval section ptrs */
acc = acc & ptr; /* cascade acc bits */
switch (T20_GETTYP (ptr)) { /* case on ptr type */
case T20_NOA: /* no access */
default: /* undefined type */
PAGE_FAIL_TRAP; /* page fail */
case T20_IMM: /* immediate */
stop = TRUE; /* exit */
break;
case T20_SHR: /* shared */
pa = (int32) (spt + (ptr & RMASK)); /* get SPT idx */
READPT (ptr, pa & PAMASK); /* get SPT entry */
stop = TRUE; /* exit */
break;
case T20_IND: /* indirect */
if (flg && (t = test_int ())) ABORT (t);
pmi = T20_GETPMI (ptr); /* get sect tbl idx */
pa = (int32) (spt + (ptr & RMASK)); /* get SPT idx */
if (pmi) { /* for dskec */
pag_nxm ((pmi << 18) | pa, REF_P, PF_OK);
PAGE_FAIL_TRAP;
}
READPT (ptr, pa & PAMASK); /* get SPT entry */
if (ptr & PTE_T20_STM) { PAGE_FAIL_TRAP; }
pa = PAG_PTEPA (ptr, pmi); /* index off page */
READPT (ptr, pa & PAMASK); /* get pointer */
break; /* continue in loop */
} /* end case */
} /* end for */
/* Second phase - found page map ptr, evaluate page pointers */
pa = PAG_PTEPA (ptr, vpn); /* get ptbl address */
for (stop = FALSE, flg = 0; !stop; flg++) { /* eval page ptrs */
if (ptr & PTE_T20_STM) { PAGE_FAIL_TRAP; } /* non-res? */
if (cst) { /* cst really there? */
csta = (int32) ((cst + (ptr & PTE_PPMASK)) & PAMASK);
READPT (cste, csta); /* get CST entry */
if ((cste & CST_AGE) == 0) { PAGE_FAIL_TRAP; }
cste = (cste & cstm) | pur; /* update entry */
WriteP (csta, cste); } /* rewrite */
READPT (ptr, pa & PAMASK); /* get pointer */
acc = acc & ptr; /* cascade acc bits */
switch (T20_GETTYP (ptr)) { /* case on ptr type */
case T20_NOA: /* no access */
default: /* undefined type */
PAGE_FAIL_TRAP; /* page fail */
case T20_IMM: /* immediate */
stop = TRUE; /* exit */
break;
case T20_SHR: /* shared */
pa = (int32) (spt + (ptr & RMASK)); /* get SPT idx */
READPT (ptr, pa & PAMASK); /* get SPT entry */
stop = TRUE; /* exit */
break;
case T20_IND: /* indirect */
if (flg && (t = test_int ())) ABORT (t);
pmi = T20_GETPMI (ptr); /* get section index */
pa = (int32) (spt + (ptr & RMASK)); /* get SPT idx */
READPT (ptr, pa & PAMASK); /* get SPT entry */
pa = PAG_PTEPA (ptr, pmi); /* index off page */
break; /* continue in loop */
} /* end case */
} /* end for */
pa = PAG_PTEPA (ptr, vpn); /* get ptbl address */
for (stop = FALSE, flg = 0; !stop; flg++) { /* eval page ptrs */
if (ptr & PTE_T20_STM) { PAGE_FAIL_TRAP; } /* non-res? */
if (cst) { /* cst really there? */
csta = (int32) ((cst + (ptr & PTE_PPMASK)) & PAMASK);
READPT (cste, csta); /* get CST entry */
if ((cste & CST_AGE) == 0) { PAGE_FAIL_TRAP; }
cste = (cste & cstm) | pur; /* update entry */
WriteP (csta, cste); /* rewrite */
}
READPT (ptr, pa & PAMASK); /* get pointer */
acc = acc & ptr; /* cascade acc bits */
switch (T20_GETTYP (ptr)) { /* case on ptr type */
case T20_NOA: /* no access */
default: /* undefined type */
PAGE_FAIL_TRAP; /* page fail */
case T20_IMM: /* immediate */
stop = TRUE; /* exit */
break;
case T20_SHR: /* shared */
pa = (int32) (spt + (ptr & RMASK)); /* get SPT idx */
READPT (ptr, pa & PAMASK); /* get SPT entry */
stop = TRUE; /* exit */
break;
case T20_IND: /* indirect */
if (flg && (t = test_int ())) ABORT (t);
pmi = T20_GETPMI (ptr); /* get section index */
pa = (int32) (spt + (ptr & RMASK)); /* get SPT idx */
READPT (ptr, pa & PAMASK); /* get SPT entry */
pa = PAG_PTEPA (ptr, pmi); /* index off page */
break; /* continue in loop */
} /* end case */
} /* end for */
/* Last phase - have final page pointer, check modifiability */
if (ptr & PTE_T20_STM) { PAGE_FAIL_TRAP; } /* non-resident? */
if (cst) { /* CST really there? */
csta = (int32) ((cst + (ptr & PTE_PPMASK)) & PAMASK);
READPT (cste, csta); /* get CST entry */
if ((cste & CST_AGE) == 0) { PAGE_FAIL_TRAP; }
cste = (cste & cstm) | pur; } /* update entry */
else cste = 0; /* no, entry = 0 */
pager_word = pager_word | PF_T20_DN; /* set eval done */
xpte = ((int32) ((ptr & PTE_PPMASK) << PAG_V_PN)) | PTBL_V;
if (mode & PTF_WR) { /* write? */
if (acc & PTE_T20_W) { /* writable? */
xpte = xpte | PTBL_M; /* set PTE M */
cste = cste | CST_M; } /* set CST M */
else { PAGE_FAIL_TRAP; } } /* no, trap */
if (cst) WriteP (csta, cste); /* write CST entry */
if (mode & PTF_MAP) pager_word = pager_word | /* map? more in pf wd */
((xpte & PTBL_M)? PF_T20_M: 0) | /* M, W, C bits */
((acc & PTE_T20_W)? PF_T20_W: 0) |
((acc & PTE_T20_C)? PF_C: 0);
if (!(mode & PTF_CON)) tbl[vpn] = xpte; /* set tbl if ~cons */
return xpte;
} /* end TOPS20 paging */
if (ptr & PTE_T20_STM) { PAGE_FAIL_TRAP; } /* non-resident? */
if (cst) { /* CST really there? */
csta = (int32) ((cst + (ptr & PTE_PPMASK)) & PAMASK);
READPT (cste, csta); /* get CST entry */
if ((cste & CST_AGE) == 0) { PAGE_FAIL_TRAP; }
cste = (cste & cstm) | pur; /* update entry */
}
else cste = 0; /* no, entry = 0 */
pager_word = pager_word | PF_T20_DN; /* set eval done */
xpte = ((int32) ((ptr & PTE_PPMASK) << PAG_V_PN)) | PTBL_V;
if (mode & PTF_WR) { /* write? */
if (acc & PTE_T20_W) { /* writable? */
xpte = xpte | PTBL_M; /* set PTE M */
cste = cste | CST_M; /* set CST M */
}
else { PAGE_FAIL_TRAP; } /* no, trap */
}
if (cst) WriteP (csta, cste); /* write CST entry */
if (mode & PTF_MAP) pager_word = pager_word | /* map? more in pf wd */
((xpte & PTBL_M)? PF_T20_M: 0) | /* M, W, C bits */
((acc & PTE_T20_W)? PF_T20_W: 0) |
((acc & PTE_T20_C)? PF_C: 0);
if (!(mode & PTF_CON)) tbl[vpn] = xpte; /* set tbl if ~cons */
return xpte;
} /* end TOPS20 paging */
}
/* Set up pointers for AC, memory, and process table access */
void set_dyn_ptrs (void)
@@ -507,19 +534,25 @@ void set_dyn_ptrs (void)
int32 t;
if (PAGING) {
ac_cur = &acs[UBR_GETCURAC (ubr) * AC_NUM];
ac_prv = &acs[UBR_GETPRVAC (ubr) * AC_NUM];
if (TSTF (F_USR)) ptbl_cur = ptbl_prv = &uptbl[0];
else {
ptbl_cur = &eptbl[0];
ptbl_prv = TSTF (F_UIO)? &uptbl[0]: &eptbl[0]; } }
else { ac_cur = ac_prv = &acs[0];
ptbl_cur = ptbl_prv = &physptbl[0]; }
ac_cur = &acs[UBR_GETCURAC (ubr) * AC_NUM];
ac_prv = &acs[UBR_GETPRVAC (ubr) * AC_NUM];
if (TSTF (F_USR)) ptbl_cur = ptbl_prv = &uptbl[0];
else {
ptbl_cur = &eptbl[0];
ptbl_prv = TSTF (F_UIO)? &uptbl[0]: &eptbl[0];
}
}
else {
ac_cur = ac_prv = &acs[0];
ptbl_cur = ptbl_prv = &physptbl[0];
}
t = EBR_GETEBR (ebr);
epta = t << PAG_V_PN;
if (ITS) upta = (int32) ubr & PAMASK;
else { t = UBR_GETUBR (ubr);
upta = t << PAG_V_PN; }
else {
t = UBR_GETUBR (ubr);
upta = t << PAG_V_PN;
}
return;
}
@@ -538,8 +571,10 @@ d10 val = (TSTF (F_USR)? PF_USER: 0);
if (!PAGING) return (val | PF_T10_A | PF_T10_W | PF_T10_S | ea);
xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, PTF_MAP); /* get exp pte */
if (xpte) val = (pager_word & ~PAMASK) | PAG_XPTEPA (xpte, ea);
else { if (pager_word & PF_HARD) val = pager_word; /* hard error */
else val = val | PF_VIRT | ea; } /* inaccessible */
else {
if (pager_word & PF_HARD) val = pager_word; /* hard error */
else val = val | PF_VIRT | ea; /* inaccessible */
}
return val;
}
@@ -550,7 +585,7 @@ a10 conmap (a10 ea, int32 mode, int32 sw)
int32 xpte, *tbl;
if (!PAGING) return ea;
set_dyn_ptrs (); /* in case changed */
set_dyn_ptrs (); /* in case changed */
if (sw & SWMASK ('E')) tbl = eptbl;
else if (sw & SWMASK ('U')) tbl = uptbl;
else tbl = ptbl_cur;
@@ -558,28 +593,31 @@ xpte = ptbl_fill (ea, tbl, mode);
if (xpte) return PAG_XPTEPA (xpte, ea);
else return MAXMEMSIZE;
}
/* Common pager instructions */
t_bool clrpt (a10 ea, int32 prv)
{
int32 vpn = PAG_GETVPN (ea); /* get page num */
int32 vpn = PAG_GETVPN (ea); /* get page num */
if (ITS) { /* ITS? */
uptbl[vpn & ~1] = 0; /* clear double size */
uptbl[vpn | 1] = 0; /* entries in */
eptbl[vpn & ~1] = 0; /* both page tables */
eptbl[vpn | 1] = 0; }
else { uptbl[vpn] = 0; /* clear entries in */
eptbl[vpn] = 0; } /* both page tables */
if (ITS) { /* ITS? */
uptbl[vpn & ~1] = 0; /* clear double size */
uptbl[vpn | 1] = 0; /* entries in */
eptbl[vpn & ~1] = 0; /* both page tables */
eptbl[vpn | 1] = 0;
}
else {
uptbl[vpn] = 0; /* clear entries in */
eptbl[vpn] = 0; /* both page tables */
}
return FALSE;
}
t_bool wrebr (a10 ea, int32 prv)
{
ebr = ea & EBR_MASK; /* store EBR */
pag_reset (&pag_dev); /* clear page tables */
set_dyn_ptrs (); /* set dynamic ptrs */
ebr = ea & EBR_MASK; /* store EBR */
pag_reset (&pag_dev); /* clear page tables */
set_dyn_ptrs (); /* set dynamic ptrs */
return FALSE;
}
@@ -592,14 +630,15 @@ return FALSE;
t_bool wrubr (a10 ea, int32 prv)
{
d10 val = Read (ea, prv);
d10 ubr_mask = (ITS)? PAMASK: UBR_UBRMASK; /* ITS: ubr is wd addr */
d10 ubr_mask = (ITS)? PAMASK: UBR_UBRMASK; /* ITS: ubr is wd addr */
if (val & UBR_SETACB) ubr = ubr & ~UBR_ACBMASK; /* set AC's? */
else val = val & ~UBR_ACBMASK; /* no, keep old val */
if (val & UBR_SETUBR) { /* set UBR? */
ubr = ubr & ~ubr_mask;
pag_reset (&pag_dev); } /* yes, clr pg tbls */
else val = val & ~ubr_mask; /* no, keep old val */
if (val & UBR_SETACB) ubr = ubr & ~UBR_ACBMASK; /* set AC's? */
else val = val & ~UBR_ACBMASK; /* no, keep old val */
if (val & UBR_SETUBR) { /* set UBR? */
ubr = ubr & ~ubr_mask;
pag_reset (&pag_dev); /* yes, clr pg tbls */
}
else val = val & ~ubr_mask; /* no, keep old val */
ubr = (ubr | val) & (UBR_ACBMASK | ubr_mask);
set_dyn_ptrs ();
return FALSE;
@@ -623,7 +662,7 @@ t_bool rdhsb (a10 ea, int32 prv)
Write (ea, hsb, prv);
return FALSE;
}
/* TOPS20 pager instructions */
t_bool wrspb (a10 ea, int32 prv)
@@ -666,7 +705,7 @@ t_bool wrcstm (a10 ea, int32 prv)
{
cstm = Read (ea, prv);
if ((cpu_unit.flags & UNIT_T20V41) && (ea == 040127))
cstm = 0770000000000;
cstm = 0770000000000;
return FALSE;
}
@@ -675,7 +714,7 @@ t_bool rdcstm (a10 ea, int32 prv)
Write (ea, cstm, prv);
return FALSE;
}
/* ITS pager instructions
The KS10 does not implement the JPC option.
*/
@@ -770,7 +809,9 @@ Write (ADDA (ea, 1), dbr2, prv);
Write (ADDA (ea, 2), quant, prv);
return FALSE;
}
/* Simulator interface routines */
t_stat pag_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
{
int32 tbln = uptr - pag_unit;
@@ -795,7 +836,8 @@ t_stat pag_reset (DEVICE *dptr)
int32 i;
for (i = 0; i < PTBL_MEMSIZE; i++) {
eptbl[i] = uptbl[i] = 0;
physptbl[i] = (i << PAG_V_PN) + PTBL_M + PTBL_V; }
eptbl[i] = uptbl[i] = 0;
physptbl[i] = (i << PAG_V_PN) + PTBL_M + PTBL_V;
}
return SCPE_OK;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/* pdp10_sys.c: PDP-10 simulator interface
Copyright (c) 1993-2004, Robert M Supnik
Copyright (c) 1993-2005, 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"),
@@ -19,21 +19,22 @@
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
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.
09-Jan-03 RMS Added DEUNA/DELUA support
12-Sep-02 RMS Added RX211 support
22-Apr-02 RMS Removed magtape record length error
17-Sep-01 RMS Removed multiconsole support
25-Aug-01 RMS Enabled DZ11
27-May-01 RMS Added multiconsole support
29-Apr-01 RMS Fixed format for RDPCST, WRPCST
Added CLRCSH for ITS
03-Apr-01 RMS Added support for loading EXE files
19-Mar-01 RMS Added support for loading SAV files
30-Oct-00 RMS Added support for examine to file
22-Jul-05 RMS Fixed warning from Solaris C (from Doug Gwyn)
09-Jan-03 RMS Added DEUNA/DELUA support
12-Sep-02 RMS Added RX211 support
22-Apr-02 RMS Removed magtape record length error
17-Sep-01 RMS Removed multiconsole support
25-Aug-01 RMS Enabled DZ11
27-May-01 RMS Added multiconsole support
29-Apr-01 RMS Fixed format for RDPCST, WRPCST
Added CLRCSH for ITS
03-Apr-01 RMS Added support for loading EXE files
19-Mar-01 RMS Added support for loading SAV files
30-Oct-00 RMS Added support for examine to file
*/
#include "pdp10_defs.h"
@@ -53,12 +54,12 @@ extern a10 saved_PC;
/* SCP data structures and interface routines
sim_name simulator name string
sim_PC pointer to saved PC register descriptor
sim_emax number of words for examine
sim_devices array of pointers to simulated devices
sim_stop_messages array of pointers to stop messages
sim_load binary loader
sim_name simulator name string
sim_PC pointer to saved PC register descriptor
sim_emax number of words for examine
sim_devices array of pointers to simulated devices
sim_stop_messages array of pointers to stop messages
sim_load binary loader
*/
char sim_name[] = "PDP-10";
@@ -68,59 +69,61 @@ REG *sim_PC = &cpu_reg[0];
int32 sim_emax = 1;
DEVICE *sim_devices[] = {
&cpu_dev,
&pag_dev,
&tim_dev,
&fe_dev,
&uba_dev,
&ptr_dev,
&ptp_dev,
&ry_dev,
&lp20_dev,
&rp_dev,
&tu_dev,
&dz_dev,
&xu_dev,
NULL };
&cpu_dev,
&pag_dev,
&tim_dev,
&fe_dev,
&uba_dev,
&ptr_dev,
&ptp_dev,
&ry_dev,
&lp20_dev,
&rp_dev,
&tu_dev,
&dz_dev,
&xu_dev,
NULL
};
const char *sim_stop_messages[] = {
"Unknown error",
"HALT instruction",
"Breakpoint",
"Illegal instruction",
"Illegal interrupt instruction",
"Paging error in interrupt",
"Zero vector table",
"NXM on UPT/EPT reference",
"Nested indirect address limit exceeded",
"Nested XCT limit exceeded",
"Invalid I/O controller",
"Address stop",
"Panic stop" };
"Unknown error",
"HALT instruction",
"Breakpoint",
"Illegal instruction",
"Illegal interrupt instruction",
"Paging error in interrupt",
"Zero vector table",
"NXM on UPT/EPT reference",
"Nested indirect address limit exceeded",
"Nested XCT limit exceeded",
"Invalid I/O controller",
"Address stop",
"Panic stop"
};
/* Binary loader, supports RIM10, SAV, EXE */
#define FMT_R 1 /* RIM10 */
#define FMT_S 2 /* SAV */
#define FMT_E 3 /* EXE */
#define FMT_R 1 /* RIM10 */
#define FMT_S 2 /* SAV */
#define FMT_E 3 /* EXE */
#define EXE_DIR 01776 /* EXE directory */
#define EXE_VEC 01775 /* EXE entry vec */
#define EXE_PDV 01774 /* EXE ignored */
#define EXE_END 01777 /* EXE end
#define EXE_DIR 01776 /* EXE directory */
#define EXE_VEC 01775 /* EXE entry vec */
#define EXE_PDV 01774 /* EXE ignored */
#define EXE_END 01777 /* EXE end
/* RIM10 loader
RIM10 format is a binary paper tape format (all data frames
are 200 or greater). It consists of blocks containing
-count,,origin-1
word
:
word
checksum (includes IOWD)
:
JRST start
-count,,origin-1
word
:
word
checksum (includes IOWD)
:
JRST start
*/
d10 getrimw (FILE *fileref)
@@ -130,10 +133,12 @@ d10 word;
word = 0;
for (i = 0; i < 6;) {
if ((tmp = getc (fileref)) == EOF) return -1;
if (tmp & 0200) {
word = (word << 6) | ((d10) tmp & 077);
i++; } }
if ((tmp = getc (fileref)) == EOF) return -1;
if (tmp & 0200) {
word = (word << 6) | ((d10) tmp & 077);
i++;
}
}
return word;
}
@@ -143,27 +148,29 @@ d10 count, cksm, data;
a10 pa;
int32 op;
for ( ;; ) { /* loop until JRST */
count = cksm = getrimw (fileref); /* get header */
if (count < 0) return SCPE_FMT; /* read err? */
if (TSTS (count)) { /* hdr = IOWD? */
for ( ; TSTS (count); count = AOB (count)) {
data = getrimw (fileref); /* get data wd */
if (data < 0) return SCPE_FMT;
cksm = cksm + data; /* add to cksm */
pa = ((a10) count + 1) & AMASK; /* store */
M[pa] = data; } /* end for */
data = getrimw (fileref); /* get cksm */
if (data < 0) return SCPE_FMT;
if ((cksm + data) & DMASK) return SCPE_CSUM;/* test cksm */
} /* end if count */
else {
op = GET_OP (count); /* not IOWD */
if (op != OP_JRST) return SCPE_FMT; /* JRST? */
saved_PC = (a10) count & AMASK; /* set PC */
return SCPE_OK; } /* end else */
} /* end for */
return SCPE_FMT;
for ( ;; ) { /* loop until JRST */
count = cksm = getrimw (fileref); /* get header */
if (count < 0) return SCPE_FMT; /* read err? */
if (TSTS (count)) { /* hdr = IOWD? */
for ( ; TSTS (count); count = AOB (count)) {
data = getrimw (fileref); /* get data wd */
if (data < 0) return SCPE_FMT;
cksm = cksm + data; /* add to cksm */
pa = ((a10) count + 1) & AMASK; /* store */
M[pa] = data;
} /* end for */
data = getrimw (fileref); /* get cksm */
if (data < 0) return SCPE_FMT;
if ((cksm + data) & DMASK) return SCPE_CSUM; /* test cksm */
} /* end if count */
else {
op = GET_OP (count); /* not IOWD */
if (op != OP_JRST) return SCPE_FMT; /* JRST? */
saved_PC = (a10) count & AMASK; /* set PC */
break;
} /* end else */
} /* end for */
return SCPE_OK;
}
/* SAV file loader
@@ -171,12 +178,12 @@ return SCPE_FMT;
SAV format is a disk file format (36b words). It consists of
blocks containing:
-count,,origin-1
word
:
word
:
JRST start
-count,,origin-1
word
:
word
:
JRST start
*/
t_stat load_sav (FILE *fileref)
@@ -185,50 +192,52 @@ d10 count, data;
a10 pa;
int32 wc, op;
for ( ;; ) { /* loop */
wc = fxread (&count, sizeof (d10), 1, fileref); /* read IOWD */
if (wc == 0) return SCPE_OK; /* done? */
if (TSTS (count)) { /* IOWD? */
for ( ; TSTS (count); count = AOB (count)) {
wc = fxread (&data, sizeof (d10), 1, fileref);
if (wc == 0) return SCPE_FMT;
pa = ((a10) count + 1) & AMASK; /* store data */
M[pa] = data; } /* end for */
} /* end if count*/
else {
op = GET_OP (count); /* not IOWD */
if (op != OP_JRST) return SCPE_FMT; /* JRST? */
saved_PC = (a10) count & AMASK; /* set PC */
return SCPE_OK; } /* end else */
} /* end for */
return SCPE_FMT;
for ( ;; ) { /* loop */
wc = fxread (&count, sizeof (d10), 1, fileref); /* read IOWD */
if (wc == 0) return SCPE_OK; /* done? */
if (TSTS (count)) { /* IOWD? */
for ( ; TSTS (count); count = AOB (count)) {
wc = fxread (&data, sizeof (d10), 1, fileref);
if (wc == 0) return SCPE_FMT;
pa = ((a10) count + 1) & AMASK; /* store data */
M[pa] = data;
} /* end for */
} /* end if count*/
else {
op = GET_OP (count); /* not IOWD */
if (op != OP_JRST) return SCPE_FMT; /* JRST? */
saved_PC = (a10) count & AMASK; /* set PC */
break;
} /* end else */
} /* end for */
return SCPE_OK;
}
/* EXE file loader
EXE format is a disk file format (36b words). It consists of
blocks containing:
block type,,total words = n
n - 1 data words
block type,,total words = n
n - 1 data words
Block types are
EXE_DIR (1776) directory
EXE_VEC (1775) entry vector
EXE_PDV (1774) optional blocks
EXE_END (1777) end block
EXE_DIR (1776) directory
EXE_VEC (1775) entry vector
EXE_PDV (1774) optional blocks
EXE_END (1777) end block
The directory blocks are the most important and contain doubleword
page loading information:
word0<0:8> = flags
<9:35> = page in file (0 if 0 page)
word1<0:8> = repeat count - 1
<9:35> = page in memory
word0<0:8> = flags
<9:35> = page in file (0 if 0 page)
word1<0:8> = repeat count - 1
<9:35> = page in memory
*/
#define DIRSIZ (2 * PAG_SIZE)
#define DIRSIZ (2 * PAG_SIZE)
t_stat load_exe (FILE *fileref)
{
@@ -237,59 +246,66 @@ int32 ndir, entvec, i, j, k, cont, bsz, bty, rpt, wc;
int32 fpage, mpage;
a10 ma;
ndir = entvec = 0; /* no dir, entvec */
ndir = entvec = 0; /* no dir, entvec */
cont = 1;
do { wc = fxread (&data, sizeof (d10), 1, fileref); /* read blk hdr */
if (wc == 0) return SCPE_FMT; /* error? */
bsz = (int32) ((data & RMASK) - 1); /* get count */
if (bsz <= 0) return SCPE_FMT; /* zero? */
bty = (int32) LRZ (data); /* get type */
switch (bty) { /* case type */
case EXE_DIR: /* directory */
if (ndir) return SCPE_FMT; /* got one */
ndir = fxread (dirbuf, sizeof (d10), bsz, fileref);
if (ndir < bsz) return SCPE_FMT; /* error */
break;
case EXE_PDV: /* ??? */
fseek (fileref, bsz * sizeof (d10), SEEK_CUR);
break;
case EXE_VEC: /* entry vec */
if (bsz != 2) return SCPE_FMT; /* must be 2 wds */
entvec = fxread (entbuf, sizeof (d10), bsz, fileref);
if (entvec < 2) return SCPE_FMT; /* error? */
cont = 0; /* stop */
break;
case EXE_END: /* end */
if (bsz != 0) return SCPE_FMT; /* must be hdr */
cont = 0; /* stop */
break;
default:
return SCPE_FMT; } /* end switch */
} /* end do */
while (cont);
do {
wc = fxread (&data, sizeof (d10), 1, fileref); /* read blk hdr */
if (wc == 0) return SCPE_FMT; /* error? */
bsz = (int32) ((data & RMASK) - 1); /* get count */
if (bsz <= 0) return SCPE_FMT; /* zero? */
bty = (int32) LRZ (data); /* get type */
switch (bty) { /* case type */
for (i = 0; i < ndir; i = i + 2) { /* loop thru dir */
fpage = (int32) (dirbuf[i] & RMASK); /* file page */
mpage = (int32) (dirbuf[i + 1] & RMASK); /* memory page */
rpt = (int32) ((dirbuf[i + 1] >> 27) + 1); /* repeat count */
for (j = 0; j < rpt; j++, mpage++) { /* loop thru rpts */
if (fpage) { /* file pages? */
fseek (fileref, (fpage << PAG_V_PN) * sizeof (d10), SEEK_SET);
wc = fxread (pagbuf, sizeof (d10), PAG_SIZE, fileref);
if (wc < PAG_SIZE) return SCPE_FMT;
fpage++; }
ma = mpage << PAG_V_PN; /* mem addr */
for (k = 0; k < PAG_SIZE; k++, ma++) { /* copy buf to mem */
if (MEM_ADDR_NXM (ma)) return SCPE_NXM;
M[ma] = fpage? (pagbuf[k] & DMASK): 0;
} /* end copy */
} /* end rpt */
} /* end directory */
case EXE_DIR: /* directory */
if (ndir) return SCPE_FMT; /* got one */
ndir = fxread (dirbuf, sizeof (d10), bsz, fileref);
if (ndir < bsz) return SCPE_FMT; /* error */
break;
case EXE_PDV: /* ??? */
fseek (fileref, bsz * sizeof (d10), SEEK_CUR);
break;
case EXE_VEC: /* entry vec */
if (bsz != 2) return SCPE_FMT; /* must be 2 wds */
entvec = fxread (entbuf, sizeof (d10), bsz, fileref);
if (entvec < 2) return SCPE_FMT; /* error? */
cont = 0; /* stop */
break;
case EXE_END: /* end */
if (bsz != 0) return SCPE_FMT; /* must be hdr */
cont = 0; /* stop */
break;
default:
return SCPE_FMT;
} /* end switch */
} while (cont); /* end do */
for (i = 0; i < ndir; i = i + 2) { /* loop thru dir */
fpage = (int32) (dirbuf[i] & RMASK); /* file page */
mpage = (int32) (dirbuf[i + 1] & RMASK); /* memory page */
rpt = (int32) ((dirbuf[i + 1] >> 27) + 1); /* repeat count */
for (j = 0; j < rpt; j++, mpage++) { /* loop thru rpts */
if (fpage) { /* file pages? */
fseek (fileref, (fpage << PAG_V_PN) * sizeof (d10), SEEK_SET);
wc = fxread (pagbuf, sizeof (d10), PAG_SIZE, fileref);
if (wc < PAG_SIZE) return SCPE_FMT;
fpage++;
}
ma = mpage << PAG_V_PN; /* mem addr */
for (k = 0; k < PAG_SIZE; k++, ma++) { /* copy buf to mem */
if (MEM_ADDR_NXM (ma)) return SCPE_NXM;
M[ma] = fpage? (pagbuf[k] & DMASK): 0;
} /* end copy */
} /* end rpt */
} /* end directory */
if (entvec && entbuf[1])
saved_PC = (int32) entbuf[1] & RMASK; /* start addr */
saved_PC = (int32) entbuf[1] & RMASK; /* start addr */
return SCPE_OK;
}
/* Master loader */
t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
@@ -298,54 +314,63 @@ d10 data;
int32 wc, fmt;
extern int32 sim_switches;
fmt = 0; /* no fmt */
if (sim_switches & SWMASK ('R')) fmt = FMT_R; /* -r? */
else if (sim_switches & SWMASK ('S')) fmt = FMT_S; /* -s? */
else if (sim_switches & SWMASK ('E')) fmt = FMT_E; /* -e? */
else if (match_ext (fnam, "RIM")) fmt = FMT_R; /* .RIM? */
else if (match_ext (fnam, "SAV")) fmt = FMT_S; /* .SAV? */
else if (match_ext (fnam, "EXE")) fmt = FMT_E; /* .EXE? */
else { wc = fxread (&data, sizeof (d10), 1, fileref); /* read hdr */
if (wc == 0) return SCPE_FMT; /* error? */
if (LRZ (data) == EXE_DIR) fmt = FMT_E; /* EXE magic? */
else if (TSTS (data)) fmt = FMT_S; /* SAV magic? */
fseek (fileref, 0, SEEK_SET); } /* rewind */
switch (fmt) { /* case fmt */
case FMT_R: /* RIM */
return load_rim (fileref);
case FMT_S: /* SAV */
return load_sav (fileref);
case FMT_E: /* EXE */
return load_exe (fileref); }
fmt = 0; /* no fmt */
if (sim_switches & SWMASK ('R')) fmt = FMT_R; /* -r? */
else if (sim_switches & SWMASK ('S')) fmt = FMT_S; /* -s? */
else if (sim_switches & SWMASK ('E')) fmt = FMT_E; /* -e? */
else if (match_ext (fnam, "RIM")) fmt = FMT_R; /* .RIM? */
else if (match_ext (fnam, "SAV")) fmt = FMT_S; /* .SAV? */
else if (match_ext (fnam, "EXE")) fmt = FMT_E; /* .EXE? */
else {
wc = fxread (&data, sizeof (d10), 1, fileref); /* read hdr */
if (wc == 0) return SCPE_FMT; /* error? */
if (LRZ (data) == EXE_DIR) fmt = FMT_E; /* EXE magic? */
else if (TSTS (data)) fmt = FMT_S; /* SAV magic? */
fseek (fileref, 0, SEEK_SET); /* rewind */
}
switch (fmt) { /* case fmt */
case FMT_R: /* RIM */
return load_rim (fileref);
case FMT_S: /* SAV */
return load_sav (fileref);
case FMT_E: /* EXE */
return load_exe (fileref);
}
printf ("Can't determine load file format\n");
return SCPE_FMT;
}
/* Symbol tables */
#define I_V_FL 39 /* inst class */
#define I_M_FL 03 /* class mask */
#define I_ITS 004000000000000 /* ITS flag */
#define I_AC 000000000000000 /* AC, address */
#define I_OP 010000000000000 /* address only */
#define I_IO 020000000000000 /* classic I/O */
#define I_V_AC 00
#define I_V_OP 01
#define I_V_IO 02
#define I_V_FL 39 /* inst class */
#define I_M_FL 03 /* class mask */
#define I_ITS 004000000000000 /* ITS flag */
#define I_AC 000000000000000 /* AC, address */
#define I_OP 010000000000000 /* address only */
#define I_IO 020000000000000 /* classic I/O */
#define I_V_AC 00
#define I_V_OP 01
#define I_V_IO 02
static const d10 masks[] = {
0777000000000, 0777740000000,
0700340000000, 0777777777777 };
0700340000000, 0777777777777
};
static const char *opcode[] = {
"XCTR", "XCTI", /* ITS only */
"XCTR", "XCTI", /* ITS only */
"IORDI", "IORDQ", "IORD", "IOWR", "IOWRI", "IOWRQ",
"IORDBI", "IORDBQ", "IORDB", "IOWRB", "IOWRBI", "IOWRBQ",
"CLRCSH", "RDPCST", "WRPCST",
"SDBR1", "SDBR2", "SDBR3", "SDBR4", "SPM",
"LDBR1", "LDBR2", "LDBR3", "LDBR4", "LPMR",
"PORTAL", "JRSTF", "HALT", /* AC defines op */
"PORTAL", "JRSTF", "HALT", /* AC defines op */
"XJRSTF", "XJEN", "XPCW",
"JEN", "SFM", "XJRST", "IBP",
"JFOV", "JCRY1", "JCRY0", "JCRY", "JOV",
@@ -418,19 +443,19 @@ static const char *opcode[] = {
"TRO", "TLO", "TROE", "TLOE", "TROA", "TLOA", "TRON", "TLON",
"TDO", "TSO", "TDOE", "TSOE", "TDOA", "TSOA", "TDON", "TSON",
"UMOVE", "UMOVEM", /* KS10 I/O */
"UMOVE", "UMOVEM", /* KS10 I/O */
"TIOE", "TION", "RDIO", "WRIO",
"BSIO", "BCIO", "BLTBU", "BLTUB",
"TIOEB", "TIONB", "RDIOB", "WRIOB",
"BSIOB", "BCIOB",
"BLKI", "DATAI", "BLKO", "DATAO", /* classic I/O */
"BLKI", "DATAI", "BLKO", "DATAO", /* classic I/O */
"CONO", "CONI", "CONSZ", "CONSO",
"CLEAR", "CLEARI", "CLEARM", "CLEARB",
"OR", "ORI", "ORM", "ORB", "XMOVEI", "XHLLI", /* alternate ops */
"OR", "ORI", "ORM", "ORB", "XMOVEI", "XHLLI", /* alternate ops */
"CMPSL", "CMPSE", "CMPSLE", /* extended ops */
"CMPSL", "CMPSE", "CMPSLE", /* extended ops */
"EDIT", "CMPSGE", "CMPSN", "CMPSG",
"CVTDBO", "CVTDBT", "CVTBDO", "CVTBDT",
"MOVSO", "MOVST", "MOVSLJ", "MOVSRJ",
@@ -438,7 +463,8 @@ static const char *opcode[] = {
"GFIX", "GDFIXR", "GFIXR", "DGFLTR",
"GFLTR", "GFSC",
NULL };
NULL
};
static const d10 opc_val[] = {
0102000000000+I_AC+I_ITS, 0103000000000+I_AC+I_ITS,
@@ -605,51 +631,57 @@ static const d10 opc_val[] = {
0020000000000+I_AC, 0021000000000+I_AC, 0022000000000+I_AC, 0023000000000+I_AC,
0024000000000+I_AC, 0025000000000+I_AC, 0026000000000+I_AC, 0027000000000+I_AC,
0030000000000+I_AC, 0031000000000+I_AC,
-1 };
-1
};
#define NUMDEV 6
#define NUMDEV 6
static const char *devnam[NUMDEV] = {
"APR", "PI", "PAG", "CCA", "TIM", "MTR"};
"APR", "PI", "PAG", "CCA", "TIM", "MTR"
};
/* Symbolic decode
Inputs:
*of = output stream
addr = current PC
*val = pointer to values
*uptr = pointer to unit
sw = switches
*of = output stream
addr = current PC
*val = pointer to values
*uptr = pointer to unit
sw = switches
Outputs:
return = status code
return = status code
*/
#define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x)
#define SIXTOASC(x) ((x) + 040)
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
UNIT *uptr, int32 sw)
UNIT *uptr, int32 sw)
{
int32 i, j, c, cflag, ac, xr, y, dev;
d10 inst;
inst = val[0];
cflag = (uptr == NULL) || (uptr == &cpu_unit);
if (sw & SWMASK ('A')) { /* ASCII? */
if (inst > 0377) return SCPE_ARG;
fprintf (of, FMTASC ((int32) (inst & 0177)));
return SCPE_OK; }
if (sw & SWMASK ('C')) { /* character? */
for (i = 30; i >= 0; i = i - 6) {
c = (int32) ((inst >> i) & 077);
fprintf (of, "%c", SIXTOASC (c)); }
return SCPE_OK; }
if (sw & SWMASK ('P')) { /* packed? */
for (i = 29; i >= 0; i = i - 7) {
c = (int32) ((inst >> i) & 0177);
fprintf (of, FMTASC (c)); }
return SCPE_OK; }
if (sw & SWMASK ('A')) { /* ASCII? */
if (inst > 0377) return SCPE_ARG;
fprintf (of, FMTASC ((int32) (inst & 0177)));
return SCPE_OK;
}
if (sw & SWMASK ('C')) { /* character? */
for (i = 30; i >= 0; i = i - 6) {
c = (int32) ((inst >> i) & 077);
fprintf (of, "%c", SIXTOASC (c));
}
return SCPE_OK;
}
if (sw & SWMASK ('P')) { /* packed? */
for (i = 29; i >= 0; i = i - 7) {
c = (int32) ((inst >> i) & 0177);
fprintf (of, FMTASC (c));
}
return SCPE_OK;
}
if (!(sw & SWMASK ('M'))) return SCPE_ARG;
/* Instruction decode */
@@ -658,38 +690,42 @@ ac = GET_AC (inst);
xr = GET_XR (inst);
y = GET_ADDR (inst);
dev = GET_DEV (inst);
for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
j = (int32) ((opc_val[i] >> I_V_FL) & I_M_FL); /* get class */
if (((opc_val[i] & DMASK) == (inst & masks[j])) && /* match? */
(((opc_val[i] & I_ITS) == 0) || ITS)) {
fprintf (of, "%s ", opcode[i]); /* opcode */
switch (j) { /* case on class */
case I_V_AC: /* AC + address */
fprintf (of, "%-o,", ac); /* print AC, fall thru */
case I_V_OP: /* address only */
if (inst & INST_IND) fprintf (of, "@");
if (xr) fprintf (of, "%-o(%-o)", y, xr);
else fprintf (of, "%-o", y);
break;
case I_V_IO: /* I/O */
if (dev < NUMDEV) fprintf (of, "%s,", devnam[dev]);
else fprintf (of, "%-o,", dev);
if (inst & INST_IND) fprintf (of, "@");
if (xr) fprintf (of, "%-o(%-o)", y, xr);
else fprintf (of, "%-o", y);
break; } /* end case */
return SCPE_OK; } /* end if */
} /* end for */
for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */
j = (int32) ((opc_val[i] >> I_V_FL) & I_M_FL); /* get class */
if (((opc_val[i] & DMASK) == (inst & masks[j])) && /* match? */
(((opc_val[i] & I_ITS) == 0) || ITS)) {
fprintf (of, "%s ", opcode[i]); /* opcode */
switch (j) { /* case on class */
case I_V_AC: /* AC + address */
fprintf (of, "%-o,", ac); /* print AC, fall thru */
case I_V_OP: /* address only */
if (inst & INST_IND) fprintf (of, "@");
if (xr) fprintf (of, "%-o(%-o)", y, xr);
else fprintf (of, "%-o", y);
break;
case I_V_IO: /* I/O */
if (dev < NUMDEV) fprintf (of, "%s,", devnam[dev]);
else fprintf (of, "%-o,", dev);
if (inst & INST_IND) fprintf (of, "@");
if (xr) fprintf (of, "%-o(%-o)", y, xr);
else fprintf (of, "%-o", y);
break;
} /* end case */
return SCPE_OK;
} /* end if */
} /* end for */
return SCPE_ARG;
}
/* Get operand, including indirect and index
Inputs:
*cptr = pointer to input string
*status = pointer to error status
*cptr = pointer to input string
*status = pointer to error status
Outputs:
val = output value
val = output value
*/
t_value get_opnd (char *cptr, t_stat *status)
@@ -698,38 +734,41 @@ int32 sign = 0;
t_value val, xr = 0, ind = 0;
char *tptr;
*status = SCPE_ARG; /* assume fail */
*status = SCPE_ARG; /* assume fail */
if (*cptr == '@') {
ind = INST_IND;
cptr++; }
ind = INST_IND;
cptr++;
}
if (*cptr == '+') cptr++;
else if (*cptr == '-') {
sign = 1;
cptr++; }
sign = 1;
cptr++;
}
val = strtotv (cptr, &tptr, 8);
if (val > 0777777) return 0;
if (sign) val = (~val + 1) & 0777777;
cptr = tptr;
if (*cptr == '(') {
cptr++;
xr = strtotv (cptr, &tptr, 8);
if ((cptr == tptr) || (*tptr != ')') ||
(xr > AC_NUM) || (xr == 0)) return 0;
cptr = ++tptr; }
cptr++;
xr = strtotv (cptr, &tptr, 8);
if ((cptr == tptr) || (*tptr != ')') ||
(xr > AC_NUM) || (xr == 0)) return 0;
cptr = ++tptr;
}
if (*cptr == 0) *status = SCPE_OK;
return (ind | (xr << 18) | val);
}
/* Symbolic input
Inputs:
*cptr = pointer to input string
addr = current PC
uptr = pointer to unit
*val = pointer to output values
sw = switches
*cptr = pointer to input string
addr = current PC
uptr = pointer to unit
*val = pointer to output values
sw = switches
Outputs:
status = error status
status = error status
*/
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
@@ -742,57 +781,70 @@ char gbuf[CBUFSIZE];
cflag = (uptr == NULL) || (uptr == &cpu_unit);
while (isspace (*cptr)) cptr++;
for (i = 0; i < 6; i++) {
if (cptr[i] == 0) {
for (j = i + 1; j <= 6; j++) cptr[j] = 0;
break; } }
if (cptr[i] == 0) {
for (j = i + 1; j <= 6; j++) cptr[j] = 0;
break;
}
}
if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
val[0] = (t_value) cptr[0];
return SCPE_OK; }
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
val[0] = (t_value) cptr[0];
return SCPE_OK;
}
if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* sixbit string? */
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
for (i = 0; i < 6; i++) {
val[0] = (val[0] << 6);
if (cptr[i]) val[0] = val[0] |
((t_value) ((cptr[i] + 040) & 077)); }
return SCPE_OK; }
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
for (i = 0; i < 6; i++) {
val[0] = (val[0] << 6);
if (cptr[i]) val[0] = val[0] |
((t_value) ((cptr[i] + 040) & 077));
}
return SCPE_OK;
}
if ((sw & SWMASK ('P')) || ((*cptr == '#') && cptr++)) { /* packed string? */
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
for (i = 0; i < 5; i++) val[0] = (val[0] << 7) | ((t_value) cptr[i]);
val[0] = val[0] << 1;
return SCPE_OK; }
if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */
for (i = 0; i < 5; i++) val[0] = (val[0] << 7) | ((t_value) cptr[i]);
val[0] = val[0] << 1;
return SCPE_OK;
}
/* Symbolic input, continued */
/* Instruction parse */
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
cptr = get_glyph (cptr, gbuf, 0); /* get opcode */
for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ;
if (opcode[i] == NULL) return SCPE_ARG;
val[0] = opc_val[i] & DMASK; /* get value */
j = (int32) ((opc_val[i] >> I_V_FL) & I_M_FL); /* get class */
switch (j) { /* case on class */
case I_V_AC: /* AC + operand */
if (strchr (cptr, ',')) { /* AC specified? */
cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
if (gbuf[0]) { /* can be omitted */
ac = get_uint (gbuf, 8, AC_NUM - 1, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | (ac << INST_V_AC); } }
case I_V_OP: /* operand */
cptr = get_glyph (cptr, gbuf, 0);
val[0] = val[0] | get_opnd (gbuf, &r);
if (r != SCPE_OK) return SCPE_ARG;
break;
case I_V_IO: /* I/O */
cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
for (dev = 0; (dev < NUMDEV) && (strcmp (devnam[dev], gbuf) != 0); dev++);
if (dev >= NUMDEV) {
dev = get_uint (gbuf, 8, INST_M_DEV, &r);
if (r != SCPE_OK) return SCPE_ARG; }
val[0] = val[0] | (dev << INST_V_DEV);
cptr = get_glyph (cptr, gbuf, 0);
val[0] = val[0] | get_opnd (gbuf, &r);
if (r != SCPE_OK) return SCPE_ARG;
break; } /* end case */
if (*cptr != 0) return SCPE_ARG; /* junk at end? */
val[0] = opc_val[i] & DMASK; /* get value */
j = (int32) ((opc_val[i] >> I_V_FL) & I_M_FL); /* get class */
switch (j) { /* case on class */
case I_V_AC: /* AC + operand */
if (strchr (cptr, ',')) { /* AC specified? */
cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
if (gbuf[0]) { /* can be omitted */
ac = get_uint (gbuf, 8, AC_NUM - 1, &r);
if (r != SCPE_OK) return SCPE_ARG;
val[0] = val[0] | (ac << INST_V_AC);
}
} /* fall through */
case I_V_OP: /* operand */
cptr = get_glyph (cptr, gbuf, 0);
val[0] = val[0] | get_opnd (gbuf, &r);
if (r != SCPE_OK) return SCPE_ARG;
break;
case I_V_IO: /* I/O */
cptr = get_glyph (cptr, gbuf, ','); /* get glyph */
for (dev = 0; (dev < NUMDEV) && (strcmp (devnam[dev], gbuf) != 0); dev++);
if (dev >= NUMDEV) {
dev = get_uint (gbuf, 8, INST_M_DEV, &r);
if (r != SCPE_OK) return SCPE_ARG;
}
val[0] = val[0] | (dev << INST_V_DEV);
cptr = get_glyph (cptr, gbuf, 0);
val[0] = val[0] | get_opnd (gbuf, &r);
if (r != SCPE_OK) return SCPE_ARG;
break;
} /* end case */
if (*cptr != 0) return SCPE_ARG; /* junk at end? */
return SCPE_OK;
}

View File

@@ -1,6 +1,6 @@
/* pdp10_tim.c: PDP-10 tim subsystem simulator
Copyright (c) 1993-2004, Robert M Supnik
Copyright (c) 1993-2005, 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"),
@@ -19,48 +19,48 @@
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
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.
tim timer subsystem
tim timer subsystem
02-Feb-04 RMS Exported variables needed by Ethernet simulator
29-Jan-02 RMS New data structures
06-Jan-02 RMS Added enable/disable support
02-Dec-01 RMS Fixed bug in ITS PC sampling (found by Dave Conroy)
31-Aug-01 RMS Changed int64 to t_int64 for Windoze
17-Jul-01 RMS Moved function prototype
04-Jul-01 RMS Added DZ11 support
02-Feb-04 RMS Exported variables needed by Ethernet simulator
29-Jan-02 RMS New data structures
06-Jan-02 RMS Added enable/disable support
02-Dec-01 RMS Fixed bug in ITS PC sampling (found by Dave Conroy)
31-Aug-01 RMS Changed int64 to t_int64 for Windoze
17-Jul-01 RMS Moved function prototype
04-Jul-01 RMS Added DZ11 support
*/
#include "pdp10_defs.h"
#include <time.h>
#define TIM_N_HWRE 12 /* hwre bits */
#define TIM_HWRE 0000000010000 /* hwre incr */
#define TIM_DELAY 500
#define TIM_TPS 1001 /* ticks per sec */
#define DZ_MULT (TIM_TPS / 60) /* DZ poll multiplier */
#define TB_MASK 037777777777777777777; /* 71 - 12 bits */
#define UNIT_V_Y2K (UNIT_V_UF) /* Y2K compliant OS */
#define UNIT_Y2K (1u << UNIT_V_Y2K)
#define TIM_N_HWRE 12 /* hwre bits */
#define TIM_HWRE 0000000010000 /* hwre incr */
#define TIM_DELAY 500
#define TIM_TPS 1001 /* ticks per sec */
#define DZ_MULT (TIM_TPS / 60) /* DZ poll multiplier */
#define TB_MASK 037777777777777777777; /* 71 - 12 bits */
#define UNIT_V_Y2K (UNIT_V_UF) /* Y2K compliant OS */
#define UNIT_Y2K (1u << UNIT_V_Y2K)
extern int32 apr_flg, pi_act;
extern UNIT cpu_unit;
extern d10 pcst;
extern a10 pager_PC;
t_int64 timebase = 0; /* 71b timebase */
d10 ttg = 0; /* time to go */
d10 period = 0; /* period */
d10 quant = 0; /* ITS quantum */
int32 diagflg = 0; /* diagnostics? */
int32 tmxr_poll = TIM_DELAY * DZ_MULT; /* term mux poll */
t_int64 timebase = 0; /* 71b timebase */
d10 ttg = 0; /* time to go */
d10 period = 0; /* period */
d10 quant = 0; /* ITS quantum */
int32 diagflg = 0; /* diagnostics? */
int32 tmxr_poll = TIM_DELAY * DZ_MULT; /* term mux poll */
/* Exported variables */
int32 clk_tps = TIM_TPS; /* clock ticks/sec */
int32 tmr_poll = TIM_DELAY; /* clock poll */
int32 clk_tps = TIM_TPS; /* clock ticks/sec */
int32 tmr_poll = TIM_DELAY; /* clock poll */
DEVICE tim_dev;
t_stat tcu_rd (int32 *data, int32 PA, int32 access);
@@ -75,9 +75,9 @@ extern int32 pi_eval (void);
/* TIM data structures
tim_dev TIM device descriptor
tim_unit TIM unit descriptor
tim_reg TIM register list
tim_dev TIM device descriptor
tim_unit TIM unit descriptor
tim_reg TIM register list
*/
DIB tcu_dib = { IOBA_TCU, IOLN_TCU, &tcu_rd, &wr_nop, 0 };
@@ -85,29 +85,32 @@ DIB tcu_dib = { IOBA_TCU, IOLN_TCU, &tcu_rd, &wr_nop, 0 };
UNIT tim_unit = { UDATA (&tim_svc, 0, 0), TIM_DELAY };
REG tim_reg[] = {
{ ORDATA (TIMEBASE, timebase, 71 - TIM_N_HWRE) },
{ ORDATA (TTG, ttg, 36) },
{ ORDATA (PERIOD, period, 36) },
{ ORDATA (QUANT, quant, 36) },
{ DRDATA (TIME, tim_unit.wait, 24), REG_NZ + PV_LEFT },
{ FLDATA (DIAG, diagflg, 0) },
{ FLDATA (Y2K, tim_unit.flags, UNIT_V_Y2K), REG_HRO },
{ NULL } };
{ ORDATA (TIMEBASE, timebase, 71 - TIM_N_HWRE) },
{ ORDATA (TTG, ttg, 36) },
{ ORDATA (PERIOD, period, 36) },
{ ORDATA (QUANT, quant, 36) },
{ DRDATA (TIME, tim_unit.wait, 24), REG_NZ + PV_LEFT },
{ FLDATA (DIAG, diagflg, 0) },
{ FLDATA (Y2K, tim_unit.flags, UNIT_V_Y2K), REG_HRO },
{ NULL }
};
MTAB tim_mod[] = {
{ UNIT_Y2K, 0, "non Y2K OS", "NOY2K", NULL },
{ UNIT_Y2K, UNIT_Y2K, "Y2K OS", "Y2K", NULL },
{ MTAB_XTD|MTAB_VDV, 000, "ADDRESS", NULL,
NULL, &show_addr, NULL },
{ 0 } };
{ UNIT_Y2K, 0, "non Y2K OS", "NOY2K", NULL },
{ UNIT_Y2K, UNIT_Y2K, "Y2K OS", "Y2K", NULL },
{ MTAB_XTD|MTAB_VDV, 000, "ADDRESS", NULL,
NULL, &show_addr, NULL },
{ 0 }
};
DEVICE tim_dev = {
"TIM", &tim_unit, tim_reg, tim_mod,
1, 0, 0, 0, 0, 0,
NULL, NULL, &tim_reset,
NULL, NULL, NULL,
&tcu_dib, DEV_DISABLE | DEV_UBUS };
"TIM", &tim_unit, tim_reg, tim_mod,
1, 0, 0, 0, 0, 0,
NULL, NULL, &tim_reset,
NULL, NULL, NULL,
&tcu_dib, DEV_DISABLE | DEV_UBUS
};
/* Timer instructions */
t_bool rdtim (a10 ea, int32 prv)
@@ -121,7 +124,7 @@ return FALSE;
t_bool wrtim (a10 ea, int32 prv)
{
timebase = (Read (ea, prv) << (35 - TIM_N_HWRE)) |
(CLRS (Read (INCA (ea), prv)) >> TIM_N_HWRE);
(CLRS (Read (INCA (ea), prv)) >> TIM_N_HWRE);
return FALSE;
}
@@ -137,32 +140,34 @@ period = Read (ea, prv);
ttg = period;
return FALSE;
}
/* Timer routines
tim_svc process event (timer tick)
tim_reset process reset
tim_svc process event (timer tick)
tim_reset process reset
*/
t_stat tim_svc (UNIT *uptr)
{
int32 t;
t = diagflg? tim_unit.wait: sim_rtc_calb (TIM_TPS); /* calibrate clock */
sim_activate (&tim_unit, t); /* reactivate unit */
tmr_poll = t; /* set timer poll */
tmxr_poll = t * DZ_MULT; /* set mux poll */
timebase = (timebase + 1) & TB_MASK; /* increment timebase */
ttg = ttg - TIM_HWRE; /* decrement timer */
if (ttg <= 0) { /* timeout? */
ttg = period; /* reload */
apr_flg = apr_flg | APRF_TIM; } /* request interrupt */
if (ITS) { /* ITS? */
if (pi_act == 0) quant = (quant + TIM_HWRE) & DMASK;
if (TSTS (pcst)) { /* PC sampling? */
WriteP ((a10) pcst & AMASK, pager_PC); /* store sample */
pcst = AOB (pcst); } /* add 1,,1 */
} /* end ITS */
t = diagflg? tim_unit.wait: sim_rtc_calb (TIM_TPS); /* calibrate clock */
sim_activate (&tim_unit, t); /* reactivate unit */
tmr_poll = t; /* set timer poll */
tmxr_poll = t * DZ_MULT; /* set mux poll */
timebase = (timebase + 1) & TB_MASK; /* increment timebase */
ttg = ttg - TIM_HWRE; /* decrement timer */
if (ttg <= 0) { /* timeout? */
ttg = period; /* reload */
apr_flg = apr_flg | APRF_TIM; /* request interrupt */
}
if (ITS) { /* ITS? */
if (pi_act == 0) quant = (quant + TIM_HWRE) & DMASK;
if (TSTS (pcst)) { /* PC sampling? */
WriteP ((a10) pcst & AMASK, pager_PC); /* store sample */
pcst = AOB (pcst); /* add 1,,1 */
}
} /* end ITS */
return SCPE_OK;
}
@@ -170,15 +175,15 @@ t_stat tim_reset (DEVICE *dptr)
{
int32 t;
period = ttg = 0; /* clear timer */
apr_flg = apr_flg & ~APRF_TIM; /* clear interrupt */
t = sim_rtc_init (tim_unit.wait); /* init timer */
sim_activate (&tim_unit, t); /* activate unit */
tmr_poll = t; /* set timer poll */
tmxr_poll = t * DZ_MULT; /* set mux poll */
period = ttg = 0; /* clear timer */
apr_flg = apr_flg & ~APRF_TIM; /* clear interrupt */
t = sim_rtc_init (tim_unit.wait); /* init timer */
sim_activate (&tim_unit, t); /* activate unit */
tmr_poll = t; /* set timer poll */
tmxr_poll = t * DZ_MULT; /* set mux poll */
return SCPE_OK;
}
/* Time of year clock */
t_stat tcu_rd (int32 *data, int32 PA, int32 access)
@@ -186,27 +191,33 @@ t_stat tcu_rd (int32 *data, int32 PA, int32 access)
time_t curtim;
struct tm *tptr;
curtim = time (NULL); /* get time */
tptr = localtime (&curtim); /* decompose */
if (tptr == NULL) return SCPE_NXM; /* Y2K prob? */
curtim = time (NULL); /* get time */
tptr = localtime (&curtim); /* decompose */
if (tptr == NULL) return SCPE_NXM; /* Y2K prob? */
if ((tptr->tm_year > 99) && !(tim_unit.flags & UNIT_Y2K))
tptr->tm_year = 99;
tptr->tm_year = 99;
switch ((PA >> 1) & 03) { /* decode PA<3:1> */
case 0: /* year/month/day */
*data = (((tptr->tm_year) & 0177) << 9) |
(((tptr->tm_mon + 1) & 017) << 5) |
((tptr->tm_mday) & 037);
return SCPE_OK;
case 1: /* hour/minute */
*data = (((tptr->tm_hour) & 037) << 8) |
((tptr->tm_min) & 077);
return SCPE_OK;
case 2: /* second */
*data = (tptr->tm_sec) & 077;
return SCPE_OK;
case 3: /* status */
*data = CSR_DONE;
return SCPE_OK; }
return SCPE_NXM; /* can't get here */
switch ((PA >> 1) & 03) { /* decode PA<3:1> */
case 0: /* year/month/day */
*data = (((tptr->tm_year) & 0177) << 9) |
(((tptr->tm_mon + 1) & 017) << 5) |
((tptr->tm_mday) & 037);
return SCPE_OK;
case 1: /* hour/minute */
*data = (((tptr->tm_hour) & 037) << 8) |
((tptr->tm_min) & 077);
return SCPE_OK;
case 2: /* second */
*data = (tptr->tm_sec) & 077;
return SCPE_OK;
case 3: /* status */
*data = CSR_DONE;
return SCPE_OK;
}
return SCPE_NXM; /* can't get here */
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff