| /* hp3000_defs.h: HP 3000 simulator general declarations | |
| Copyright (c) 2016, 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. | |
| 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. | |
| */ | |
| #ifndef HP3000_DEFS_H_ | |
| #define HP3000_DEFS_H_ | |
| #include "sim_defs.h" | |
| #include "sim_rev.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-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_A (1 << REG_V_UF + 0) /* permit any display */ | |
| #define REG_B (1 << REG_V_UF + 1) /* permit binary display */ | |
| #define REG_M (1 << REG_V_UF + 2) /* default to instruction mnemonic display */ | |
| #define REG_S (1 << REG_V_UF + 3) /* default to status mnemonic display */ | |
| /* Register macros. | |
| These additional register definition macros are used to define: | |
| FBDATA -- a one-bit flag in an arrayed register | |
| SRDATA -- an array of bytes large enough to hold a structure | |
| YRDATA -- a binary register | |
| The FBDATA macro defines flag bits that are replicated in the same place 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 SRDATA 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. | |
| */ | |
| /* Macro name loc radix width offset depth desc fields */ | |
| /* ---------------------- ---- ------- ----- ----- ------ ---------- ---- ------ */ | |
| #define FBDATA(nm,loc,ofs,dep) #nm, &(loc), 2, 1, (ofs), (dep), NULL, NULL | |
| #define SRDATA(nm,loc) #nm, &(loc), 8, 8, 0, sizeof loc, NULL, NULL | |
| #define YRDATA(nm,loc,wid) #nm, &(loc), 2, (wid), 0, 1, NULL, NULL | |
| /* 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 */ | |
| /* 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). | |
| Implementation notes: | |
| 1. The HP_WORD type is a 32-bit unsigned type, instead of the more logical | |
| 16-bit unsigned type. This is because 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. | |
| */ | |
| #define HP_WORD uint32 /* HP 16-bit word representation */ | |
| #define R_MASK 0177777u /* 16-bit register 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 ((1 << LA_WIDTH) - 1) /* logical address mask (2 ** 16 - 1) */ | |
| #define LA_MAX ((1 << LA_WIDTH) - 1) /* logical address maximum (2 ** 16 - 1) */ | |
| #define BA_WIDTH 4 /* bank address bit width */ | |
| #define BA_MASK ((1 << BA_WIDTH) - 1) /* bank address mask (2 ** 4 - 1) */ | |
| #define BA_MAX ((1 << BA_WIDTH) - 1) /* bank address maximum (2 ** 4 - 1) */ | |
| #define PA_WIDTH (LA_WIDTH + BA_WIDTH) /* physical address bit width */ | |
| #define PA_MASK ((1 << PA_WIDTH) - 1) /* physical address mask (2 ** 20 - 1) */ | |
| #define PA_MAX ((1 << PA_WIDTH) - 1) /* physical address maximum (2 ** 20 - 1) */ | |
| #define DV_WIDTH 16 /* data value bit width */ | |
| #define DV_MASK ((1 << DV_WIDTH) - 1) /* data value mask (2 ** 16 - 1) */ | |
| #define DV_SIGN (1 << (DV_WIDTH - 1)) /* data value sign (2 ** 15) */ | |
| #define DV_UMAX ((1 << DV_WIDTH) - 1) /* data value unsigned maximum (2 ** 16 - 1) */ | |
| #define DV_SMAX ((1 << (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) | |
| /* 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: | |
| - SEXT -- int16 sign-extended to int32 | |
| - 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 SEXT(x) (int32) ((x) & D16_SIGN ? (x) | ~D16_MASK : (x)) | |
| #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)) | |
| /* 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 = (ff ^ 1) /* toggle a flip-flop variable */ | |
| #define D_FF(b) ((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 uint16 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 previously 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); | |
| /* System interface global utility routines */ | |
| extern t_bool hp_device_conflict (void); | |
| extern t_stat fprint_cpu (FILE *ofile, t_value *val, uint32 radix, int32 switches); | |
| 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, ...); | |
| #endif |