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:
committed by
Mark Pizzolato
parent
ec60bbf329
commit
b7c1eae41f
2639
PDP10/pdp10_cpu.c
2639
PDP10/pdp10_cpu.c
File diff suppressed because it is too large
Load Diff
1062
PDP10/pdp10_defs.h
1062
PDP10/pdp10_defs.h
File diff suppressed because it is too large
Load Diff
@@ -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:
|
||||
|
||||
|
||||
113
PDP10/pdp10_fe.c
113
PDP10/pdp10_fe.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
1771
PDP10/pdp10_rp.c
1771
PDP10/pdp10_rp.c
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
}
|
||||
|
||||
1721
PDP10/pdp10_tu.c
1721
PDP10/pdp10_tu.c
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user