/* hp3000_defs.h: HP 3000 simulator general declarations

   Copyright (c) 2016-2023, 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.

   30-Jun-23    JDB     Added HP-IB I/O instruction accessors
   24-Jun-23    JDB     Added "-Wparentheses" to list of idiot clang warnings
   23-May-23    JDB     Added "bank_0" memory classification definition
   14-Mar-23    JDB     Added SIM_DEVICE_SIZE definition for cloning support
   13-Nov-22    JDB     Added "hp_word_examine" and "hp_word_deposit" declarations
   06-Oct-22    JDB     Added bitfield constructors and scanners
                        Suppressed MSVC warning 4204
   08-Sep-22    JDB     Added "fmt_value", TRACE_IMBUS declarations
   29-Aug-22    JDB     Added VM_EMAX declaration
   26-Oct-21    JDB     Added global trace flags
   08-Apr-21    JDB     Expanded bank register widths from 4 to 6 bits
   19-Mar-21    JDB     Added "iso646.h" inclusion to use "not" for "!"
   07-Feb-21    JDB     Changed register macros to use new generic XRDATA macro
   30-Sep-20    JDB     Added HIGH_UPPER_WORD, LOW_UPPER_WORD for EIS
   23-Sep-20    JDB     Added HP_BYTE type for EIS
   17-Aug-20    JDB     Corrected "cputc" definition
   09-Dec-19    JDB     Replaced debugging macros with tracing macros
   28-Mar-19    JDB     Added extensions
   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++
   -----------------------------------------------------

   This simulator is written in ISO-standard C, specifically to the ISO/IEC
   9899:1999 standard.  While it might be desirable to compile the simulator
   with a C++ compiler to obtain more careful type checking, the simulator would
   have to be 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 {...};".  Some 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 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 <iso646.h>

#include "sim_rev.h"
#include "sim_defs.h"
#include "sim_extension.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"
            [this is legal per C99]

    - 4204: "nonstandard extension used : non-constant aggregate initializer"
            [this is 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 "-Wparentheses"
  #pragma clang diagnostic ignored "-Wdangling-else"

#elif defined (_MSC_VER)

  #pragma warning (disable: 4114 4204 4554 4996)

#endif


/* Device table size.

   This value is the number of elements in the device table array.  The table
   contains pointers to all of the user-configurable devices and consists of
   static entries, such as the CPU and system clock, and extra space for dynamic
   creation of additional specified devices, such as the GIC.  The element count
   reflects the number of static entries plus the number of allowed dynamic
   entries (in the case of the GIC, up to 13 copies can be added to the original
   entry, as GIC channel numbers are restricted to the range 2-15 and must be
   unique).
*/

#define SIM_DEVICE_SIZE     50                  /* number of elements in sim_devices */


/* Maximum instruction length.

   This value is the length in words of the longest machine instruction.  It is
   used to set "sim_emax", which, in turn, is used to allocate the "sim_eval"
   array.  This array holds the words of a machine instruction to be formatted
   and printed or to be parsed and stored.

   Machine instructions in the 3000 family are either one or two words in
   length.  Channel program instructions are either 2, 3, 5, or a variable
   number up to 258 words for the Device Specified Jump instruction.  Rather
   than read the maximum for every instruction decode, we handle CPP
   instructions separately.
*/

#define VM_EMAX    2                            /* the (typical) maximum instruction length */


/* Bitfield constructors.

   Constructors are provided to set single bits and bit fields in a word, and to
   extract values from bit fields.

   For fields using the C bit numbering (increasing from right to left):

     BIT(n)         -- a value corresponding to bit number "n".
     BITS(h,l)      -- a field corresponding to bits "h" through "l" inclusive.

     TO_BITS(h,l,v) -- a value "v" aligned to a field in bits "h" through "l".
     BITS_TO(h,l,w) -- a field extracted from bits "h" through "l" of word "w".

   For fields using the C bit numbering (increasing from right to left) for use
   in the flags fields of DEVICEs:

     DF_BIT(n)         -- a value corresponding to bit number "n".
     DF_BITS(l,h)      -- a field corresponding to bits "l" through "h" inclusive.

     TO_DF_BITS(l,h,v) -- a value "v" aligned to a field in bits "l" through "h".
     DF_BITS_TO(l,h,w) -- a field extracted from bits "l" through "h" of word "w".

   For fields using the C bit numbering (increasing from right to left) for use
   in the flags fields of UNITs:

     UF_BIT(n)         -- a value corresponding to bit number "n".
     UF_BITS(l,h)      -- a field corresponding to bits "l" through "h" inclusive.

     TO_UF_BITS(l,h,v) -- a value "v" aligned to a field in bits "l" through "h".
     UF_BITS_TO(l,h,w) -- a field extracted from bits "l" through "h" of word "w".

   For fields using the C bit numbering (increasing from right to left) for use
   in the flags fields of UNITs used with the Magnetic Tape library:

     MT_BIT(n)         -- a value corresponding to bit number "n".
     MT_BITS(l,h)      -- a field corresponding to bits "l" through "h" inclusive.

     TO_MT_BITS(l,h,v) -- a value "v" aligned to a field in bits "l" through "h".
     MT_BITS_TO(l,h,w) -- a field extracted from bits "l" through "h" of word "w".


   For fields using the HP 3000 bit numbering (increasing from left to right
   for the lower 16 bits):

     HP_BIT(n)         -- a value corresponding to bit number "n".
     HP_BITS(l,h)      -- a field corresponding to bits "l" through "h" inclusive.

     TO_HP_BITS(l,h,v) -- a value "v" aligned to a field in bits "l" through "h".
     HP_BITS_TO(l,h,w) -- a field extracted from bits "l" through "h" of word "w".

   For bits using the HP-IB bit numbering (increasing from left to right for the
   lower 8 bits):

     HPIB_BIT(n) -- a value corresponding to bit number "n".


 Implementation notes:

    1. The HP_BIT constructor could have been "D16_SIGN >> (n)", but it is
       written as is to be symmetric with the other constructors.  Implementing
       the HP_BITS constructors with sign-bit shifts is more complicated than
       using LSB shifts, due to required additional result masking to 16 bits.

    2. The HPIB_BIT macro generates the parallel poll response bit.
*/

#define BIT(n)              (1u << (n))
#define BITS(h,l)           ((1u << (h) - (l) + 1) - 1 << (l))

#define TO_BITS(h,l,v)      ((v) << (l) & BITS (h, l))
#define BITS_TO(h,l,w)      (((w) & BITS (h, l)) >> (l))


#define DF_BIT(n)           (BIT (n) << DEV_V_UF)
#define DF_BITS(h,l)        (BITS (h, l) << DEV_V_UF)

#define TO_DF_BITS(h,l,v)   (TO_BITS (h, l, v) << DEV_V_UF)
#define DF_BITS_TO(h,l,w)   (BITS_TO (h, l, ((w) >> DEV_V_UF)))


#define UF_BIT(n)           (BIT (n) << UNIT_V_UF)
#define UF_BITS(h,l)        (BITS (h, l) << UNIT_V_UF)

#define TO_UF_BITS(h,l,v)   (TO_BITS (h, l, v) << UNIT_V_UF)
#define UF_BITS_TO(h,l,w)   (BITS_TO (h, l, ((w) >> UNIT_V_UF)))


#define MT_BIT(n)           (BIT (n) << MTUF_V_UF)
#define MT_BITS(h,l)        (BITS (h, l) << MTUF_V_UF)

#define TO_MT_BITS(h,l,v)   (TO_BITS (h, l, v) << MTUF_V_UF)
#define MT_BITS_TO(h,l,w)   (BITS_TO (h, l, ((w) >> MTUF_V_UF)))


#define HP_BIT(n)           (1u << 15 - (n))
#define HP_BITS(l,h)        ((1u << (h) - (l) + 1) - 1 << 15 - (h))

#define TO_HP_BITS(l,h,v)   ((v) << 15 - (h) & HP_BITS (l, h))
#define HP_BITS_TO(l,h,w)   (((w) & HP_BITS (l, h)) >> 15 - (h))


#define HPIB_BIT(n)         (1u << 7 - (n))


/* Bit scanners.

   Scanning for the most- or least-significant 1-bit can use intrinsic machine
   instructions when provided by the compiler (e.g., the BSF and BSR
   instructions are used with the x86 family).  gcc, clang, and MSVC are known
   to provide intrinsics.  For other compilers, a call to a C function in our
   system module is used.

   The following operations are provided:

     BIT_NUMBER(n)      -- return the LSB number (ascending from 0-31)
     HP_BIT_NUMBER(n)   -- return the LSB number (descending from 15-0)
     HPIB_BIT_NUMBER(n) -- return the MSB number (ascending from 0-7)

   For example, the value 0x0020 would return 5 for BIT_NUMBER, 10 for
   HP_BIT_NUMBER, and 2 for HPIB_BIT_NUMBER.


   Implementation notes:

    1. The gcc/clang intrinsics return indeterminate results if the "bits" value
       is zero.

    2. The MSVC intrinsics return the bit number in a variable and success or
       failure as the function result.  Consequently, the scanner macro is
       defined as a "comma-operator expression" so that the bit number is
       returned.

    3. We take advantage of the compiler-specific sections to define the
       "inline" keyword, which MSVC does not support directly.
*/

#define HP_BIT_NUMBER(bits)     (15 - BIT_NUMBER (bits))

#if defined (__GNUC__)                          /* gcc and clang */

  #define BIT_NUMBER(bits)      ((uint32) __builtin_ctz (bits))
  #define HPIB_BIT_NUMBER(bits) ((uint32) __builtin_clz (bits) - (sizeof (unsigned int) - 1) * 8)

  #define INLINE    inline

#elif defined (_MSC_VER)                        /* MSVC++ */

  extern unsigned long int hp_bit_number;       /* target for the _BitScanX intrinsics */

  #define BIT_NUMBER(bits)      (_BitScanForward (&hp_bit_number, bits), (uint32) hp_bit_number)
  #define HPIB_BIT_NUMBER(bits) (_BitScanReverse (&hp_bit_number, bits), (uint32) 7 - hp_bit_number)

  #define INLINE    __inline

#else                                           /* others */

  extern unsigned int hp_bit_number (unsigned int bits, unsigned int hpib);

  #define BIT_NUMBER(bits)      ((uint32) hp_bit_number (bits, 0))
  #define HPIB_BIT_NUMBER(bits) ((uint32) hp_bit_number (bits, 1))

  #define INLINE

#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
     YRDATA -- a binary register
     SVDATA -- a register only used for SAVE/RESTORE

   The FBDATA macro defines a flag that is replicated in the same bit position
   in each element of an array.  The YRDATA macro extends the functionality of
   the ORDATA, DRDATA, and HRDATA macros to registers with binary (base 2)
   representation.  The SVDATA macro is used solely to SAVE data so that it may
   be RESTOREd later.
*/

/*              Macro                    name   loc    radix  width  offset  depth       size          stride     */
/*      ----------------------           ----  ------  -----  -----  ------  -----  --------------  ------------- */
#define FBDATA(nm,loc,ofs,dep)  XRDATA   (nm,  (loc),    2,     1,   (ofs),  (dep), sizeof  *(loc), sizeof  *(loc))
#define YRDATA(nm,loc,wid)      GRDATA   (nm,  (loc),    2,   (wid),   0)
#define SVDATA(nm,loc)          SAVEDATA (nm,  (loc))


/* Global tracing flags.

   Global tracing flags are allocated in ascending order, as they may be used
   by modules that allocate their own private flags in descending order.  No
   check is made for overlapping values.
*/

#define TRACE_CMD           (1u <<  0)          /* trace interface or controller commands */
#define TRACE_INCO          (1u <<  1)          /* trace interface or controller command initiations and completions */
#define TRACE_CSRW          (1u <<  2)          /* trace interface control, status, read, and write actions */
#define TRACE_STATE         (1u <<  3)          /* trace state changes */
#define TRACE_SERV          (1u <<  4)          /* trace unit service scheduling calls and entries */
#define TRACE_PSERV         (1u <<  5)          /* trace periodic unit service scheduling calls and entries */
#define TRACE_XFER          (1u <<  6)          /* trace data receptions and transmissions */
#define TRACE_FIFO          (1u <<  7)          /* trace data buffer reads and writes */
#define TRACE_IOBUS         (1u <<  8)          /* trace I/O bus signals and data words received and returned */
#define TRACE_IMBUS         (1u <<  9)          /* trace IMB signals and data words received and returned */


/* Tracing and console output.

   "tprintf" is used to write tracing messages.  It does an "fprintf" to the
   debug output stream if the stream is open and the trace "flag" is currently
   enabled in device "dev".  Otherwise, it's a NOP.  "..." is the format string
   and associated values.

   "tpprintf" is identical to "tprintf", except that a device pointer is passed
   instead of a device structure.

   "TRACING" and "TRACINGP" implement the test conditions for device and device
   pointer tracing, respectively.  They are used explicitly only when several
   trace 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 TRACING(d,f)        (sim_deb != NULL && ((d).dctrl & (f)))

#define TRACINGP(d,f)       (sim_deb != NULL && ((d)->dctrl & (f)))

#define tprintf(dev, flag, ...) \
          if (TRACING (dev, flag)) \
              hp_trace (&(dev), (flag), __VA_ARGS__); \
          else \
              (void) 0

#define tpprintf(dptr, flag, ...) \
          if (TRACINGP (dptr, flag)) \
              hp_trace ((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 { \
              putchar (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 data 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.  The reason for this is that IA-32 processors (in
       32-bit mode) execute instructions with 8-bit or 32-bit operands much
       faster than with 16-bit operands.

       The "Operand-Size and Address-Size Attributes" section of the "Intel 64
       and IA-32 Architectures Software Developer's Manual" states:

          When the processor is executing in protected mode, every code segment
          has a default operand-size attribute and address-size attribute.

          The operand-size attribute selects the size of operands.  When the
          16-bit operand-size attribute is in force, operands can generally be
          either 8 bits or 16 bits, and when the 32-bit operand-size attribute
          is in force, operands can generally be 8 bits or 32 bits.

          The default operand-size attribute...can be overridden for a
          particular instruction by adding an operand-size...prefix to an
          instruction.

       The "Instruction PreDecode" section of the "Intel 64 and IA-32
       Architectures Optimization Reference Manual" states:

          The following instruction prefixes cause problems during length
          decoding.  These prefixes can dynamically change the length of
          instructions and are known as length changing prefixes (LCPs):

            * Operand Size Override (66H) preceding an instruction with a word
              immediate data

            * Address Size Override (67H) preceding an instruction with a mod
              R/M in real, 16-bit protected or 32-bit protected modes

          When the predecoder encounters an LCP in the fetch line, it must use a
          slower length decoding algorithm.  With the slower length decoding
          algorithm, the predecoder decodes the fetch in 6 cycles, instead of
          the usual 1 cycle.

       As an example, consider the code generated by gcc for the following
       operations:

         uint16 a, b;
         b = (a & 0xFFF) == 1;

            movzwl  _b, %eax
            andw    $4095, %ax
            cmpw    $1, %ax
            sete    %al
            movzbl  %al, %eax
            movw    %ax, _a

         uint32 x, y;
         z = (y & 0xFFF) == 1;

            movl    _y, %eax
            andl    $4095, %eax
            cmpl    $1, %eax
            sete    %al
            movzbl  %al, %eax
            movl    %eax, _x

       Even though the code sequences are the same length, the first one takes
       nearly three times longer (16 cycles vs. 6 cycles) because of the length
       overrides on the "andw" and "cmpw" instructions.

       Using 16-bit operands does omit the masking that is required for 32-bit
       values:

         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 savings is only one cycle, which is quickly outweighed as
       soon as a 16-bit value is added, compared, or masked by a constant.

       8-bit operand instructions also execute in one clock cycle, as does the
       8-bit-to-32-bit "movzbl" conversion instruction.  So on IA-32 platforms,
       int16 and uint16 variables are to be avoided.

       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 */
typedef uint8               HP_BYTE;                    /* HP 8-bit data word representation */

#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 */

#define R_MASK              D16_MASK                    /* 16-bit register mask */


/* Architectural memory constants.

   These macros specify the width, data mask, and maximum unsigned values for
   the implementation of logical and physical addresses.

   HP 3000 Series II and III CPUs address a maximum of 64K words with 16-bit
   addresses.  This is the logical address space, which is used by the program
   counter (P), stack pointer (S), and the program, data, and stack segment
   bounds registers.  Code and data segment table layouts further limit the
   segment sizes to 16K and 32K, respectively.

   Each segment bounds register set is augmented with a bank register holding
   two bits (Series II) or four bits (Series III).  The bank register indicates
   the 64K bank associated with the segment.  The combination of bank number and
   offset within the bank forms the physical address used to access the word
   within the 1024K physical address space.

   The logical address form is:

      15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     |                          bank offset                          |
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

   The physical address form is:

      19  18  17  16  15  14  13  12  11  10   9   8   7   6   5   4   3   2   1   0
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     |     bank      |                          bank offset                          |
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+


   Implementation notes:

    1. MPE V/R accommodates 6-bit bank numbers, even though no machine with a
       main memory larger than the Series III was produced.  As the bank address
       mask must be set dynamically, depending on the selected CPU model, we
       provide 6-bit banks and 4096K-word memories for those interested in
       exploring this unsupported feature of MPE V/R.
*/

#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            6                               /* 6-bit bank address bit width */
#define BA_MASK             mem_bank_mask                   /* bank address mask (varies with CPU model) */
#define BA_MAX              mem_bank_mask                   /* bank address maximum (varies with CPU model) */

#define PA_WIDTH            (LA_WIDTH + BA_WIDTH)           /* physical address bit width */
#define PA_MASK             ((1u << PA_WIDTH) - 1)          /* physical address mask (2 ** 22 - 1) */
#define PA_MAX              ((1u << PA_WIDTH) - 1)          /* physical address maximum (2 ** 22 - 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.

    2. The size of the bank number field is dependent on the CPU model selected.
       Bank registers are two bits wide for the Series II and four bits wide for
       the Series III, although MPE V/R supported six-bit bank register widths.
*/

#define TO_PA(b,o)          (((uint32) (b) & mem_bank_mask) << LA_WIDTH | (uint32) (o))
#define TO_BANK(p)          ((p) >> LA_WIDTH & mem_bank_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, DMA,
   and channel 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, fetch, dma,
   and bank 0 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
     bank 0      N        N

   Implementation notes:

    1. The enumeration values for the program and data identifiers must be
       ordered such that the "checked" classes are odd and differ from their
       corresponding "unchecked" classes only in the LSBs.  Only these four
       classes use the INVERT_CHECK macro to change from checked to unchecked
       and vice versa, so the ordering of the other classes is arbitrary.

    2. The "dma" class exists only to differentiate DMA memory accesses from CPU
       memory accesses when tracing.

    3. The bank 0 classification is identical to the absolute classification,
       except that it always represents an offset into bank 0.  Certain MPE
       structures, e.g., channel programs, must reside in the first 64K of
       memory, corresponding to memory bank 0, and it is less error-prone to
       apply the constraint in the memory read and write calls than in every
       address calculation.
*/

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 access */
    bank_0                                      /* memory bank 0 access */
    } ACCESS_CLASS;

#define INVERT_CHECK(c)     ((c) ^ 1u)          /* convert checked to unchecked and vice versa */


/* HP-IB I/O instruction accessors.

       0 | 1   2   3 | 4   5   6 | 7   8   9 |10  11  12 |13  14  15
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
     | -   -   -   -   -   -   -   -   - |    Channel    |  Device   |
     +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
*/

#define IO_CHANNEL_MASK     HP_BITS ( 9, 12)    /* channel number mask */

#define IO_CHANNEL(w)       HP_BITS_TO ( 9, 12, w)
#define IO_DEVICE(w)        HP_BITS_TO (13, 15, w)

#define TO_DEVNO(c,d)       (TO_HP_BITS (9, 12, c) | TO_HP_BITS (13, 15, d))


/* 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
     - NEG8   -- 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)
#define TO_BYTE(u,l)        (HP_BYTE) (((u) & D4_MASK) << D4_WIDTH | (l) & 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)       (HP_BYTE) ((w) >> D8_WIDTH & D8_MASK)
#define LOWER_BYTE(w)       (HP_BYTE) ((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))


/* Quad-word accessors */

#define UPPER_DWORD(q)      (uint32) ((q) >> D32_WIDTH & D32_MASK)
#define LOWER_DWORD(q)      (uint32) ((q) &  D32_MASK)

#define HIGH_UPPER_WORD(q)  (HP_WORD) ((q) >> D48_WIDTH & D16_MASK)
#define LOW_UPPER_WORD(q)   (HP_WORD) ((q) >> D32_WIDTH & D16_MASK)
#define TO_QWORD(h,a,b,l)   ((t_uint64) (h) << D48_WIDTH | (t_uint64) (a) << D32_WIDTH \
                              | (uint32) (b) << 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,  char   *cptr, 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  (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,  char  *cptr, void *desc);
extern t_stat hp_show_dib (FILE *st,   UNIT  *uptr, int32 code,  void *desc);

extern t_stat hp_word_examine (t_value *value, t_addr addr, UNIT *uptr, int32 switches);
extern t_stat hp_word_deposit (t_value  value, t_addr addr, UNIT *uptr, int32 switches);


/* 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_value  (uint32 value, uint32 radix, uint32 width, uint32 format);
extern const char *fmt_bitset (uint32 bitset, const BITSET_FORMAT bitfmt);

extern void   hp_trace           (DEVICE *dptr, uint32 flag, ...);
extern t_bool hp_device_conflict (void);
