723 lines
32 KiB
C
723 lines
32 KiB
C
/* hp3000_defs.h: HP 3000 simulator general declarations
|
|
|
|
Copyright (c) 2016-2017, J. David Bryan
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of the author shall not be used
|
|
in advertising or otherwise to promote the sale, use or other dealings in
|
|
this Software without prior written authorization from the author.
|
|
|
|
16-Oct-17 JDB Suppressed logical-not-parentheses warning on clang
|
|
29-Dec-16 JDB Changed the status mnemonic flag from REG_S to REG_T
|
|
20-Nov-16 JDB Added mapped memory access classes
|
|
24-Oct-16 JDB Added half-byte definitions for CIS decoding
|
|
10-Oct-16 JDB Moved ACCESS_CLASS definition here from hp3000_cpu.h
|
|
03-Sep-16 JDB Added the STOP_POWER and STOP_ARSINH codes
|
|
13-May-16 JDB Modified for revised SCP API function parameter types
|
|
21-Mar-16 JDB Changed uint16 types to HP_WORD
|
|
19-Mar-16 JDB Added UNDEFs for the additional register macros
|
|
04-Feb-16 JDB First release version
|
|
11-Dec-12 JDB Created
|
|
|
|
|
|
This file provides the general declarations used throughout the HP 3000
|
|
simulator. It is required by all modules.
|
|
|
|
The author gratefully acknowledges the help of Frank McConnell in answering
|
|
questions about the HP 3000.
|
|
|
|
|
|
-----------------------------------------------------
|
|
Implementation Note -- Compiling the Simulator as C++
|
|
-----------------------------------------------------
|
|
|
|
Although simulators are written in C, the SIMH project encourages developers
|
|
to compile them with a C++ compiler to obtain the more careful type checking
|
|
provided. To obtain successful compilations, the simulator must be written
|
|
in the subset of C that is also valid C++. Using valid C features beyond
|
|
that subset, as the HP 3000 simulator does, will produce C++ compiler errors.
|
|
|
|
The standard C features used by the simulator that prevent error-free C++
|
|
compilation are:
|
|
|
|
1. Incomplete types.
|
|
|
|
In C, mutually recursive type definitions are allowed by the use of
|
|
incomplete type declarations, such as "DEVICE ms_dev;" followed later by
|
|
"DEVICE ms_dev {...};". Several HP device simulators use this feature to
|
|
place a pointer to the device structure in the "desc" field of an MTAB
|
|
array element, typically when the associated validation or display
|
|
routine handles multiple devices. As the DEVICE contains a pointer to
|
|
the MTAB array, and an MTAB array element contains a pointer to the
|
|
DEVICE, the definitions are mutually recursive, and incomplete types are
|
|
employed. C++ does not permit incomplete types.
|
|
|
|
2. Implicit conversion of ints to enums.
|
|
|
|
In C, enumeration types are compatible with integer types, and its
|
|
members are constants having type "int". As such, they are semantically
|
|
equivalent to and may be used interchangeably with integers. For the
|
|
developer, though, C enumerations have some advantages. In particular,
|
|
the compiler may check a "switch" statement to ensure that all of the
|
|
enumeration cases are covered. Also, a mathematical set may be modeled
|
|
by an enumeration type with disjoint enumerator values, with the bitwise
|
|
integer OR and AND operators modeling the set union and intersection
|
|
operations. The latter has direct support in the "gdb" debugger, which
|
|
will display an enumerated type value as a union of the various
|
|
enumerators. The HP simulator makes extensive use of both features to
|
|
model hardware signal buses (e.g., INBOUND_SET, OUTBOUND_SET) and so
|
|
performs bitwise integer operations on the enumerations to model signal
|
|
assertion and denial. In C++, implicit conversion from enumerations to
|
|
integers is allowed, but conversion from integers to enumerations is
|
|
illegal without explicit casts. Therefore, the idiom employed by the
|
|
simulator to assert a signal (e.g., "outbound_signals |= INTREQ") is
|
|
rejected by the C++ compiler.
|
|
|
|
3. Implicit increment operations on enums.
|
|
|
|
Because enums are compatible with integers in C, no special enumerator
|
|
increment operator is provided. To cycle through the range of an
|
|
enumeration type, e.g. in a "for" statement, the standard integer
|
|
increment operator, "++", is used. In C++, the "++" operator must be
|
|
overloaded with a version specific to the enumeration type; applying the
|
|
integer "++" to an enumeration is illegal.
|
|
|
|
4. Use of C++ keywords as variable names.
|
|
|
|
C++ reserves a number of additional keywords beyond those reserved by C.
|
|
Use of any of these keywords as a variable or type name is legal C but
|
|
illegal C++. The HP simulator uses variables named "class" and
|
|
"operator", which are keywords in C++.
|
|
|
|
The HP simulator is written in ISO standard C and will compile cleanly with a
|
|
compiler implementing the 1999 C standard. Compilation as C++ is not a goal
|
|
of the simulator and cannot work, given the incompatibilities listed above.
|
|
*/
|
|
|
|
|
|
|
|
#include "sim_rev.h"
|
|
#include "sim_defs.h"
|
|
|
|
|
|
|
|
/* The following pragmas quell clang and Microsoft Visual C++ warnings that are
|
|
on by default but should not be, in my opinion. They warn about the use of
|
|
perfectly valid code and require the addition of redundant parentheses and
|
|
braces to silence them. Rather than clutter up the code with scores of extra
|
|
symbols that, in my view, make the code harder to read and maintain, I elect
|
|
to suppress these warnings.
|
|
|
|
VC++ 2008 warning descriptions:
|
|
|
|
- 4114: "same type qualifier used more than once" [legal per C99]
|
|
|
|
- 4554: "check operator precedence for possible error; use parentheses to
|
|
clarify precedence"
|
|
|
|
- 4996: "function was declared deprecated"
|
|
*/
|
|
|
|
#if defined (__clang__)
|
|
#pragma clang diagnostic ignored "-Wlogical-not-parentheses"
|
|
#pragma clang diagnostic ignored "-Wlogical-op-parentheses"
|
|
#pragma clang diagnostic ignored "-Wbitwise-op-parentheses"
|
|
#pragma clang diagnostic ignored "-Wshift-op-parentheses"
|
|
#pragma clang diagnostic ignored "-Wdangling-else"
|
|
|
|
#elif defined (_MSC_VER)
|
|
#pragma warning (disable: 4114 4554 4996)
|
|
|
|
#endif
|
|
|
|
|
|
/* Device register display mode flags */
|
|
|
|
#define REG_X REG_VMIO /* permit symbolic display overrides */
|
|
|
|
#define REG_A (1u << REG_V_UF + 0) /* default format is -A (one ASCII character) */
|
|
#define REG_C (1u << REG_V_UF + 1) /* default format is -C (two ASCII characters) */
|
|
#define REG_M (1u << REG_V_UF + 2) /* default format is -M (mnemonic) */
|
|
#define REG_T (1u << REG_V_UF + 3) /* default format is -T (status mnemonic) */
|
|
|
|
|
|
/* Register macros.
|
|
|
|
These additional register definition macros are used to define:
|
|
|
|
FBDATA -- a one-bit flag in an arrayed register
|
|
SVDATA -- a register only used for SAVE/RESTORE
|
|
YRDATA -- a binary register
|
|
|
|
The FBDATA macro defines a flag that is replicated in the same bit position
|
|
in each element of an array; the array element size is assumed to be the
|
|
minimum necessary to hold the bit at the given offset. The SVDATA macro is
|
|
used solely to SAVE data stored in a structure so that it may be RESTOREd
|
|
later. The YRDATA macro extends the functionality of the ORDATA, DRDATA, and
|
|
HRDATA macros to registers with binary (base 2) representation.
|
|
|
|
|
|
Implementation notes:
|
|
|
|
1. Use caution that multiple FBDATA registers referencing the same array
|
|
have offsets that imply the same array element size. For example,
|
|
offsets of 3 and 5 can be used with an array of 8-bit elements, and
|
|
offsets 13 and 15 can be used with an array of 16-bit elements. However,
|
|
offsets 3 and 13 cannot be used, as the first implies 8-bit elements, and
|
|
the second implies 16-bit elements.
|
|
|
|
2. The macro names are UNDEFed to avoid potential name clashes with
|
|
sim_def.h macros.
|
|
|
|
3. The REG structure for version 4.0 contains several fields that are not
|
|
present in 3.x versions. The 4.x REGDATA macro maps to the REG strcture
|
|
in a field-order- and preprocessor-independent manner. There is no
|
|
corresponding macro in 3.x, so we must handle standard vs. non-standard
|
|
preprocessor differences by creating our own REGMAP macro to handle the
|
|
mapping.
|
|
*/
|
|
|
|
#undef FBDATA
|
|
#undef SRDATA
|
|
#undef YRDATA
|
|
#undef REGMAP
|
|
|
|
#if (SIM_MAJOR >= 4)
|
|
#define REGMAP(nm,loc,rdx,wd,off,dep,fl,siz) \
|
|
REGDATA (nm, loc, rdx, wd, off, dep, NULL, NULL, fl, 0, siz)
|
|
|
|
#elif defined (__STDC__) || defined (_WIN32)
|
|
#define REGMAP(nm,loc,rdx,wd,off,dep,fl,siz) \
|
|
#nm, &(loc), (rdx), (wd), (off), (dep), (fl), 0
|
|
|
|
#else
|
|
#define REGMAP(nm,loc,rdx,wd,off,dep,fl,siz) \
|
|
"nm", &(loc), (rdx), (wd), (off), (dep), (fl), 0
|
|
|
|
#endif
|
|
|
|
/* Macro name loc radix width offset depth flags size */
|
|
/* ------------------------- ---- ------ ----- ----- ------ ---------- ----- -------------- */
|
|
#define FBDATA(nm,loc,ofs,dep,fl) REGMAP (nm, (loc), 2, 1, (ofs), (dep), (fl), sizeof *(loc))
|
|
#define SVDATA(nm,loc) SAVEDATA (nm, (loc))
|
|
#define YRDATA(nm,loc,wid,fl) BINRDATA (nm, (loc), (wid)), (fl)
|
|
|
|
|
|
/* Debugging and console output.
|
|
|
|
"dprintf" is used to write debugging messages. It does an "fprintf" to the
|
|
debug output stream if the stream is open and the debug "flag" is currently
|
|
enabled in device "dev". Otherwise, it's a NOP. "..." is the format string
|
|
and associated values.
|
|
|
|
"dpprintf" is identical to "dprintf", except that a device pointer is passed
|
|
instead of a device structure.
|
|
|
|
"DPRINTING" and "DPPRINTING" implement the test conditions for device and
|
|
device pointer debugging, respectively. They are used explicitly only when
|
|
several debug statements employing the same flag are required, and it is
|
|
desirable to avoid repeating the stream and flag test for each one.
|
|
|
|
"cprintf", "cputs", and "cputc" are used to write messages to the console
|
|
and, if console logging is enabled, to the log output stream. They do
|
|
"(f)printf", "fputs", or "(f)putc", respectively. "..." is the format string
|
|
and associated values, "str" is the string to write, and "ch" is the
|
|
character to write.
|
|
|
|
|
|
Implementation notes:
|
|
|
|
1. The "cputs" macro uses "fputs" for both console and log file output
|
|
because "puts" appends a newline, whereas "fputs" does not.
|
|
*/
|
|
|
|
#define DPRINTING(d,f) (sim_deb && ((d).dctrl & (f)))
|
|
|
|
#define DPPRINTING(d,f) (sim_deb && ((d)->dctrl & (f)))
|
|
|
|
#define dprintf(dev, flag, ...) \
|
|
if (DPRINTING (dev, flag)) \
|
|
hp_debug (&(dev), (flag), __VA_ARGS__); \
|
|
else \
|
|
(void) 0
|
|
|
|
#define dpprintf(dptr, flag, ...) \
|
|
if (DPPRINTING (dptr, flag)) \
|
|
hp_debug ((dptr), (flag), __VA_ARGS__); \
|
|
else \
|
|
(void) 0
|
|
|
|
#define cprintf(...) \
|
|
do { \
|
|
printf (__VA_ARGS__); \
|
|
if (sim_log) \
|
|
fprintf (sim_log, __VA_ARGS__); \
|
|
} \
|
|
while (0)
|
|
|
|
#define cputs(str) \
|
|
do { \
|
|
fputs (str, stdout); \
|
|
if (sim_log) \
|
|
fputs (str, sim_log); \
|
|
} \
|
|
while (0)
|
|
|
|
#define cputc(ch) \
|
|
do { \
|
|
putc (ch); \
|
|
if (sim_log) \
|
|
fputc (ch, sim_log); \
|
|
} \
|
|
while (0)
|
|
|
|
|
|
/* Simulation stop codes.
|
|
|
|
These VM-specific status codes stop the simulator. The "sim_stop_messages"
|
|
array in "hp3000_sys.c" contains the message strings that correspond
|
|
one-for-one with the stop codes.
|
|
|
|
|
|
Implementation notes:
|
|
|
|
1. Codes before STOP_RERUN cause the instruction to be rerun, so P is backed
|
|
up twice. For codes after, P points to the next instruction to be
|
|
executed (which is the current instruction for an infinite loop stop).
|
|
*/
|
|
|
|
#define STOP_SYSHALT 1 /* system halt */
|
|
#define STOP_UNIMPL 2 /* unimplemented instruction stop */
|
|
#define STOP_UNDEF 3 /* undefined instruction stop */
|
|
#define STOP_PAUS 4 /* PAUS instruction stop */
|
|
|
|
#define STOP_RERUN 4 /* stops above here cause the instruction to be re-run */
|
|
|
|
#define STOP_HALT 5 /* programmed halt */
|
|
#define STOP_BRKPNT 6 /* breakpoint */
|
|
#define STOP_INFLOOP 7 /* infinite loop stop */
|
|
#define STOP_CLOAD 8 /* cold load complete */
|
|
#define STOP_CDUMP 9 /* cold dump complete */
|
|
#define STOP_ARSINH 10 /* auto-restart inhibited */
|
|
#define STOP_POWER 11 /* power is off */
|
|
|
|
|
|
/* Modifier validation identifiers */
|
|
|
|
#define MTAB_XDV (MTAB_XTD | MTAB_VDV)
|
|
#define MTAB_XUN (MTAB_XTD | MTAB_VUN)
|
|
|
|
#define VAL_DEVNO 0 /* validate DEVNO=0-127 */
|
|
#define VAL_INTMASK 1 /* validate INTMASK=0-15/E/D */
|
|
#define VAL_INTPRI 2 /* validate INTPRI=0-31 */
|
|
#define VAL_SRNO 3 /* validate SRNO=0-15 */
|
|
|
|
|
|
/* I/O event timing.
|
|
|
|
I/O events are scheduled for future service by specifying the desired delay
|
|
in units of event ticks. Typically, one event tick represents the execution
|
|
of one CPU instruction, and this is the way event ticks are defined in the
|
|
current simulator implementation. However, while the average execution time
|
|
of a typical instruction mix on a Series II is given as 2.57 microseconds,
|
|
actual instruction times vary greatly, due to the presence of block move and
|
|
loop instructions. Variations of an order of magnitude are common, and two
|
|
orders or more are possible for longer blocks.
|
|
|
|
To accommodate possible future variable instruction timing, I/O service
|
|
activation times must not assume a constant 2.57 microseconds per event tick.
|
|
Delays should be defined in terms of the "uS" (microseconds), "mS"
|
|
(milliseconds), and "S" (seconds) macros below.
|
|
*/
|
|
|
|
#define USEC_PER_EVENT 2.57 /* average CPU instruction time in microseconds */
|
|
|
|
#define uS(t) (uint32) ((t) > USEC_PER_EVENT ? (t) / USEC_PER_EVENT + 0.5 : 1)
|
|
#define mS(t) (uint32) (((t) * 1000.0) / USEC_PER_EVENT + 0.5)
|
|
#define S(t) (uint32) (((t) * 1000000.0) / USEC_PER_EVENT + 0.5)
|
|
|
|
|
|
/* Architectural constants.
|
|
|
|
These macros specify the width, sign location, value mask, and minimum and
|
|
maximum signed and unsigned values for the data sizes supported by the
|
|
simulator. In addition, masks for 16-bit and 32-bit overflow are defined (an
|
|
overflow is indicated if the masked bits are not all ones or all zeros).
|
|
|
|
The HP_WORD type is used to declare variables that represent 16-bit registers
|
|
or buses in hardware.
|
|
|
|
|
|
Implementation notes:
|
|
|
|
1. The HP_WORD type is a 32-bit unsigned type, instead of the more logical
|
|
16-bit unsigned type. There are two reasons for this. First, SCP
|
|
requires that scalars referenced by REG (register) entries be 32 bits in
|
|
size. Second, IA-32 processors execute instructions with 32-bit operands
|
|
much faster than those with 16-bit operands.
|
|
|
|
Using 16-bit operands omits the masking required for 32-bit values. For
|
|
example, the code generated for the following operations is as follows:
|
|
|
|
uint16 a, b, c;
|
|
a = b + c & 0xFFFF;
|
|
|
|
movzwl _b, %eax
|
|
addw _c, %ax
|
|
movw %ax, _a
|
|
|
|
uint32 x, y, z;
|
|
x = y + z & 0xFFFF;
|
|
|
|
movl _z, %eax
|
|
addl _y, %eax
|
|
andl $65535, %eax
|
|
movl %eax, _x
|
|
|
|
However, the first case uses operand override prefixes, which require
|
|
substantially more time to decode (6 clock cycles vs. 1 clock cycle).
|
|
This time outweighs the additional 32-bit AND instruction, which executes
|
|
in 1 clock cycle.
|
|
|
|
On an Intel Core 2 Duo processor, defining HP_WORD as uint16 causes the
|
|
HP 3000 memory diagnostic to run about 10% slower.
|
|
*/
|
|
|
|
typedef uint32 HP_WORD; /* HP 16-bit data word representation */
|
|
|
|
#define R_MASK 0177777u /* 16-bit register mask */
|
|
|
|
#define D4_WIDTH 4 /* 4-bit data bit width */
|
|
#define D4_MASK 0017u /* 4-bit data mask */
|
|
|
|
#define D8_WIDTH 8 /* 8-bit data bit width */
|
|
#define D8_MASK 0377u /* 8-bit data mask */
|
|
#define D8_UMAX 0377u /* 8-bit unsigned maximum value */
|
|
#define D8_SMAX 0177u /* 8-bit signed maximum value */
|
|
#define D8_SMIN 0200u /* 8-bit signed minimum value */
|
|
#define D8_SIGN 0200u /* 8-bit sign */
|
|
|
|
#define D16_WIDTH 16 /* 16-bit data bit width */
|
|
#define D16_MASK 0177777u /* 16-bit data mask */
|
|
#define D16_UMAX 0177777u /* 16-bit unsigned maximum value */
|
|
#define D16_SMAX 0077777u /* 16-bit signed maximum value */
|
|
#define D16_SMIN 0100000u /* 16-bit signed minimum value */
|
|
#define D16_SIGN 0100000u /* 16-bit sign */
|
|
|
|
#define D32_WIDTH 32 /* 32-bit data bit width */
|
|
#define D32_MASK 037777777777u /* 32-bit data mask */
|
|
#define D32_UMAX 037777777777u /* 32-bit unsigned maximum value */
|
|
#define D32_SMAX 017777777777u /* 32-bit signed maximum value */
|
|
#define D32_SMIN 020000000000u /* 32-bit signed minimum value */
|
|
#define D32_SIGN 020000000000u /* 32-bit sign */
|
|
|
|
#define D48_WIDTH 48 /* 48-bit data bit width */
|
|
#define D48_MASK 07777777777777777uL /* 48-bit data mask */
|
|
#define D48_UMAX 07777777777777777uL /* 48-bit unsigned maximum value */
|
|
#define D48_SMAX 03777777777777777uL /* 48-bit signed maximum value */
|
|
#define D48_SMIN 04000000000000000uL /* 48-bit signed minimum value */
|
|
#define D48_SIGN 04000000000000000uL /* 48-bit sign */
|
|
|
|
#define D64_WIDTH 64 /* 64-bit data bit width */
|
|
#define D64_MASK 01777777777777777777777uL /* 64-bit data mask */
|
|
#define D64_UMAX 01777777777777777777777uL /* 64-bit unsigned maximum value */
|
|
#define D64_SMAX 00777777777777777777777uL /* 64-bit signed maximum value */
|
|
#define D64_SMIN 01000000000000000000000uL /* 64-bit signed minimum value */
|
|
#define D64_SIGN 01000000000000000000000uL /* 64-bit sign */
|
|
|
|
#define S16_OVFL_MASK ((uint32) D16_UMAX << D16_WIDTH | \
|
|
D16_SIGN) /* 16-bit signed overflow mask */
|
|
|
|
#define S32_OVFL_MASK ((t_uint64) D32_UMAX << D32_WIDTH | \
|
|
D32_SIGN) /* 32-bit signed overflow mask */
|
|
|
|
|
|
/* Memory constants */
|
|
|
|
#define LA_WIDTH 16 /* logical address bit width */
|
|
#define LA_MASK ((1u << LA_WIDTH) - 1) /* logical address mask (2 ** 16 - 1) */
|
|
#define LA_MAX ((1u << LA_WIDTH) - 1) /* logical address maximum (2 ** 16 - 1) */
|
|
|
|
#define BA_WIDTH 4 /* bank address bit width */
|
|
#define BA_MASK ((1u << BA_WIDTH) - 1) /* bank address mask (2 ** 4 - 1) */
|
|
#define BA_MAX ((1u << BA_WIDTH) - 1) /* bank address maximum (2 ** 4 - 1) */
|
|
|
|
#define PA_WIDTH (LA_WIDTH + BA_WIDTH) /* physical address bit width */
|
|
#define PA_MASK ((1u << PA_WIDTH) - 1) /* physical address mask (2 ** 20 - 1) */
|
|
#define PA_MAX ((1u << PA_WIDTH) - 1) /* physical address maximum (2 ** 20 - 1) */
|
|
|
|
#define DV_WIDTH 16 /* data value bit width */
|
|
#define DV_MASK ((1u << DV_WIDTH) - 1) /* data value mask (2 ** 16 - 1) */
|
|
#define DV_SIGN ( 1u << (DV_WIDTH - 1)) /* data value sign (2 ** 15) */
|
|
#define DV_UMAX ((1u << DV_WIDTH) - 1) /* data value unsigned maximum (2 ** 16 - 1) */
|
|
#define DV_SMAX ((1u << (DV_WIDTH - 1)) - 1) /* data value signed maximum (2 ** 15 - 1) */
|
|
|
|
|
|
/* Memory address macros.
|
|
|
|
These macros convert between logical and physical addresses. The functions
|
|
provided are:
|
|
|
|
- TO_PA -- merge a bank number and offset into a physical address
|
|
- TO_BANK -- extract the bank number part of a physical address
|
|
- TO_OFFSET -- extract the offset part of a physical address
|
|
|
|
|
|
Implementation notes:
|
|
|
|
1. The TO_PA offset parameter is not masked to 16 bits, as this value is
|
|
almost always derived from a value that is inherently 16 bits in size.
|
|
In the few cases where it is not, explicit masking is required.
|
|
*/
|
|
|
|
#define TO_PA(b,o) (((uint32) (b) & BA_MASK) << LA_WIDTH | (uint32) (o))
|
|
#define TO_BANK(p) ((p) >> LA_WIDTH & BA_MASK)
|
|
#define TO_OFFSET(p) ((p) & LA_MASK)
|
|
|
|
|
|
/* Memory access classifications.
|
|
|
|
The access classification determines which bank register is used with the
|
|
supplied offset to access memory, whether or not the access is bounds
|
|
checked, and whether or not the access is mapped to the TOS registers if the
|
|
address is between SM and SM + SR.
|
|
|
|
Bounds checking is optionally performed on program (including instruction
|
|
fetch), data, and stack accesses when not in privileged mode. Absolute
|
|
addresses are always accessed in privileged mode, so bounds checking is never
|
|
performed.
|
|
|
|
If the memory address lies between SM and SM + SR within the stack bank, then
|
|
access to the TOS registers may be substituted for access to memory.
|
|
Register mapping is always performed on stack accesses, optionally performed
|
|
on absolute and data accesses, and is never performed on program (and fetch)
|
|
accesses.
|
|
|
|
To summarize bounds checking and TOS register mapping:
|
|
|
|
Bounds TOS
|
|
Access Check Mapping
|
|
-------- ------ -------
|
|
absolute N O
|
|
fetch O N
|
|
program O N
|
|
data O O
|
|
stack O Y
|
|
dma N N
|
|
|
|
|
|
Implementation notes:
|
|
|
|
1. The enumeration values must be ordered such that the "checked" classes
|
|
are odd and differ from their corresponding "unchecked" classes only in
|
|
the LSBs.
|
|
|
|
2. There is no hardware DMA bank register. The "dma" class exists only to
|
|
differentiate DMA memory accesses from CPU memory accesses when tracing.
|
|
*/
|
|
|
|
typedef enum {
|
|
absolute, /* absolute bank */
|
|
absolute_mapped, /* absolute bank, TOS registers mapped */
|
|
fetch, /* program bank, instruction fetch */
|
|
fetch_checked, /* program bank, instruction fetch, bounds checked */
|
|
program, /* program bank, data access */
|
|
program_checked, /* program bank, data access, bounds checked */
|
|
data, /* data bank, data access */
|
|
data_checked, /* data bank, data access, bounds checked */
|
|
data_mapped, /* data bank, data or TOS register access */
|
|
data_mapped_checked, /* data bank, data or TOS register access, bounds checked */
|
|
stack, /* stack bank, data or TOS register access */
|
|
stack_checked, /* stack bank, data or TOS register access, bounds checked */
|
|
dma /* DMA bank */
|
|
} ACCESS_CLASS;
|
|
|
|
#define UNCHECKED(c) ((c) & ~1u) /* reclassify a request as unchecked */
|
|
#define INVERT_CHECK(c) ((c) ^ 1u) /* convert checked to unchecked and vice versa */
|
|
|
|
|
|
/* Portable conversions.
|
|
|
|
SIMH is written with the assumption that the defined-size types (e.g.,
|
|
uint16) are at least the required number of bits but may be larger.
|
|
Conversions that otherwise would make inherent size assumptions must instead
|
|
be coded explicitly. For example, doing:
|
|
|
|
negative_value_32 = (int32) negative_value_16;
|
|
|
|
...will not guarantee that bits 0-15 of "negative_value_32" are ones, whereas
|
|
the supplied sign-extension macro will.
|
|
|
|
The conversions available are:
|
|
|
|
- SEXT8 -- int8 sign-extended to int32
|
|
- SEXT16 -- int16 sign-extended to int32
|
|
- NEG16 -- int8 negated
|
|
- NEG16 -- int16 negated
|
|
- NEG32 -- int32 negated
|
|
- INT16 -- uint16 to int16
|
|
- INT32 -- uint32 to int32
|
|
|
|
|
|
Implementation notes:
|
|
|
|
1. The routines assume that 16-bit values are masked to exactly 16 bits
|
|
before invoking.
|
|
*/
|
|
|
|
#define SEXT8(x) (int32) ((x) & D8_SIGN ? (x) | ~D8_MASK : (x))
|
|
#define SEXT16(x) (int32) ((x) & D16_SIGN ? (x) | ~D16_MASK : (x))
|
|
|
|
#define NEG8(x) ((~(x) + 1) & D8_MASK)
|
|
#define NEG16(x) ((~(x) + 1) & D16_MASK)
|
|
#define NEG32(x) ((~(x) + 1) & D32_MASK)
|
|
|
|
#define INT16(u) ((u) > D16_SMAX ? (-(int16) (D16_UMAX - (u)) - 1) : (int16) (u))
|
|
#define INT32(u) ((u) > D32_SMAX ? (-(int32) (D32_UMAX - (u)) - 1) : (int32) (u))
|
|
|
|
|
|
/* Half-byte accessors */
|
|
|
|
#define UPPER_HALF(b) ((b) >> D4_WIDTH & D4_MASK)
|
|
#define LOWER_HALF(b) ((b) & D4_MASK)
|
|
|
|
|
|
/* Byte accessors.
|
|
|
|
These macros extract the upper and lower bytes from a word and form a word
|
|
from upper and lower bytes. Replacement of a byte within a word is also
|
|
provided, as is an enumeration type that defines byte selection.
|
|
|
|
The accessors are:
|
|
|
|
- UPPER_BYTE -- return the byte from the upper position of a word value
|
|
- LOWER_BYTE -- return the byte from the lower position of a word value
|
|
- TO_WORD -- return a word with the specified upper and lower bytes
|
|
|
|
- REPLACE_UPPER -- replace the upper byte of the word value
|
|
- REPLACE_LOWER -- replace the lower byte of the word value
|
|
|
|
*/
|
|
|
|
typedef enum {
|
|
upper, /* upper byte selected */
|
|
lower /* lower byte selected */
|
|
} BYTE_SELECTOR;
|
|
|
|
#define UPPER_BYTE(w) (uint8) ((w) >> D8_WIDTH & D8_MASK)
|
|
#define LOWER_BYTE(w) (uint8) ((w) & D8_MASK)
|
|
#define TO_WORD(u,l) (HP_WORD) (((u) & D8_MASK) << D8_WIDTH | (l) & D8_MASK)
|
|
|
|
#define REPLACE_UPPER(w,b) ((w) & D8_MASK | ((b) & D8_MASK) << D8_WIDTH)
|
|
#define REPLACE_LOWER(w,b) ((w) & D8_MASK << D8_WIDTH | (b) & D8_MASK)
|
|
|
|
|
|
/* Double-word accessors */
|
|
|
|
#define UPPER_WORD(d) (HP_WORD) ((d) >> D16_WIDTH & D16_MASK)
|
|
#define LOWER_WORD(d) (HP_WORD) ((d) & D16_MASK)
|
|
|
|
#define TO_DWORD(u,l) ((uint32) (u) << D16_WIDTH | (l))
|
|
|
|
|
|
/* Flip-flops */
|
|
|
|
typedef enum {
|
|
CLEAR = 0, /* the flip-flop is clear */
|
|
SET = 1 /* the flip-flop is set */
|
|
} FLIP_FLOP;
|
|
|
|
#define TOGGLE(ff) ff = (FLIP_FLOP) (ff ^ 1) /* toggle a flip-flop variable */
|
|
|
|
#define D_FF(b) (FLIP_FLOP) ((b) != 0) /* use a Boolean expression for a D flip-flop */
|
|
|
|
|
|
/* Bitset formatting.
|
|
|
|
See the comments at the "fmt_bitset" function (hp3000_sys.c) for details of
|
|
the specification of bitset names and format structures.
|
|
*/
|
|
|
|
typedef enum { /* direction of interpretation */
|
|
msb_first, /* left-to-right */
|
|
lsb_first /* right-to-left */
|
|
} BITSET_DIRECTION;
|
|
|
|
typedef enum { /* alternate names */
|
|
no_alt, /* no alternates are present in the name array */
|
|
has_alt /* the name array contains alternates */
|
|
} BITSET_ALTERNATE;
|
|
|
|
typedef enum { /* trailing separator */
|
|
no_bar, /* omit a trailing separator */
|
|
append_bar /* append a trailing separator */
|
|
} BITSET_BAR;
|
|
|
|
typedef const char *const BITSET_NAME; /* a bit name string pointer */
|
|
|
|
typedef struct { /* bit set format descriptor */
|
|
uint32 name_count; /* count of bit names */
|
|
BITSET_NAME *names; /* pointer to an array of bit names */
|
|
uint32 offset; /* offset from LSB to first bit */
|
|
BITSET_DIRECTION direction; /* direction of interpretation */
|
|
BITSET_ALTERNATE alternate; /* alternate interpretations presence */
|
|
BITSET_BAR bar; /* trailing separator choice */
|
|
} BITSET_FORMAT;
|
|
|
|
/* Bitset format specifier initialization */
|
|
|
|
#define FMT_INIT(names,offset,dir,alt,bar) \
|
|
sizeof (names) / sizeof (names) [0], \
|
|
(names), (offset), (dir), (alt), (bar)
|
|
|
|
|
|
/* System interface global data structures */
|
|
|
|
extern const HP_WORD odd_parity [256]; /* a table of parity bits for odd parity */
|
|
|
|
extern const BITSET_FORMAT inbound_format; /* the inbound signal format structure */
|
|
extern const BITSET_FORMAT outbound_format; /* the outbound signal format structure */
|
|
|
|
|
|
/* System interface global SCP support routines declared in scp.h
|
|
|
|
extern t_stat sim_load (FILE *fptr, CONST char *cptr, CONST char *fnam, int flag);
|
|
extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, UNIT *uptr, int32 sw);
|
|
extern t_stat parse_sym (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw);
|
|
*/
|
|
|
|
/* System interface global SCP support routines */
|
|
|
|
extern t_stat hp_set_dib (UNIT *uptr, int32 code, CONST char *cptr, void *desc);
|
|
extern t_stat hp_show_dib (FILE *st, UNIT *uptr, int32 code, CONST void *desc);
|
|
|
|
|
|
/* System interface global utility routines */
|
|
|
|
extern t_stat fprint_cpu (FILE *ofile, t_value *val, uint32 radix, int32 switches);
|
|
extern uint32 fprint_edit (FILE *ofile, t_value *val, uint32 radix, uint32 byte_address);
|
|
|
|
extern const char *fmt_status (uint32 status);
|
|
extern const char *fmt_char (uint32 charval);
|
|
extern const char *fmt_bitset (uint32 bitset, const BITSET_FORMAT bitfmt);
|
|
|
|
extern void hp_debug (DEVICE *dptr, uint32 flag, ...);
|
|
extern t_bool hp_device_conflict (void);
|
|
|
|
extern void hp_one_time_init (void); /* One time initialization activities now called in cpu_reset() */
|