mirror of
https://github.com/simh/simh.git
synced 2026-04-09 22:39:04 +00:00
Notes For V3.0-0
Because some key files have changed, V3.0 should be unzipped to a clean directory. 1. New Features in 3.0-0 1.1 SCP and Libraries - Added ASSIGN/DEASSIGN (logical name) commands. - Changed RESTORE to unconditionally detach files. - Added E11 and TPC format support to magtape library. - Fixed bug in SHOW CONNECTIONS. - Added USE_ADDR64 support 1.2 All magtapes - Magtapes support SIMH format, E11 format, and TPC format (read only). - SET <tape_unit> FORMAT=format sets the specified tape unit's format. - SHOW <tape_unit> FORMAT displays the specified tape unit's format. - Tape format can also be set as part of the ATTACH command, using the -F switch. 1.3 VAX - VAX can be compiled without USE_INT64. - If compiled with USE_INT64 and USE_ADDR64, RQ and TQ controllers support files > 2GB. - VAX ROM has speed control (SET ROM DELAY/NODELAY). 2. Bugs Fixed in 3.01-0 2.1 VAX - Fixed CVTfi bug: integer overflow not set if exponent out of range - Fixed EMODx bugs: o First and second operands reversed o Separated fraction received wrong exponent o Overflow calculation on separated integer incorrect o Fraction not set to zero if exponent out of range - Fixed interval timer and ROM access to pass power-up self-test even on very fast host processors (fixes from Mark Pizzolato). 2.2 1401 - Fixed mnemonic, instruction lengths, and reverse scan length check bug for MCS. - Fixed MCE bug, BS off by 1 if zero suppress. - Fixed chaining bug, D lost if return to SCP. - Fixed H branch, branch occurs after continue. - Added check for invalid 8 character MCW, LCA. - Fixed magtape load-mode end of record response. 2.3 Nova - Fixed DSK variable size interaction with restore. 2.4 PDP-1 - Fixed DT variable size interaction with restore. 2.5 PDP-11 - Fixed DT variable size interaction with restore. - Fixed bug in MMR1 update (found by Tim Stark). - Added XQ features and fixed bugs: o Corrected XQ interrupts on IE state transition (code by Tom Evans). o Added XQ interrupt clear on soft reset. o Removed XQ interrupt when setting XL or RL (multiple people). o Added SET/SHOW XQ STATS. o Added SHOW XQ FILTERS. o Added ability to split received packet into multiple buffers. o Added explicit runt and giant packet processing. 2.6 PDP-18B - Fixed DT, RF variable size interaction with restore. - Fixed MT bug in MTTR. 2.7 PDP-8 - Fixed DT, DF, RF, RX variable size interaction with restore. - Fixed MT bug in SKTR. 2.8 HP2100 - Fixed bug in DP (13210A controller only), DQ read status. - Fixed bug in DP, DQ seek complete. 2.9 GRI - Fixed bug in SC queue pointer management. 3. New Features in 3.0 vs prior releases N/A 4. Bugs Fixed in 3.0 vs prior releases N/A 5. General Notes WARNING: The RESTORE command has changed. RESTORE will now detach an attached file on a unit, if that unit did not have an attached file in the saved configuration. This is required to assure that the unit flags and the file state are consistent. WARNING: The compilation scheme for the PDP-10, PDP-11, and VAX has changed. Use one of the supplied build files, or read the documentation carefully, before compiling any of these simulators.
This commit is contained in:
committed by
Mark Pizzolato
parent
43385c9616
commit
4ffd3be790
@@ -25,6 +25,8 @@
|
||||
|
||||
cpu CVAX central processor
|
||||
|
||||
17-May-03 RMS Fixed operand order in EMODx
|
||||
23-Apr-03 RMS Revised for 32b/64b t_addr
|
||||
05-Jan-02 RMS Added memory size restore support
|
||||
25-Dec-02 RMS Added instruction history (from Mark Pizzolato)
|
||||
29-Sep-02 RMS Revised to build dib_tab dynamically
|
||||
@@ -307,12 +309,12 @@ extern void op_polyd (int32 *opnd, int32 acc);
|
||||
extern void op_polyg (int32 *opnd, int32 acc);
|
||||
extern int32 op_emulate (int32 *opnd, int32 cc, int32 opc, int32 acc);
|
||||
extern int32 intexc (int32 vec, int32 cc, int32 ipl, int ei);
|
||||
extern int32 Read (t_addr va, int32 lnt, int32 acc);
|
||||
extern void Write (t_addr va, int32 val, int32 lnt, int32 acc);
|
||||
extern int32 ReadB (t_addr pa);
|
||||
extern int32 WriteB (t_addr pa, int32 val);
|
||||
extern int32 Test (t_addr va, int32 acc, int32 *status);
|
||||
extern int32 ReadLP (t_addr pa);
|
||||
extern int32 Read (uint32 va, int32 lnt, int32 acc);
|
||||
extern void Write (uint32 va, int32 val, int32 lnt, int32 acc);
|
||||
extern int32 ReadB (uint32 pa);
|
||||
extern int32 WriteB (uint32 pa, int32 val);
|
||||
extern int32 Test (uint32 va, int32 acc, int32 *status);
|
||||
extern int32 ReadLP (uint32 pa);
|
||||
extern int32 eval_int (void);
|
||||
extern int32 get_vector (int32 lvl);
|
||||
extern void set_map_reg (void);
|
||||
@@ -322,8 +324,8 @@ extern t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||
|
||||
t_stat cpu_reset (DEVICE *dptr);
|
||||
t_stat cpu_boot (int32 unitno, DEVICE *dptr);
|
||||
t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
|
||||
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
|
||||
t_stat cpu_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw);
|
||||
t_stat cpu_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw);
|
||||
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat cpu_show_virt (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||
@@ -512,7 +514,7 @@ for ( ;; ) {
|
||||
int32 spec, disp, rn, index, numspec;
|
||||
int32 vfldrp1, brdisp, flg, mstat;
|
||||
int32 i, j, r, rh, temp;
|
||||
t_addr va, iad;
|
||||
uint32 va, iad;
|
||||
int32 opnd[OPND_SIZE]; /* operand queue */
|
||||
|
||||
if (cpu_astop) {
|
||||
@@ -2120,8 +2122,8 @@ case ACBG:
|
||||
|
||||
/* EMODF
|
||||
|
||||
op0 = extension
|
||||
op1 = multiplier
|
||||
op0 = multiplier
|
||||
op1 = extension
|
||||
op2 = multiplicand
|
||||
op3:op4 = integer destination (int.wl)
|
||||
op5:op6 = floating destination (flt.wl)
|
||||
@@ -2139,8 +2141,8 @@ case EMODF:
|
||||
|
||||
/* EMODD, EMODG
|
||||
|
||||
op0 = extension
|
||||
op1:op2 = multiplier
|
||||
op0:op1 = multiplier
|
||||
op2 = extension
|
||||
op3:op4 = multiplicand
|
||||
op5:op6 = integer destination (int.wl)
|
||||
op7:op8 = floating destination (flt.wq)
|
||||
@@ -2315,7 +2317,7 @@ ASTLVL = 4;
|
||||
MSER = 0;
|
||||
CADR = 0;
|
||||
mapen = 0;
|
||||
if (M == NULL) M = calloc (MEMSIZE >> 2, sizeof (int32));
|
||||
if (M == NULL) M = calloc (((uint32) MEMSIZE) >> 2, sizeof (int32));
|
||||
if (M == NULL) return SCPE_MEM;
|
||||
pcq_r = find_reg ("PCQ", NULL, dptr);
|
||||
if (pcq_r) pcq_r->qptr = 0;
|
||||
@@ -2356,9 +2358,10 @@ return SCPE_OK;
|
||||
|
||||
/* Memory examine */
|
||||
|
||||
t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
|
||||
t_stat cpu_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw)
|
||||
{
|
||||
int32 st;
|
||||
uint32 addr = (uint32) exta;
|
||||
|
||||
if (vptr == NULL) return SCPE_ARG;
|
||||
if (sw & SWMASK ('V')) addr = Test (addr, RD, &st);
|
||||
@@ -2372,9 +2375,10 @@ return SCPE_NXM;
|
||||
|
||||
/* Memory deposit */
|
||||
|
||||
t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
|
||||
t_stat cpu_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw)
|
||||
{
|
||||
int32 st;
|
||||
uint32 addr = (uint32) exta;
|
||||
|
||||
if (sw & SWMASK ('V')) addr = Test (addr, RD, &st);
|
||||
else addr = addr & PAMASK;
|
||||
@@ -2393,7 +2397,7 @@ return SCPE_NXM;
|
||||
t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
int32 mc = 0;
|
||||
t_addr i, clim;
|
||||
uint32 i, clim;
|
||||
uint32 *nM = NULL;
|
||||
|
||||
if ((val <= 0) || (val > MAXMEMSIZE)) return SCPE_ARG;
|
||||
@@ -2402,7 +2406,7 @@ if ((mc != 0) && !get_yn ("Really truncate memory [N]?", FALSE))
|
||||
return SCPE_OK;
|
||||
nM = calloc (val >> 2, sizeof (uint32));
|
||||
if (nM == NULL) return SCPE_MEM;
|
||||
clim = (((t_addr) val) < MEMSIZE)? val: MEMSIZE;
|
||||
clim = (uint32) ((((uint32) val) < MEMSIZE)? val: MEMSIZE);
|
||||
for (i = 0; i < clim; i = i + 4) nM[i >> 2] = M[i >> 2];
|
||||
free (M);
|
||||
M = nM;
|
||||
@@ -2414,7 +2418,7 @@ return SCPE_OK; }
|
||||
t_stat cpu_show_virt (UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||
{
|
||||
t_stat r;
|
||||
t_addr va, pa;
|
||||
uint32 va, pa;
|
||||
int32 st;
|
||||
static const char *mm_str[] = {
|
||||
"Access control violation",
|
||||
@@ -2426,7 +2430,7 @@ static const char *mm_str[] = {
|
||||
"Process PTE translation not valid" };
|
||||
|
||||
if (cptr == NULL) return SCPE_ARG;
|
||||
va = (t_addr) get_uint (cptr, 16, 0xFFFFFFFF, &r);
|
||||
va = (uint32) get_uint (cptr, 16, 0xFFFFFFFF, &r);
|
||||
if (r != SCPE_OK) return SCPE_ARG;
|
||||
pa = Test (va, RD, &st);
|
||||
if (st == PR_OK) printf ("Virtual %-X = physical %-X\n", va, pa);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* vax_cpu1.c: VAX complex instructions
|
||||
|
||||
Copyright (c) 1998-2002, Robert M Supnik
|
||||
Copyright (c) 1998-2003, 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"),
|
||||
@@ -101,15 +101,15 @@ extern int32 ibcnt, ppc;
|
||||
extern int32 cpu_log;
|
||||
extern FILE *sim_log;
|
||||
|
||||
extern int32 Read (t_addr va, int32 lnt, int32 acc);
|
||||
extern void Write (t_addr va, int32 val, int32 lnt, int32 acc);
|
||||
extern int32 Test (t_addr va, int32 acc, int32 *status);
|
||||
extern int32 ReadLP (t_addr pa);
|
||||
extern void WriteLP (t_addr pa, int32 val);
|
||||
extern int32 Read (uint32 va, int32 lnt, int32 acc);
|
||||
extern void Write (uint32 va, int32 val, int32 lnt, int32 acc);
|
||||
extern int32 Test (uint32 va, int32 acc, int32 *status);
|
||||
extern int32 ReadLP (uint32 pa);
|
||||
extern void WriteLP (uint32 pa, int32 val);
|
||||
extern void set_map_reg (void);
|
||||
extern void zap_tb (int stb);
|
||||
extern void zap_tb_ent (t_addr va);
|
||||
extern t_bool chk_tb_ent (t_addr va);
|
||||
extern void zap_tb_ent (uint32 va);
|
||||
extern t_bool chk_tb_ent (uint32 va);
|
||||
extern int32 ReadIPR (int32 rg);
|
||||
extern void WriteIPR (int32 rg, int32 val);
|
||||
extern jmp_buf save_env;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* vax_defs.h: VAX architecture definitions file
|
||||
|
||||
Copyright (c) 1998-2002, Robert M Supnik
|
||||
Copyright (c) 1998-2003, 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"),
|
||||
@@ -26,10 +26,18 @@
|
||||
The author gratefully acknowledges the help of Stephen Shirron, Antonio
|
||||
Carlini, and Kevin Peterson in providing specifications for the Qbus VAX's
|
||||
|
||||
19-May-03 RMS Revised for new conditional compilation scheme
|
||||
14-Jul-02 RMS Added infinite loop message
|
||||
30-Apr-02 RMS Added CLR_TRAPS macro
|
||||
*/
|
||||
|
||||
#ifndef _VAX_DEFS_H
|
||||
#define _VAX_DEFS_H 0
|
||||
|
||||
#ifndef VM_VAX
|
||||
#define VM_VAX 0
|
||||
#endif
|
||||
|
||||
#include "sim_defs.h"
|
||||
#include <setjmp.h>
|
||||
|
||||
@@ -563,3 +571,5 @@ enum opcodes {
|
||||
/* Model dependent definitions */
|
||||
|
||||
#include "vaxmod_defs.h"
|
||||
|
||||
#endif /* _VAX_DEFS_H */
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
To: Users
|
||||
From: Bob Supnik
|
||||
Subj: VAX Simulator Usage
|
||||
Date: 15-Nov-2002
|
||||
Date: 15-Jun-2003
|
||||
|
||||
COPYRIGHT NOTICE
|
||||
|
||||
The following copyright notice applies to both the SIMH source and binary:
|
||||
|
||||
Original code published in 1993-2002, written by Robert M Supnik
|
||||
Copyright (c) 1993-2002, Robert M Supnik
|
||||
Original code published in 1993-2003, written by Robert M Supnik
|
||||
Copyright (c) 1993-2003, 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"),
|
||||
@@ -36,12 +36,10 @@ This memorandum documents the VAX simulator.
|
||||
|
||||
1. Simulator Files
|
||||
|
||||
To compile the VAX, you must define USE_INT64 as part of the compilation
|
||||
To compile the VAX, you must define VM_VAX and USE_INT64 as part of the compilation
|
||||
command line.
|
||||
|
||||
sim/ dec_dz.h
|
||||
dec_pt.h
|
||||
sim_defs.h
|
||||
sim/ sim_defs.h
|
||||
sim_ether.h
|
||||
sim_rev.h
|
||||
sim_sock.h
|
||||
@@ -65,6 +63,7 @@ sim/vax/ vax_defs.h
|
||||
sim/pdp11/ pdp11_mscp.h
|
||||
pdp11_uqssp.h
|
||||
pdp11_xq.h
|
||||
pdp11_xq_bootrom.h
|
||||
pdp11_dz.c
|
||||
pdp11_lp.c
|
||||
pdp11_pt.c
|
||||
@@ -100,9 +99,10 @@ RQD fourth RQDX3 MSCP controller with four drives
|
||||
TS TSV11/TSV05 magnetic tape controller with one drive
|
||||
TQ TQK50 TMSCP magnetic tape controller with four drives
|
||||
XQ DELQA/DEQNA Ethernet controller
|
||||
XQB second DELQA/DEQNA Ethernet controller
|
||||
|
||||
The PTR, PTP, LPT, DZ, RL, RQ, RQB, RQC, RQD, TS, TQ, and XQ devices can
|
||||
be set DISABLED. RQB, RQC, and RQD are disabled by default.
|
||||
The PTR, PTP, LPT, DZ, RL, RQ, RQB, RQC, RQD, TS, TQ, XQ, and XQB devices
|
||||
can be set DISABLED. RQB, RQC, RQD, and XQB are disabled by default.
|
||||
|
||||
The VAX simulator implements several unique stop conditions:
|
||||
|
||||
@@ -227,6 +227,14 @@ using the LOAD -r command:
|
||||
|
||||
LOAD -r KA655.BIN -- load boot ROM image KA655.BIN
|
||||
|
||||
ROM accesses a use a calibrated delay that slows ROM-based execution to
|
||||
about 500K instructions per second. This delay is required to make the
|
||||
power-up self-test routines run correctly on very fast hosts. The delay
|
||||
is controlled with the commands:
|
||||
|
||||
SET ROM NODELAY -- ROM runs like RAM
|
||||
SET ROM DELAY -- ROM runs slowly
|
||||
|
||||
2.1.4 Non-volatile Memory (NVR)
|
||||
|
||||
The NVR consists of a single unit, representing 1KB of battery-backed up
|
||||
@@ -320,7 +328,7 @@ longer recognizes the explicitly configured device. A device can be
|
||||
reset to autoconfigure with the SET <device> AUTOCONFIGURE command.
|
||||
|
||||
The current I/O map can be displayed with the SHOW CPU IOSPACE command.
|
||||
Address that have set by autoconfiguration are marked with an asterisk (*).
|
||||
Addresses that have set by autoconfiguration are marked with an asterisk (*).
|
||||
|
||||
All devices support the SHOW ADDRESS and SHOW VECTOR commands, which display
|
||||
the device address and vector, respectively.
|
||||
@@ -780,9 +788,10 @@ Error handling is as follows:
|
||||
|
||||
OS I/O error report error and stop
|
||||
|
||||
2.8 DELQA/DEQNA Ethernet Controller (XQ)
|
||||
2.8 DELQA/DEQNA Qbus Ethernet Controllers (XQ, XQB)
|
||||
|
||||
XQ simulates the DELQA/DEQNA 10Mbps Ethernet controller. Options allow
|
||||
The simulator implements two DELQA/DEQNA Qbus Ethernet controllers (XQ,
|
||||
XQB). Initially, XQ is enabled, and XQB is disabled. Options allow
|
||||
control of the MAC address, the controller mode, and the sanity timer.
|
||||
|
||||
SET XQ MAC=<mac-address> ex. 08-00-2B-AA-BB-CC
|
||||
|
||||
1250
VAX/vax_fpa.c
1250
VAX/vax_fpa.c
File diff suppressed because it is too large
Load Diff
152
VAX/vax_io.c
152
VAX/vax_io.c
@@ -1,6 +1,6 @@
|
||||
/* vax_io.c: VAX Qbus IO simulator
|
||||
|
||||
Copyright (c) 1998-2002, Robert M Supnik
|
||||
Copyright (c) 1998-2003, 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"),
|
||||
@@ -25,7 +25,9 @@
|
||||
|
||||
qba Qbus adapter
|
||||
|
||||
22-Dec-02 RMS Addec console halt support
|
||||
19-Apr-03 RMS Added optimized byte and word DMA routines
|
||||
12-Mar-03 RMS Added logical name support
|
||||
22-Dec-02 RMS Added console halt support
|
||||
12-Oct-02 RMS Added autoconfigure support
|
||||
Added SHOW IO space routine
|
||||
29-Sep-02 RMS Added dynamic table support
|
||||
@@ -101,12 +103,12 @@ extern int32 ssc_bto;
|
||||
extern jmp_buf save_env;
|
||||
extern DEVICE *sim_devices[];
|
||||
|
||||
extern int32 ReadB (t_addr pa);
|
||||
extern int32 ReadW (t_addr pa);
|
||||
extern int32 ReadL (t_addr pa);
|
||||
extern int32 WriteB (t_addr pa, int32 val);
|
||||
extern int32 WriteW (t_addr pa, int32 val);
|
||||
extern int32 WriteL (t_addr pa, int32 val);
|
||||
extern int32 ReadB (uint32 pa);
|
||||
extern int32 ReadW (uint32 pa);
|
||||
extern int32 ReadL (uint32 pa);
|
||||
extern int32 WriteB (uint32 pa, int32 val);
|
||||
extern int32 WriteW (uint32 pa, int32 val);
|
||||
extern int32 WriteL (uint32 pa, int32 val);
|
||||
extern FILE *sim_log;
|
||||
|
||||
t_stat dbl_rd (int32 *data, int32 addr, int32 access);
|
||||
@@ -409,7 +411,7 @@ return;
|
||||
int32 cqmem_rd (int32 pa)
|
||||
{
|
||||
int32 qa = pa & CQMAMASK; /* Qbus addr */
|
||||
t_addr ma;
|
||||
uint32 ma;
|
||||
|
||||
if (map_addr (qa, &ma)) return M[ma >> 2]; /* map addr */
|
||||
MACH_CHECK (MCHK_READ); /* err? mcheck */
|
||||
@@ -419,7 +421,7 @@ return 0;
|
||||
void cqmem_wr (int32 pa, int32 val, int32 lnt)
|
||||
{
|
||||
int32 qa = pa & CQMAMASK; /* Qbus addr */
|
||||
t_addr ma;
|
||||
uint32 ma;
|
||||
|
||||
if (map_addr (qa, &ma)) { /* map addr */
|
||||
if (lnt < L_LONG) {
|
||||
@@ -434,7 +436,7 @@ return;
|
||||
|
||||
/* Map an address via the translation map */
|
||||
|
||||
t_bool map_addr (t_addr qa, t_addr *ma)
|
||||
t_bool map_addr (uint32 qa, uint32 *ma)
|
||||
{
|
||||
int32 qblk = (qa >> VA_V_VPN); /* Qbus blk */
|
||||
int32 qmma = ((qblk << 2) & CQMAPAMASK) + cq_mbr; /* map entry */
|
||||
@@ -511,40 +513,64 @@ return qba_reset (&qba_dev);
|
||||
map_WriteL - store longword buffer into memory
|
||||
*/
|
||||
|
||||
int32 map_readB (t_addr ba, int32 bc, uint8 *buf)
|
||||
int32 map_readB (uint32 ba, int32 bc, uint8 *buf)
|
||||
{
|
||||
int32 i;
|
||||
t_addr ma;
|
||||
uint32 ma, dat;
|
||||
|
||||
for (i = ma = 0; i < bc; i++, buf++) { /* by bytes */
|
||||
if ((ma & VA_M_OFF) == 0) { /* need map? */
|
||||
if (!map_addr (ba + i, &ma) || /* inv or NXM? */
|
||||
!ADDR_IS_MEM (ma)) return (bc - i); }
|
||||
*buf = ReadB (ma);
|
||||
ma = ma + 1; }
|
||||
if ((ba | bc) & 03) { /* check alignment */
|
||||
for (i = ma = 0; i < bc; i++, buf++) { /* by bytes */
|
||||
if ((ma & VA_M_OFF) == 0) { /* need map? */
|
||||
if (!map_addr (ba + i, &ma) || /* inv or NXM? */
|
||||
!ADDR_IS_MEM (ma)) return (bc - i); }
|
||||
*buf = ReadB (ma);
|
||||
ma = ma + 1; }
|
||||
}
|
||||
else { for (i = ma = 0; i < bc; i = i + 4, buf++) { /* by longwords */
|
||||
if ((ma & VA_M_OFF) == 0) { /* need map? */
|
||||
if (!map_addr (ba + i, &ma) || /* inv or NXM? */
|
||||
!ADDR_IS_MEM (ma)) return (bc - i); }
|
||||
dat = ReadL (ma); /* get lw */
|
||||
*buf++ = dat & BMASK; /* low 8b */
|
||||
*buf++ = (dat >> 8) & BMASK; /* next 8b */
|
||||
*buf++ = (dat >> 16) & BMASK; /* next 8b */
|
||||
*buf = (dat >> 24) & BMASK;
|
||||
ma = ma + 4; }
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 map_readW (t_addr ba, int32 bc, uint16 *buf)
|
||||
int32 map_readW (uint32 ba, int32 bc, uint16 *buf)
|
||||
{
|
||||
int32 i;
|
||||
t_addr ma;
|
||||
uint32 ma,dat;
|
||||
|
||||
ba = ba & ~01;
|
||||
bc = bc & ~01;
|
||||
for (i = ma = 0; i < bc; i = i + 2, buf++) { /* by words */
|
||||
if ((ma & VA_M_OFF) == 0) { /* need map? */
|
||||
if (!map_addr (ba + i, &ma) || /* inv or NXM? */
|
||||
!ADDR_IS_MEM (ma)) return (bc - i); }
|
||||
*buf = ReadW (ma);
|
||||
ma = ma + 2; }
|
||||
if ((ba | bc) & 03) { /* check alignment */
|
||||
for (i = ma = 0; i < bc; i = i + 2, buf++) { /* by words */
|
||||
if ((ma & VA_M_OFF) == 0) { /* need map? */
|
||||
if (!map_addr (ba + i, &ma) || /* inv or NXM? */
|
||||
!ADDR_IS_MEM (ma)) return (bc - i); }
|
||||
*buf = ReadW (ma);
|
||||
ma = ma + 2; }
|
||||
}
|
||||
else { for (i = ma = 0; i < bc; i = i + 4, buf++) { /* by longwords */
|
||||
if ((ma & VA_M_OFF) == 0) { /* need map? */
|
||||
if (!map_addr (ba + i, &ma) || /* inv or NXM? */
|
||||
!ADDR_IS_MEM (ma)) return (bc - i); }
|
||||
dat = ReadL (ma); /* get lw */
|
||||
*buf++ = dat & WMASK; /* low 16b */
|
||||
*buf = (dat >> 16) & WMASK; /* high 16b */
|
||||
ma = ma + 4; }
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 map_readL (t_addr ba, int32 bc, uint32 *buf)
|
||||
int32 map_readL (uint32 ba, int32 bc, uint32 *buf)
|
||||
{
|
||||
int32 i;
|
||||
t_addr ma;
|
||||
uint32 ma;
|
||||
|
||||
ba = ba & ~03;
|
||||
bc = bc & ~03;
|
||||
@@ -557,40 +583,64 @@ for (i = ma = 0; i < bc; i = i + 4, buf++) { /* by lw */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 map_writeB (t_addr ba, int32 bc, uint8 *buf)
|
||||
int32 map_writeB (uint32 ba, int32 bc, uint8 *buf)
|
||||
{
|
||||
int32 i;
|
||||
t_addr ma;
|
||||
uint32 ma, dat;
|
||||
|
||||
for (i = ma = 0; i < bc; i++, buf++) { /* by bytes */
|
||||
if ((ma & VA_M_OFF) == 0) { /* need map? */
|
||||
if (!map_addr (ba + i, &ma) || /* inv or NXM? */
|
||||
!ADDR_IS_MEM (ma)) return (bc - i); }
|
||||
WriteB (ma, *buf);
|
||||
ma = ma + 1; }
|
||||
if ((ba | bc) & 03) { /* check alignment */
|
||||
for (i = ma = 0; i < bc; i++, buf++) { /* by bytes */
|
||||
if ((ma & VA_M_OFF) == 0) { /* need map? */
|
||||
if (!map_addr (ba + i, &ma) || /* inv or NXM? */
|
||||
!ADDR_IS_MEM (ma)) return (bc - i); }
|
||||
WriteB (ma, *buf);
|
||||
ma = ma + 1; }
|
||||
}
|
||||
else { for (i = ma = 0; i < bc; i = i + 4, buf++) { /* by longwords */
|
||||
if ((ma & VA_M_OFF) == 0) { /* need map? */
|
||||
if (!map_addr (ba + i, &ma) || /* inv or NXM? */
|
||||
!ADDR_IS_MEM (ma)) return (bc - i); }
|
||||
dat = (uint32) *buf++; /* get low 8b */
|
||||
dat = dat | (((uint32) *buf++) << 8); /* merge next 8b */
|
||||
dat = dat | (((uint32) *buf++) << 16); /* merge next 8b */
|
||||
dat = dat | (((uint32) *buf) << 24); /* merge hi 8b */
|
||||
WriteL (ma, dat); /* store lw */
|
||||
ma = ma + 4; }
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 map_writeW (t_addr ba, int32 bc, uint16 *buf)
|
||||
int32 map_writeW (uint32 ba, int32 bc, uint16 *buf)
|
||||
{
|
||||
int32 i;
|
||||
t_addr ma;
|
||||
uint32 ma, dat;
|
||||
|
||||
ba = ba & ~01;
|
||||
bc = bc & ~01;
|
||||
for (i = ma = 0; i < bc; i = i + 2, buf++) { /* by words */
|
||||
if ((ma & VA_M_OFF) == 0) { /* need map? */
|
||||
if (!map_addr (ba + i, &ma) || /* inv or NXM? */
|
||||
!ADDR_IS_MEM (ma)) return (bc - i); }
|
||||
WriteW (ma, *buf);
|
||||
ma = ma + 2; }
|
||||
if ((ba | bc) & 03) { /* check alignment */
|
||||
for (i = ma = 0; i < bc; i = i + 2, buf++) { /* by words */
|
||||
if ((ma & VA_M_OFF) == 0) { /* need map? */
|
||||
if (!map_addr (ba + i, &ma) || /* inv or NXM? */
|
||||
!ADDR_IS_MEM (ma)) return (bc - i); }
|
||||
WriteW (ma, *buf);
|
||||
ma = ma + 2; }
|
||||
}
|
||||
else { for (i = ma = 0; i < bc; i = i + 4, buf++) { /* by longwords */
|
||||
if ((ma & VA_M_OFF) == 0) { /* need map? */
|
||||
if (!map_addr (ba + i, &ma) || /* inv or NXM? */
|
||||
!ADDR_IS_MEM (ma)) return (bc - i); }
|
||||
dat = (uint32) *buf++; /* get low 16b */
|
||||
dat = dat | (((uint32) *buf) << 16); /* merge hi 16b */
|
||||
WriteL (ma, dat); /* store lw */
|
||||
ma = ma + 4; }
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 map_writeL (t_addr ba, int32 bc, uint32 *buf)
|
||||
int32 map_writeL (uint32 ba, int32 bc, uint32 *buf)
|
||||
{
|
||||
int32 i;
|
||||
t_addr ma;
|
||||
uint32 ma;
|
||||
|
||||
ba = ba & ~03;
|
||||
bc = bc & ~03;
|
||||
@@ -722,9 +772,11 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */
|
||||
(curr->ba < (dibp->ba + dibp->lnt))) ||
|
||||
((end >= dibp->ba) && /* overlap end? */
|
||||
(end < (dibp->ba + dibp->lnt)))) {
|
||||
printf ("Device %s address conflict at %08X\n", dptr->name, dibp->ba);
|
||||
printf ("Device %s address conflict at %08X\n",
|
||||
sim_dname (dptr), dibp->ba);
|
||||
if (sim_log) fprintf (sim_log,
|
||||
"Device %s address conflict at %08X\n", dptr->name, dibp->ba);
|
||||
"Device %s address conflict at %08X\n",
|
||||
sim_dname (dptr), dibp->ba);
|
||||
return TRUE; } }
|
||||
return FALSE;
|
||||
}
|
||||
@@ -797,7 +849,7 @@ for (i = 0; dib_tab[i] != NULL; i++) { /* print table */
|
||||
fprintf (st, "%08X - %08X%c\t%s\n", dib_tab[i]->ba,
|
||||
dib_tab[i]->ba + dib_tab[i]->lnt - 1,
|
||||
(dptr && (dptr->flags & DEV_FLTA))? '*': ' ',
|
||||
dptr? dptr->name: "CPU");
|
||||
dptr? sim_dname (dptr): "CPU");
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* vax_mm.c - VAX memory management simulator
|
||||
|
||||
Copyright (c) 1998-2002, Robert M Supnik
|
||||
Copyright (c) 1998-2003, Robert M Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
@@ -23,6 +23,8 @@
|
||||
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.
|
||||
|
||||
01-Jun-03 RMS Fixed compilation problem with USE_ADDR64
|
||||
|
||||
This module contains the instruction simulators for
|
||||
|
||||
Read - read virtual
|
||||
@@ -95,19 +97,19 @@ t_stat tlb_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
|
||||
t_stat tlb_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
|
||||
t_stat tlb_reset (DEVICE *dptr);
|
||||
|
||||
TLBENT fill (t_addr va, int32 lnt, int32 acc, int32 *stat);
|
||||
int32 ReadB (t_addr pa);
|
||||
void WriteB (t_addr pa, int32 val);
|
||||
int32 ReadW (t_addr pa);
|
||||
void WriteW (t_addr pa, int32 val);
|
||||
int32 ReadL (t_addr pa);
|
||||
void WriteL (t_addr pa, int32 val);
|
||||
int32 ReadLP (t_addr pa);
|
||||
void WriteLP (t_addr pa, int32 val);
|
||||
extern int32 ReadIO (t_addr pa, int32 lnt);
|
||||
extern void WriteIO (t_addr pa, int32 val, int32 lnt);
|
||||
extern int32 ReadReg (t_addr pa, int32 lnt);
|
||||
extern void WriteReg (t_addr pa, int32 val, int32 lnt);
|
||||
TLBENT fill (uint32 va, int32 lnt, int32 acc, int32 *stat);
|
||||
int32 ReadB (uint32 pa);
|
||||
void WriteB (uint32 pa, int32 val);
|
||||
int32 ReadW (uint32 pa);
|
||||
void WriteW (uint32 pa, int32 val);
|
||||
int32 ReadL (uint32 pa);
|
||||
void WriteL (uint32 pa, int32 val);
|
||||
int32 ReadLP (uint32 pa);
|
||||
void WriteLP (uint32 pa, int32 val);
|
||||
extern int32 ReadIO (uint32 pa, int32 lnt);
|
||||
extern void WriteIO (uint32 pa, int32 val, int32 lnt);
|
||||
extern int32 ReadReg (uint32 pa, int32 lnt);
|
||||
extern void WriteReg (uint32 pa, int32 val, int32 lnt);
|
||||
|
||||
/* TLB data structures
|
||||
|
||||
@@ -156,7 +158,7 @@ DEVICE tlb_dev = {
|
||||
returned data, right justified in 32b longword
|
||||
*/
|
||||
|
||||
int32 Read (t_addr va, int32 lnt, int32 acc)
|
||||
int32 Read (uint32 va, int32 lnt, int32 acc)
|
||||
{
|
||||
int32 vpn, off, tbi, pa;
|
||||
int32 pa1, bo, sc, wl, wh;
|
||||
@@ -209,7 +211,7 @@ else { wl = ReadL (pa); /* word cross lw */
|
||||
none
|
||||
*/
|
||||
|
||||
void Write (t_addr va, int32 val, int32 lnt, int32 acc)
|
||||
void Write (uint32 va, int32 val, int32 lnt, int32 acc)
|
||||
{
|
||||
int32 vpn, off, tbi, pa;
|
||||
int32 pa1, bo, sc, wl, wh;
|
||||
@@ -289,7 +291,7 @@ return va & PAMASK; /* ret phys addr */
|
||||
returned data, right justified in 32b longword
|
||||
*/
|
||||
|
||||
int32 ReadB (t_addr pa)
|
||||
int32 ReadB (uint32 pa)
|
||||
{
|
||||
int32 dat;
|
||||
|
||||
@@ -300,7 +302,7 @@ else { mchk_ref = REF_V;
|
||||
return ((dat >> ((pa & 3) << 3)) & BMASK);
|
||||
}
|
||||
|
||||
int32 ReadW (t_addr pa)
|
||||
int32 ReadW (uint32 pa)
|
||||
{
|
||||
int32 dat;
|
||||
|
||||
@@ -311,7 +313,7 @@ else { mchk_ref = REF_V;
|
||||
return ((dat >> ((pa & 2)? 16: 0)) & WMASK);
|
||||
}
|
||||
|
||||
int32 ReadL (t_addr pa)
|
||||
int32 ReadL (uint32 pa)
|
||||
{
|
||||
if (ADDR_IS_MEM (pa)) return M[pa >> 2];
|
||||
mchk_ref = REF_V;
|
||||
@@ -319,7 +321,7 @@ if (ADDR_IS_IO (pa)) return ReadIO (pa, L_LONG);
|
||||
return ReadReg (pa, L_LONG);
|
||||
}
|
||||
|
||||
int32 ReadLP (t_addr pa)
|
||||
int32 ReadLP (uint32 pa)
|
||||
{
|
||||
if (ADDR_IS_MEM (pa)) return M[pa >> 2];
|
||||
mchk_va = pa;
|
||||
@@ -337,7 +339,7 @@ return ReadReg (pa, L_LONG);
|
||||
none
|
||||
*/
|
||||
|
||||
void WriteB (t_addr pa, int32 val)
|
||||
void WriteB (uint32 pa, int32 val)
|
||||
{
|
||||
if (ADDR_IS_MEM (pa)) {
|
||||
int32 id = pa >> 2;
|
||||
@@ -350,7 +352,7 @@ else { mchk_ref = REF_V;
|
||||
return;
|
||||
}
|
||||
|
||||
void WriteW (t_addr pa, int32 val)
|
||||
void WriteW (uint32 pa, int32 val)
|
||||
{
|
||||
if (ADDR_IS_MEM (pa)) {
|
||||
int32 id = pa >> 2;
|
||||
@@ -362,7 +364,7 @@ else { mchk_ref = REF_V;
|
||||
return;
|
||||
}
|
||||
|
||||
void WriteL (t_addr pa, int32 val)
|
||||
void WriteL (uint32 pa, int32 val)
|
||||
{
|
||||
if (ADDR_IS_MEM (pa)) M[pa >> 2] = val;
|
||||
else { mchk_ref = REF_V;
|
||||
@@ -371,7 +373,7 @@ else { mchk_ref = REF_V;
|
||||
return;
|
||||
}
|
||||
|
||||
void WriteLP (t_addr pa, int32 val)
|
||||
void WriteLP (uint32 pa, int32 val)
|
||||
{
|
||||
if (ADDR_IS_MEM (pa)) M[pa >> 2] = val;
|
||||
else { mchk_va = pa;
|
||||
@@ -398,7 +400,7 @@ return;
|
||||
p2 = va; \
|
||||
ABORT ((param & PR_TNV)? ABORT_TNV: ABORT_ACV); }
|
||||
|
||||
TLBENT fill (t_addr va, int32 lnt, int32 acc, int32 *stat)
|
||||
TLBENT fill (uint32 va, int32 lnt, int32 acc, int32 *stat)
|
||||
{
|
||||
int32 ptidx = (((uint32) va) >> 7) & ~03;
|
||||
int32 tlbpte, ptead, pte, tbi, vpn;
|
||||
@@ -500,7 +502,7 @@ return FALSE;
|
||||
t_stat tlb_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
|
||||
{
|
||||
int32 tlbn = uptr - tlb_unit;
|
||||
int32 idx = addr >> 1;
|
||||
int32 idx = (uint32) addr >> 1;
|
||||
|
||||
if (idx >= VA_TBSIZE) return SCPE_NXM;
|
||||
if (addr & 1) *vptr = ((uint32) (tlbn? stlb[idx].pte: ptlb[idx].pte));
|
||||
@@ -513,7 +515,7 @@ return SCPE_OK;
|
||||
t_stat tlb_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
|
||||
{
|
||||
int32 tlbn = uptr - tlb_unit;
|
||||
int32 idx = addr >> 1;
|
||||
int32 idx = (uint32) addr >> 1;
|
||||
|
||||
if (idx >= VA_TBSIZE) return SCPE_NXM;
|
||||
if (addr & 1) {
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
tto terminal output
|
||||
clk 100Hz and TODR clock
|
||||
|
||||
25-Apr-03 RMS Revised for extended file support
|
||||
02-Mar-02 RMS Added SET TTI CTRL-C
|
||||
22-Dec-02 RMS Added console halt capability
|
||||
01-Nov-02 RMS Added 7B/8B capability to terminal
|
||||
@@ -93,7 +94,7 @@ REG tti_reg[] = {
|
||||
{ FLDATA (INT, int_req[IPL_TTI], INT_V_TTI) },
|
||||
{ FLDATA (DONE, tti_csr, CSR_V_DONE) },
|
||||
{ FLDATA (IE, tti_csr, CSR_V_IE) },
|
||||
{ DRDATA (POS, tti_unit.pos, 32), PV_LEFT },
|
||||
{ DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT },
|
||||
{ NULL } };
|
||||
|
||||
@@ -130,7 +131,7 @@ REG tto_reg[] = {
|
||||
{ FLDATA (INT, int_req[IPL_TTO], INT_V_TTO) },
|
||||
{ FLDATA (DONE, tto_csr, CSR_V_DONE) },
|
||||
{ FLDATA (IE, tto_csr, CSR_V_IE) },
|
||||
{ DRDATA (POS, tto_unit.pos, 32), PV_LEFT },
|
||||
{ DRDATA (POS, tto_unit.pos, T_ADDR_W), PV_LEFT },
|
||||
{ DRDATA (TIME, tto_unit.wait, 24), PV_LEFT },
|
||||
{ NULL } };
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* vax_sys.c: VAX simulator interface
|
||||
|
||||
Copyright (c) 1998-2002, Robert M Supnik
|
||||
Copyright (c) 1998-2003, Robert M Supnik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
@@ -23,6 +23,7 @@
|
||||
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.
|
||||
|
||||
06-May-03 RMS Added support for second DELQA
|
||||
12-Oct-02 RMS Added multiple RQ controller support
|
||||
10-Oct-02 RMS Added DELQA support
|
||||
21-Sep-02 RMS Extended symbolic ex/mod to all byte devices
|
||||
@@ -33,17 +34,23 @@
|
||||
#include "vax_defs.h"
|
||||
#include <ctype.h>
|
||||
|
||||
extern DEVICE cpu_dev, tlb_dev;
|
||||
extern DEVICE rom_dev, nvr_dev;
|
||||
extern DEVICE sysd_dev, qba_dev;
|
||||
extern DEVICE cpu_dev;
|
||||
extern DEVICE tlb_dev;
|
||||
extern DEVICE rom_dev;
|
||||
extern DEVICE nvr_dev;
|
||||
extern DEVICE sysd_dev;
|
||||
extern DEVICE qba_dev;
|
||||
extern DEVICE ptr_dev, ptp_dev;
|
||||
extern DEVICE tti_dev, tto_dev;
|
||||
extern DEVICE csi_dev, cso_dev;
|
||||
extern DEVICE lpt_dev, clk_dev;
|
||||
extern DEVICE lpt_dev;
|
||||
extern DEVICE clk_dev;
|
||||
extern DEVICE rq_dev, rqb_dev, rqc_dev, rqd_dev;
|
||||
extern DEVICE rl_dev;
|
||||
extern DEVICE ts_dev, tq_dev;
|
||||
extern DEVICE dz_dev, xq_dev;
|
||||
extern DEVICE ts_dev;
|
||||
extern DEVICE tq_dev;
|
||||
extern DEVICE dz_dev;
|
||||
extern DEVICE xq_dev, xqb_dev;
|
||||
extern UNIT cpu_unit;
|
||||
extern REG cpu_reg[];
|
||||
extern uint32 *M;
|
||||
@@ -52,12 +59,12 @@ extern int32 sim_switches;
|
||||
|
||||
extern void WriteB (int32 pa, int32 val);
|
||||
extern void rom_wr (int32 pa, int32 val, int32 lnt);
|
||||
t_stat fprint_sym_m (FILE *of, t_addr addr, t_value *val);
|
||||
t_stat fprint_sym_m (FILE *of, uint32 addr, t_value *val);
|
||||
int32 fprint_sym_qoimm (FILE *of, t_value *val, int32 vp, int32 lnt);
|
||||
t_stat parse_sym_m (char *cptr, t_addr addr, t_value *val);
|
||||
int32 parse_brdisp (char *cptr, t_addr addr, t_value *val,
|
||||
t_stat parse_sym_m (char *cptr, uint32 addr, t_value *val);
|
||||
int32 parse_brdisp (char *cptr, uint32 addr, t_value *val,
|
||||
int32 vp, int32 lnt, t_stat *r);
|
||||
int32 parse_spec (char *cptr, t_addr addr, t_value *val,
|
||||
int32 parse_spec (char *cptr, uint32 addr, t_value *val,
|
||||
int32 vp, int32 disp, t_stat *r);
|
||||
char *parse_rnum (char *cptr, int32 *rn);
|
||||
int32 parse_sym_qoimm (int32 *lit, t_value *val, int32 vp,
|
||||
@@ -103,6 +110,7 @@ DEVICE *sim_devices[] = {
|
||||
&ts_dev,
|
||||
&tq_dev,
|
||||
&xq_dev,
|
||||
&xqb_dev,
|
||||
NULL };
|
||||
|
||||
const char *sim_stop_messages[] = {
|
||||
@@ -135,7 +143,7 @@ t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
|
||||
{
|
||||
t_stat r;
|
||||
int32 i;
|
||||
t_addr origin, limit;
|
||||
uint32 origin, limit;
|
||||
extern int32 ssc_cnf;
|
||||
#define SSCCNF_BLO 0x80000000
|
||||
|
||||
@@ -148,7 +156,7 @@ else if (sim_switches & SWMASK ('N')) { /* NVR? */
|
||||
limit = NVRBASE + NVRSIZE;
|
||||
ssc_cnf = ssc_cnf & ~SSCCNF_BLO; }
|
||||
else { origin = 0; /* memory */
|
||||
limit = cpu_unit.capac;
|
||||
limit = (uint32) cpu_unit.capac;
|
||||
if (sim_switches & SWMASK ('O')) { /* origin? */
|
||||
origin = (int32) get_uint (cptr, 16, 0xFFFFFFFF, &r);
|
||||
if (r != SCPE_OK) return SCPE_ARG; } }
|
||||
@@ -189,7 +197,7 @@ int32 *buf;
|
||||
if ((sec < 2) || (wds < 16)) return SCPE_ARG;
|
||||
if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT;
|
||||
if (!get_yn ("Overwrite last track? [N]", FALSE)) return SCPE_OK;
|
||||
da = (uptr->capac - (sec * wds)) * sizeof (int16);
|
||||
da = (int32) (uptr->capac - (sec * wds)) * sizeof (int16);
|
||||
if (fseek (uptr->fileref, da, SEEK_SET)) return SCPE_IOERR;
|
||||
if ((buf = malloc (wds * sizeof (int32))) == NULL) return SCPE_MEM;
|
||||
buf[0] = 0x12345678;
|
||||
@@ -821,9 +829,10 @@ const char* regname[] = {
|
||||
if < 0, number of extra bytes retired
|
||||
*/
|
||||
|
||||
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
|
||||
t_stat fprint_sym (FILE *of, t_addr exta, t_value *val,
|
||||
UNIT *uptr, int32 sw)
|
||||
{
|
||||
uint32 addr = (uint32) exta;
|
||||
int32 c, k, num, vp, lnt, rdx;
|
||||
t_stat r;
|
||||
DEVICE *dptr;
|
||||
@@ -869,7 +878,7 @@ return -(vp - 1);
|
||||
if < 0, number of extra bytes retired
|
||||
*/
|
||||
|
||||
t_stat fprint_sym_m (FILE *of, t_addr addr, t_value *val)
|
||||
t_stat fprint_sym_m (FILE *of, uint32 addr, t_value *val)
|
||||
{
|
||||
int32 i, k, vp, inst, numspec;
|
||||
int32 num, spec, rn, disp, index;
|
||||
@@ -999,8 +1008,9 @@ return vp;
|
||||
<= 0 -number of extra words
|
||||
*/
|
||||
|
||||
t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
|
||||
t_stat parse_sym (char *cptr, t_addr exta, UNIT *uptr, t_value *val, int32 sw)
|
||||
{
|
||||
uint32 addr = (uint32) exta;
|
||||
int32 k, rdx, lnt, num, vp;
|
||||
t_stat r;
|
||||
DEVICE *dptr;
|
||||
@@ -1047,7 +1057,7 @@ return -(lnt - 1);
|
||||
<= 0 -number of extra words
|
||||
*/
|
||||
|
||||
t_stat parse_sym_m (char *cptr, t_addr addr, t_value *val)
|
||||
t_stat parse_sym_m (char *cptr, uint32 addr, t_value *val)
|
||||
{
|
||||
int32 i, numspec, disp, opc, vp;
|
||||
t_stat r;
|
||||
@@ -1090,7 +1100,7 @@ return -(vp - 1);
|
||||
vp = updated output pointer
|
||||
*/
|
||||
|
||||
int32 parse_brdisp (char *cptr, t_addr addr, t_value *val, int32 vp,
|
||||
int32 parse_brdisp (char *cptr, uint32 addr, t_value *val, int32 vp,
|
||||
int32 lnt, t_stat *r)
|
||||
{
|
||||
int32 k, dest, num;
|
||||
@@ -1133,7 +1143,7 @@ return vp;
|
||||
#define PARSE_LOSE { *r = SCPE_ARG; return vp; }
|
||||
#define SEL_LIM(p,m,u) ((fl & SP_PLUS)? (p): ((fl & SP_MINUS)? (m): (u)))
|
||||
|
||||
int32 parse_spec (char *cptr, t_addr addr, t_value *val, int32 vp, int32 disp, t_stat *r)
|
||||
int32 parse_spec (char *cptr, uint32 addr, t_value *val, int32 vp, int32 disp, t_stat *r)
|
||||
{
|
||||
int32 i, k, litsize, rn, index;
|
||||
int32 num, dispsize, mode;
|
||||
|
||||
150
VAX/vax_sysdev.c
150
VAX/vax_sysdev.c
@@ -1,6 +1,6 @@
|
||||
/* vax_sysreg.c: VAX system registers simulator
|
||||
|
||||
Copyright (c) 1998-2002, Robert M Supnik
|
||||
Copyright (c) 1998-2003, 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"),
|
||||
@@ -33,6 +33,10 @@
|
||||
cso console storage output
|
||||
sysd system devices (SSC miscellany)
|
||||
|
||||
7-Jun-03 MP Added calibrated delay to ROM reads (from Mark Pizzolato)
|
||||
Fixed calibration problems interval timer (from Mark Pizzolato)
|
||||
12-May-03 RMS Fixed compilation warnings from VC.Net
|
||||
23-Apr-03 RMS Revised for 32b/64b t_addr
|
||||
19-Aug-02 RMS Removed unused variables (found by David Hittner)
|
||||
Allowed NVR to be attached to file
|
||||
30-May-02 RMS Widened POS to 32b
|
||||
@@ -41,6 +45,9 @@
|
||||
|
||||
#include "vax_defs.h"
|
||||
|
||||
#define UNIT_V_NODELAY (UNIT_V_UF + 0) /* ROM access equal to RAM access */
|
||||
#define UNIT_NODELAY (1u << UNIT_V_NODELAY)
|
||||
|
||||
/* Console storage control/status */
|
||||
|
||||
#define CSICSR_IMP (CSR_DONE + CSR_IE) /* console input */
|
||||
@@ -156,6 +163,7 @@
|
||||
|
||||
extern int32 int_req[IPL_HLVL];
|
||||
extern UNIT cpu_unit;
|
||||
extern UNIT clk_unit;
|
||||
extern jmp_buf save_env;
|
||||
extern int32 p1;
|
||||
extern int32 sim_switches;
|
||||
@@ -182,12 +190,13 @@ uint32 tmr_sav[2] = { 0 }; /* saved inst cnt */
|
||||
int32 ssc_adsm[2] = { 0 }; /* addr strobes */
|
||||
int32 ssc_adsk[2] = { 0 };
|
||||
int32 cdg_dat[CDASIZE >> 2]; /* cache data */
|
||||
static uint32 rom_delay = 0;
|
||||
|
||||
t_stat rom_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
|
||||
t_stat rom_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
|
||||
t_stat rom_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw);
|
||||
t_stat rom_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw);
|
||||
t_stat rom_reset (DEVICE *dptr);
|
||||
t_stat nvr_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
|
||||
t_stat nvr_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw);
|
||||
t_stat nvr_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw);
|
||||
t_stat nvr_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw);
|
||||
t_stat nvr_reset (DEVICE *dptr);
|
||||
t_stat nvr_attach (UNIT *uptr, char *cptr);
|
||||
t_stat nvr_detach (UNIT *uptr);
|
||||
@@ -241,6 +250,7 @@ extern void rxcs_wr (int32 dat);
|
||||
extern void txcs_wr (int32 dat);
|
||||
extern void txdb_wr (int32 dat);
|
||||
extern void ioreset_wr (int32 dat);
|
||||
extern uint32 sim_os_msec();
|
||||
|
||||
/* ROM data structures
|
||||
|
||||
@@ -254,8 +264,13 @@ UNIT rom_unit = { UDATA (NULL, UNIT_FIX+UNIT_BINK, ROMSIZE) };
|
||||
REG rom_reg[] = {
|
||||
{ NULL } };
|
||||
|
||||
MTAB rom_mod[] = {
|
||||
{ UNIT_NODELAY, UNIT_NODELAY, "fast access", "NODELAY", NULL },
|
||||
{ UNIT_NODELAY, 0, "1usec calibrated access", "DELAY", NULL },
|
||||
{ 0 } };
|
||||
|
||||
DEVICE rom_dev = {
|
||||
"ROM", &rom_unit, rom_reg, NULL,
|
||||
"ROM", &rom_unit, rom_reg, rom_mod,
|
||||
1, 16, ROMAWIDTH, 4, 16, 32,
|
||||
&rom_ex, &rom_dep, &rom_reset,
|
||||
NULL, NULL, NULL,
|
||||
@@ -395,13 +410,70 @@ DEVICE sysd_dev = {
|
||||
|
||||
/* ROM: read only memory - stored in a buffered file
|
||||
Register space access routines see ROM twice
|
||||
|
||||
ROM access has been 'regulated' to about 1Mhz to avoid issues
|
||||
with testing the interval timers in self-test. Specifically,
|
||||
the VAX boot ROM (ka655.bin) contains code which presumes that
|
||||
the VAX runs at a particular slower speed when code is running
|
||||
from ROM (which is not cached). These assumptions are built
|
||||
into instruction based timing loops. As the host platform gets
|
||||
much faster than the original VAX, the assumptions embedded in
|
||||
these code loops are no longer valid.
|
||||
|
||||
Code has been added to the ROM implementation to limit CPU speed
|
||||
to about 500K instructions per second. This heads off any future
|
||||
issues with the embedded timing loops.
|
||||
*/
|
||||
|
||||
int32 rom_swapb(int32 val)
|
||||
{
|
||||
return ((val << 24) & 0xff000000) | (( val << 8) & 0xff0000) |
|
||||
((val >> 8) & 0xff00) | ((val >> 24) & 0xff);
|
||||
}
|
||||
|
||||
int32 rom_read_delay (int32 val)
|
||||
{
|
||||
uint32 i, l = rom_delay;
|
||||
int32 loopval = 0;
|
||||
|
||||
if (rom_unit.flags & UNIT_NODELAY) return val;
|
||||
|
||||
/* Calibrate the loop delay factor when first used.
|
||||
Do this 4 times to and use the largest value computed. */
|
||||
|
||||
if (rom_delay == 0) {
|
||||
uint32 ts, te, c = 10000, samples = 0;
|
||||
while (1) {
|
||||
c = c * 2;
|
||||
te = sim_os_msec();
|
||||
while (te == (ts = sim_os_msec ())); /* align on ms tick */
|
||||
|
||||
/* This is merely a busy wait with some "work" that won't get optimized
|
||||
away by a good compiler. loopval always is zero. To avoid smart compilers,
|
||||
the loopval variable is referenced in the function arguments so that the
|
||||
function expression is not loop invariant. It also must be referenced
|
||||
by subsequent code or to avoid the whole computation being eliminated. */
|
||||
|
||||
for (i = 0; i < c; i++)
|
||||
loopval |= (loopval + ts) ^ rom_swapb (rom_swapb (loopval + ts));
|
||||
te = sim_os_msec ();
|
||||
if ((te - ts) < 50) continue; /* sample big enough? */
|
||||
if (rom_delay < (loopval + (c / (te - ts) / 1000) + 1))
|
||||
rom_delay = loopval + (c / (te - ts) / 1000) + 1;
|
||||
if (++samples >= 4) break;
|
||||
c = c / 2; }
|
||||
if (rom_delay < 5) rom_delay = 5; }
|
||||
|
||||
for (i = 0; i < l; i++)
|
||||
loopval |= (loopval + val) ^ rom_swapb (rom_swapb (loopval + val));
|
||||
return val + loopval;
|
||||
}
|
||||
|
||||
int32 rom_rd (int32 pa)
|
||||
{
|
||||
int32 rg = ((pa - ROMBASE) & ROMAMASK) >> 2;
|
||||
|
||||
return rom[rg];
|
||||
return rom_read_delay (rom[rg]);
|
||||
}
|
||||
|
||||
void rom_wr (int32 pa, int32 val, int32 lnt)
|
||||
@@ -418,8 +490,10 @@ return;
|
||||
|
||||
/* ROM examine */
|
||||
|
||||
t_stat rom_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
|
||||
t_stat rom_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw)
|
||||
{
|
||||
uint32 addr = (uint32) exta;
|
||||
|
||||
if ((vptr == NULL) || (addr & 03)) return SCPE_ARG;
|
||||
if (addr >= ROMSIZE) return SCPE_NXM;
|
||||
*vptr = rom[addr >> 2];
|
||||
@@ -428,8 +502,10 @@ return SCPE_OK;
|
||||
|
||||
/* ROM deposit */
|
||||
|
||||
t_stat rom_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
|
||||
t_stat rom_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw)
|
||||
{
|
||||
uint32 addr = (uint32) exta;
|
||||
|
||||
if (addr & 03) return SCPE_ARG;
|
||||
if (addr >= ROMSIZE) return SCPE_NXM;
|
||||
rom[addr >> 2] = (uint32) val;
|
||||
@@ -468,8 +544,10 @@ return;
|
||||
|
||||
/* NVR examine */
|
||||
|
||||
t_stat nvr_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw)
|
||||
t_stat nvr_ex (t_value *vptr, t_addr exta, UNIT *uptr, int32 sw)
|
||||
{
|
||||
uint32 addr = (uint32) exta;
|
||||
|
||||
if ((vptr == NULL) || (addr & 03)) return SCPE_ARG;
|
||||
if (addr >= NVRSIZE) return SCPE_NXM;
|
||||
*vptr = nvr[addr >> 2];
|
||||
@@ -478,8 +556,10 @@ return SCPE_OK;
|
||||
|
||||
/* NVR deposit */
|
||||
|
||||
t_stat nvr_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw)
|
||||
t_stat nvr_dep (t_value val, t_addr exta, UNIT *uptr, int32 sw)
|
||||
{
|
||||
uint32 addr = (uint32) exta;
|
||||
|
||||
if (addr & 03) return SCPE_ARG;
|
||||
if (addr >= NVRSIZE) return SCPE_NXM;
|
||||
nvr[addr >> 2] = (uint32) val;
|
||||
@@ -711,8 +791,8 @@ return;
|
||||
struct reglink { /* register linkage */
|
||||
int32 low; /* low addr */
|
||||
int32 high; /* high addr */
|
||||
t_stat (*read)(); /* read routine */
|
||||
void (*write)(); }; /* write routine */
|
||||
t_stat (*read)(int32 pa); /* read routine */
|
||||
void (*write)(int32 pa, int32 val, int32 lnt); }; /* write routine */
|
||||
|
||||
struct reglink regtable[] = {
|
||||
{ CQMAPBASE, CQMAPBASE+CQMAPSIZE, &cqmap_rd, &cqmap_wr },
|
||||
@@ -1031,13 +1111,31 @@ return;
|
||||
clock events per second. Instead, a gross hack is used. When
|
||||
a timer is started, the clock interval is inspected.
|
||||
|
||||
if (int < 0 and small) then testing timer, count instructions
|
||||
if (int < 0 and small) then testing timer, count instructions.
|
||||
Small is determined by when the requested interval is less
|
||||
than the size of a 100hz system clock tick.
|
||||
if (int >= 0 or large) then counting a real interval, schedule
|
||||
clock events at 100Hz using calibrated line clock delay
|
||||
and when the remaining time value gets small enough, behave
|
||||
like the small case above.
|
||||
|
||||
If the interval register is read, then its value between events
|
||||
is interpolated using the current instruction count versus the
|
||||
count when the most recent event started.
|
||||
count when the most recent event started, the result is scaled
|
||||
to the calibrated system clock, unless the interval being timed
|
||||
is less than a calibrated system clock tick (or the calibrated
|
||||
clock is running very slowly) at which time the result will be
|
||||
the elapsed instruction count.
|
||||
|
||||
The powerup TOY Test sometimes fails its tolerance test. This was
|
||||
due to varying system load causing varying calibration values to be
|
||||
used at different times while referencing the TIR. While timing long
|
||||
intervals, we now synchronize the stepping (and calibration) of the
|
||||
system tick with the opportunity to reference the value. This gives
|
||||
precise tolerance measurement values (when interval timers are used
|
||||
to measure the system clock), regardless of other load issues on the
|
||||
host system which might cause varying values of the system clock's
|
||||
calibration factor.
|
||||
*/
|
||||
|
||||
int32 tmr_tir_rd (int32 tmr, t_bool interp)
|
||||
@@ -1046,6 +1144,9 @@ uint32 delta;
|
||||
|
||||
if (interp || (tmr_csr[tmr] & TMR_CSR_RUN)) { /* interp, running? */
|
||||
delta = sim_grtime () - tmr_sav[tmr]; /* delta inst */
|
||||
if ((tmr_inc[tmr] == TMR_INC) && /* scale large int */
|
||||
(tmr_poll > TMR_INC))
|
||||
delta = (uint32) ((((double) delta) * TMR_INC) / tmr_poll);
|
||||
if (delta >= tmr_inc[tmr]) delta = tmr_inc[tmr] - 1;
|
||||
return tmr_tir[tmr] + delta; }
|
||||
return tmr_tir[tmr];
|
||||
@@ -1117,12 +1218,27 @@ return;
|
||||
|
||||
void tmr_sched (int32 tmr)
|
||||
{
|
||||
int32 clk_time = sim_is_active (&clk_unit) - 1;
|
||||
int32 tmr_time;
|
||||
|
||||
tmr_sav[tmr] = sim_grtime (); /* save intvl base */
|
||||
if (tmr_tir[tmr] > (0xFFFFFFFFu - TMR_INC)) { /* short interval? */
|
||||
tmr_inc[tmr] = (~tmr_tir[tmr] + 1); /* inc = interval */
|
||||
sim_activate (&sysd_unit[tmr], tmr_inc[tmr]); }
|
||||
tmr_time = tmr_inc[tmr]; }
|
||||
else { tmr_inc[tmr] = TMR_INC; /* usec/interval */
|
||||
sim_activate (&sysd_unit[tmr], tmr_poll); } /* use calib clock */
|
||||
tmr_time = tmr_poll; }
|
||||
if (tmr_time == 0) tmr_time = 1;
|
||||
if ((tmr_inc[tmr] = TMR_INC) && (tmr_time > clk_time)) {
|
||||
|
||||
/* Align scheduled event to be identical to the event for the next clock
|
||||
tick. This lets us always see a consistent calibrated value, both for
|
||||
this scheduling, AND for any query of the current timer register that
|
||||
may happen in tmr_tir_rd (). This presumes that sim_activate will
|
||||
queue the interval timer behind the event for the clock tick. */
|
||||
|
||||
tmr_inc[tmr] = (uint32) (((double) clk_time * TMR_INC) / tmr_poll);
|
||||
tmr_time = clk_time; }
|
||||
sim_activate (&sysd_unit[tmr], tmr_time);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
#define MAXMEMMASK (MAXMEMSIZE - 1) /* max mem addr mask */
|
||||
#define INITMEMSIZE (1 << 24) /* initial memory size */
|
||||
#define MEMSIZE (cpu_unit.capac)
|
||||
#define ADDR_IS_MEM(x) (((t_addr) (x)) < MEMSIZE)
|
||||
#define ADDR_IS_MEM(x) (((uint32) (x)) < MEMSIZE)
|
||||
|
||||
/* Cache diagnostic space */
|
||||
|
||||
@@ -101,8 +101,8 @@
|
||||
#define CDG_GETTAG(x) (((x) >> CDAAWIDTH) & CTGMASK)
|
||||
#define CTG_V (1u << (CTGAWIDTH + 0)) /* tag valid */
|
||||
#define CTG_WP (1u << (CTGAWIDTH + 1)) /* wrong parity */
|
||||
#define ADDR_IS_CDG(x) ((((t_addr) (x)) >= CDGBASE) && \
|
||||
(((t_addr) (x)) < (CDGBASE + CDGSIZE)))
|
||||
#define ADDR_IS_CDG(x) ((((uint32) (x)) >= CDGBASE) && \
|
||||
(((uint32) (x)) < (CDGBASE + CDGSIZE)))
|
||||
|
||||
/* Qbus I/O registers */
|
||||
|
||||
@@ -110,8 +110,8 @@
|
||||
#define IOPAGESIZE (1u << IOPAGEAWIDTH) /* IO page length */
|
||||
#define IOPAGEMASK (IOPAGESIZE - 1) /* IO addr mask */
|
||||
#define IOPAGEBASE 0x20000000 /* IO page base */
|
||||
#define ADDR_IS_IO(x) ((((t_addr) (x)) >= IOPAGEBASE) && \
|
||||
(((t_addr) (x)) < (IOPAGEBASE + IOPAGESIZE)))
|
||||
#define ADDR_IS_IO(x) ((((uint32) (x)) >= IOPAGEBASE) && \
|
||||
(((uint32) (x)) < (IOPAGEBASE + IOPAGESIZE)))
|
||||
|
||||
/* Read only memory - appears twice */
|
||||
|
||||
@@ -119,8 +119,8 @@
|
||||
#define ROMSIZE (1u << ROMAWIDTH) /* ROM length */
|
||||
#define ROMAMASK (ROMSIZE - 1) /* ROM addr mask */
|
||||
#define ROMBASE 0x20040000 /* ROM base */
|
||||
#define ADDR_IS_ROM(x) ((((t_addr) (x)) >= ROMBASE) && \
|
||||
(((t_addr) (x)) < (ROMBASE + ROMSIZE + ROMSIZE)))
|
||||
#define ADDR_IS_ROM(x) ((((uint32) (x)) >= ROMBASE) && \
|
||||
(((uint32) (x)) < (ROMBASE + ROMSIZE + ROMSIZE)))
|
||||
|
||||
/* Local register space */
|
||||
|
||||
@@ -161,8 +161,8 @@
|
||||
#define NVRSIZE (1u << NVRAWIDTH) /* NVR length */
|
||||
#define NVRAMASK (NVRSIZE - 1) /* NVR addr mask */
|
||||
#define NVRBASE 0x20140400 /* NVR base */
|
||||
#define ADDR_IS_NVR(x) ((((t_addr) (x)) >= NVRBASE) && \
|
||||
(((t_addr) (x)) < (NVRBASE + NVRSIZE)))
|
||||
#define ADDR_IS_NVR(x) ((((uint32) (x)) >= NVRBASE) && \
|
||||
(((uint32) (x)) < (NVRBASE + NVRSIZE)))
|
||||
|
||||
/* CQBIC Qbus memory space (seen from CVAX) */
|
||||
|
||||
@@ -211,6 +211,8 @@
|
||||
|
||||
#define UNIBUS FALSE /* 22b only */
|
||||
|
||||
#define DEV_RDX 16 /* default device radix */
|
||||
|
||||
/* Device information block */
|
||||
|
||||
#define VEC_DEVMAX 4 /* max device vec */
|
||||
@@ -223,7 +225,7 @@ struct pdp_dib {
|
||||
int32 vnum; /* vectors: number */
|
||||
int32 vloc; /* locator */
|
||||
int32 vec; /* value */
|
||||
int32 (*ack[VEC_DEVMAX])(void); /* ack routines */
|
||||
int32 (*ack[VEC_DEVMAX])(void); /* ack routine */
|
||||
};
|
||||
|
||||
typedef struct pdp_dib DIB;
|
||||
@@ -386,13 +388,13 @@ typedef struct pdp_dib DIB;
|
||||
|
||||
/* Function prototypes for I/O */
|
||||
|
||||
t_bool map_addr (t_addr qa, t_addr *ma);
|
||||
int32 map_readB (t_addr ba, int32 bc, uint8 *buf);
|
||||
int32 map_readW (t_addr ba, int32 bc, uint16 *buf);
|
||||
int32 map_readL (t_addr ba, int32 bc, uint32 *buf);
|
||||
int32 map_writeB (t_addr ba, int32 bc, uint8 *buf);
|
||||
int32 map_writeW (t_addr ba, int32 bc, uint16 *buf);
|
||||
int32 map_writeL (t_addr ba, int32 bc, uint32 *buf);
|
||||
t_bool map_addr (uint32 qa, uint32 *ma);
|
||||
int32 map_readB (uint32 ba, int32 bc, uint8 *buf);
|
||||
int32 map_readW (uint32 ba, int32 bc, uint16 *buf);
|
||||
int32 map_readL (uint32 ba, int32 bc, uint32 *buf);
|
||||
int32 map_writeB (uint32 ba, int32 bc, uint8 *buf);
|
||||
int32 map_writeW (uint32 ba, int32 bc, uint16 *buf);
|
||||
int32 map_writeL (uint32 ba, int32 bc, uint32 *buf);
|
||||
|
||||
#define Map_Addr(a,b) map_addr (a, b)
|
||||
#define Map_ReadB(a,b,c,d) map_readB (a, b, c)
|
||||
|
||||
Reference in New Issue
Block a user