diff --git a/0readme_37.txt b/0readme_37.txt deleted file mode 100644 index 37d95680..00000000 --- a/0readme_37.txt +++ /dev/null @@ -1,66 +0,0 @@ -Notes For V3.7 - - -1. New Features - -1.1 3.7-0 - -1.1.1 SCP - -- Added SET THROTTLE and SET NOTHROTTLE commands to regulate simulator - execution rate and host resource utilization. -- Added idle support (based on work by Mark Pizzolato). -- Added -e to control error processing in nested DO commands (from - Dave Bryan). - -1.1.2 HP2100 - -- Added Double Integer instructions, 1000-F CPU, and Floating Point - Processor (from Dave Bryan). -- Added 2114 and 2115 CPUs, 12607B and 12578A DMA controllers, and - 21xx binary loader protection (from Dave Bryan). - -1.1.3 Interdata - -- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait - state. - -1.1.4 PDP-11 - -- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait - state (WAIT instruction executed). -- Added TA11/TU60 cassette support. - -1.1.5 PDP-8 - -- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait - state (keyboard poll loop or jump-to-self). -- Added TA8E/TU60 cassette support. - -1.1.6 PDP-1 - -- Added support for 16-channel sequence break system. -- Added support for PDP-1D extended features and timesharing clock. -- Added support for Type 630 data communications subsystem. - -1.1.6 PDP-4/7/9/15 - -- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait - state (keyboard poll loop or jump-to-self). - -1.1.7 VAX, VAX780 - -- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait - state (more than 200 cycles at IPL's 0, 1, or 3 in kernel mode). - -1.1.8 PDP-10 - -- Added SET IDLE and SET NOIDLE commands to idle the simulator in wait - state (operating system dependent). -- Added CD20 (CD11) support. - - -2. Bugs Fixed - -Please see the revision history on http://simh.trailing-edge.com or -in the source module sim_rev.h. diff --git a/0readme_38.txt b/0readme_38.txt new file mode 100644 index 00000000..3ba9383c --- /dev/null +++ b/0readme_38.txt @@ -0,0 +1,45 @@ +Notes For V3.8 + + +The makefile now works for Linux and most Unix's. Howevr, for Solaris +and MacOS, you must first export the OSTYPE environment variable: + +> export OSTYPE +> make + +Otherwise, you will get build errors. + + +1. New Features + +1.1 3.8-0 + +1.1.1 SCP and Libraries + +- BREAK, NOBREAK, and SHOW BREAK with no argument will set, clear, and + show (respectively) a breakpoint at the current PC. + +1.2 GRI + +- Added support for the GRI-99 processor. + +1.3 HP2100 + +- Added support for the BACI terminal interface. +- Added support for RTE OS/VMA/EMA, SIGNAL, VIS firmware extensions. + +1.4 Nova + +- Added support for 64KW memory (implemented in third-party CPU's). + +1.5 PDP-11 + +- Added support for DC11, RC11, KE11A, KG11A. +- Added modem control support for DL11. +- Added ASCII character support for all 8b devices. + + +2. Bugs Fixed + +Please see the revision history on http://simh.trailing-edge.com or +in the source module sim_rev.h. diff --git a/AltairZ80/altairZ80_cpu.c b/AltairZ80/altairZ80_cpu.c index 8483f81b..7d696cd1 100644 --- a/AltairZ80/altairZ80_cpu.c +++ b/AltairZ80/altairZ80_cpu.c @@ -1,6264 +1,6615 @@ -/* altairz80_cpu.c: MITS Altair CPU (8080 and Z80) - - Copyright (c) 2002-2007, Peter Schorn - - 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 - PETER SCHORN 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 Peter Schorn shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Peter Schorn. - - Based on work by Charles E Owen (c) 1997 - Code for Z80 CPU from Frank D. Cringle ((c) 1995 under GNU license) -*/ - -#include "altairz80_defs.h" - -#if defined (_WIN32) -#include -#else -#include -#endif - -#define PCQ_SIZE 64 /* must be 2**n */ -#define PCQ_SIZE_LOG2 6 /* log2 of PCQ_SIZE */ -#define PCQ_MASK (PCQ_SIZE - 1) -#define PCQ_ENTRY(PC) pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC - -/* simulator stop codes */ -#define STOP_HALT 0 /* HALT */ -#define STOP_IBKPT 1 /* breakpoint (program counter) */ -#define STOP_MEM 2 /* breakpoint (memory access) */ -#define STOP_OPCODE 3 /* unknown 8080 or Z80 instruction */ - -#define FLAG_C 1 -#define FLAG_N 2 -#define FLAG_P 4 -#define FLAG_H 16 -#define FLAG_Z 64 -#define FLAG_S 128 - -#define SETFLAG(f,c) AF = (c) ? AF | FLAG_ ## f : AF & ~FLAG_ ## f -#define TSTFLAG(f) ((AF & FLAG_ ## f) != 0) - -#define LOW_DIGIT(x) ((x) & 0xf) -#define HIGH_DIGIT(x) (((x) >> 4) & 0xf) -#define LOW_REGISTER(x) ((x) & 0xff) -#define HIGH_REGISTER(x) (((x) >> 8) & 0xff) - -#define SET_LOW_REGISTER(x, v) x = (((x) & 0xff00) | ((v) & 0xff)) -#define SET_HIGH_REGISTER(x, v) x = (((x) & 0xff) | (((v) & 0xff) << 8)) - -#define PARITY(x) parityTable[(x) & 0xff] -/* SET_PV and SET_PV2 are used to provide correct PARITY flag semantics for the 8080 in cases - where the Z80 uses the overflow flag -*/ -#define SET_PVS(s) ((cpu_unit.flags & UNIT_CHIP) ? (((cbits >> 6) ^ (cbits >> 5)) & 4) : (PARITY(s))) -#define SET_PV (SET_PVS(sum)) -#define SET_PV2(x) ((cpu_unit.flags & UNIT_CHIP) ? (((temp == (x)) << 2)) : (PARITY(temp))) - -/* CHECK_CPU_8080 must be invoked whenever a Z80 only instruction is executed - In case a Z80 instruction is executed on an 8080 the following two cases exist: - 1) Trapping is enabled: execution stops - 2) Trapping is not enabled: decoding continues with the next byte -*/ -#define CHECK_CPU_8080 \ - if ((cpu_unit.flags & UNIT_CHIP) == 0) { \ - if (cpu_unit.flags & UNIT_OPSTOP) { \ - reason = STOP_OPCODE; \ - goto end_decode; \ - } \ - else { \ - sim_brk_pend[0] = FALSE; \ - continue; \ - } \ - } - -/* CHECK_CPU_Z80 must be invoked whenever a non Z80 instruction is executed */ -#define CHECK_CPU_Z80 \ - if (cpu_unit.flags & UNIT_OPSTOP) { \ - reason = STOP_OPCODE; \ - goto end_decode; \ - } - -#define POP(x) { \ - register uint32 y = RAM_PP(SP); \ - x = y + (RAM_PP(SP) << 8); \ -} - -#define JPC(cond) { \ - tStates += 10; \ - if (cond) { \ - PCQ_ENTRY(PC - 1); \ - PC = GET_WORD(PC); \ - } \ - else { \ - PC += 2; \ - } \ -} - -#define CALLC(cond) { \ - if (cond) { \ - register uint32 adrr = GET_WORD(PC); \ - CHECK_BREAK_WORD(SP - 2); \ - PUSH(PC + 2); \ - PCQ_ENTRY(PC - 1); \ - PC = adrr; \ - tStates += 17; \ - } \ - else { \ - sim_brk_pend[0] = FALSE; \ - PC += 2; \ - tStates += 10; \ - } \ -} - -extern int32 sim_int_char; -extern int32 sio0s (const int32 port, const int32 io, const int32 data); -extern int32 sio0d (const int32 port, const int32 io, const int32 data); -extern int32 sio1s (const int32 port, const int32 io, const int32 data); -extern int32 sio1d (const int32 port, const int32 io, const int32 data); -extern int32 dsk10 (const int32 port, const int32 io, const int32 data); -extern int32 dsk11 (const int32 port, const int32 io, const int32 data); -extern int32 dsk12 (const int32 port, const int32 io, const int32 data); -extern int32 netStatus (const int32 port, const int32 io, const int32 data); -extern int32 netData (const int32 port, const int32 io, const int32 data); -extern int32 nulldev (const int32 port, const int32 io, const int32 data); -extern int32 hdsk_io (const int32 port, const int32 io, const int32 data); -extern int32 simh_dev (const int32 port, const int32 io, const int32 data); -extern int32 sr_dev (const int32 port, const int32 io, const int32 data); -extern char messageBuffer[]; -extern void printMessage(void); - -/* function prototypes */ -t_stat cpu_ex(t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); -t_stat cpu_dep(t_value val, t_addr addr, UNIT *uptr, int32 sw); -t_stat cpu_reset(DEVICE *dptr); -t_stat sim_load(FILE *fileref, char *cptr, char *fnam, int32 flag); - -void PutBYTEBasic(const uint32 Addr, const uint32 Bank, const uint32 Value); -t_stat sim_instr(void); -int32 install_bootrom(void); -void protect(const int32 l, const int32 h); -uint8 GetBYTEWrapper(const uint32 Addr); -void PutBYTEWrapper(const uint32 Addr, const uint32 Value); -int32 getBankSelect(void); -void setBankSelect(const int32 b); -uint32 getCommon(void); -static t_stat cpu_set_rom (UNIT *uptr, int32 value, char *cptr, void *desc); -static t_stat cpu_set_norom (UNIT *uptr, int32 value, char *cptr, void *desc); -static t_stat cpu_set_altairrom (UNIT *uptr, int32 value, char *cptr, void *desc); -static t_stat cpu_set_warnrom (UNIT *uptr, int32 value, char *cptr, void *desc); -static t_stat cpu_set_banked (UNIT *uptr, int32 value, char *cptr, void *desc); -static t_stat cpu_set_nonbanked (UNIT *uptr, int32 value, char *cptr, void *desc); -static t_stat cpu_set_size (UNIT *uptr, int32 value, char *cptr, void *desc); - -/* CPU data structures - cpu_dev CPU device descriptor - cpu_unit CPU unit descriptor - cpu_reg CPU register list - cpu_mod CPU modifiers list -*/ - -UNIT cpu_unit = { - UDATA (NULL, UNIT_FIX + UNIT_BINK + UNIT_ROM + UNIT_ALTAIRROM, MAXMEMSIZE) -}; - - int32 PCX = 0; /* external view of PC */ - int32 saved_PC = 0; /* program counter */ -static int32 AF_S; /* AF register */ -static int32 BC_S; /* BC register */ -static int32 DE_S; /* DE register */ -static int32 HL_S; /* HL register */ -static int32 IX_S; /* IX register */ -static int32 IY_S; /* IY register */ -static int32 SP_S; /* SP register */ -static int32 AF1_S; /* alternate AF register */ -static int32 BC1_S; /* alternate BC register */ -static int32 DE1_S; /* alternate DE register */ -static int32 HL1_S; /* alternate HL register */ -static int32 IFF_S; /* interrupt Flip Flop */ -static int32 IR_S; /* interrupt (upper)/refresh (lower) register */ - int32 SR = 0; /* switch register */ -static int32 bankSelect = 0; /* determines selected memory bank */ -static uint32 common = 0xc000; /* addresses >= 'common' are in common memory */ -static uint32 ROMLow = DEFAULT_ROM_LOW; /* lowest address of ROM */ -static uint32 ROMHigh = DEFAULT_ROM_HIGH; /* highest address of ROM */ -static uint32 previousCapacity = 0; /* safe for previous memory capacity */ -static uint32 clockFrequency = 0; /* in kHz, 0 means as fast as possible */ -static uint32 sliceLength = 10; /* length of time-slice for CPU speed */ - /* adjustment in milliseconds */ -static uint32 executedTStates = 0; /* executed t-states */ -static uint16 pcq[PCQ_SIZE] = { /* PC queue */ - 0 -}; -static int32 pcq_p = 0; /* PC queue ptr */ -static REG *pcq_r = NULL; /* PC queue reg ptr */ - -REG cpu_reg[] = { - { HRDATA (PC, saved_PC, 16) }, - { HRDATA (AF, AF_S, 16) }, - { HRDATA (BC, BC_S, 16) }, - { HRDATA (DE, DE_S, 16) }, - { HRDATA (HL, HL_S, 16) }, - { HRDATA (IX, IX_S, 16) }, - { HRDATA (IY, IY_S, 16) }, - { HRDATA (SP, SP_S, 16) }, - { HRDATA (AF1, AF1_S, 16) }, - { HRDATA (BC1, BC1_S, 16) }, - { HRDATA (DE1, DE1_S, 16) }, - { HRDATA (HL1, HL1_S, 16) }, - { GRDATA (IFF, IFF_S, 2, 2, 0) }, - { FLDATA (IR, IR_S, 8) }, - { FLDATA (Z80, cpu_unit.flags, UNIT_V_CHIP), REG_HRO }, - { FLDATA (OPSTOP, cpu_unit.flags, UNIT_V_OPSTOP), REG_HRO }, - { HRDATA (SR, SR, 8) }, - { HRDATA (BANK, bankSelect, MAXBANKSLOG2) }, - { HRDATA (COMMON, common, 16) }, - { HRDATA (ROMLOW, ROMLow, 16) }, - { HRDATA (ROMHIGH, ROMHigh, 16) }, - { DRDATA (CLOCK, clockFrequency, 32) }, - { DRDATA (SLICE, sliceLength, 16) }, - { DRDATA (TSTATES, executedTStates, 32), REG_RO }, - { HRDATA (CAPACITY, cpu_unit.capac, 32), REG_RO }, - { HRDATA (PREVCAP, previousCapacity, 32), REG_RO }, - { BRDATA (PCQ, pcq, 16, 16, PCQ_SIZE), REG_RO + REG_CIRC }, - { DRDATA (PCQP, pcq_p, PCQ_SIZE_LOG2), REG_HRO }, - { HRDATA (WRU, sim_int_char, 8) }, - { NULL } -}; - -static MTAB cpu_mod[] = { - { UNIT_CHIP, UNIT_CHIP, "Z80", "Z80", NULL }, - { UNIT_CHIP, 0, "8080", "8080", NULL }, - { UNIT_OPSTOP, UNIT_OPSTOP, "ITRAP", "ITRAP", NULL }, - { UNIT_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL }, - { UNIT_BANKED, UNIT_BANKED, "BANKED", "BANKED", &cpu_set_banked }, - { UNIT_BANKED, 0, "NONBANKED", "NONBANKED", &cpu_set_nonbanked }, - { UNIT_ROM, UNIT_ROM, "ROM", "ROM", &cpu_set_rom }, - { UNIT_ROM, 0, "NOROM", "NOROM", &cpu_set_norom }, - { UNIT_ALTAIRROM, UNIT_ALTAIRROM, "ALTAIRROM", "ALTAIRROM", &cpu_set_altairrom }, - { UNIT_ALTAIRROM, 0, "NOALTAIRROM", "NOALTAIRROM", NULL }, - { UNIT_WARNROM, UNIT_WARNROM, "WARNROM", "WARNROM", &cpu_set_warnrom }, - { UNIT_WARNROM, 0, "NOWARNROM", "NOWARNROM", NULL }, - { UNIT_MSIZE, 4 * KB, NULL, "4K", &cpu_set_size }, - { UNIT_MSIZE, 8 * KB, NULL, "8K", &cpu_set_size }, - { UNIT_MSIZE, 12 * KB, NULL, "12K", &cpu_set_size }, - { UNIT_MSIZE, 16 * KB, NULL, "16K", &cpu_set_size }, - { UNIT_MSIZE, 20 * KB, NULL, "20K", &cpu_set_size }, - { UNIT_MSIZE, 24 * KB, NULL, "24K", &cpu_set_size }, - { UNIT_MSIZE, 28 * KB, NULL, "28K", &cpu_set_size }, - { UNIT_MSIZE, 32 * KB, NULL, "32K", &cpu_set_size }, - { UNIT_MSIZE, 36 * KB, NULL, "36K", &cpu_set_size }, - { UNIT_MSIZE, 40 * KB, NULL, "40K", &cpu_set_size }, - { UNIT_MSIZE, 44 * KB, NULL, "44K", &cpu_set_size }, - { UNIT_MSIZE, 48 * KB, NULL, "48K", &cpu_set_size }, - { UNIT_MSIZE, 52 * KB, NULL, "52K", &cpu_set_size }, - { UNIT_MSIZE, 56 * KB, NULL, "56K", &cpu_set_size }, - { UNIT_MSIZE, 60 * KB, NULL, "60K", &cpu_set_size }, - { UNIT_MSIZE, 64 * KB, NULL, "64K", &cpu_set_size }, - { 0 } -}; - -DEVICE cpu_dev = { - "CPU", &cpu_unit, cpu_reg, cpu_mod, - 1, 16, 16, 1, 16, 8, - &cpu_ex, &cpu_dep, &cpu_reset, - NULL, NULL, NULL, - NULL, 0, 0, - NULL, NULL, NULL -}; - -/* data structure for IN/OUT instructions */ -struct idev { - int32 (*routine)(const int32, const int32, const int32); -}; - -/* This is the I/O configuration table. There are 255 possible - device addresses, if a device is plugged to a port it's routine - address is here, 'nulldev' means no device is available -*/ -static const struct idev dev_table[256] = { - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 00 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 04 */ - {&dsk10}, {&dsk11}, {&dsk12}, {&nulldev}, /* 08 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0C */ - {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /* 10 */ - {&sio0s}, {&sio0d}, {&sio0s}, {&sio0d}, /* 14 */ - {&sio0s}, {&sio0d}, {&nulldev}, {&nulldev}, /* 18 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1C */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 20 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 24 */ - {&netStatus},{&netData},{&netStatus},{&netData}, /* 28 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2C */ - {&nulldev}, {&nulldev}, {&netStatus},{&netData}, /* 30 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 34 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 38 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3C */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 40 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 44 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 48 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 4C */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 50 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 54 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 58 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 5C */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 60 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 64 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 68 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 6C */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 70 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 74 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 78 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 7C */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 80 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 84 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 88 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 8C */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 90 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 94 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 98 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 9C */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* A0 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* A4 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* A8 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* AC */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* B0 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* B4 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* B8 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* BC */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* C0 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* C4 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* C8 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* CC */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D0 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D4 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D8 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* DC */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D0 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* E4 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* E8 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* EC */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F0 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F4 */ - {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F8 */ - {&nulldev}, {&hdsk_io}, {&simh_dev}, {&sr_dev} /* FC */ -}; - -static void out(const uint32 Port, const uint32 Value) { - dev_table[Port].routine(Port, 1, Value); -} - -static uint32 in(const uint32 Port) { - return dev_table[Port].routine(Port, 0, 0); -} - -/* the following tables precompute some common subexpressions - parityTable[i] 0..255 (number of 1's in i is odd) ? 0 : 4 - incTable[i] 0..256! (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0) << 4) - decTable[i] 0..255 (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0xf) << 4) | 2 - cbitsTable[i] 0..511 (i & 0x10) | ((i >> 8) & 1) - cbitsDup8Table[i] 0..511 (i & 0x10) | ((i >> 8) & 1) | ((i & 0xff) << 8) | (i & 0xa8) | - (((i & 0xff) == 0) << 6) - cbitsDup16Table[i] 0..511 (i & 0x10) | ((i >> 8) & 1) | (i & 0x28) - cbits2Table[i] 0..511 (i & 0x10) | ((i >> 8) & 1) | 2 - rrcaTable[i] 0..255 ((i & 1) << 15) | ((i >> 1) << 8) | ((i >> 1) & 0x28) | (i & 1) - rraTable[i] 0..255 ((i >> 1) << 8) | ((i >> 1) & 0x28) | (i & 1) - addTable[i] 0..511 ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) - subTable[i] 0..255 ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) | 2 - andTable[i] 0..255 (i << 8) | (i & 0xa8) | ((i == 0) << 6) | 0x10 | parityTable[i] - xororTable[i] 0..255 (i << 8) | (i & 0xa8) | ((i == 0) << 6) | parityTable[i] - rotateShiftTable[i] 0..255 (i & 0xa8) | (((i & 0xff) == 0) << 6) | parityTable[i & 0xff] - incZ80Table[i] 0..256! (i & 0xa8) | (((i & 0xff) == 0) << 6) | - (((i & 0xf) == 0) << 4) | ((i == 0x80) << 2) - decZ80Table[i] 0..255 (i & 0xa8) | (((i & 0xff) == 0) << 6) | - (((i & 0xf) == 0xf) << 4) | ((i == 0x7f) << 2) | 2 - cbitsZ80Table[i] 0..511 (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) - cbitsZ80DupTable[i] 0..511 (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | - ((i >> 8) & 1) | (i & 0xa8) - cbits2Z80Table[i] 0..511 (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | 2 - cbits2Z80DupTable[i] 0..511 (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | 2 | - (i & 0xa8) - negTable[i] 0..255 (((i & 0x0f) != 0) << 4) | ((i == 0x80) << 2) | 2 | (i != 0) - rrdrldTable[i] 0..255 (i << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) | parityTable[i] - cpTable[i] 0..255 (i & 0x80) | (((i & 0xff) == 0) << 6) -*/ - -/* parityTable[i] = (number of 1's in i is odd) ? 0 : 4, i = 0..255 */ -static const uint8 parityTable[256] = { - 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, - 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, - 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, - 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, - 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, - 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, - 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, - 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, - 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, - 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, - 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, - 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, - 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, - 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, - 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, - 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, -}; - -/* incTable[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0) << 4), i = 0..256 */ -static const uint8 incTable[257] = { - 80, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, - 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, - 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, - 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, - 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, - 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, - 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, - 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, - 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, - 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, - 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, - 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, 80 -}; - -/* decTable[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0xf) << 4) | 2, i = 0..255 */ -static const uint8 decTable[256] = { - 66, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, - 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, - 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, - 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, - 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, - 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, - 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, - 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, - 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, - 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, - 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, - 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, - 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, - 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, - 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, - 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, -}; - -/* cbitsTable[i] = (i & 0x10) | ((i >> 8) & 1), i = 0..511 */ -static const uint8 cbitsTable[512] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, -}; - -/* cbitsDup8Table[i] = (i & 0x10) | ((i >> 8) & 1) | ((i & 0xff) << 8) | (i & 0xa8) | - (((i & 0xff) == 0) << 6), i = 0..511 */ -static const uint16 cbitsDup8Table[512] = { - 0x0040,0x0100,0x0200,0x0300,0x0400,0x0500,0x0600,0x0700, - 0x0808,0x0908,0x0a08,0x0b08,0x0c08,0x0d08,0x0e08,0x0f08, - 0x1010,0x1110,0x1210,0x1310,0x1410,0x1510,0x1610,0x1710, - 0x1818,0x1918,0x1a18,0x1b18,0x1c18,0x1d18,0x1e18,0x1f18, - 0x2020,0x2120,0x2220,0x2320,0x2420,0x2520,0x2620,0x2720, - 0x2828,0x2928,0x2a28,0x2b28,0x2c28,0x2d28,0x2e28,0x2f28, - 0x3030,0x3130,0x3230,0x3330,0x3430,0x3530,0x3630,0x3730, - 0x3838,0x3938,0x3a38,0x3b38,0x3c38,0x3d38,0x3e38,0x3f38, - 0x4000,0x4100,0x4200,0x4300,0x4400,0x4500,0x4600,0x4700, - 0x4808,0x4908,0x4a08,0x4b08,0x4c08,0x4d08,0x4e08,0x4f08, - 0x5010,0x5110,0x5210,0x5310,0x5410,0x5510,0x5610,0x5710, - 0x5818,0x5918,0x5a18,0x5b18,0x5c18,0x5d18,0x5e18,0x5f18, - 0x6020,0x6120,0x6220,0x6320,0x6420,0x6520,0x6620,0x6720, - 0x6828,0x6928,0x6a28,0x6b28,0x6c28,0x6d28,0x6e28,0x6f28, - 0x7030,0x7130,0x7230,0x7330,0x7430,0x7530,0x7630,0x7730, - 0x7838,0x7938,0x7a38,0x7b38,0x7c38,0x7d38,0x7e38,0x7f38, - 0x8080,0x8180,0x8280,0x8380,0x8480,0x8580,0x8680,0x8780, - 0x8888,0x8988,0x8a88,0x8b88,0x8c88,0x8d88,0x8e88,0x8f88, - 0x9090,0x9190,0x9290,0x9390,0x9490,0x9590,0x9690,0x9790, - 0x9898,0x9998,0x9a98,0x9b98,0x9c98,0x9d98,0x9e98,0x9f98, - 0xa0a0,0xa1a0,0xa2a0,0xa3a0,0xa4a0,0xa5a0,0xa6a0,0xa7a0, - 0xa8a8,0xa9a8,0xaaa8,0xaba8,0xaca8,0xada8,0xaea8,0xafa8, - 0xb0b0,0xb1b0,0xb2b0,0xb3b0,0xb4b0,0xb5b0,0xb6b0,0xb7b0, - 0xb8b8,0xb9b8,0xbab8,0xbbb8,0xbcb8,0xbdb8,0xbeb8,0xbfb8, - 0xc080,0xc180,0xc280,0xc380,0xc480,0xc580,0xc680,0xc780, - 0xc888,0xc988,0xca88,0xcb88,0xcc88,0xcd88,0xce88,0xcf88, - 0xd090,0xd190,0xd290,0xd390,0xd490,0xd590,0xd690,0xd790, - 0xd898,0xd998,0xda98,0xdb98,0xdc98,0xdd98,0xde98,0xdf98, - 0xe0a0,0xe1a0,0xe2a0,0xe3a0,0xe4a0,0xe5a0,0xe6a0,0xe7a0, - 0xe8a8,0xe9a8,0xeaa8,0xeba8,0xeca8,0xeda8,0xeea8,0xefa8, - 0xf0b0,0xf1b0,0xf2b0,0xf3b0,0xf4b0,0xf5b0,0xf6b0,0xf7b0, - 0xf8b8,0xf9b8,0xfab8,0xfbb8,0xfcb8,0xfdb8,0xfeb8,0xffb8, - 0x0041,0x0101,0x0201,0x0301,0x0401,0x0501,0x0601,0x0701, - 0x0809,0x0909,0x0a09,0x0b09,0x0c09,0x0d09,0x0e09,0x0f09, - 0x1011,0x1111,0x1211,0x1311,0x1411,0x1511,0x1611,0x1711, - 0x1819,0x1919,0x1a19,0x1b19,0x1c19,0x1d19,0x1e19,0x1f19, - 0x2021,0x2121,0x2221,0x2321,0x2421,0x2521,0x2621,0x2721, - 0x2829,0x2929,0x2a29,0x2b29,0x2c29,0x2d29,0x2e29,0x2f29, - 0x3031,0x3131,0x3231,0x3331,0x3431,0x3531,0x3631,0x3731, - 0x3839,0x3939,0x3a39,0x3b39,0x3c39,0x3d39,0x3e39,0x3f39, - 0x4001,0x4101,0x4201,0x4301,0x4401,0x4501,0x4601,0x4701, - 0x4809,0x4909,0x4a09,0x4b09,0x4c09,0x4d09,0x4e09,0x4f09, - 0x5011,0x5111,0x5211,0x5311,0x5411,0x5511,0x5611,0x5711, - 0x5819,0x5919,0x5a19,0x5b19,0x5c19,0x5d19,0x5e19,0x5f19, - 0x6021,0x6121,0x6221,0x6321,0x6421,0x6521,0x6621,0x6721, - 0x6829,0x6929,0x6a29,0x6b29,0x6c29,0x6d29,0x6e29,0x6f29, - 0x7031,0x7131,0x7231,0x7331,0x7431,0x7531,0x7631,0x7731, - 0x7839,0x7939,0x7a39,0x7b39,0x7c39,0x7d39,0x7e39,0x7f39, - 0x8081,0x8181,0x8281,0x8381,0x8481,0x8581,0x8681,0x8781, - 0x8889,0x8989,0x8a89,0x8b89,0x8c89,0x8d89,0x8e89,0x8f89, - 0x9091,0x9191,0x9291,0x9391,0x9491,0x9591,0x9691,0x9791, - 0x9899,0x9999,0x9a99,0x9b99,0x9c99,0x9d99,0x9e99,0x9f99, - 0xa0a1,0xa1a1,0xa2a1,0xa3a1,0xa4a1,0xa5a1,0xa6a1,0xa7a1, - 0xa8a9,0xa9a9,0xaaa9,0xaba9,0xaca9,0xada9,0xaea9,0xafa9, - 0xb0b1,0xb1b1,0xb2b1,0xb3b1,0xb4b1,0xb5b1,0xb6b1,0xb7b1, - 0xb8b9,0xb9b9,0xbab9,0xbbb9,0xbcb9,0xbdb9,0xbeb9,0xbfb9, - 0xc081,0xc181,0xc281,0xc381,0xc481,0xc581,0xc681,0xc781, - 0xc889,0xc989,0xca89,0xcb89,0xcc89,0xcd89,0xce89,0xcf89, - 0xd091,0xd191,0xd291,0xd391,0xd491,0xd591,0xd691,0xd791, - 0xd899,0xd999,0xda99,0xdb99,0xdc99,0xdd99,0xde99,0xdf99, - 0xe0a1,0xe1a1,0xe2a1,0xe3a1,0xe4a1,0xe5a1,0xe6a1,0xe7a1, - 0xe8a9,0xe9a9,0xeaa9,0xeba9,0xeca9,0xeda9,0xeea9,0xefa9, - 0xf0b1,0xf1b1,0xf2b1,0xf3b1,0xf4b1,0xf5b1,0xf6b1,0xf7b1, - 0xf8b9,0xf9b9,0xfab9,0xfbb9,0xfcb9,0xfdb9,0xfeb9,0xffb9, -}; - -/* cbitsDup16Table[i] = (i & 0x10) | ((i >> 8) & 1) | (i & 0x28), i = 0..511 */ -static const uint8 cbitsDup16Table[512] = { - 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24, - 32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40, - 48,48,48,48,48,48,48,48,56,56,56,56,56,56,56,56, - 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24, - 32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40, - 48,48,48,48,48,48,48,48,56,56,56,56,56,56,56,56, - 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24, - 32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40, - 48,48,48,48,48,48,48,48,56,56,56,56,56,56,56,56, - 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24, - 32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40, - 48,48,48,48,48,48,48,48,56,56,56,56,56,56,56,56, - 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, - 17,17,17,17,17,17,17,17,25,25,25,25,25,25,25,25, - 33,33,33,33,33,33,33,33,41,41,41,41,41,41,41,41, - 49,49,49,49,49,49,49,49,57,57,57,57,57,57,57,57, - 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, - 17,17,17,17,17,17,17,17,25,25,25,25,25,25,25,25, - 33,33,33,33,33,33,33,33,41,41,41,41,41,41,41,41, - 49,49,49,49,49,49,49,49,57,57,57,57,57,57,57,57, - 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, - 17,17,17,17,17,17,17,17,25,25,25,25,25,25,25,25, - 33,33,33,33,33,33,33,33,41,41,41,41,41,41,41,41, - 49,49,49,49,49,49,49,49,57,57,57,57,57,57,57,57, - 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, - 17,17,17,17,17,17,17,17,25,25,25,25,25,25,25,25, - 33,33,33,33,33,33,33,33,41,41,41,41,41,41,41,41, - 49,49,49,49,49,49,49,49,57,57,57,57,57,57,57,57, -}; - -/* cbits2Table[i] = (i & 0x10) | ((i >> 8) & 1) | 2, i = 0..511 */ -static const uint8 cbits2Table[512] = { - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, -}; - -/* rrcaTable[i] = ((i & 1) << 15) | ((i >> 1) << 8) | ((i >> 1) & 0x28) | (i & 1), i = 0..255 */ -static const uint16 rrcaTable[256] = { - 0x0000,0x8001,0x0100,0x8101,0x0200,0x8201,0x0300,0x8301, - 0x0400,0x8401,0x0500,0x8501,0x0600,0x8601,0x0700,0x8701, - 0x0808,0x8809,0x0908,0x8909,0x0a08,0x8a09,0x0b08,0x8b09, - 0x0c08,0x8c09,0x0d08,0x8d09,0x0e08,0x8e09,0x0f08,0x8f09, - 0x1000,0x9001,0x1100,0x9101,0x1200,0x9201,0x1300,0x9301, - 0x1400,0x9401,0x1500,0x9501,0x1600,0x9601,0x1700,0x9701, - 0x1808,0x9809,0x1908,0x9909,0x1a08,0x9a09,0x1b08,0x9b09, - 0x1c08,0x9c09,0x1d08,0x9d09,0x1e08,0x9e09,0x1f08,0x9f09, - 0x2020,0xa021,0x2120,0xa121,0x2220,0xa221,0x2320,0xa321, - 0x2420,0xa421,0x2520,0xa521,0x2620,0xa621,0x2720,0xa721, - 0x2828,0xa829,0x2928,0xa929,0x2a28,0xaa29,0x2b28,0xab29, - 0x2c28,0xac29,0x2d28,0xad29,0x2e28,0xae29,0x2f28,0xaf29, - 0x3020,0xb021,0x3120,0xb121,0x3220,0xb221,0x3320,0xb321, - 0x3420,0xb421,0x3520,0xb521,0x3620,0xb621,0x3720,0xb721, - 0x3828,0xb829,0x3928,0xb929,0x3a28,0xba29,0x3b28,0xbb29, - 0x3c28,0xbc29,0x3d28,0xbd29,0x3e28,0xbe29,0x3f28,0xbf29, - 0x4000,0xc001,0x4100,0xc101,0x4200,0xc201,0x4300,0xc301, - 0x4400,0xc401,0x4500,0xc501,0x4600,0xc601,0x4700,0xc701, - 0x4808,0xc809,0x4908,0xc909,0x4a08,0xca09,0x4b08,0xcb09, - 0x4c08,0xcc09,0x4d08,0xcd09,0x4e08,0xce09,0x4f08,0xcf09, - 0x5000,0xd001,0x5100,0xd101,0x5200,0xd201,0x5300,0xd301, - 0x5400,0xd401,0x5500,0xd501,0x5600,0xd601,0x5700,0xd701, - 0x5808,0xd809,0x5908,0xd909,0x5a08,0xda09,0x5b08,0xdb09, - 0x5c08,0xdc09,0x5d08,0xdd09,0x5e08,0xde09,0x5f08,0xdf09, - 0x6020,0xe021,0x6120,0xe121,0x6220,0xe221,0x6320,0xe321, - 0x6420,0xe421,0x6520,0xe521,0x6620,0xe621,0x6720,0xe721, - 0x6828,0xe829,0x6928,0xe929,0x6a28,0xea29,0x6b28,0xeb29, - 0x6c28,0xec29,0x6d28,0xed29,0x6e28,0xee29,0x6f28,0xef29, - 0x7020,0xf021,0x7120,0xf121,0x7220,0xf221,0x7320,0xf321, - 0x7420,0xf421,0x7520,0xf521,0x7620,0xf621,0x7720,0xf721, - 0x7828,0xf829,0x7928,0xf929,0x7a28,0xfa29,0x7b28,0xfb29, - 0x7c28,0xfc29,0x7d28,0xfd29,0x7e28,0xfe29,0x7f28,0xff29, -}; - -/* rraTable[i] = ((i >> 1) << 8) | ((i >> 1) & 0x28) | (i & 1), i = 0..255 */ -static const uint16 rraTable[256] = { - 0x0000,0x0001,0x0100,0x0101,0x0200,0x0201,0x0300,0x0301, - 0x0400,0x0401,0x0500,0x0501,0x0600,0x0601,0x0700,0x0701, - 0x0808,0x0809,0x0908,0x0909,0x0a08,0x0a09,0x0b08,0x0b09, - 0x0c08,0x0c09,0x0d08,0x0d09,0x0e08,0x0e09,0x0f08,0x0f09, - 0x1000,0x1001,0x1100,0x1101,0x1200,0x1201,0x1300,0x1301, - 0x1400,0x1401,0x1500,0x1501,0x1600,0x1601,0x1700,0x1701, - 0x1808,0x1809,0x1908,0x1909,0x1a08,0x1a09,0x1b08,0x1b09, - 0x1c08,0x1c09,0x1d08,0x1d09,0x1e08,0x1e09,0x1f08,0x1f09, - 0x2020,0x2021,0x2120,0x2121,0x2220,0x2221,0x2320,0x2321, - 0x2420,0x2421,0x2520,0x2521,0x2620,0x2621,0x2720,0x2721, - 0x2828,0x2829,0x2928,0x2929,0x2a28,0x2a29,0x2b28,0x2b29, - 0x2c28,0x2c29,0x2d28,0x2d29,0x2e28,0x2e29,0x2f28,0x2f29, - 0x3020,0x3021,0x3120,0x3121,0x3220,0x3221,0x3320,0x3321, - 0x3420,0x3421,0x3520,0x3521,0x3620,0x3621,0x3720,0x3721, - 0x3828,0x3829,0x3928,0x3929,0x3a28,0x3a29,0x3b28,0x3b29, - 0x3c28,0x3c29,0x3d28,0x3d29,0x3e28,0x3e29,0x3f28,0x3f29, - 0x4000,0x4001,0x4100,0x4101,0x4200,0x4201,0x4300,0x4301, - 0x4400,0x4401,0x4500,0x4501,0x4600,0x4601,0x4700,0x4701, - 0x4808,0x4809,0x4908,0x4909,0x4a08,0x4a09,0x4b08,0x4b09, - 0x4c08,0x4c09,0x4d08,0x4d09,0x4e08,0x4e09,0x4f08,0x4f09, - 0x5000,0x5001,0x5100,0x5101,0x5200,0x5201,0x5300,0x5301, - 0x5400,0x5401,0x5500,0x5501,0x5600,0x5601,0x5700,0x5701, - 0x5808,0x5809,0x5908,0x5909,0x5a08,0x5a09,0x5b08,0x5b09, - 0x5c08,0x5c09,0x5d08,0x5d09,0x5e08,0x5e09,0x5f08,0x5f09, - 0x6020,0x6021,0x6120,0x6121,0x6220,0x6221,0x6320,0x6321, - 0x6420,0x6421,0x6520,0x6521,0x6620,0x6621,0x6720,0x6721, - 0x6828,0x6829,0x6928,0x6929,0x6a28,0x6a29,0x6b28,0x6b29, - 0x6c28,0x6c29,0x6d28,0x6d29,0x6e28,0x6e29,0x6f28,0x6f29, - 0x7020,0x7021,0x7120,0x7121,0x7220,0x7221,0x7320,0x7321, - 0x7420,0x7421,0x7520,0x7521,0x7620,0x7621,0x7720,0x7721, - 0x7828,0x7829,0x7928,0x7929,0x7a28,0x7a29,0x7b28,0x7b29, - 0x7c28,0x7c29,0x7d28,0x7d29,0x7e28,0x7e29,0x7f28,0x7f29, -}; - -/* addTable[i] = ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6), i = 0..511 */ -static const uint16 addTable[512] = { - 0x0040,0x0100,0x0200,0x0300,0x0400,0x0500,0x0600,0x0700, - 0x0808,0x0908,0x0a08,0x0b08,0x0c08,0x0d08,0x0e08,0x0f08, - 0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700, - 0x1808,0x1908,0x1a08,0x1b08,0x1c08,0x1d08,0x1e08,0x1f08, - 0x2020,0x2120,0x2220,0x2320,0x2420,0x2520,0x2620,0x2720, - 0x2828,0x2928,0x2a28,0x2b28,0x2c28,0x2d28,0x2e28,0x2f28, - 0x3020,0x3120,0x3220,0x3320,0x3420,0x3520,0x3620,0x3720, - 0x3828,0x3928,0x3a28,0x3b28,0x3c28,0x3d28,0x3e28,0x3f28, - 0x4000,0x4100,0x4200,0x4300,0x4400,0x4500,0x4600,0x4700, - 0x4808,0x4908,0x4a08,0x4b08,0x4c08,0x4d08,0x4e08,0x4f08, - 0x5000,0x5100,0x5200,0x5300,0x5400,0x5500,0x5600,0x5700, - 0x5808,0x5908,0x5a08,0x5b08,0x5c08,0x5d08,0x5e08,0x5f08, - 0x6020,0x6120,0x6220,0x6320,0x6420,0x6520,0x6620,0x6720, - 0x6828,0x6928,0x6a28,0x6b28,0x6c28,0x6d28,0x6e28,0x6f28, - 0x7020,0x7120,0x7220,0x7320,0x7420,0x7520,0x7620,0x7720, - 0x7828,0x7928,0x7a28,0x7b28,0x7c28,0x7d28,0x7e28,0x7f28, - 0x8080,0x8180,0x8280,0x8380,0x8480,0x8580,0x8680,0x8780, - 0x8888,0x8988,0x8a88,0x8b88,0x8c88,0x8d88,0x8e88,0x8f88, - 0x9080,0x9180,0x9280,0x9380,0x9480,0x9580,0x9680,0x9780, - 0x9888,0x9988,0x9a88,0x9b88,0x9c88,0x9d88,0x9e88,0x9f88, - 0xa0a0,0xa1a0,0xa2a0,0xa3a0,0xa4a0,0xa5a0,0xa6a0,0xa7a0, - 0xa8a8,0xa9a8,0xaaa8,0xaba8,0xaca8,0xada8,0xaea8,0xafa8, - 0xb0a0,0xb1a0,0xb2a0,0xb3a0,0xb4a0,0xb5a0,0xb6a0,0xb7a0, - 0xb8a8,0xb9a8,0xbaa8,0xbba8,0xbca8,0xbda8,0xbea8,0xbfa8, - 0xc080,0xc180,0xc280,0xc380,0xc480,0xc580,0xc680,0xc780, - 0xc888,0xc988,0xca88,0xcb88,0xcc88,0xcd88,0xce88,0xcf88, - 0xd080,0xd180,0xd280,0xd380,0xd480,0xd580,0xd680,0xd780, - 0xd888,0xd988,0xda88,0xdb88,0xdc88,0xdd88,0xde88,0xdf88, - 0xe0a0,0xe1a0,0xe2a0,0xe3a0,0xe4a0,0xe5a0,0xe6a0,0xe7a0, - 0xe8a8,0xe9a8,0xeaa8,0xeba8,0xeca8,0xeda8,0xeea8,0xefa8, - 0xf0a0,0xf1a0,0xf2a0,0xf3a0,0xf4a0,0xf5a0,0xf6a0,0xf7a0, - 0xf8a8,0xf9a8,0xfaa8,0xfba8,0xfca8,0xfda8,0xfea8,0xffa8, - 0x0040,0x0100,0x0200,0x0300,0x0400,0x0500,0x0600,0x0700, - 0x0808,0x0908,0x0a08,0x0b08,0x0c08,0x0d08,0x0e08,0x0f08, - 0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700, - 0x1808,0x1908,0x1a08,0x1b08,0x1c08,0x1d08,0x1e08,0x1f08, - 0x2020,0x2120,0x2220,0x2320,0x2420,0x2520,0x2620,0x2720, - 0x2828,0x2928,0x2a28,0x2b28,0x2c28,0x2d28,0x2e28,0x2f28, - 0x3020,0x3120,0x3220,0x3320,0x3420,0x3520,0x3620,0x3720, - 0x3828,0x3928,0x3a28,0x3b28,0x3c28,0x3d28,0x3e28,0x3f28, - 0x4000,0x4100,0x4200,0x4300,0x4400,0x4500,0x4600,0x4700, - 0x4808,0x4908,0x4a08,0x4b08,0x4c08,0x4d08,0x4e08,0x4f08, - 0x5000,0x5100,0x5200,0x5300,0x5400,0x5500,0x5600,0x5700, - 0x5808,0x5908,0x5a08,0x5b08,0x5c08,0x5d08,0x5e08,0x5f08, - 0x6020,0x6120,0x6220,0x6320,0x6420,0x6520,0x6620,0x6720, - 0x6828,0x6928,0x6a28,0x6b28,0x6c28,0x6d28,0x6e28,0x6f28, - 0x7020,0x7120,0x7220,0x7320,0x7420,0x7520,0x7620,0x7720, - 0x7828,0x7928,0x7a28,0x7b28,0x7c28,0x7d28,0x7e28,0x7f28, - 0x8080,0x8180,0x8280,0x8380,0x8480,0x8580,0x8680,0x8780, - 0x8888,0x8988,0x8a88,0x8b88,0x8c88,0x8d88,0x8e88,0x8f88, - 0x9080,0x9180,0x9280,0x9380,0x9480,0x9580,0x9680,0x9780, - 0x9888,0x9988,0x9a88,0x9b88,0x9c88,0x9d88,0x9e88,0x9f88, - 0xa0a0,0xa1a0,0xa2a0,0xa3a0,0xa4a0,0xa5a0,0xa6a0,0xa7a0, - 0xa8a8,0xa9a8,0xaaa8,0xaba8,0xaca8,0xada8,0xaea8,0xafa8, - 0xb0a0,0xb1a0,0xb2a0,0xb3a0,0xb4a0,0xb5a0,0xb6a0,0xb7a0, - 0xb8a8,0xb9a8,0xbaa8,0xbba8,0xbca8,0xbda8,0xbea8,0xbfa8, - 0xc080,0xc180,0xc280,0xc380,0xc480,0xc580,0xc680,0xc780, - 0xc888,0xc988,0xca88,0xcb88,0xcc88,0xcd88,0xce88,0xcf88, - 0xd080,0xd180,0xd280,0xd380,0xd480,0xd580,0xd680,0xd780, - 0xd888,0xd988,0xda88,0xdb88,0xdc88,0xdd88,0xde88,0xdf88, - 0xe0a0,0xe1a0,0xe2a0,0xe3a0,0xe4a0,0xe5a0,0xe6a0,0xe7a0, - 0xe8a8,0xe9a8,0xeaa8,0xeba8,0xeca8,0xeda8,0xeea8,0xefa8, - 0xf0a0,0xf1a0,0xf2a0,0xf3a0,0xf4a0,0xf5a0,0xf6a0,0xf7a0, - 0xf8a8,0xf9a8,0xfaa8,0xfba8,0xfca8,0xfda8,0xfea8,0xffa8, -}; - -/* subTable[i] = ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) | 2, i = 0..255 */ -static const uint16 subTable[256] = { - 0x0042,0x0102,0x0202,0x0302,0x0402,0x0502,0x0602,0x0702, - 0x080a,0x090a,0x0a0a,0x0b0a,0x0c0a,0x0d0a,0x0e0a,0x0f0a, - 0x1002,0x1102,0x1202,0x1302,0x1402,0x1502,0x1602,0x1702, - 0x180a,0x190a,0x1a0a,0x1b0a,0x1c0a,0x1d0a,0x1e0a,0x1f0a, - 0x2022,0x2122,0x2222,0x2322,0x2422,0x2522,0x2622,0x2722, - 0x282a,0x292a,0x2a2a,0x2b2a,0x2c2a,0x2d2a,0x2e2a,0x2f2a, - 0x3022,0x3122,0x3222,0x3322,0x3422,0x3522,0x3622,0x3722, - 0x382a,0x392a,0x3a2a,0x3b2a,0x3c2a,0x3d2a,0x3e2a,0x3f2a, - 0x4002,0x4102,0x4202,0x4302,0x4402,0x4502,0x4602,0x4702, - 0x480a,0x490a,0x4a0a,0x4b0a,0x4c0a,0x4d0a,0x4e0a,0x4f0a, - 0x5002,0x5102,0x5202,0x5302,0x5402,0x5502,0x5602,0x5702, - 0x580a,0x590a,0x5a0a,0x5b0a,0x5c0a,0x5d0a,0x5e0a,0x5f0a, - 0x6022,0x6122,0x6222,0x6322,0x6422,0x6522,0x6622,0x6722, - 0x682a,0x692a,0x6a2a,0x6b2a,0x6c2a,0x6d2a,0x6e2a,0x6f2a, - 0x7022,0x7122,0x7222,0x7322,0x7422,0x7522,0x7622,0x7722, - 0x782a,0x792a,0x7a2a,0x7b2a,0x7c2a,0x7d2a,0x7e2a,0x7f2a, - 0x8082,0x8182,0x8282,0x8382,0x8482,0x8582,0x8682,0x8782, - 0x888a,0x898a,0x8a8a,0x8b8a,0x8c8a,0x8d8a,0x8e8a,0x8f8a, - 0x9082,0x9182,0x9282,0x9382,0x9482,0x9582,0x9682,0x9782, - 0x988a,0x998a,0x9a8a,0x9b8a,0x9c8a,0x9d8a,0x9e8a,0x9f8a, - 0xa0a2,0xa1a2,0xa2a2,0xa3a2,0xa4a2,0xa5a2,0xa6a2,0xa7a2, - 0xa8aa,0xa9aa,0xaaaa,0xabaa,0xacaa,0xadaa,0xaeaa,0xafaa, - 0xb0a2,0xb1a2,0xb2a2,0xb3a2,0xb4a2,0xb5a2,0xb6a2,0xb7a2, - 0xb8aa,0xb9aa,0xbaaa,0xbbaa,0xbcaa,0xbdaa,0xbeaa,0xbfaa, - 0xc082,0xc182,0xc282,0xc382,0xc482,0xc582,0xc682,0xc782, - 0xc88a,0xc98a,0xca8a,0xcb8a,0xcc8a,0xcd8a,0xce8a,0xcf8a, - 0xd082,0xd182,0xd282,0xd382,0xd482,0xd582,0xd682,0xd782, - 0xd88a,0xd98a,0xda8a,0xdb8a,0xdc8a,0xdd8a,0xde8a,0xdf8a, - 0xe0a2,0xe1a2,0xe2a2,0xe3a2,0xe4a2,0xe5a2,0xe6a2,0xe7a2, - 0xe8aa,0xe9aa,0xeaaa,0xebaa,0xecaa,0xedaa,0xeeaa,0xefaa, - 0xf0a2,0xf1a2,0xf2a2,0xf3a2,0xf4a2,0xf5a2,0xf6a2,0xf7a2, - 0xf8aa,0xf9aa,0xfaaa,0xfbaa,0xfcaa,0xfdaa,0xfeaa,0xffaa, -}; - -/* andTable[i] = (i << 8) | (i & 0xa8) | ((i == 0) << 6) | 0x10 | parityTable[i], i = 0..255 */ -static const uint16 andTable[256] = { - 0x0054,0x0110,0x0210,0x0314,0x0410,0x0514,0x0614,0x0710, - 0x0818,0x091c,0x0a1c,0x0b18,0x0c1c,0x0d18,0x0e18,0x0f1c, - 0x1010,0x1114,0x1214,0x1310,0x1414,0x1510,0x1610,0x1714, - 0x181c,0x1918,0x1a18,0x1b1c,0x1c18,0x1d1c,0x1e1c,0x1f18, - 0x2030,0x2134,0x2234,0x2330,0x2434,0x2530,0x2630,0x2734, - 0x283c,0x2938,0x2a38,0x2b3c,0x2c38,0x2d3c,0x2e3c,0x2f38, - 0x3034,0x3130,0x3230,0x3334,0x3430,0x3534,0x3634,0x3730, - 0x3838,0x393c,0x3a3c,0x3b38,0x3c3c,0x3d38,0x3e38,0x3f3c, - 0x4010,0x4114,0x4214,0x4310,0x4414,0x4510,0x4610,0x4714, - 0x481c,0x4918,0x4a18,0x4b1c,0x4c18,0x4d1c,0x4e1c,0x4f18, - 0x5014,0x5110,0x5210,0x5314,0x5410,0x5514,0x5614,0x5710, - 0x5818,0x591c,0x5a1c,0x5b18,0x5c1c,0x5d18,0x5e18,0x5f1c, - 0x6034,0x6130,0x6230,0x6334,0x6430,0x6534,0x6634,0x6730, - 0x6838,0x693c,0x6a3c,0x6b38,0x6c3c,0x6d38,0x6e38,0x6f3c, - 0x7030,0x7134,0x7234,0x7330,0x7434,0x7530,0x7630,0x7734, - 0x783c,0x7938,0x7a38,0x7b3c,0x7c38,0x7d3c,0x7e3c,0x7f38, - 0x8090,0x8194,0x8294,0x8390,0x8494,0x8590,0x8690,0x8794, - 0x889c,0x8998,0x8a98,0x8b9c,0x8c98,0x8d9c,0x8e9c,0x8f98, - 0x9094,0x9190,0x9290,0x9394,0x9490,0x9594,0x9694,0x9790, - 0x9898,0x999c,0x9a9c,0x9b98,0x9c9c,0x9d98,0x9e98,0x9f9c, - 0xa0b4,0xa1b0,0xa2b0,0xa3b4,0xa4b0,0xa5b4,0xa6b4,0xa7b0, - 0xa8b8,0xa9bc,0xaabc,0xabb8,0xacbc,0xadb8,0xaeb8,0xafbc, - 0xb0b0,0xb1b4,0xb2b4,0xb3b0,0xb4b4,0xb5b0,0xb6b0,0xb7b4, - 0xb8bc,0xb9b8,0xbab8,0xbbbc,0xbcb8,0xbdbc,0xbebc,0xbfb8, - 0xc094,0xc190,0xc290,0xc394,0xc490,0xc594,0xc694,0xc790, - 0xc898,0xc99c,0xca9c,0xcb98,0xcc9c,0xcd98,0xce98,0xcf9c, - 0xd090,0xd194,0xd294,0xd390,0xd494,0xd590,0xd690,0xd794, - 0xd89c,0xd998,0xda98,0xdb9c,0xdc98,0xdd9c,0xde9c,0xdf98, - 0xe0b0,0xe1b4,0xe2b4,0xe3b0,0xe4b4,0xe5b0,0xe6b0,0xe7b4, - 0xe8bc,0xe9b8,0xeab8,0xebbc,0xecb8,0xedbc,0xeebc,0xefb8, - 0xf0b4,0xf1b0,0xf2b0,0xf3b4,0xf4b0,0xf5b4,0xf6b4,0xf7b0, - 0xf8b8,0xf9bc,0xfabc,0xfbb8,0xfcbc,0xfdb8,0xfeb8,0xffbc, -}; - -/* xororTable[i] = (i << 8) | (i & 0xa8) | ((i == 0) << 6) | parityTable[i], i = 0..255 */ -static const uint16 xororTable[256] = { - 0x0044,0x0100,0x0200,0x0304,0x0400,0x0504,0x0604,0x0700, - 0x0808,0x090c,0x0a0c,0x0b08,0x0c0c,0x0d08,0x0e08,0x0f0c, - 0x1000,0x1104,0x1204,0x1300,0x1404,0x1500,0x1600,0x1704, - 0x180c,0x1908,0x1a08,0x1b0c,0x1c08,0x1d0c,0x1e0c,0x1f08, - 0x2020,0x2124,0x2224,0x2320,0x2424,0x2520,0x2620,0x2724, - 0x282c,0x2928,0x2a28,0x2b2c,0x2c28,0x2d2c,0x2e2c,0x2f28, - 0x3024,0x3120,0x3220,0x3324,0x3420,0x3524,0x3624,0x3720, - 0x3828,0x392c,0x3a2c,0x3b28,0x3c2c,0x3d28,0x3e28,0x3f2c, - 0x4000,0x4104,0x4204,0x4300,0x4404,0x4500,0x4600,0x4704, - 0x480c,0x4908,0x4a08,0x4b0c,0x4c08,0x4d0c,0x4e0c,0x4f08, - 0x5004,0x5100,0x5200,0x5304,0x5400,0x5504,0x5604,0x5700, - 0x5808,0x590c,0x5a0c,0x5b08,0x5c0c,0x5d08,0x5e08,0x5f0c, - 0x6024,0x6120,0x6220,0x6324,0x6420,0x6524,0x6624,0x6720, - 0x6828,0x692c,0x6a2c,0x6b28,0x6c2c,0x6d28,0x6e28,0x6f2c, - 0x7020,0x7124,0x7224,0x7320,0x7424,0x7520,0x7620,0x7724, - 0x782c,0x7928,0x7a28,0x7b2c,0x7c28,0x7d2c,0x7e2c,0x7f28, - 0x8080,0x8184,0x8284,0x8380,0x8484,0x8580,0x8680,0x8784, - 0x888c,0x8988,0x8a88,0x8b8c,0x8c88,0x8d8c,0x8e8c,0x8f88, - 0x9084,0x9180,0x9280,0x9384,0x9480,0x9584,0x9684,0x9780, - 0x9888,0x998c,0x9a8c,0x9b88,0x9c8c,0x9d88,0x9e88,0x9f8c, - 0xa0a4,0xa1a0,0xa2a0,0xa3a4,0xa4a0,0xa5a4,0xa6a4,0xa7a0, - 0xa8a8,0xa9ac,0xaaac,0xaba8,0xacac,0xada8,0xaea8,0xafac, - 0xb0a0,0xb1a4,0xb2a4,0xb3a0,0xb4a4,0xb5a0,0xb6a0,0xb7a4, - 0xb8ac,0xb9a8,0xbaa8,0xbbac,0xbca8,0xbdac,0xbeac,0xbfa8, - 0xc084,0xc180,0xc280,0xc384,0xc480,0xc584,0xc684,0xc780, - 0xc888,0xc98c,0xca8c,0xcb88,0xcc8c,0xcd88,0xce88,0xcf8c, - 0xd080,0xd184,0xd284,0xd380,0xd484,0xd580,0xd680,0xd784, - 0xd88c,0xd988,0xda88,0xdb8c,0xdc88,0xdd8c,0xde8c,0xdf88, - 0xe0a0,0xe1a4,0xe2a4,0xe3a0,0xe4a4,0xe5a0,0xe6a0,0xe7a4, - 0xe8ac,0xe9a8,0xeaa8,0xebac,0xeca8,0xedac,0xeeac,0xefa8, - 0xf0a4,0xf1a0,0xf2a0,0xf3a4,0xf4a0,0xf5a4,0xf6a4,0xf7a0, - 0xf8a8,0xf9ac,0xfaac,0xfba8,0xfcac,0xfda8,0xfea8,0xffac, -}; - -/* rotateShiftTable[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | parityTable[i & 0xff], i = 0..255 */ -static const uint8 rotateShiftTable[256] = { - 68, 0, 0, 4, 0, 4, 4, 0, 8, 12, 12, 8, 12, 8, 8, 12, - 0, 4, 4, 0, 4, 0, 0, 4, 12, 8, 8, 12, 8, 12, 12, 8, - 32, 36, 36, 32, 36, 32, 32, 36, 44, 40, 40, 44, 40, 44, 44, 40, - 36, 32, 32, 36, 32, 36, 36, 32, 40, 44, 44, 40, 44, 40, 40, 44, - 0, 4, 4, 0, 4, 0, 0, 4, 12, 8, 8, 12, 8, 12, 12, 8, - 4, 0, 0, 4, 0, 4, 4, 0, 8, 12, 12, 8, 12, 8, 8, 12, - 36, 32, 32, 36, 32, 36, 36, 32, 40, 44, 44, 40, 44, 40, 40, 44, - 32, 36, 36, 32, 36, 32, 32, 36, 44, 40, 40, 44, 40, 44, 44, 40, - 128,132,132,128,132,128,128,132,140,136,136,140,136,140,140,136, - 132,128,128,132,128,132,132,128,136,140,140,136,140,136,136,140, - 164,160,160,164,160,164,164,160,168,172,172,168,172,168,168,172, - 160,164,164,160,164,160,160,164,172,168,168,172,168,172,172,168, - 132,128,128,132,128,132,132,128,136,140,140,136,140,136,136,140, - 128,132,132,128,132,128,128,132,140,136,136,140,136,140,140,136, - 160,164,164,160,164,160,160,164,172,168,168,172,168,172,172,168, - 164,160,160,164,160,164,164,160,168,172,172,168,172,168,168,172, -}; - -/* incZ80Table[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | - (((i & 0xf) == 0) << 4) | ((i == 0x80) << 2), i = 0..256 */ -static const uint8 incZ80Table[257] = { - 80, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, - 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, - 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, - 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, - 148,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, - 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, - 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, - 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, - 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, - 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, - 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, - 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, 80, -}; - -/* decZ80Table[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | - (((i & 0xf) == 0xf) << 4) | ((i == 0x7f) << 2) | 2, i = 0..255 */ -static const uint8 decZ80Table[256] = { - 66, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, - 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, - 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, - 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, - 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, - 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, - 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, - 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 62, - 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, - 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, - 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, - 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, - 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, - 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, - 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, - 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, -}; - -/* cbitsZ80Table[i] = (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1), i = 0..511 */ -static const uint8 cbitsZ80Table[512] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, -}; - -/* cbitsZ80DupTable[i] = (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | - ((i >> 8) & 1) | (i & 0xa8), i = 0..511 */ -static const uint8 cbitsZ80DupTable[512] = { - 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 16, 16, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, - 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, - 48, 48, 48, 48, 48, 48, 48, 48, 56, 56, 56, 56, 56, 56, 56, 56, - 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, - 16, 16, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, - 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, - 48, 48, 48, 48, 48, 48, 48, 48, 56, 56, 56, 56, 56, 56, 56, 56, - 132,132,132,132,132,132,132,132,140,140,140,140,140,140,140,140, - 148,148,148,148,148,148,148,148,156,156,156,156,156,156,156,156, - 164,164,164,164,164,164,164,164,172,172,172,172,172,172,172,172, - 180,180,180,180,180,180,180,180,188,188,188,188,188,188,188,188, - 132,132,132,132,132,132,132,132,140,140,140,140,140,140,140,140, - 148,148,148,148,148,148,148,148,156,156,156,156,156,156,156,156, - 164,164,164,164,164,164,164,164,172,172,172,172,172,172,172,172, - 180,180,180,180,180,180,180,180,188,188,188,188,188,188,188,188, - 5, 5, 5, 5, 5, 5, 5, 5, 13, 13, 13, 13, 13, 13, 13, 13, - 21, 21, 21, 21, 21, 21, 21, 21, 29, 29, 29, 29, 29, 29, 29, 29, - 37, 37, 37, 37, 37, 37, 37, 37, 45, 45, 45, 45, 45, 45, 45, 45, - 53, 53, 53, 53, 53, 53, 53, 53, 61, 61, 61, 61, 61, 61, 61, 61, - 5, 5, 5, 5, 5, 5, 5, 5, 13, 13, 13, 13, 13, 13, 13, 13, - 21, 21, 21, 21, 21, 21, 21, 21, 29, 29, 29, 29, 29, 29, 29, 29, - 37, 37, 37, 37, 37, 37, 37, 37, 45, 45, 45, 45, 45, 45, 45, 45, - 53, 53, 53, 53, 53, 53, 53, 53, 61, 61, 61, 61, 61, 61, 61, 61, - 129,129,129,129,129,129,129,129,137,137,137,137,137,137,137,137, - 145,145,145,145,145,145,145,145,153,153,153,153,153,153,153,153, - 161,161,161,161,161,161,161,161,169,169,169,169,169,169,169,169, - 177,177,177,177,177,177,177,177,185,185,185,185,185,185,185,185, - 129,129,129,129,129,129,129,129,137,137,137,137,137,137,137,137, - 145,145,145,145,145,145,145,145,153,153,153,153,153,153,153,153, - 161,161,161,161,161,161,161,161,169,169,169,169,169,169,169,169, - 177,177,177,177,177,177,177,177,185,185,185,185,185,185,185,185, -}; - -/* cbits2Z80Table[i] = (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | 2, i = 0..511 */ -static const uint8 cbits2Z80Table[512] = { - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, -}; - -/* cbits2Z80DupTable[i] = (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | 2 | - (i & 0xa8), i = 0..511 */ -static const uint8 cbits2Z80DupTable[512] = { - 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 10, - 18, 18, 18, 18, 18, 18, 18, 18, 26, 26, 26, 26, 26, 26, 26, 26, - 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 42, - 50, 50, 50, 50, 50, 50, 50, 50, 58, 58, 58, 58, 58, 58, 58, 58, - 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 10, - 18, 18, 18, 18, 18, 18, 18, 18, 26, 26, 26, 26, 26, 26, 26, 26, - 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 42, - 50, 50, 50, 50, 50, 50, 50, 50, 58, 58, 58, 58, 58, 58, 58, 58, - 134,134,134,134,134,134,134,134,142,142,142,142,142,142,142,142, - 150,150,150,150,150,150,150,150,158,158,158,158,158,158,158,158, - 166,166,166,166,166,166,166,166,174,174,174,174,174,174,174,174, - 182,182,182,182,182,182,182,182,190,190,190,190,190,190,190,190, - 134,134,134,134,134,134,134,134,142,142,142,142,142,142,142,142, - 150,150,150,150,150,150,150,150,158,158,158,158,158,158,158,158, - 166,166,166,166,166,166,166,166,174,174,174,174,174,174,174,174, - 182,182,182,182,182,182,182,182,190,190,190,190,190,190,190,190, - 7, 7, 7, 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 15, 15, - 23, 23, 23, 23, 23, 23, 23, 23, 31, 31, 31, 31, 31, 31, 31, 31, - 39, 39, 39, 39, 39, 39, 39, 39, 47, 47, 47, 47, 47, 47, 47, 47, - 55, 55, 55, 55, 55, 55, 55, 55, 63, 63, 63, 63, 63, 63, 63, 63, - 7, 7, 7, 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 15, 15, - 23, 23, 23, 23, 23, 23, 23, 23, 31, 31, 31, 31, 31, 31, 31, 31, - 39, 39, 39, 39, 39, 39, 39, 39, 47, 47, 47, 47, 47, 47, 47, 47, - 55, 55, 55, 55, 55, 55, 55, 55, 63, 63, 63, 63, 63, 63, 63, 63, - 131,131,131,131,131,131,131,131,139,139,139,139,139,139,139,139, - 147,147,147,147,147,147,147,147,155,155,155,155,155,155,155,155, - 163,163,163,163,163,163,163,163,171,171,171,171,171,171,171,171, - 179,179,179,179,179,179,179,179,187,187,187,187,187,187,187,187, - 131,131,131,131,131,131,131,131,139,139,139,139,139,139,139,139, - 147,147,147,147,147,147,147,147,155,155,155,155,155,155,155,155, - 163,163,163,163,163,163,163,163,171,171,171,171,171,171,171,171, - 179,179,179,179,179,179,179,179,187,187,187,187,187,187,187,187, -}; - -/* negTable[i] = (((i & 0x0f) != 0) << 4) | ((i == 0x80) << 2) | 2 | (i != 0), i = 0..255 */ -static const uint8 negTable[256] = { - 2,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 7,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, - 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, -}; - -/* rrdrldTable[i] = (i << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) | parityTable[i], i = 0..255 */ -static const uint16 rrdrldTable[256] = { - 0x0044,0x0100,0x0200,0x0304,0x0400,0x0504,0x0604,0x0700, - 0x0808,0x090c,0x0a0c,0x0b08,0x0c0c,0x0d08,0x0e08,0x0f0c, - 0x1000,0x1104,0x1204,0x1300,0x1404,0x1500,0x1600,0x1704, - 0x180c,0x1908,0x1a08,0x1b0c,0x1c08,0x1d0c,0x1e0c,0x1f08, - 0x2020,0x2124,0x2224,0x2320,0x2424,0x2520,0x2620,0x2724, - 0x282c,0x2928,0x2a28,0x2b2c,0x2c28,0x2d2c,0x2e2c,0x2f28, - 0x3024,0x3120,0x3220,0x3324,0x3420,0x3524,0x3624,0x3720, - 0x3828,0x392c,0x3a2c,0x3b28,0x3c2c,0x3d28,0x3e28,0x3f2c, - 0x4000,0x4104,0x4204,0x4300,0x4404,0x4500,0x4600,0x4704, - 0x480c,0x4908,0x4a08,0x4b0c,0x4c08,0x4d0c,0x4e0c,0x4f08, - 0x5004,0x5100,0x5200,0x5304,0x5400,0x5504,0x5604,0x5700, - 0x5808,0x590c,0x5a0c,0x5b08,0x5c0c,0x5d08,0x5e08,0x5f0c, - 0x6024,0x6120,0x6220,0x6324,0x6420,0x6524,0x6624,0x6720, - 0x6828,0x692c,0x6a2c,0x6b28,0x6c2c,0x6d28,0x6e28,0x6f2c, - 0x7020,0x7124,0x7224,0x7320,0x7424,0x7520,0x7620,0x7724, - 0x782c,0x7928,0x7a28,0x7b2c,0x7c28,0x7d2c,0x7e2c,0x7f28, - 0x8080,0x8184,0x8284,0x8380,0x8484,0x8580,0x8680,0x8784, - 0x888c,0x8988,0x8a88,0x8b8c,0x8c88,0x8d8c,0x8e8c,0x8f88, - 0x9084,0x9180,0x9280,0x9384,0x9480,0x9584,0x9684,0x9780, - 0x9888,0x998c,0x9a8c,0x9b88,0x9c8c,0x9d88,0x9e88,0x9f8c, - 0xa0a4,0xa1a0,0xa2a0,0xa3a4,0xa4a0,0xa5a4,0xa6a4,0xa7a0, - 0xa8a8,0xa9ac,0xaaac,0xaba8,0xacac,0xada8,0xaea8,0xafac, - 0xb0a0,0xb1a4,0xb2a4,0xb3a0,0xb4a4,0xb5a0,0xb6a0,0xb7a4, - 0xb8ac,0xb9a8,0xbaa8,0xbbac,0xbca8,0xbdac,0xbeac,0xbfa8, - 0xc084,0xc180,0xc280,0xc384,0xc480,0xc584,0xc684,0xc780, - 0xc888,0xc98c,0xca8c,0xcb88,0xcc8c,0xcd88,0xce88,0xcf8c, - 0xd080,0xd184,0xd284,0xd380,0xd484,0xd580,0xd680,0xd784, - 0xd88c,0xd988,0xda88,0xdb8c,0xdc88,0xdd8c,0xde8c,0xdf88, - 0xe0a0,0xe1a4,0xe2a4,0xe3a0,0xe4a4,0xe5a0,0xe6a0,0xe7a4, - 0xe8ac,0xe9a8,0xeaa8,0xebac,0xeca8,0xedac,0xeeac,0xefa8, - 0xf0a4,0xf1a0,0xf2a0,0xf3a4,0xf4a0,0xf5a4,0xf6a4,0xf7a0, - 0xf8a8,0xf9ac,0xfaac,0xfba8,0xfcac,0xfda8,0xfea8,0xffac, -}; - -/* cpTable[i] = (i & 0x80) | (((i & 0xff) == 0) << 6), i = 0..255 */ -static const uint8 cpTable[256] = { - 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, - 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, -}; - -/* remove comments to generate table contents and define globally NEED_SIM_VM_INIT -static void altairz80_init(void); -void (*sim_vm_init) (void) = &altairz80_init; -static void altairz80_init(void) { -*/ -/* parityTable */ -/* - uint32 i, v; - for (i = 0; i < 256; i++) { - v = ((i & 1) + ((i & 2) >> 1) + ((i & 4) >> 2) + ((i & 8) >> 3) + - ((i & 16) >> 4) + ((i & 32) >> 5) + ((i & 64) >> 6) + ((i & 128) >> 7)) % 2 ? 0 : 4; - printf("%1d,", v); - if ( ((i+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* incTable */ -/* - uint32 temp, v; - for (temp = 0; temp <= 256; temp++) { - v = (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | (((temp & 0xf) == 0) << 4); - printf("%3d,", v); - if ( ((temp+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* decTable */ -/* - uint32 temp, v; - for (temp = 0; temp < 256; temp++) { - v = (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | (((temp & 0xf) == 0xf) << 4) | 2; - printf("%3d,", v); - if ( ((temp+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* cbitsTable */ -/* - uint32 cbits, v; - for (cbits = 0; cbits < 512; cbits++) { - v = (cbits & 0x10) | ((cbits >> 8) & 1); - printf("%2d,", v); - if ( ((cbits+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* cbitsDup8Table */ -/* - uint32 cbits, v; - for (cbits = 0; cbits < 512; cbits++) { - v = (cbits & 0x10) | ((cbits >> 8) & 1) | ((cbits & 0xff) << 8) | (cbits & 0xa8) | (((cbits & 0xff) == 0) << 6); - printf("0x%04x,", v); - if ( ((cbits+1) & 0x7) == 0) { - printf("\n"); - } - } -*/ -/* cbitsDup16Table */ -/* - uint32 cbits, v; - for (cbits = 0; cbits < 512; cbits++) { - v = (cbits & 0x10) | ((cbits >> 8) & 1) | (cbits & 0x28); - printf("%2d,", v); - if ( ((cbits+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* cbits2Table */ -/* - uint32 cbits, v; - for (cbits = 0; cbits < 512; cbits++) { - v = (cbits & 0x10) | ((cbits >> 8) & 1) | 2; - printf("%2d,", v); - if ( ((cbits+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* rrcaTable */ -/* - uint32 temp, sum, v; - for (temp = 0; temp < 256; temp++) { - sum = temp >> 1; - v = ((temp & 1) << 15) | (sum << 8) | (sum & 0x28) | (temp & 1); - printf("0x%04x,", v); - if ( ((temp+1) & 0x7) == 0) { - printf("\n"); - } - } -*/ -/* rraTable */ -/* - uint32 temp, sum, v; - for (temp = 0; temp < 256; temp++) { - sum = temp >> 1; - v = (sum << 8) | (sum & 0x28) | (temp & 1); - printf("0x%04x,", v); - if ( ((temp+1) & 0x7) == 0) { - printf("\n"); - } - } -*/ -/* addTable */ -/* - uint32 sum, v; - for (sum = 0; sum < 512; sum++) { - v = ((sum & 0xff) << 8) | (sum & 0xa8) | (((sum & 0xff) == 0) << 6); - printf("0x%04x,", v); - if ( ((sum+1) & 0x7) == 0) { - printf("\n"); - } - } -*/ -/* subTable */ -/* - uint32 sum, v; - for (sum = 0; sum < 256; sum++) { - v = ((sum & 0xff) << 8) | (sum & 0xa8) | (((sum & 0xff) == 0) << 6) | 2; - printf("0x%04x,", v); - if ( ((sum+1) & 0x7) == 0) { - printf("\n"); - } - } -*/ -/* andTable */ -/* - uint32 sum, v; - for (sum = 0; sum < 256; sum++) { - v = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | 0x10 | parityTable[sum]; - printf("0x%04x,", v); - if ( ((sum+1) & 0x7) == 0) { - printf("\n"); - } - } -*/ -/* xororTable */ -/* - uint32 sum, v; - for (sum = 0; sum < 256; sum++) { - v = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | parityTable[sum]; - printf("0x%04x,", v); - if ( ((sum+1) & 0x7) == 0) { - printf("\n"); - } - } -*/ -/* rotateShiftTable */ -/* - uint32 temp, v; - for (temp = 0; temp < 256; temp++) { - v = (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | PARITY(temp); - printf("%3d,", v); - if ( ((temp+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* incZ80Table */ -/* - uint32 temp, v; - for (temp = 0; temp < 256; temp++) { - v = (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | - (((temp & 0xf) == 0) << 4) | ((temp == 0x80) << 2); - printf("%3d,", v); - if ( ((temp+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* decZ80Table */ -/* - uint32 temp, v; - for (temp = 0; temp < 256; temp++) { - v = (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | - (((temp & 0xf) == 0xf) << 4) | ((temp == 0x7f) << 2) | 2; - printf("%3d,", v); - if ( ((temp+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* cbitsZ80Table */ -/* - uint32 cbits, v; - for (cbits = 0; cbits < 512; cbits++) { - v = (cbits & 0x10) | (((cbits >> 6) ^ (cbits >> 5)) & 4) | - ((cbits >> 8) & 1); - printf("%2d,", v); - if ( ((cbits+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* cbitsZ80DupTable */ -/* - uint32 cbits, v; - for (cbits = 0; cbits < 512; cbits++) { - v = (cbits & 0x10) | (((cbits >> 6) ^ (cbits >> 5)) & 4) | - ((cbits >> 8) & 1) | (cbits & 0xa8); - printf("%3d,", v); - if ( ((cbits+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* cbits2Z80Table */ -/* - uint32 cbits, v; - for (cbits = 0; cbits < 512; cbits++) { - v = (((cbits >> 6) ^ (cbits >> 5)) & 4) | (cbits & 0x10) | 2 | ((cbits >> 8) & 1); - printf("%2d,", v); - if ( ((cbits+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* cbits2Z80DupTable */ -/* - uint32 cbits, v; - for (cbits = 0; cbits < 512; cbits++) { - v = (((cbits >> 6) ^ (cbits >> 5)) & 4) | (cbits & 0x10) | 2 | ((cbits >> 8) & 1) | - (cbits & 0xa8); - printf("%3d,", v); - if ( ((cbits+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* negTable */ -/* - uint32 temp, v; - for (temp = 0; temp < 256; temp++) { - v = (((temp & 0x0f) != 0) << 4) | ((temp == 0x80) << 2) | 2 | (temp != 0); - printf("%2d,", v); - if ( ((temp+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* rrdrldTable */ -/* - uint32 acu, v; - for (acu = 0; acu < 256; acu++) { - v = (acu << 8) | (acu & 0xa8) | (((acu & 0xff) == 0) << 6) | parityTable[acu]; - printf("0x%04x,", v); - if ( ((acu+1) & 0x7) == 0) { - printf("\n"); - } - } -*/ -/* cpTable */ -/* - uint32 sum, v; - for (sum = 0; sum < 256; sum++) { - v = (sum & 0x80) | (((sum & 0xff) == 0) << 6); - printf("%3d,", v); - if ( ((sum+1) & 0xf) == 0) { - printf("\n"); - } - } -*/ -/* remove comments to generate table contents -} -*/ - -/* Memory management */ - -static int32 lowProtect; -static int32 highProtect; -static int32 isProtected = FALSE; - -void protect(const int32 l, const int32 h) { - isProtected = TRUE; - lowProtect = l; - highProtect = h; -} - -static uint8 M[MAXMEMSIZE][MAXBANKS]; /* RAM which is present */ - -/* determine whether Addr points to Read Only Memory */ -static int32 addressIsInROM(const uint32 Addr) { - uint32 addr = Addr & ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ - return (cpu_unit.flags & UNIT_ROM) && ( /* must have ROM enabled */ - /* in banked case we have standard Altair ROM */ - ((cpu_unit.flags & UNIT_BANKED) && (DEFAULT_ROM_LOW <= addr)) || - /* in non-banked case we check the bounds of the ROM */ - (((cpu_unit.flags & UNIT_BANKED) == 0) && (ROMLow <= addr) && (addr <= ROMHigh))); -} - -static void warnUnsuccessfulWriteAttempt(const uint32 Addr) { - if (cpu_unit.flags & UNIT_WARNROM) { - if (addressIsInROM(Addr)) { - MESSAGE_2("Attempt to write to ROM " ADDRESS_FORMAT ".", Addr); - } - else { - MESSAGE_2("Attempt to write to non existing memory " ADDRESS_FORMAT ".", Addr); - } - } -} - -static uint8 warnUnsuccessfulReadAttempt(const uint32 Addr) { - if (cpu_unit.flags & UNIT_WARNROM) { - MESSAGE_2("Attempt to read from non existing memory " ADDRESS_FORMAT ".", Addr); - } - return 0xff; -} - -/* determine whether Addr points to a valid memory address */ -static int32 addressExists(const uint32 Addr) { - uint32 addr = Addr & ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ - return (cpu_unit.flags & UNIT_BANKED) || (addr < MEMSIZE) || - ( ((cpu_unit.flags & UNIT_BANKED) == 0) && (cpu_unit.flags & UNIT_ROM) - && (ROMLow <= addr) && (addr <= ROMHigh) ); -} - -static void PutBYTE(register uint32 Addr, const register uint32 Value) { - Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ - if (cpu_unit.flags & UNIT_BANKED) { - if (Addr < common) { - M[Addr][bankSelect] = Value; - } - else if ((Addr < DEFAULT_ROM_LOW) || ((cpu_unit.flags & UNIT_ROM) == 0)) { - M[Addr][0] = Value; - } - else { - warnUnsuccessfulWriteAttempt(Addr); - } - } - else { - if ((Addr < MEMSIZE) && ((Addr < ROMLow) || (Addr > ROMHigh) || ((cpu_unit.flags & UNIT_ROM) == 0))) { - M[Addr][0] = Value; - } - else { - warnUnsuccessfulWriteAttempt(Addr); - } - } -} - -static void PutWORD(register uint32 Addr, const register uint32 Value) { - Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ - if (cpu_unit.flags & UNIT_BANKED) { - if (Addr < common) { - M[Addr][bankSelect] = Value; - } - else if ((Addr < DEFAULT_ROM_LOW) || ((cpu_unit.flags & UNIT_ROM) == 0)) { - M[Addr][0] = Value; - } - else { - warnUnsuccessfulWriteAttempt(Addr); - } - Addr = (Addr + 1) & ADDRMASK; - if (Addr < common) { - M[Addr][bankSelect] = Value >> 8; - } - else if ((Addr < DEFAULT_ROM_LOW) || ((cpu_unit.flags & UNIT_ROM) == 0)) { - M[Addr][0] = Value >> 8; - } - else { - warnUnsuccessfulWriteAttempt(Addr); - } - } - else { - if ((Addr < MEMSIZE) && ((Addr < ROMLow) || (Addr > ROMHigh) || ((cpu_unit.flags & UNIT_ROM) == 0))) { - M[Addr][0] = Value; - } - else { - warnUnsuccessfulWriteAttempt(Addr); - } - Addr = (Addr + 1) & ADDRMASK; - if ((Addr < MEMSIZE) && ((Addr < ROMLow) || (Addr > ROMHigh) || ((cpu_unit.flags & UNIT_ROM) == 0))) { - M[Addr][0] = Value >> 8; - } - else { - warnUnsuccessfulWriteAttempt(Addr); - } - } -} - -static void PutBYTEForced(uint32 Addr, const uint32 Value) { - Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ - if ((cpu_unit.flags & UNIT_BANKED) && (Addr < common)) { - M[Addr][bankSelect] = Value; - } - else { - M[Addr][0] = Value; - } -} - -void PutBYTEBasic(const uint32 Addr, const uint32 Bank, const uint32 Value) { - M[Addr & ADDRMASK][Bank & BANKMASK] = Value; -} - -int32 install_bootrom(void) { - extern int32 bootrom[BOOTROM_SIZE]; - int32 i, cnt = 0; - for (i = 0; i < BOOTROM_SIZE; i++) { - if (M[i + DEFAULT_ROM_LOW][0] != (bootrom[i] & 0xff)) { - cnt++; - M[i + DEFAULT_ROM_LOW][0] = bootrom[i] & 0xff; - } - } - return cnt; -} - -static void resetCell(const int32 address, const int32 bank) { - if (!(isProtected && (bank == 0) && (lowProtect <= address) && (address <= highProtect))) { - M[address][bank] = 0; - } -} - -/* memory examine */ -t_stat cpu_ex(t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) { - *vptr = M[addr & ADDRMASK][(addr >> 16) & BANKMASK]; - return SCPE_OK; -} - -/* memory deposit */ -t_stat cpu_dep(t_value val, t_addr addr, UNIT *uptr, int32 sw) { - M[addr & ADDRMASK][(addr >> 16) & BANKMASK] = val & 0xff; - return SCPE_OK; -} - -int32 getBankSelect(void) { - return bankSelect; -} - -void setBankSelect(const int32 b) { - bankSelect = b; -} - -uint32 getCommon(void) { - return common; -} - -#define REDUCE(Addr) ((Addr) & ADDRMASK) - -#define GET_BYTE(Addr) \ - ((cpu_unit.flags & UNIT_BANKED) ? \ - (REDUCE(Addr) < common ? \ - M[REDUCE(Addr)][bankSelect] \ - : \ - M[REDUCE(Addr)][0]) \ - : \ - (((REDUCE(Addr) < MEMSIZE) || ( (cpu_unit.flags & UNIT_ROM) && (ROMLow <= REDUCE(Addr)) && (REDUCE(Addr) <= ROMHigh) )) ? \ - M[REDUCE(Addr)][0] \ - : \ - warnUnsuccessfulReadAttempt(REDUCE(Addr)))) - -#define RAM_PP(Addr) \ - ((cpu_unit.flags & UNIT_BANKED) ? \ - (REDUCE(Addr) < common ? \ - M[REDUCE(Addr++)][bankSelect] \ - : \ - M[REDUCE(Addr++)][0]) \ - : \ - (((REDUCE(Addr) < MEMSIZE) || ( (cpu_unit.flags & UNIT_ROM) && (ROMLow <= REDUCE(Addr)) && (REDUCE(Addr) <= ROMHigh) )) ? \ - M[REDUCE(Addr++)][0] \ - : \ - warnUnsuccessfulReadAttempt(REDUCE(Addr++)))) - -#define RAM_MM(Addr) \ - ((cpu_unit.flags & UNIT_BANKED) ? \ - (REDUCE(Addr) < common ? \ - M[REDUCE(Addr--)][bankSelect] \ - : \ - M[REDUCE(Addr--)][0]) \ - : \ - (((REDUCE(Addr) < MEMSIZE) || ( (cpu_unit.flags & UNIT_ROM) && (ROMLow <= REDUCE(Addr)) && (REDUCE(Addr) <= ROMHigh) )) ? \ - M[REDUCE(Addr--)][0] \ - : \ - warnUnsuccessfulReadAttempt(REDUCE(Addr--)))) - -#define GET_WORD(Addr) (GET_BYTE(Addr) | (GET_BYTE(Addr + 1) << 8)) - -uint8 GetBYTEWrapper(const uint32 Addr) { - return GET_BYTE(Addr); -} - -void PutBYTEWrapper(const uint32 Addr, const uint32 Value) { - PutBYTE(Addr, Value); -} - -#define PUT_BYTE_PP(a,v) PutBYTE(a++, v) -#define PUT_BYTE_MM(a,v) PutBYTE(a--, v) -#define MM_PUT_BYTE(a,v) PutBYTE(--a, v) - -#define MASK_BRK (TRUE + 1) - -/* this is a modified version of sim_brk_test with two differences: - 1) is does not set sim_brk_pend to FALSE (this is left to the instruction decode) - 2) it returns MASK_BRK if a breakpoint is found but should be ignored -*/ -static int32 sim_brk_lookup (const t_addr loc, const int32 btyp) { - extern t_bool sim_brk_pend[SIM_BKPT_N_SPC]; - extern t_addr sim_brk_ploc[SIM_BKPT_N_SPC]; - extern char *sim_brk_act; - BRKTAB *bp; - if ((bp = sim_brk_fnd (loc)) && /* entry in table? */ - (btyp & bp -> typ) && /* type match? */ - (!sim_brk_pend[0] || (loc != sim_brk_ploc[0])) && /* new location? */ - (--(bp -> cnt) <= 0)) { /* count reach 0? */ - bp -> cnt = 0; /* reset count */ - sim_brk_ploc[0] = loc; /* save location */ - sim_brk_act = bp -> act; /* set up actions */ - sim_brk_pend[0] = TRUE; /* don't do twice */ - return TRUE; - } - return (sim_brk_pend[0] && (loc == sim_brk_ploc[0])) ? MASK_BRK : FALSE; -} - -static void prepareMemoryAccessMessage(t_addr loc) { - extern char memoryAccessMessage[]; - sprintf(memoryAccessMessage, "Memory access breakpoint [%04xh]", loc); -} - -#define PUSH(x) { \ - MM_PUT_BYTE(SP, (x) >> 8); \ - MM_PUT_BYTE(SP, x); \ -} - -#define CHECK_BREAK_BYTE(a) \ - if (sim_brk_summ && sim_brk_test(a & 0xffff, SWMASK('M'))) {\ - reason = STOP_MEM; \ - prepareMemoryAccessMessage(a & 0xffff); \ - goto end_decode; \ - } - -#define CHECK_BREAK_TWO_BYTES_EXTENDED(a1, a2, iCode) \ - if (sim_brk_summ) { \ - br1 = sim_brk_lookup(a1 & 0xffff, SWMASK('M')); \ - br2 = br1 ? FALSE : sim_brk_lookup(a2 & 0xffff, SWMASK('M'));\ - if ((br1 == MASK_BRK) || (br2 == MASK_BRK)) { \ - sim_brk_pend[0] = FALSE; \ - } \ - else if (br1 || br2) { \ - reason = STOP_MEM; \ - if (br1) { \ - prepareMemoryAccessMessage(a1 & 0xffff); \ - } \ - else { \ - prepareMemoryAccessMessage(a2 & 0xffff); \ - } \ - iCode; \ - goto end_decode; \ - } \ - else { \ - sim_brk_pend[0] = FALSE; \ - } \ - } - -#define CHECK_BREAK_TWO_BYTES(a1, a2) CHECK_BREAK_TWO_BYTES_EXTENDED(a1, a2,;) - -#define CHECK_BREAK_WORD(a) CHECK_BREAK_TWO_BYTES(a, (a + 1)) - -t_stat sim_instr (void) { - extern int32 sim_interval; - extern t_bool sim_brk_pend[SIM_BKPT_N_SPC]; - extern int32 timerInterrupt; - extern int32 timerInterruptHandler; - extern uint32 sim_os_msec(void); - extern t_bool rtc_avail; - extern uint32 sim_brk_summ; - int32 reason = 0; - register uint32 specialProcessing; - register uint32 AF; - register uint32 BC; - register uint32 DE; - register uint32 HL; - register uint32 PC; - register uint32 SP; - register uint32 IX; - register uint32 IY; - register uint32 temp = 0; - register uint32 acu = 0; - register uint32 sum; - register uint32 cbits; - register uint32 op; - register uint32 adr; - /* tStates contains the number of t-states executed. One t-state is executed - in one microsecond on a 1MHz CPU. tStates is used for real-time simulations. */ - register uint32 tStates; - uint32 tStatesInSlice; /* number of t-states in 10 mSec time-slice */ - uint32 startTime, now; - int32 br1, br2, tStateModifier = FALSE; - - AF = AF_S; - BC = BC_S; - DE = DE_S; - HL = HL_S; - PC = saved_PC & ADDRMASK; - SP = SP_S; - IX = IX_S; - IY = IY_S; - specialProcessing = clockFrequency | timerInterrupt | sim_brk_summ; - tStates = 0; - if (rtc_avail) { - startTime = sim_os_msec(); - tStatesInSlice = sliceLength*clockFrequency; - } - else { /* make sure that sim_os_msec() is not called later */ - clockFrequency = startTime = tStatesInSlice = 0; - } - - /* main instruction fetch/decode loop */ - while (TRUE) { /* loop until halted */ - if (sim_interval <= 0) { /* check clock queue */ -#if !UNIX_PLATFORM - if ((reason = sim_poll_kbd()) == SCPE_STOP) { /* poll on platforms without reliable signalling */ - break; - } -#endif - if ( (reason = sim_process_event()) ) { - break; - } - else { - specialProcessing = clockFrequency | timerInterrupt | sim_brk_summ; - } - } - - if (specialProcessing) { /* quick check for special processing */ - if (clockFrequency && (tStates >= tStatesInSlice)) { - /* clockFrequency != 0 implies that real time clock is available */ - startTime += sliceLength; - tStates -= tStatesInSlice; - if (startTime > (now = sim_os_msec())) { -#if defined (_WIN32) - Sleep(startTime - now); -#else - usleep(1000 * (startTime - now)); -#endif - } - } - - if (timerInterrupt && (IFF_S & 1)) { - timerInterrupt = FALSE; - specialProcessing = clockFrequency | sim_brk_summ; - IFF_S = 0; /* disable interrupts */ - CHECK_BREAK_TWO_BYTES_EXTENDED(SP - 2, SP - 1, (timerInterrupt = TRUE, IFF_S |= 1)); - PUSH(PC); - PCQ_ENTRY(PC - 1); - PC = timerInterruptHandler & ADDRMASK; - } - - if (sim_brk_summ && (sim_brk_lookup(PC, SWMASK('E')) == TRUE)) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - break; - } - } - - PCX = PC; - sim_interval--; - - /* make sure that each instructions properly sets sim_brk_pend: - 1) Either directly to FALSE if no memory access takes place or - 2) through a call to a Check... routine - */ - switch(RAM_PP(PC)) { - - case 0x00: /* NOP */ - tStates += 4; - sim_brk_pend[0] = FALSE; - break; - - case 0x01: /* LD BC,nnnn */ - tStates += 10; - sim_brk_pend[0] = FALSE; - BC = GET_WORD(PC); - PC += 2; - break; - - case 0x02: /* LD (BC),A */ - tStates += 7; - CHECK_BREAK_BYTE(BC) - PutBYTE(BC, HIGH_REGISTER(AF)); - break; - - case 0x03: /* INC BC */ - tStates += 6; - sim_brk_pend[0] = FALSE; - ++BC; - break; - - case 0x04: /* INC B */ - tStates += 4; - sim_brk_pend[0] = FALSE; - BC += 0x100; - temp = HIGH_REGISTER(BC); - AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); /* SET_PV2 uses temp */ - break; - - case 0x05: /* DEC B */ - tStates += 4; - sim_brk_pend[0] = FALSE; - BC -= 0x100; - temp = HIGH_REGISTER(BC); - AF = (AF & ~0xfe) | decTable[temp] | SET_PV2(0x7f); /* SET_PV2 uses temp */ - break; - - case 0x06: /* LD B,nn */ - tStates += 7; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(BC, RAM_PP(PC)); - break; - - case 0x07: /* RLCA */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = ((AF >> 7) & 0x0128) | ((AF << 1) & ~0x1ff) | - (AF & 0xc4) | ((AF >> 15) & 1); - break; - - case 0x08: /* EX AF,AF' */ - tStates += 4; - sim_brk_pend[0] = FALSE; - CHECK_CPU_8080; - temp = AF; - AF = AF1_S; - AF1_S = temp; - break; - - case 0x09: /* ADD HL,BC */ - tStates += 11; - sim_brk_pend[0] = FALSE; - HL &= ADDRMASK; - BC &= ADDRMASK; - sum = HL + BC; - AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(HL ^ BC ^ sum) >> 8]; - HL = sum; - break; - - case 0x0a: /* LD A,(BC) */ - tStates += 7; - CHECK_BREAK_BYTE(BC) - SET_HIGH_REGISTER(AF, GET_BYTE(BC)); - break; - - case 0x0b: /* DEC BC */ - tStates += 6; - sim_brk_pend[0] = FALSE; - --BC; - break; - - case 0x0c: /* INC C */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(BC) + 1; - SET_LOW_REGISTER(BC, temp); - AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); - break; - - case 0x0d: /* DEC C */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(BC) - 1; - SET_LOW_REGISTER(BC, temp); - AF = (AF & ~0xfe) | decTable[temp & 0xff] | SET_PV2(0x7f); - break; - - case 0x0e: /* LD C,nn */ - tStates += 7; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(BC, RAM_PP(PC)); - break; - - case 0x0f: /* RRCA */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = (AF & 0xc4) | rrcaTable[HIGH_REGISTER(AF)]; - break; - - case 0x10: /* DJNZ dd */ - sim_brk_pend[0] = FALSE; - CHECK_CPU_8080; - if ((BC -= 0x100) & 0xff00) { - PCQ_ENTRY(PC - 1); - PC += (int8) GET_BYTE(PC) + 1; - tStates += 13; - } - else { - PC++; - tStates += 8; - } - break; - - case 0x11: /* LD DE,nnnn */ - tStates += 10; - sim_brk_pend[0] = FALSE; - DE = GET_WORD(PC); - PC += 2; - break; - - case 0x12: /* LD (DE),A */ - tStates += 7; - CHECK_BREAK_BYTE(DE) - PutBYTE(DE, HIGH_REGISTER(AF)); - break; - - case 0x13: /* INC DE */ - tStates += 6; - sim_brk_pend[0] = FALSE; - ++DE; - break; - - case 0x14: /* INC D */ - tStates += 4; - sim_brk_pend[0] = FALSE; - DE += 0x100; - temp = HIGH_REGISTER(DE); - AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); /* SET_PV2 uses temp */ - break; - - case 0x15: /* DEC D */ - tStates += 4; - sim_brk_pend[0] = FALSE; - DE -= 0x100; - temp = HIGH_REGISTER(DE); - AF = (AF & ~0xfe) | decTable[temp] | SET_PV2(0x7f); /* SET_PV2 uses temp */ - break; - - case 0x16: /* LD D,nn */ - tStates += 7; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(DE, RAM_PP(PC)); - break; - - case 0x17: /* RLA */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = ((AF << 8) & 0x0100) | ((AF >> 7) & 0x28) | ((AF << 1) & ~0x01ff) | - (AF & 0xc4) | ((AF >> 15) & 1); - break; - - case 0x18: /* JR dd */ - tStates += 12; - sim_brk_pend[0] = FALSE; - CHECK_CPU_8080; - PCQ_ENTRY(PC - 1); - PC += (int8) GET_BYTE(PC) + 1; - break; - - case 0x19: /* ADD HL,DE */ - tStates += 11; - sim_brk_pend[0] = FALSE; - HL &= ADDRMASK; - DE &= ADDRMASK; - sum = HL + DE; - AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(HL ^ DE ^ sum) >> 8]; - HL = sum; - break; - - case 0x1a: /* LD A,(DE) */ - tStates += 7; - CHECK_BREAK_BYTE(DE) - SET_HIGH_REGISTER(AF, GET_BYTE(DE)); - break; - - case 0x1b: /* DEC DE */ - tStates += 6; - sim_brk_pend[0] = FALSE; - --DE; - break; - - case 0x1c: /* INC E */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(DE) + 1; - SET_LOW_REGISTER(DE, temp); - AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); - break; - - case 0x1d: /* DEC E */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(DE) - 1; - SET_LOW_REGISTER(DE, temp); - AF = (AF & ~0xfe) | decTable[temp & 0xff] | SET_PV2(0x7f); - break; - - case 0x1e: /* LD E,nn */ - tStates += 7; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(DE, RAM_PP(PC)); - break; - - case 0x1f: /* RRA */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = ((AF & 1) << 15) | (AF & 0xc4) | rraTable[HIGH_REGISTER(AF)]; - break; - - case 0x20: /* JR NZ,dd */ - sim_brk_pend[0] = FALSE; - CHECK_CPU_8080; - if (TSTFLAG(Z)) { - PC++; - tStates += 7; - } - else { - PCQ_ENTRY(PC - 1); - PC += (int8) GET_BYTE(PC) + 1; - tStates += 12; - } - break; - - case 0x21: /* LD HL,nnnn */ - tStates += 10; - sim_brk_pend[0] = FALSE; - HL = GET_WORD(PC); - PC += 2; - break; - - case 0x22: /* LD (nnnn),HL */ - tStates += 16; - temp = GET_WORD(PC); - CHECK_BREAK_WORD(temp); - PutWORD(temp, HL); - PC += 2; - break; - - case 0x23: /* INC HL */ - tStates += 6; - sim_brk_pend[0] = FALSE; - ++HL; - break; - - case 0x24: /* INC H */ - tStates += 4; - sim_brk_pend[0] = FALSE; - HL += 0x100; - temp = HIGH_REGISTER(HL); - AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); /* SET_PV2 uses temp */ - break; - - case 0x25: /* DEC H */ - tStates += 4; - sim_brk_pend[0] = FALSE; - HL -= 0x100; - temp = HIGH_REGISTER(HL); - AF = (AF & ~0xfe) | decTable[temp] | SET_PV2(0x7f); /* SET_PV2 uses temp */ - break; - - case 0x26: /* LD H,nn */ - tStates += 7; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(HL, RAM_PP(PC)); - break; - - case 0x27: /* DAA */ - tStates += 4; - sim_brk_pend[0] = FALSE; - acu = HIGH_REGISTER(AF); - temp = LOW_DIGIT(acu); - cbits = TSTFLAG(C); - if (TSTFLAG(N)) { /* last operation was a subtract */ - int hd = cbits || acu > 0x99; - if (TSTFLAG(H) || (temp > 9)) { /* adjust low digit */ - if (temp > 5) { - SETFLAG(H, 0); - } - acu -= 6; - acu &= 0xff; - } - if (hd) { /* adjust high digit */ - acu -= 0x160; - } - } - else { /* last operation was an add */ - if (TSTFLAG(H) || (temp > 9)) { /* adjust low digit */ - SETFLAG(H, (temp > 9)); - acu += 6; - } - if (cbits || ((acu & 0x1f0) > 0x90)) { /* adjust high digit */ - acu += 0x60; - } - } - AF = (AF & 0x12) | rrdrldTable[acu & 0xff] | ((acu >> 8) & 1) | cbits; - break; - - case 0x28: /* JR Z,dd */ - sim_brk_pend[0] = FALSE; - CHECK_CPU_8080; - if (TSTFLAG(Z)) { - PCQ_ENTRY(PC - 1); - PC += (int8) GET_BYTE(PC) + 1; - tStates += 12; - } - else { - PC++; - tStates += 7; - } - break; - - case 0x29: /* ADD HL,HL */ - tStates += 11; - sim_brk_pend[0] = FALSE; - HL &= ADDRMASK; - sum = HL + HL; - AF = (AF & ~0x3b) | cbitsDup16Table[sum >> 8]; - HL = sum; - break; - - case 0x2a: /* LD HL,(nnnn) */ - tStates += 16; - temp = GET_WORD(PC); - CHECK_BREAK_WORD(temp); - HL = GET_WORD(temp); - PC += 2; - break; - - case 0x2b: /* DEC HL */ - tStates += 6; - sim_brk_pend[0] = FALSE; - --HL; - break; - - case 0x2c: /* INC L */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(HL) + 1; - SET_LOW_REGISTER(HL, temp); - AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); - break; - - case 0x2d: /* DEC L */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(HL) - 1; - SET_LOW_REGISTER(HL, temp); - AF = (AF & ~0xfe) | decTable[temp & 0xff] | SET_PV2(0x7f); - break; - - case 0x2e: /* LD L,nn */ - tStates += 7; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(HL, RAM_PP(PC)); - break; - - case 0x2f: /* CPL */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = (~AF & ~0xff) | (AF & 0xc5) | ((~AF >> 8) & 0x28) | 0x12; - break; - - case 0x30: /* JR NC,dd */ - sim_brk_pend[0] = FALSE; - CHECK_CPU_8080; - if (TSTFLAG(C)) { - PC++; - tStates += 7; - } - else { - PCQ_ENTRY(PC - 1); - PC += (int8) GET_BYTE(PC) + 1; - tStates += 12; - } - break; - - case 0x31: /* LD SP,nnnn */ - tStates += 10; - sim_brk_pend[0] = FALSE; - SP = GET_WORD(PC); - PC += 2; - break; - - case 0x32: /* LD (nnnn),A */ - tStates += 13; - temp = GET_WORD(PC); - CHECK_BREAK_BYTE(temp); - PutBYTE(temp, HIGH_REGISTER(AF)); - PC += 2; - break; - - case 0x33: /* INC SP */ - tStates += 6; - sim_brk_pend[0] = FALSE; - ++SP; - break; - - case 0x34: /* INC (HL) */ - tStates += 11; - CHECK_BREAK_BYTE(HL); - temp = GET_BYTE(HL) + 1; - PutBYTE(HL, temp); - AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); - break; - - case 0x35: /* DEC (HL) */ - tStates += 11; - CHECK_BREAK_BYTE(HL); - temp = GET_BYTE(HL) - 1; - PutBYTE(HL, temp); - AF = (AF & ~0xfe) | decTable[temp & 0xff] | SET_PV2(0x7f); - break; - - case 0x36: /* LD (HL),nn */ - tStates += 10; - CHECK_BREAK_BYTE(HL); - PutBYTE(HL, RAM_PP(PC)); - break; - - case 0x37: /* SCF */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = (AF & ~0x3b) | ((AF >> 8) & 0x28) | 1; - break; - - case 0x38: /* JR C,dd */ - sim_brk_pend[0] = FALSE; - CHECK_CPU_8080; - if (TSTFLAG(C)) { - PCQ_ENTRY(PC - 1); - PC += (int8) GET_BYTE(PC) + 1; - tStates += 12; - } - else { - PC++; - tStates += 7; - } - break; - - case 0x39: /* ADD HL,SP */ - tStates += 11; - sim_brk_pend[0] = FALSE; - HL &= ADDRMASK; - SP &= ADDRMASK; - sum = HL + SP; - AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(HL ^ SP ^ sum) >> 8]; - HL = sum; - break; - - case 0x3a: /* LD A,(nnnn) */ - tStates += 13; - temp = GET_WORD(PC); - CHECK_BREAK_BYTE(temp); - SET_HIGH_REGISTER(AF, GET_BYTE(temp)); - PC += 2; - break; - - case 0x3b: /* DEC SP */ - tStates += 6; - sim_brk_pend[0] = FALSE; - --SP; - break; - - case 0x3c: /* INC A */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF += 0x100; - temp = HIGH_REGISTER(AF); - AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); /* SET_PV2 uses temp */ - break; - - case 0x3d: /* DEC A */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF -= 0x100; - temp = HIGH_REGISTER(AF); - AF = (AF & ~0xfe) | decTable[temp] | SET_PV2(0x7f); /* SET_PV2 uses temp */ - break; - - case 0x3e: /* LD A,nn */ - tStates += 7; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(AF, RAM_PP(PC)); - break; - - case 0x3f: /* CCF */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = (AF & ~0x3b) | ((AF >> 8) & 0x28) | ((AF & 1) << 4) | (~AF & 1); - break; - - case 0x40: /* LD B,B */ - tStates += 4; - sim_brk_pend[0] = FALSE; /* nop */ - break; - - case 0x41: /* LD B,C */ - tStates += 4; - sim_brk_pend[0] = FALSE; - BC = (BC & 0xff) | ((BC & 0xff) << 8); - break; - - case 0x42: /* LD B,D */ - tStates += 4; - sim_brk_pend[0] = FALSE; - BC = (BC & 0xff) | (DE & ~0xff); - break; - - case 0x43: /* LD B,E */ - tStates += 4; - sim_brk_pend[0] = FALSE; - BC = (BC & 0xff) | ((DE & 0xff) << 8); - break; - - case 0x44: /* LD B,H */ - tStates += 4; - sim_brk_pend[0] = FALSE; - BC = (BC & 0xff) | (HL & ~0xff); - break; - - case 0x45: /* LD B,L */ - tStates += 4; - sim_brk_pend[0] = FALSE; - BC = (BC & 0xff) | ((HL & 0xff) << 8); - break; - - case 0x46: /* LD B,(HL) */ - tStates += 7; - CHECK_BREAK_BYTE(HL); - SET_HIGH_REGISTER(BC, GET_BYTE(HL)); - break; - - case 0x47: /* LD B,A */ - tStates += 4; - sim_brk_pend[0] = FALSE; - BC = (BC & 0xff) | (AF & ~0xff); - break; - - case 0x48: /* LD C,B */ - tStates += 4; - sim_brk_pend[0] = FALSE; - BC = (BC & ~0xff) | ((BC >> 8) & 0xff); - break; - - case 0x49: /* LD C,C */ - tStates += 4; - sim_brk_pend[0] = FALSE; /* nop */ - break; - - case 0x4a: /* LD C,D */ - tStates += 4; - sim_brk_pend[0] = FALSE; - BC = (BC & ~0xff) | ((DE >> 8) & 0xff); - break; - - case 0x4b: /* LD C,E */ - tStates += 4; - sim_brk_pend[0] = FALSE; - BC = (BC & ~0xff) | (DE & 0xff); - break; - - case 0x4c: /* LD C,H */ - tStates += 4; - sim_brk_pend[0] = FALSE; - BC = (BC & ~0xff) | ((HL >> 8) & 0xff); - break; - - case 0x4d: /* LD C,L */ - tStates += 4; - sim_brk_pend[0] = FALSE; - BC = (BC & ~0xff) | (HL & 0xff); - break; - - case 0x4e: /* LD C,(HL) */ - tStates += 7; - CHECK_BREAK_BYTE(HL); - SET_LOW_REGISTER(BC, GET_BYTE(HL)); - break; - - case 0x4f: /* LD C,A */ - tStates += 4; - sim_brk_pend[0] = FALSE; - BC = (BC & ~0xff) | ((AF >> 8) & 0xff); - break; - - case 0x50: /* LD D,B */ - tStates += 4; - sim_brk_pend[0] = FALSE; - DE = (DE & 0xff) | (BC & ~0xff); - break; - - case 0x51: /* LD D,C */ - tStates += 4; - sim_brk_pend[0] = FALSE; - DE = (DE & 0xff) | ((BC & 0xff) << 8); - break; - - case 0x52: /* LD D,D */ - tStates += 4; - sim_brk_pend[0] = FALSE; /* nop */ - break; - - case 0x53: /* LD D,E */ - tStates += 4; - sim_brk_pend[0] = FALSE; - DE = (DE & 0xff) | ((DE & 0xff) << 8); - break; - - case 0x54: /* LD D,H */ - tStates += 4; - sim_brk_pend[0] = FALSE; - DE = (DE & 0xff) | (HL & ~0xff); - break; - - case 0x55: /* LD D,L */ - tStates += 4; - sim_brk_pend[0] = FALSE; - DE = (DE & 0xff) | ((HL & 0xff) << 8); - break; - - case 0x56: /* LD D,(HL) */ - tStates += 7; - CHECK_BREAK_BYTE(HL); - SET_HIGH_REGISTER(DE, GET_BYTE(HL)); - break; - - case 0x57: /* LD D,A */ - tStates += 4; - sim_brk_pend[0] = FALSE; - DE = (DE & 0xff) | (AF & ~0xff); - break; - - case 0x58: /* LD E,B */ - tStates += 4; - sim_brk_pend[0] = FALSE; - DE = (DE & ~0xff) | ((BC >> 8) & 0xff); - break; - - case 0x59: /* LD E,C */ - tStates += 4; - sim_brk_pend[0] = FALSE; - DE = (DE & ~0xff) | (BC & 0xff); - break; - - case 0x5a: /* LD E,D */ - tStates += 4; - sim_brk_pend[0] = FALSE; - DE = (DE & ~0xff) | ((DE >> 8) & 0xff); - break; - - case 0x5b: /* LD E,E */ - tStates += 4; - sim_brk_pend[0] = FALSE; /* nop */ - break; - - case 0x5c: /* LD E,H */ - tStates += 4; - sim_brk_pend[0] = FALSE; - DE = (DE & ~0xff) | ((HL >> 8) & 0xff); - break; - - case 0x5d: /* LD E,L */ - tStates += 4; - sim_brk_pend[0] = FALSE; - DE = (DE & ~0xff) | (HL & 0xff); - break; - - case 0x5e: /* LD E,(HL) */ - tStates += 7; - CHECK_BREAK_BYTE(HL); - SET_LOW_REGISTER(DE, GET_BYTE(HL)); - break; - - case 0x5f: /* LD E,A */ - tStates += 4; - sim_brk_pend[0] = FALSE; - DE = (DE & ~0xff) | ((AF >> 8) & 0xff); - break; - - case 0x60: /* LD H,B */ - tStates += 4; - sim_brk_pend[0] = FALSE; - HL = (HL & 0xff) | (BC & ~0xff); - break; - - case 0x61: /* LD H,C */ - tStates += 4; - sim_brk_pend[0] = FALSE; - HL = (HL & 0xff) | ((BC & 0xff) << 8); - break; - - case 0x62: /* LD H,D */ - tStates += 4; - sim_brk_pend[0] = FALSE; - HL = (HL & 0xff) | (DE & ~0xff); - break; - - case 0x63: /* LD H,E */ - tStates += 4; - sim_brk_pend[0] = FALSE; - HL = (HL & 0xff) | ((DE & 0xff) << 8); - break; - - case 0x64: /* LD H,H */ - tStates += 4; - sim_brk_pend[0] = FALSE; /* nop */ - break; - - case 0x65: /* LD H,L */ - tStates += 4; - sim_brk_pend[0] = FALSE; - HL = (HL & 0xff) | ((HL & 0xff) << 8); - break; - - case 0x66: /* LD H,(HL) */ - tStates += 7; - CHECK_BREAK_BYTE(HL); - SET_HIGH_REGISTER(HL, GET_BYTE(HL)); - break; - - case 0x67: /* LD H,A */ - tStates += 4; - sim_brk_pend[0] = FALSE; - HL = (HL & 0xff) | (AF & ~0xff); - break; - - case 0x68: /* LD L,B */ - tStates += 4; - sim_brk_pend[0] = FALSE; - HL = (HL & ~0xff) | ((BC >> 8) & 0xff); - break; - - case 0x69: /* LD L,C */ - tStates += 4; - sim_brk_pend[0] = FALSE; - HL = (HL & ~0xff) | (BC & 0xff); - break; - - case 0x6a: /* LD L,D */ - tStates += 4; - sim_brk_pend[0] = FALSE; - HL = (HL & ~0xff) | ((DE >> 8) & 0xff); - break; - - case 0x6b: /* LD L,E */ - tStates += 4; - sim_brk_pend[0] = FALSE; - HL = (HL & ~0xff) | (DE & 0xff); - break; - - case 0x6c: /* LD L,H */ - tStates += 4; - sim_brk_pend[0] = FALSE; - HL = (HL & ~0xff) | ((HL >> 8) & 0xff); - break; - - case 0x6d: /* LD L,L */ - tStates += 4; - sim_brk_pend[0] = FALSE; /* nop */ - break; - - case 0x6e: /* LD L,(HL) */ - tStates += 7; - CHECK_BREAK_BYTE(HL); - SET_LOW_REGISTER(HL, GET_BYTE(HL)); - break; - - case 0x6f: /* LD L,A */ - tStates += 4; - sim_brk_pend[0] = FALSE; - HL = (HL & ~0xff) | ((AF >> 8) & 0xff); - break; - - case 0x70: /* LD (HL),B */ - tStates += 7; - CHECK_BREAK_BYTE(HL); - PutBYTE(HL, HIGH_REGISTER(BC)); - break; - - case 0x71: /* LD (HL),C */ - tStates += 7; - CHECK_BREAK_BYTE(HL); - PutBYTE(HL, LOW_REGISTER(BC)); - break; - - case 0x72: /* LD (HL),D */ - tStates += 7; - CHECK_BREAK_BYTE(HL); - PutBYTE(HL, HIGH_REGISTER(DE)); - break; - - case 0x73: /* LD (HL),E */ - tStates += 7; - CHECK_BREAK_BYTE(HL); - PutBYTE(HL, LOW_REGISTER(DE)); - break; - - case 0x74: /* LD (HL),H */ - tStates += 7; - CHECK_BREAK_BYTE(HL); - PutBYTE(HL, HIGH_REGISTER(HL)); - break; - - case 0x75: /* LD (HL),L */ - tStates += 7; - CHECK_BREAK_BYTE(HL); - PutBYTE(HL, LOW_REGISTER(HL)); - break; - - case 0x76: /* HALT */ - tStates += 4; - sim_brk_pend[0] = FALSE; - reason = STOP_HALT; - PC--; - goto end_decode; - - case 0x77: /* LD (HL),A */ - tStates += 7; - CHECK_BREAK_BYTE(HL); - PutBYTE(HL, HIGH_REGISTER(AF)); - break; - - case 0x78: /* LD A,B */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = (AF & 0xff) | (BC & ~0xff); - break; - - case 0x79: /* LD A,C */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = (AF & 0xff) | ((BC & 0xff) << 8); - break; - - case 0x7a: /* LD A,D */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = (AF & 0xff) | (DE & ~0xff); - break; - - case 0x7b: /* LD A,E */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = (AF & 0xff) | ((DE & 0xff) << 8); - break; - - case 0x7c: /* LD A,H */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = (AF & 0xff) | (HL & ~0xff); - break; - - case 0x7d: /* LD A,L */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = (AF & 0xff) | ((HL & 0xff) << 8); - break; - - case 0x7e: /* LD A,(HL) */ - tStates += 7; - CHECK_BREAK_BYTE(HL); - SET_HIGH_REGISTER(AF, GET_BYTE(HL)); - break; - - case 0x7f: /* LD A,A */ - tStates += 4; - sim_brk_pend[0] = FALSE; /* nop */ - break; - - case 0x80: /* ADD A,B */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = HIGH_REGISTER(BC); - acu = HIGH_REGISTER(AF); - sum = acu + temp; - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); - break; - - case 0x81: /* ADD A,C */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(BC); - acu = HIGH_REGISTER(AF); - sum = acu + temp; - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); - break; - - case 0x82: /* ADD A,D */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = HIGH_REGISTER(DE); - acu = HIGH_REGISTER(AF); - sum = acu + temp; - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); - break; - - case 0x83: /* ADD A,E */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(DE); - acu = HIGH_REGISTER(AF); - sum = acu + temp; - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); - break; - - case 0x84: /* ADD A,H */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = HIGH_REGISTER(HL); - acu = HIGH_REGISTER(AF); - sum = acu + temp; - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); - break; - - case 0x85: /* ADD A,L */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(HL); - acu = HIGH_REGISTER(AF); - sum = acu + temp; - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); - break; - - case 0x86: /* ADD A,(HL) */ - tStates += 7; - CHECK_BREAK_BYTE(HL); - temp = GET_BYTE(HL); - acu = HIGH_REGISTER(AF); - sum = acu + temp; - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); - break; - - case 0x87: /* ADD A,A */ - tStates += 4; - sim_brk_pend[0] = FALSE; - cbits = 2 * HIGH_REGISTER(AF); - AF = cbitsDup8Table[cbits] | (SET_PVS(cbits)); - break; - - case 0x88: /* ADC A,B */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = HIGH_REGISTER(BC); - acu = HIGH_REGISTER(AF); - sum = acu + temp + TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); - break; - - case 0x89: /* ADC A,C */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(BC); - acu = HIGH_REGISTER(AF); - sum = acu + temp + TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); - break; - - case 0x8a: /* ADC A,D */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = HIGH_REGISTER(DE); - acu = HIGH_REGISTER(AF); - sum = acu + temp + TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); - break; - - case 0x8b: /* ADC A,E */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(DE); - acu = HIGH_REGISTER(AF); - sum = acu + temp + TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); - break; - - case 0x8c: /* ADC A,H */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = HIGH_REGISTER(HL); - acu = HIGH_REGISTER(AF); - sum = acu + temp + TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); - break; - - case 0x8d: /* ADC A,L */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(HL); - acu = HIGH_REGISTER(AF); - sum = acu + temp + TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); - break; - - case 0x8e: /* ADC A,(HL) */ - tStates += 7; - CHECK_BREAK_BYTE(HL); - temp = GET_BYTE(HL); - acu = HIGH_REGISTER(AF); - sum = acu + temp + TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); - break; - - case 0x8f: /* ADC A,A */ - tStates += 4; - sim_brk_pend[0] = FALSE; - cbits = 2 * HIGH_REGISTER(AF) + TSTFLAG(C); - AF = cbitsDup8Table[cbits] | (SET_PVS(cbits)); - break; - - case 0x90: /* SUB B */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = HIGH_REGISTER(BC); - acu = HIGH_REGISTER(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); - break; - - case 0x91: /* SUB C */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(BC); - acu = HIGH_REGISTER(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); - break; - - case 0x92: /* SUB D */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = HIGH_REGISTER(DE); - acu = HIGH_REGISTER(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); - break; - - case 0x93: /* SUB E */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(DE); - acu = HIGH_REGISTER(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); - break; - - case 0x94: /* SUB H */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = HIGH_REGISTER(HL); - acu = HIGH_REGISTER(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); - break; - - case 0x95: /* SUB L */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(HL); - acu = HIGH_REGISTER(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); - break; - - case 0x96: /* SUB (HL) */ - tStates += 7; - CHECK_BREAK_BYTE(HL); - temp = GET_BYTE(HL); - acu = HIGH_REGISTER(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); - break; - - case 0x97: /* SUB A */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = cpu_unit.flags & UNIT_CHIP ? 0x42 : 0x46; - break; - - case 0x98: /* SBC A,B */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = HIGH_REGISTER(BC); - acu = HIGH_REGISTER(AF); - sum = acu - temp - TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); - break; - - case 0x99: /* SBC A,C */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(BC); - acu = HIGH_REGISTER(AF); - sum = acu - temp - TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); - break; - - case 0x9a: /* SBC A,D */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = HIGH_REGISTER(DE); - acu = HIGH_REGISTER(AF); - sum = acu - temp - TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); - break; - - case 0x9b: /* SBC A,E */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(DE); - acu = HIGH_REGISTER(AF); - sum = acu - temp - TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); - break; - - case 0x9c: /* SBC A,H */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = HIGH_REGISTER(HL); - acu = HIGH_REGISTER(AF); - sum = acu - temp - TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); - break; - - case 0x9d: /* SBC A,L */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(HL); - acu = HIGH_REGISTER(AF); - sum = acu - temp - TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); - break; - - case 0x9e: /* SBC A,(HL) */ - tStates += 7; - CHECK_BREAK_BYTE(HL); - temp = GET_BYTE(HL); - acu = HIGH_REGISTER(AF); - sum = acu - temp - TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); - break; - - case 0x9f: /* SBC A,A */ - tStates += 4; - sim_brk_pend[0] = FALSE; - cbits = -TSTFLAG(C); - AF = subTable[cbits & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PVS(cbits)); - break; - - case 0xa0: /* AND B */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = andTable[((AF & BC) >> 8) & 0xff]; - break; - - case 0xa1: /* AND C */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = andTable[((AF >> 8) & BC) & 0xff]; - break; - - case 0xa2: /* AND D */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = andTable[((AF & DE) >> 8) & 0xff]; - break; - - case 0xa3: /* AND E */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = andTable[((AF >> 8) & DE) & 0xff]; - break; - - case 0xa4: /* AND H */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = andTable[((AF & HL) >> 8) & 0xff]; - break; - - case 0xa5: /* AND L */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = andTable[((AF >> 8) & HL) & 0xff]; - break; - - case 0xa6: /* AND (HL) */ - tStates += 7; - CHECK_BREAK_BYTE(HL); - AF = andTable[((AF >> 8) & GET_BYTE(HL)) & 0xff]; - break; - - case 0xa7: /* AND A */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = andTable[(AF >> 8) & 0xff]; - break; - - case 0xa8: /* XOR B */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = xororTable[((AF ^ BC) >> 8) & 0xff]; - break; - - case 0xa9: /* XOR C */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = xororTable[((AF >> 8) ^ BC) & 0xff]; - break; - - case 0xaa: /* XOR D */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = xororTable[((AF ^ DE) >> 8) & 0xff]; - break; - - case 0xab: /* XOR E */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = xororTable[((AF >> 8) ^ DE) & 0xff]; - break; - - case 0xac: /* XOR H */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = xororTable[((AF ^ HL) >> 8) & 0xff]; - break; - - case 0xad: /* XOR L */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = xororTable[((AF >> 8) ^ HL) & 0xff]; - break; - - case 0xae: /* XOR (HL) */ - tStates += 7; - CHECK_BREAK_BYTE(HL); - AF = xororTable[((AF >> 8) ^ GET_BYTE(HL)) & 0xff]; - break; - - case 0xaf: /* XOR A */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = 0x44; - break; - - case 0xb0: /* OR B */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = xororTable[((AF | BC) >> 8) & 0xff]; - break; - - case 0xb1: /* OR C */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = xororTable[((AF >> 8) | BC) & 0xff]; - break; - - case 0xb2: /* OR D */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = xororTable[((AF | DE) >> 8) & 0xff]; - break; - - case 0xb3: /* OR E */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = xororTable[((AF >> 8) | DE) & 0xff]; - break; - - case 0xb4: /* OR H */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = xororTable[((AF | HL) >> 8) & 0xff]; - break; - - case 0xb5: /* OR L */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = xororTable[((AF >> 8) | HL) & 0xff]; - break; - - case 0xb6: /* OR (HL) */ - tStates += 7; - CHECK_BREAK_BYTE(HL); - AF = xororTable[((AF >> 8) | GET_BYTE(HL)) & 0xff]; - break; - - case 0xb7: /* OR A */ - tStates += 4; - sim_brk_pend[0] = FALSE; - AF = xororTable[(AF >> 8) & 0xff]; - break; - - case 0xb8: /* CP B */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = HIGH_REGISTER(BC); - AF = (AF & ~0x28) | (temp & 0x28); - acu = HIGH_REGISTER(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - (SET_PV) | cbits2Table[cbits & 0x1ff]; - break; - - case 0xb9: /* CP C */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(BC); - AF = (AF & ~0x28) | (temp & 0x28); - acu = HIGH_REGISTER(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - (SET_PV) | cbits2Table[cbits & 0x1ff]; - break; - - case 0xba: /* CP D */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = HIGH_REGISTER(DE); - AF = (AF & ~0x28) | (temp & 0x28); - acu = HIGH_REGISTER(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - (SET_PV) | cbits2Table[cbits & 0x1ff]; - break; - - case 0xbb: /* CP E */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(DE); - AF = (AF & ~0x28) | (temp & 0x28); - acu = HIGH_REGISTER(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - (SET_PV) | cbits2Table[cbits & 0x1ff]; - break; - - case 0xbc: /* CP H */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = HIGH_REGISTER(HL); - AF = (AF & ~0x28) | (temp & 0x28); - acu = HIGH_REGISTER(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - (SET_PV) | cbits2Table[cbits & 0x1ff]; - break; - - case 0xbd: /* CP L */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(HL); - AF = (AF & ~0x28) | (temp & 0x28); - acu = HIGH_REGISTER(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - (SET_PV) | cbits2Table[cbits & 0x1ff]; - break; - - case 0xbe: /* CP (HL) */ - tStates += 7; - CHECK_BREAK_BYTE(HL); - temp = GET_BYTE(HL); - AF = (AF & ~0x28) | (temp & 0x28); - acu = HIGH_REGISTER(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - (SET_PV) | cbits2Table[cbits & 0x1ff]; - break; - - case 0xbf: /* CP A */ - tStates += 4; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(AF, (HIGH_REGISTER(AF) & 0x28) | (cpu_unit.flags & UNIT_CHIP ? 0x42 : 0x46)); - break; - - case 0xc0: /* RET NZ */ - if (TSTFLAG(Z)) { - sim_brk_pend[0] = FALSE; - tStates += 5; - } - else { - CHECK_BREAK_WORD(SP); - PCQ_ENTRY(PC - 1); - POP(PC); - tStates += 11; - } - break; - - case 0xc1: /* POP BC */ - tStates += 10; - CHECK_BREAK_WORD(SP); - POP(BC); - break; - - case 0xc2: /* JP NZ,nnnn */ - sim_brk_pend[0] = FALSE; - JPC(!TSTFLAG(Z)); /* also updates tStates */ - break; - - case 0xc3: /* JP nnnn */ - sim_brk_pend[0] = FALSE; - JPC(1); /* also updates tStates */ - break; - - case 0xc4: /* CALL NZ,nnnn */ - CALLC(!TSTFLAG(Z)); /* also updates tStates */ - break; - - case 0xc5: /* PUSH BC */ - tStates += 11; - CHECK_BREAK_WORD(SP - 2); - PUSH(BC); - break; - - case 0xc6: /* ADD A,nn */ - tStates += 7; - sim_brk_pend[0] = FALSE; - temp = RAM_PP(PC); - acu = HIGH_REGISTER(AF); - sum = acu + temp; - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); - break; - - case 0xc7: /* RST 0 */ - tStates += 11; - CHECK_BREAK_WORD(SP - 2); - PUSH(PC); - PCQ_ENTRY(PC - 1); - PC = 0; - break; - - case 0xc8: /* RET Z */ - if (TSTFLAG(Z)) { - CHECK_BREAK_WORD(SP); - PCQ_ENTRY(PC - 1); - POP(PC); - tStates += 11; - } - else { - sim_brk_pend[0] = FALSE; - tStates += 5; - } - break; - - case 0xc9: /* RET */ - tStates += 10; - CHECK_BREAK_WORD(SP); - PCQ_ENTRY(PC - 1); - POP(PC); - break; - - case 0xca: /* JP Z,nnnn */ - sim_brk_pend[0] = FALSE; - JPC(TSTFLAG(Z)); /* also updates tStates */ - break; - - case 0xcb: /* CB prefix */ - CHECK_CPU_8080; - adr = HL; - switch ((op = GET_BYTE(PC)) & 7) { - - case 0: - sim_brk_pend[0] = tStateModifier = FALSE; - ++PC; - acu = HIGH_REGISTER(BC); - tStates += 8; - break; - - case 1: - sim_brk_pend[0] = tStateModifier = FALSE; - ++PC; - acu = LOW_REGISTER(BC); - tStates += 8; - break; - - case 2: - sim_brk_pend[0] = tStateModifier = FALSE; - ++PC; - acu = HIGH_REGISTER(DE); - tStates += 8; - break; - - case 3: - sim_brk_pend[0] = tStateModifier = FALSE; - ++PC; - acu = LOW_REGISTER(DE); - tStates += 8; - break; - - case 4: - sim_brk_pend[0] = tStateModifier = FALSE; - ++PC; - acu = HIGH_REGISTER(HL); - tStates += 8; - break; - - case 5: - sim_brk_pend[0] = tStateModifier = FALSE; - ++PC; - acu = LOW_REGISTER(HL); - tStates += 8; - break; - - case 6: - CHECK_BREAK_BYTE(adr); - ++PC; - acu = GET_BYTE(adr); - tStateModifier = TRUE; - tStates += 15; - break; - - case 7: - sim_brk_pend[0] = tStateModifier = FALSE; - ++PC; - acu = HIGH_REGISTER(AF); - tStates += 8; - break; - } - switch (op & 0xc0) { - - case 0x00: /* shift/rotate */ - switch (op & 0x38) { - - case 0x00: /* RLC */ - temp = (acu << 1) | (acu >> 7); - cbits = temp & 1; - goto cbshflg1; - - case 0x08: /* RRC */ - temp = (acu >> 1) | (acu << 7); - cbits = temp & 0x80; - goto cbshflg1; - - case 0x10: /* RL */ - temp = (acu << 1) | TSTFLAG(C); - cbits = acu & 0x80; - goto cbshflg1; - - case 0x18: /* RR */ - temp = (acu >> 1) | (TSTFLAG(C) << 7); - cbits = acu & 1; - goto cbshflg1; - - case 0x20: /* SLA */ - temp = acu << 1; - cbits = acu & 0x80; - goto cbshflg1; - - case 0x28: /* SRA */ - temp = (acu >> 1) | (acu & 0x80); - cbits = acu & 1; - goto cbshflg1; - - case 0x30: /* SLIA */ - temp = (acu << 1) | 1; - cbits = acu & 0x80; - goto cbshflg1; - - case 0x38: /* SRL */ - temp = acu >> 1; - cbits = acu & 1; - cbshflg1: - AF = (AF & ~0xff) | rotateShiftTable[temp & 0xff] | !!cbits; - } - break; - - case 0x40: /* BIT */ - if (tStateModifier) { - tStates -= 3; - } - if (acu & (1 << ((op >> 3) & 7))) { - AF = (AF & ~0xfe) | 0x10 | (((op & 0x38) == 0x38) << 7); - } - else { - AF = (AF & ~0xfe) | 0x54; - } - if ((op & 7) != 6) { - AF |= (acu & 0x28); - } - temp = acu; - break; - - case 0x80: /* RES */ - temp = acu & ~(1 << ((op >> 3) & 7)); - break; - - case 0xc0: /* SET */ - temp = acu | (1 << ((op >> 3) & 7)); - break; - } - - switch (op & 7) { - - case 0: - SET_HIGH_REGISTER(BC, temp); - break; - - case 1: - SET_LOW_REGISTER(BC, temp); - break; - - case 2: - SET_HIGH_REGISTER(DE, temp); - break; - - case 3: - SET_LOW_REGISTER(DE, temp); - break; - - case 4: - SET_HIGH_REGISTER(HL, temp); - break; - - case 5: - SET_LOW_REGISTER(HL, temp); - break; - - case 6: - PutBYTE(adr, temp); - break; - - case 7: - SET_HIGH_REGISTER(AF, temp); - break; - } - break; - - case 0xcc: /* CALL Z,nnnn */ - CALLC(TSTFLAG(Z)); /* also updates tStates */ - break; - - case 0xcd: /* CALL nnnn */ - CALLC(1); /* also updates tStates */ - break; - - case 0xce: /* ADC A,nn */ - tStates += 7; - sim_brk_pend[0] = FALSE; - temp = RAM_PP(PC); - acu = HIGH_REGISTER(AF); - sum = acu + temp + TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); - break; - - case 0xcf: /* RST 8 */ - tStates += 11; - CHECK_BREAK_WORD(SP - 2); - PUSH(PC); - PCQ_ENTRY(PC - 1); - PC = 8; - break; - - case 0xd0: /* RET NC */ - if (TSTFLAG(C)) { - sim_brk_pend[0] = FALSE; - tStates += 5; - } - else { - CHECK_BREAK_WORD(SP); - PCQ_ENTRY(PC - 1); - POP(PC); - tStates += 11; - } - break; - - case 0xd1: /* POP DE */ - tStates += 10; - CHECK_BREAK_WORD(SP); - POP(DE); - break; - - case 0xd2: /* JP NC,nnnn */ - sim_brk_pend[0] = FALSE; - JPC(!TSTFLAG(C)); /* also updates tStates */ - break; - - case 0xd3: /* OUT (nn),A */ - tStates += 11; - sim_brk_pend[0] = FALSE; - out(RAM_PP(PC), HIGH_REGISTER(AF)); - break; - - case 0xd4: /* CALL NC,nnnn */ - CALLC(!TSTFLAG(C)); /* also updates tStates */ - break; - - case 0xd5: /* PUSH DE */ - tStates += 11; - CHECK_BREAK_WORD(SP - 2); - PUSH(DE); - break; - - case 0xd6: /* SUB nn */ - tStates += 7; - sim_brk_pend[0] = FALSE; - temp = RAM_PP(PC); - acu = HIGH_REGISTER(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); - break; - - case 0xd7: /* RST 10H */ - tStates += 11; - CHECK_BREAK_WORD(SP - 2); - PUSH(PC); - PCQ_ENTRY(PC - 1); - PC = 0x10; - break; - - case 0xd8: /* RET C */ - if (TSTFLAG(C)) { - CHECK_BREAK_WORD(SP); - PCQ_ENTRY(PC - 1); - POP(PC); - tStates += 11; - } - else { - sim_brk_pend[0] = FALSE; - tStates += 5; - } - break; - - case 0xd9: /* EXX */ - tStates += 4; - sim_brk_pend[0] = FALSE; - CHECK_CPU_8080; - temp = BC; - BC = BC1_S; - BC1_S = temp; - temp = DE; - DE = DE1_S; - DE1_S = temp; - temp = HL; - HL = HL1_S; - HL1_S = temp; - break; - - case 0xda: /* JP C,nnnn */ - sim_brk_pend[0] = FALSE; - JPC(TSTFLAG(C)); /* also updates tStates */ - break; - - case 0xdb: /* IN A,(nn) */ - tStates += 11; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(AF, in(RAM_PP(PC))); - break; - - case 0xdc: /* CALL C,nnnn */ - CALLC(TSTFLAG(C)); /* also updates tStates */ - break; - - case 0xdd: /* DD prefix */ - CHECK_CPU_8080; - switch (op = RAM_PP(PC)) { - - case 0x09: /* ADD IX,BC */ - tStates += 15; - sim_brk_pend[0] = FALSE; - IX &= ADDRMASK; - BC &= ADDRMASK; - sum = IX + BC; - AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IX ^ BC ^ sum) >> 8]; - IX = sum; - break; - - case 0x19: /* ADD IX,DE */ - tStates += 15; - sim_brk_pend[0] = FALSE; - IX &= ADDRMASK; - DE &= ADDRMASK; - sum = IX + DE; - AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IX ^ DE ^ sum) >> 8]; - IX = sum; - break; - - case 0x21: /* LD IX,nnnn */ - tStates += 14; - sim_brk_pend[0] = FALSE; - IX = GET_WORD(PC); - PC += 2; - break; - - case 0x22: /* LD (nnnn),IX */ - tStates += 20; - temp = GET_WORD(PC); - CHECK_BREAK_WORD(temp); - PutWORD(temp, IX); - PC += 2; - break; - - case 0x23: /* INC IX */ - tStates += 10; - sim_brk_pend[0] = FALSE; - ++IX; - break; - - case 0x24: /* INC IXH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - IX += 0x100; - AF = (AF & ~0xfe) | incZ80Table[HIGH_REGISTER(IX)]; - break; - - case 0x25: /* DEC IXH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - IX -= 0x100; - AF = (AF & ~0xfe) | decZ80Table[HIGH_REGISTER(IX)]; - break; - - case 0x26: /* LD IXH,nn */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(IX, RAM_PP(PC)); - break; - - case 0x29: /* ADD IX,IX */ - tStates += 15; - sim_brk_pend[0] = FALSE; - IX &= ADDRMASK; - sum = IX + IX; - AF = (AF & ~0x3b) | cbitsDup16Table[sum >> 8]; - IX = sum; - break; - - case 0x2a: /* LD IX,(nnnn) */ - tStates += 20; - temp = GET_WORD(PC); - CHECK_BREAK_WORD(temp); - IX = GET_WORD(temp); - PC += 2; - break; - - case 0x2b: /* DEC IX */ - tStates += 10; - sim_brk_pend[0] = FALSE; - --IX; - break; - - case 0x2c: /* INC IXL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(IX) + 1; - SET_LOW_REGISTER(IX, temp); - AF = (AF & ~0xfe) | incZ80Table[temp]; - break; - - case 0x2d: /* DEC IXL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(IX) - 1; - SET_LOW_REGISTER(IX, temp); - AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; - break; - - case 0x2e: /* LD IXL,nn */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(IX, RAM_PP(PC)); - break; - - case 0x34: /* INC (IX+dd) */ - tStates += 23; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - temp = GET_BYTE(adr) + 1; - PutBYTE(adr, temp); - AF = (AF & ~0xfe) | incZ80Table[temp]; - break; - - case 0x35: /* DEC (IX+dd) */ - tStates += 23; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - temp = GET_BYTE(adr) - 1; - PutBYTE(adr, temp); - AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; - break; - - case 0x36: /* LD (IX+dd),nn */ - tStates += 19; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - PutBYTE(adr, RAM_PP(PC)); - break; - - case 0x39: /* ADD IX,SP */ - tStates += 15; - sim_brk_pend[0] = FALSE; - IX &= ADDRMASK; - SP &= ADDRMASK; - sum = IX + SP; - AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IX ^ SP ^ sum) >> 8]; - IX = sum; - break; - - case 0x44: /* LD B,IXH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(BC, HIGH_REGISTER(IX)); - break; - - case 0x45: /* LD B,IXL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(BC, LOW_REGISTER(IX)); - break; - - case 0x46: /* LD B,(IX+dd) */ - tStates += 19; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - SET_HIGH_REGISTER(BC, GET_BYTE(adr)); - break; - - case 0x4c: /* LD C,IXH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(BC, HIGH_REGISTER(IX)); - break; - - case 0x4d: /* LD C,IXL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(BC, LOW_REGISTER(IX)); - break; - - case 0x4e: /* LD C,(IX+dd) */ - tStates += 19; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - SET_LOW_REGISTER(BC, GET_BYTE(adr)); - break; - - case 0x54: /* LD D,IXH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(DE, HIGH_REGISTER(IX)); - break; - - case 0x55: /* LD D,IXL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(DE, LOW_REGISTER(IX)); - break; - - case 0x56: /* LD D,(IX+dd) */ - tStates += 19; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - SET_HIGH_REGISTER(DE, GET_BYTE(adr)); - break; - - case 0x5c: /* LD E,IXH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(DE, HIGH_REGISTER(IX)); - break; - - case 0x5d: /* LD E,IXL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(DE, LOW_REGISTER(IX)); - break; - - case 0x5e: /* LD E,(IX+dd) */ - tStates += 19; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - SET_LOW_REGISTER(DE, GET_BYTE(adr)); - break; - - case 0x60: /* LD IXH,B */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(IX, HIGH_REGISTER(BC)); - break; - - case 0x61: /* LD IXH,C */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(IX, LOW_REGISTER(BC)); - break; - - case 0x62: /* LD IXH,D */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(IX, HIGH_REGISTER(DE)); - break; - - case 0x63: /* LD IXH,E */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(IX, LOW_REGISTER(DE)); - break; - - case 0x64: /* LD IXH,IXH */ - tStates += 9; - sim_brk_pend[0] = FALSE; /* nop */ - break; - - case 0x65: /* LD IXH,IXL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(IX, LOW_REGISTER(IX)); - break; - - case 0x66: /* LD H,(IX+dd) */ - tStates += 19; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - SET_HIGH_REGISTER(HL, GET_BYTE(adr)); - break; - - case 0x67: /* LD IXH,A */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(IX, HIGH_REGISTER(AF)); - break; - - case 0x68: /* LD IXL,B */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(IX, HIGH_REGISTER(BC)); - break; - - case 0x69: /* LD IXL,C */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(IX, LOW_REGISTER(BC)); - break; - - case 0x6a: /* LD IXL,D */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(IX, HIGH_REGISTER(DE)); - break; - - case 0x6b: /* LD IXL,E */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(IX, LOW_REGISTER(DE)); - break; - - case 0x6c: /* LD IXL,IXH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(IX, HIGH_REGISTER(IX)); - break; - - case 0x6d: /* LD IXL,IXL */ - tStates += 9; - sim_brk_pend[0] = FALSE; /* nop */ - break; - - case 0x6e: /* LD L,(IX+dd) */ - tStates += 19; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - SET_LOW_REGISTER(HL, GET_BYTE(adr)); - break; - - case 0x6f: /* LD IXL,A */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(IX, HIGH_REGISTER(AF)); - break; - - case 0x70: /* LD (IX+dd),B */ - tStates += 19; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - PutBYTE(adr, HIGH_REGISTER(BC)); - break; - - case 0x71: /* LD (IX+dd),C */ - tStates += 19; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - PutBYTE(adr, LOW_REGISTER(BC)); - break; - - case 0x72: /* LD (IX+dd),D */ - tStates += 19; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - PutBYTE(adr, HIGH_REGISTER(DE)); - break; - - case 0x73: /* LD (IX+dd),E */ - tStates += 19; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - PutBYTE(adr, LOW_REGISTER(DE)); - break; - - case 0x74: /* LD (IX+dd),H */ - tStates += 19; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - PutBYTE(adr, HIGH_REGISTER(HL)); - break; - - case 0x75: /* LD (IX+dd),L */ - tStates += 19; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - PutBYTE(adr, LOW_REGISTER(HL)); - break; - - case 0x77: /* LD (IX+dd),A */ - tStates += 19; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - PutBYTE(adr, HIGH_REGISTER(AF)); - break; - - case 0x7c: /* LD A,IXH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(AF, HIGH_REGISTER(IX)); - break; - - case 0x7d: /* LD A,IXL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(AF, LOW_REGISTER(IX)); - break; - - case 0x7e: /* LD A,(IX+dd) */ - tStates += 19; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - SET_HIGH_REGISTER(AF, GET_BYTE(adr)); - break; - - case 0x84: /* ADD A,IXH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - temp = HIGH_REGISTER(IX); - acu = HIGH_REGISTER(AF); - sum = acu + temp; - AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; - break; - - case 0x85: /* ADD A,IXL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(IX); - acu = HIGH_REGISTER(AF); - sum = acu + temp; - AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; - break; - - case 0x86: /* ADD A,(IX+dd) */ - tStates += 19; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - temp = GET_BYTE(adr); - acu = HIGH_REGISTER(AF); - sum = acu + temp; - AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; - break; - - case 0x8c: /* ADC A,IXH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - temp = HIGH_REGISTER(IX); - acu = HIGH_REGISTER(AF); - sum = acu + temp + TSTFLAG(C); - AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; - break; - - case 0x8d: /* ADC A,IXL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(IX); - acu = HIGH_REGISTER(AF); - sum = acu + temp + TSTFLAG(C); - AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; - break; - - case 0x8e: /* ADC A,(IX+dd) */ - tStates += 19; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - temp = GET_BYTE(adr); - acu = HIGH_REGISTER(AF); - sum = acu + temp + TSTFLAG(C); - AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; - break; - - case 0x96: /* SUB (IX+dd) */ - tStates += 19; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - temp = GET_BYTE(adr); - acu = HIGH_REGISTER(AF); - sum = acu - temp; - AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - - case 0x94: /* SUB IXH */ - SETFLAG(C, 0);/* fall through, a bit less efficient but smaller code */ - - case 0x9c: /* SBC A,IXH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - temp = HIGH_REGISTER(IX); - acu = HIGH_REGISTER(AF); - sum = acu - temp - TSTFLAG(C); - AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - - case 0x95: /* SUB IXL */ - SETFLAG(C, 0);/* fall through, a bit less efficient but smaller code */ - - case 0x9d: /* SBC A,IXL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(IX); - acu = HIGH_REGISTER(AF); - sum = acu - temp - TSTFLAG(C); - AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - - case 0x9e: /* SBC A,(IX+dd) */ - tStates += 19; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - temp = GET_BYTE(adr); - acu = HIGH_REGISTER(AF); - sum = acu - temp - TSTFLAG(C); - AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - - case 0xa4: /* AND IXH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - AF = andTable[((AF & IX) >> 8) & 0xff]; - break; - - case 0xa5: /* AND IXL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - AF = andTable[((AF >> 8) & IX) & 0xff]; - break; - - case 0xa6: /* AND (IX+dd) */ - tStates += 19; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - AF = andTable[((AF >> 8) & GET_BYTE(adr)) & 0xff]; - break; - - case 0xac: /* XOR IXH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - AF = xororTable[((AF ^ IX) >> 8) & 0xff]; - break; - - case 0xad: /* XOR IXL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - AF = xororTable[((AF >> 8) ^ IX) & 0xff]; - break; - - case 0xae: /* XOR (IX+dd) */ - tStates += 19; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - AF = xororTable[((AF >> 8) ^ GET_BYTE(adr)) & 0xff]; - break; - - case 0xb4: /* OR IXH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - AF = xororTable[((AF | IX) >> 8) & 0xff]; - break; - - case 0xb5: /* OR IXL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - AF = xororTable[((AF >> 8) | IX) & 0xff]; - break; - - case 0xb6: /* OR (IX+dd) */ - tStates += 19; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - AF = xororTable[((AF >> 8) | GET_BYTE(adr)) & 0xff]; - break; - - case 0xbc: /* CP IXH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - temp = HIGH_REGISTER(IX); - AF = (AF & ~0x28) | (temp & 0x28); - acu = HIGH_REGISTER(AF); - sum = acu - temp; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - - case 0xbd: /* CP IXL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(IX); - AF = (AF & ~0x28) | (temp & 0x28); - acu = HIGH_REGISTER(AF); - sum = acu - temp; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - - case 0xbe: /* CP (IX+dd) */ - tStates += 19; - adr = IX + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - temp = GET_BYTE(adr); - AF = (AF & ~0x28) | (temp & 0x28); - acu = HIGH_REGISTER(AF); - sum = acu - temp; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - - case 0xcb: /* CB prefix */ - adr = IX + (int8) RAM_PP(PC); - switch ((op = GET_BYTE(PC)) & 7) { - - case 0: - sim_brk_pend[0] = FALSE; - ++PC; - acu = HIGH_REGISTER(BC); - break; - - case 1: - sim_brk_pend[0] = FALSE; - ++PC; - acu = LOW_REGISTER(BC); - break; - - case 2: - sim_brk_pend[0] = FALSE; - ++PC; - acu = HIGH_REGISTER(DE); - break; - - case 3: - sim_brk_pend[0] = FALSE; - ++PC; - acu = LOW_REGISTER(DE); - break; - - case 4: - sim_brk_pend[0] = FALSE; - ++PC; - acu = HIGH_REGISTER(HL); - break; - - case 5: - sim_brk_pend[0] = FALSE; - ++PC; - acu = LOW_REGISTER(HL); - break; - - case 6: - CHECK_BREAK_BYTE(adr); - ++PC; - acu = GET_BYTE(adr); - break; - - case 7: - sim_brk_pend[0] = FALSE; - ++PC; - acu = HIGH_REGISTER(AF); - break; - } - switch (op & 0xc0) { - - case 0x00: /* shift/rotate */ - tStates += 23; - switch (op & 0x38) { - - case 0x00: /* RLC */ - temp = (acu << 1) | (acu >> 7); - cbits = temp & 1; - goto cbshflg2; - - case 0x08: /* RRC */ - temp = (acu >> 1) | (acu << 7); - cbits = temp & 0x80; - goto cbshflg2; - - case 0x10: /* RL */ - temp = (acu << 1) | TSTFLAG(C); - cbits = acu & 0x80; - goto cbshflg2; - - case 0x18: /* RR */ - temp = (acu >> 1) | (TSTFLAG(C) << 7); - cbits = acu & 1; - goto cbshflg2; - - case 0x20: /* SLA */ - temp = acu << 1; - cbits = acu & 0x80; - goto cbshflg2; - - case 0x28: /* SRA */ - temp = (acu >> 1) | (acu & 0x80); - cbits = acu & 1; - goto cbshflg2; - - case 0x30: /* SLIA */ - temp = (acu << 1) | 1; - cbits = acu & 0x80; - goto cbshflg2; - - case 0x38: /* SRL */ - temp = acu >> 1; - cbits = acu & 1; - cbshflg2: - AF = (AF & ~0xff) | rotateShiftTable[temp & 0xff] | !!cbits; - } - break; - - case 0x40: /* BIT */ - tStates += 20; - if (acu & (1 << ((op >> 3) & 7))) { - AF = (AF & ~0xfe) | 0x10 | (((op & 0x38) == 0x38) << 7); - } - else { - AF = (AF & ~0xfe) | 0x54; - } - if ((op & 7) != 6) { - AF |= (acu & 0x28); - } - temp = acu; - break; - - case 0x80: /* RES */ - tStates += 23; - temp = acu & ~(1 << ((op >> 3) & 7)); - break; - - case 0xc0: /* SET */ - tStates += 23; - temp = acu | (1 << ((op >> 3) & 7)); - break; - } - switch (op & 7) { - - case 0: - SET_HIGH_REGISTER(BC, temp); - break; - - case 1: - SET_LOW_REGISTER(BC, temp); - break; - - case 2: - SET_HIGH_REGISTER(DE, temp); - break; - - case 3: - SET_LOW_REGISTER(DE, temp); - break; - - case 4: - SET_HIGH_REGISTER(HL, temp); - break; - - case 5: - SET_LOW_REGISTER(HL, temp); - break; - - case 6: - PutBYTE(adr, temp); - break; - - case 7: - SET_HIGH_REGISTER(AF, temp); - break; - } - break; - - case 0xe1: /* POP IX */ - tStates += 14; - CHECK_BREAK_WORD(SP); - POP(IX); - break; - - case 0xe3: /* EX (SP),IX */ - tStates += 23; - CHECK_BREAK_WORD(SP); - temp = IX; - POP(IX); - PUSH(temp); - break; - - case 0xe5: /* PUSH IX */ - tStates += 15; - CHECK_BREAK_WORD(SP - 2); - PUSH(IX); - break; - - case 0xe9: /* JP (IX) */ - tStates += 8; - sim_brk_pend[0] = FALSE; - PCQ_ENTRY(PC - 2); - PC = IX; - break; - - case 0xf9: /* LD SP,IX */ - tStates += 10; - sim_brk_pend[0] = FALSE; - SP = IX; - break; - - default: /* ignore DD */ - sim_brk_pend[0] = FALSE; - CHECK_CPU_Z80; - PC--; - } - break; - - case 0xde: /* SBC A,nn */ - tStates += 7; - sim_brk_pend[0] = FALSE; - temp = RAM_PP(PC); - acu = HIGH_REGISTER(AF); - sum = acu - temp - TSTFLAG(C); - cbits = acu ^ temp ^ sum; - AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); - break; - - case 0xdf: /* RST 18H */ - tStates += 11; - CHECK_BREAK_WORD(SP - 2); - PUSH(PC); - PCQ_ENTRY(PC - 1); - PC = 0x18; - break; - - case 0xe0: /* RET PO */ - if (TSTFLAG(P)) { - sim_brk_pend[0] = FALSE; - tStates += 5; - } - else { - CHECK_BREAK_WORD(SP); - PCQ_ENTRY(PC - 1); - POP(PC); - tStates += 11; - } - break; - - case 0xe1: /* POP HL */ - tStates += 10; - CHECK_BREAK_WORD(SP); - POP(HL); - break; - - case 0xe2: /* JP PO,nnnn */ - sim_brk_pend[0] = FALSE; - JPC(!TSTFLAG(P)); /* also updates tStates */ - break; - - case 0xe3: /* EX (SP),HL */ - tStates += 19; - CHECK_BREAK_WORD(SP); - temp = HL; - POP(HL); - PUSH(temp); - break; - - case 0xe4: /* CALL PO,nnnn */ - CALLC(!TSTFLAG(P)); /* also updates tStates */ - break; - - case 0xe5: /* PUSH HL */ - tStates += 11; - CHECK_BREAK_WORD(SP - 2); - PUSH(HL); - break; - - case 0xe6: /* AND nn */ - tStates += 7; - sim_brk_pend[0] = FALSE; - AF = andTable[((AF >> 8) & RAM_PP(PC)) & 0xff]; - break; - - case 0xe7: /* RST 20H */ - tStates += 11; - CHECK_BREAK_WORD(SP - 2); - PUSH(PC); - PCQ_ENTRY(PC - 1); - PC = 0x20; - break; - - case 0xe8: /* RET PE */ - if (TSTFLAG(P)) { - CHECK_BREAK_WORD(SP); - PCQ_ENTRY(PC - 1); - POP(PC); - tStates += 11; - } - else { - sim_brk_pend[0] = FALSE; - tStates += 5; - } - break; - - case 0xe9: /* JP (HL) */ - tStates += 4; - sim_brk_pend[0] = FALSE; - PCQ_ENTRY(PC - 1); - PC = HL; - break; - - case 0xea: /* JP PE,nnnn */ - sim_brk_pend[0] = FALSE; - JPC(TSTFLAG(P)); /* also updates tStates */ - break; - - case 0xeb: /* EX DE,HL */ - tStates += 4; - sim_brk_pend[0] = FALSE; - temp = HL; - HL = DE; - DE = temp; - break; - - case 0xec: /* CALL PE,nnnn */ - CALLC(TSTFLAG(P)); /* also updates tStates */ - break; - - case 0xed: /* ED prefix */ - CHECK_CPU_8080; - switch (op = RAM_PP(PC)) { - - case 0x40: /* IN B,(C) */ - tStates += 12; - sim_brk_pend[0] = FALSE; - temp = in(LOW_REGISTER(BC)); - SET_HIGH_REGISTER(BC, temp); - AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; - break; - - case 0x41: /* OUT (C),B */ - tStates += 12; - sim_brk_pend[0] = FALSE; - out(LOW_REGISTER(BC), HIGH_REGISTER(BC)); - break; - - case 0x42: /* SBC HL,BC */ - tStates += 15; - sim_brk_pend[0] = FALSE; - HL &= ADDRMASK; - BC &= ADDRMASK; - sum = HL - BC - TSTFLAG(C); - AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | - cbits2Z80Table[((HL ^ BC ^ sum) >> 8) & 0x1ff]; - HL = sum; - break; - - case 0x43: /* LD (nnnn),BC */ - tStates += 20; - temp = GET_WORD(PC); - CHECK_BREAK_WORD(temp); - PutWORD(temp, BC); - PC += 2; - break; - - case 0x44: /* NEG */ - - case 0x4C: /* NEG, unofficial */ - - case 0x54: /* NEG, unofficial */ - - case 0x5C: /* NEG, unofficial */ - - case 0x64: /* NEG, unofficial */ - - case 0x6C: /* NEG, unofficial */ - - case 0x74: /* NEG, unofficial */ - - case 0x7C: /* NEG, unofficial */ - tStates += 8; - sim_brk_pend[0] = FALSE; - temp = HIGH_REGISTER(AF); - AF = ((~(AF & 0xff00) + 1) & 0xff00); /* AF = (-(AF & 0xff00) & 0xff00); */ - AF |= ((AF >> 8) & 0xa8) | (((AF & 0xff00) == 0) << 6) | negTable[temp]; - break; - - case 0x45: /* RETN */ - - case 0x55: /* RETN, unofficial */ - - case 0x5D: /* RETN, unofficial */ - - case 0x65: /* RETN, unofficial */ - - case 0x6D: /* RETN, unofficial */ - - case 0x75: /* RETN, unofficial */ - - case 0x7D: /* RETN, unofficial */ - tStates += 14; - IFF_S |= IFF_S >> 1; - CHECK_BREAK_WORD(SP); - PCQ_ENTRY(PC - 2); - POP(PC); - break; - - case 0x46: /* IM 0 */ - tStates += 8; - sim_brk_pend[0] = FALSE; - /* interrupt mode 0 */ - break; - - case 0x47: /* LD I,A */ - tStates += 9; - sim_brk_pend[0] = FALSE; - IR_S = (IR_S & 0xff) | (AF & ~0xff); - break; - - case 0x48: /* IN C,(C) */ - tStates += 12; - sim_brk_pend[0] = FALSE; - temp = in(LOW_REGISTER(BC)); - SET_LOW_REGISTER(BC, temp); - AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; - break; - - case 0x49: /* OUT (C),C */ - tStates += 12; - sim_brk_pend[0] = FALSE; - out(LOW_REGISTER(BC), LOW_REGISTER(BC)); - break; - - case 0x4a: /* ADC HL,BC */ - tStates += 15; - sim_brk_pend[0] = FALSE; - HL &= ADDRMASK; - BC &= ADDRMASK; - sum = HL + BC + TSTFLAG(C); - AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | - cbitsZ80Table[(HL ^ BC ^ sum) >> 8]; - HL = sum; - break; - - case 0x4b: /* LD BC,(nnnn) */ - tStates += 20; - temp = GET_WORD(PC); - CHECK_BREAK_WORD(temp); - BC = GET_WORD(temp); - PC += 2; - break; - - case 0x4d: /* RETI */ - tStates += 14; - IFF_S |= IFF_S >> 1; - CHECK_BREAK_WORD(SP); - PCQ_ENTRY(PC - 2); - POP(PC); - break; - - case 0x4f: /* LD R,A */ - tStates += 9; - sim_brk_pend[0] = FALSE; - IR_S = (IR_S & ~0xff) | ((AF >> 8) & 0xff); - break; - - case 0x50: /* IN D,(C) */ - tStates += 12; - sim_brk_pend[0] = FALSE; - temp = in(LOW_REGISTER(BC)); - SET_HIGH_REGISTER(DE, temp); - AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; - break; - - case 0x51: /* OUT (C),D */ - tStates += 12; - sim_brk_pend[0] = FALSE; - out(LOW_REGISTER(BC), HIGH_REGISTER(DE)); - break; - - case 0x52: /* SBC HL,DE */ - tStates += 15; - sim_brk_pend[0] = FALSE; - HL &= ADDRMASK; - DE &= ADDRMASK; - sum = HL - DE - TSTFLAG(C); - AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | - cbits2Z80Table[((HL ^ DE ^ sum) >> 8) & 0x1ff]; - HL = sum; - break; - - case 0x53: /* LD (nnnn),DE */ - tStates += 20; - temp = GET_WORD(PC); - CHECK_BREAK_WORD(temp); - PutWORD(temp, DE); - PC += 2; - break; - - case 0x56: /* IM 1 */ - tStates += 8; - sim_brk_pend[0] = FALSE; - /* interrupt mode 1 */ - break; - - case 0x57: /* LD A,I */ - tStates += 9; - sim_brk_pend[0] = FALSE; - AF = (AF & 0x29) | (IR_S & ~0xff) | ((IR_S >> 8) & 0x80) | (((IR_S & ~0xff) == 0) << 6) | ((IFF_S & 2) << 1); - break; - - case 0x58: /* IN E,(C) */ - tStates += 12; - sim_brk_pend[0] = FALSE; - temp = in(LOW_REGISTER(BC)); - SET_LOW_REGISTER(DE, temp); - AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; - break; - - case 0x59: /* OUT (C),E */ - tStates += 12; - sim_brk_pend[0] = FALSE; - out(LOW_REGISTER(BC), LOW_REGISTER(DE)); - break; - - case 0x5a: /* ADC HL,DE */ - tStates += 15; - sim_brk_pend[0] = FALSE; - HL &= ADDRMASK; - DE &= ADDRMASK; - sum = HL + DE + TSTFLAG(C); - AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | - cbitsZ80Table[(HL ^ DE ^ sum) >> 8]; - HL = sum; - break; - - case 0x5b: /* LD DE,(nnnn) */ - tStates += 20; - temp = GET_WORD(PC); - CHECK_BREAK_WORD(temp); - DE = GET_WORD(temp); - PC += 2; - break; - - case 0x5e: /* IM 2 */ - tStates += 8; - sim_brk_pend[0] = FALSE; - /* interrupt mode 2 */ - break; - - case 0x5f: /* LD A,R */ - tStates += 9; - sim_brk_pend[0] = FALSE; - AF = (AF & 0x29) | ((IR_S & 0xff) << 8) | (IR_S & 0x80) | - (((IR_S & 0xff) == 0) << 6) | ((IFF_S & 2) << 1); - break; - - case 0x60: /* IN H,(C) */ - tStates += 12; - sim_brk_pend[0] = FALSE; - temp = in(LOW_REGISTER(BC)); - SET_HIGH_REGISTER(HL, temp); - AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; - break; - - case 0x61: /* OUT (C),H */ - tStates += 12; - sim_brk_pend[0] = FALSE; - out(LOW_REGISTER(BC), HIGH_REGISTER(HL)); - break; - - case 0x62: /* SBC HL,HL */ - tStates += 15; - sim_brk_pend[0] = FALSE; - HL &= ADDRMASK; - sum = HL - HL - TSTFLAG(C); - AF = (AF & ~0xff) | (((sum & ADDRMASK) == 0) << 6) | - cbits2Z80DupTable[(sum >> 8) & 0x1ff]; - HL = sum; - break; - - case 0x63: /* LD (nnnn),HL */ - tStates += 20; - temp = GET_WORD(PC); - CHECK_BREAK_WORD(temp); - PutWORD(temp, HL); - PC += 2; - break; - - case 0x67: /* RRD */ - tStates += 18; - sim_brk_pend[0] = FALSE; - temp = GET_BYTE(HL); - acu = HIGH_REGISTER(AF); - PutBYTE(HL, HIGH_DIGIT(temp) | (LOW_DIGIT(acu) << 4)); - AF = rrdrldTable[(acu & 0xf0) | LOW_DIGIT(temp)] | (AF & 1); - break; - - case 0x68: /* IN L,(C) */ - tStates += 12; - sim_brk_pend[0] = FALSE; - temp = in(LOW_REGISTER(BC)); - SET_LOW_REGISTER(HL, temp); - AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; - break; - - case 0x69: /* OUT (C),L */ - tStates += 12; - sim_brk_pend[0] = FALSE; - out(LOW_REGISTER(BC), LOW_REGISTER(HL)); - break; - - case 0x6a: /* ADC HL,HL */ - tStates += 15; - sim_brk_pend[0] = FALSE; - HL &= ADDRMASK; - sum = HL + HL + TSTFLAG(C); - AF = (AF & ~0xff) | (((sum & ADDRMASK) == 0) << 6) | - cbitsZ80DupTable[sum >> 8]; - HL = sum; - break; - - case 0x6b: /* LD HL,(nnnn) */ - tStates += 20; - temp = GET_WORD(PC); - CHECK_BREAK_WORD(temp); - HL = GET_WORD(temp); - PC += 2; - break; - - case 0x6f: /* RLD */ - tStates += 18; - sim_brk_pend[0] = FALSE; - temp = GET_BYTE(HL); - acu = HIGH_REGISTER(AF); - PutBYTE(HL, (LOW_DIGIT(temp) << 4) | LOW_DIGIT(acu)); - AF = rrdrldTable[(acu & 0xf0) | HIGH_DIGIT(temp)] | (AF & 1); - break; - - case 0x70: /* IN (C) */ - tStates += 12; - sim_brk_pend[0] = FALSE; - temp = in(LOW_REGISTER(BC)); - SET_LOW_REGISTER(temp, temp); - AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; - break; - - case 0x71: /* OUT (C),0 */ - tStates += 12; - sim_brk_pend[0] = FALSE; - out(LOW_REGISTER(BC), 0); - break; - - case 0x72: /* SBC HL,SP */ - tStates += 15; - sim_brk_pend[0] = FALSE; - HL &= ADDRMASK; - SP &= ADDRMASK; - sum = HL - SP - TSTFLAG(C); - AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | - cbits2Z80Table[((HL ^ SP ^ sum) >> 8) & 0x1ff]; - HL = sum; - break; - - case 0x73: /* LD (nnnn),SP */ - tStates += 20; - temp = GET_WORD(PC); - CHECK_BREAK_WORD(temp); - PutWORD(temp, SP); - PC += 2; - break; - - case 0x78: /* IN A,(C) */ - tStates += 12; - sim_brk_pend[0] = FALSE; - temp = in(LOW_REGISTER(BC)); - SET_HIGH_REGISTER(AF, temp); - AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; - break; - - case 0x79: /* OUT (C),A */ - tStates += 12; - sim_brk_pend[0] = FALSE; - out(LOW_REGISTER(BC), HIGH_REGISTER(AF)); - break; - - case 0x7a: /* ADC HL,SP */ - tStates += 15; - sim_brk_pend[0] = FALSE; - HL &= ADDRMASK; - SP &= ADDRMASK; - sum = HL + SP + TSTFLAG(C); - AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | - cbitsZ80Table[(HL ^ SP ^ sum) >> 8]; - HL = sum; - break; - - case 0x7b: /* LD SP,(nnnn) */ - tStates += 20; - temp = GET_WORD(PC); - CHECK_BREAK_WORD(temp); - SP = GET_WORD(temp); - PC += 2; - break; - - case 0xa0: /* LDI */ - tStates += 16; - CHECK_BREAK_TWO_BYTES(HL, DE); - acu = RAM_PP(HL); - PUT_BYTE_PP(DE, acu); - acu += HIGH_REGISTER(AF); - AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4) | - (((--BC & ADDRMASK) != 0) << 2); - break; - - case 0xa1: /* CPI */ - tStates += 16; - CHECK_BREAK_BYTE(HL); - acu = HIGH_REGISTER(AF); - temp = RAM_PP(HL); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | - (((sum - ((cbits & 16) >> 4)) & 2) << 4) | (cbits & 16) | - ((sum - ((cbits >> 4) & 1)) & 8) | - ((--BC & ADDRMASK) != 0) << 2 | 2; - if ((sum & 15) == 8 && (cbits & 16) != 0) { - AF &= ~8; - } - break; - - case 0xa2: /* INI */ - tStates += 16; - CHECK_BREAK_BYTE(HL); - PutBYTE(HL, in(LOW_REGISTER(BC))); - ++HL; - SETFLAG(N, 1); - SETFLAG(P, (--BC & ADDRMASK) != 0); - break; - - case 0xa3: /* OUTI */ - tStates += 16; - CHECK_BREAK_BYTE(HL); - out(LOW_REGISTER(BC), GET_BYTE(HL)); - ++HL; - SETFLAG(N, 1); - SET_HIGH_REGISTER(BC, LOW_REGISTER(BC) - 1); - SETFLAG(Z, LOW_REGISTER(BC) == 0); - break; - - case 0xa8: /* LDD */ - tStates += 16; - CHECK_BREAK_TWO_BYTES(HL, DE); - acu = RAM_MM(HL); - PUT_BYTE_MM(DE, acu); - acu += HIGH_REGISTER(AF); - AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4) | - (((--BC & ADDRMASK) != 0) << 2); - break; - - case 0xa9: /* CPD */ - tStates += 16; - CHECK_BREAK_BYTE(HL); - acu = HIGH_REGISTER(AF); - temp = RAM_MM(HL); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | - (((sum - ((cbits & 16) >> 4)) & 2) << 4) | (cbits & 16) | - ((sum - ((cbits >> 4) & 1)) & 8) | - ((--BC & ADDRMASK) != 0) << 2 | 2; - if ((sum & 15) == 8 && (cbits & 16) != 0) { - AF &= ~8; - } - break; - - case 0xaa: /* IND */ - tStates += 16; - CHECK_BREAK_BYTE(HL); - PutBYTE(HL, in(LOW_REGISTER(BC))); - --HL; - SETFLAG(N, 1); - SET_HIGH_REGISTER(BC, LOW_REGISTER(BC) - 1); - SETFLAG(Z, LOW_REGISTER(BC) == 0); - break; - - case 0xab: /* OUTD */ - tStates += 16; - CHECK_BREAK_BYTE(HL); - out(LOW_REGISTER(BC), GET_BYTE(HL)); - --HL; - SETFLAG(N, 1); - SET_HIGH_REGISTER(BC, LOW_REGISTER(BC) - 1); - SETFLAG(Z, LOW_REGISTER(BC) == 0); - break; - - case 0xb0: /* LDIR */ - tStates -= 5; - acu = HIGH_REGISTER(AF); - BC &= ADDRMASK; - if (BC == 0) BC = 0x10000; - do { - tStates += 21; - CHECK_BREAK_TWO_BYTES(HL, DE); - acu = RAM_PP(HL); - PUT_BYTE_PP(DE, acu); - } while (--BC); - acu += HIGH_REGISTER(AF); - AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4); - break; - - case 0xb1: /* CPIR */ - tStates -= 5; - acu = HIGH_REGISTER(AF); - BC &= ADDRMASK; - if (BC == 0) BC = 0x10000; - do { - tStates += 21; - CHECK_BREAK_BYTE(HL); - temp = RAM_PP(HL); - op = --BC != 0; - sum = acu - temp; - } while (op && sum != 0); - cbits = acu ^ temp ^ sum; - AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | - (((sum - ((cbits & 16) >> 4)) & 2) << 4) | - (cbits & 16) | ((sum - ((cbits >> 4) & 1)) & 8) | - op << 2 | 2; - if ((sum & 15) == 8 && (cbits & 16) != 0) { - AF &= ~8; - } - break; - - case 0xb2: /* INIR */ - tStates -= 5; - temp = HIGH_REGISTER(BC); - if (temp == 0) temp = 0x100; - do { - tStates += 21; - CHECK_BREAK_BYTE(HL); - PutBYTE(HL, in(LOW_REGISTER(BC))); - ++HL; - } while (--temp); - SET_HIGH_REGISTER(BC, 0); - SETFLAG(N, 1); - SETFLAG(Z, 1); - break; - - case 0xb3: /* OTIR */ - tStates -= 5; - temp = HIGH_REGISTER(BC); - if (temp == 0) temp = 0x100; - do { - tStates += 21; - CHECK_BREAK_BYTE(HL); - out(LOW_REGISTER(BC), GET_BYTE(HL)); - ++HL; - } while (--temp); - SET_HIGH_REGISTER(BC, 0); - SETFLAG(N, 1); - SETFLAG(Z, 1); - break; - - case 0xb8: /* LDDR */ - tStates -= 5; - BC &= ADDRMASK; - if (BC == 0) BC = 0x10000; - do { - tStates += 21; - CHECK_BREAK_TWO_BYTES(HL, DE); - acu = RAM_MM(HL); - PUT_BYTE_MM(DE, acu); - } while (--BC); - acu += HIGH_REGISTER(AF); - AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4); - break; - - case 0xb9: /* CPDR */ - tStates -= 5; - acu = HIGH_REGISTER(AF); - BC &= ADDRMASK; - if (BC == 0) BC = 0x10000; - do { - tStates += 21; - CHECK_BREAK_BYTE(HL); - temp = RAM_MM(HL); - op = --BC != 0; - sum = acu - temp; - } while (op && sum != 0); - cbits = acu ^ temp ^ sum; - AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | - (((sum - ((cbits & 16) >> 4)) & 2) << 4) | - (cbits & 16) | ((sum - ((cbits >> 4) & 1)) & 8) | - op << 2 | 2; - if ((sum & 15) == 8 && (cbits & 16) != 0) { - AF &= ~8; - } - break; - - case 0xba: /* INDR */ - tStates -= 5; - temp = HIGH_REGISTER(BC); - if (temp == 0) temp = 0x100; - do { - tStates += 21; - CHECK_BREAK_BYTE(HL); - PutBYTE(HL, in(LOW_REGISTER(BC))); - --HL; - } while (--temp); - SET_HIGH_REGISTER(BC, 0); - SETFLAG(N, 1); - SETFLAG(Z, 1); - break; - - case 0xbb: /* OTDR */ - tStates -= 5; - temp = HIGH_REGISTER(BC); - if (temp == 0) temp = 0x100; - do { - tStates += 21; - CHECK_BREAK_BYTE(HL); - out(LOW_REGISTER(BC), GET_BYTE(HL)); - --HL; - } while (--temp); - SET_HIGH_REGISTER(BC, 0); - SETFLAG(N, 1); - SETFLAG(Z, 1); - break; - - default: /* ignore ED and following byte */ - sim_brk_pend[0] = FALSE; - CHECK_CPU_Z80; - } - break; - - case 0xee: /* XOR nn */ - tStates += 7; - sim_brk_pend[0] = FALSE; - AF = xororTable[((AF >> 8) ^ RAM_PP(PC)) & 0xff]; - break; - - case 0xef: /* RST 28H */ - tStates += 11; - CHECK_BREAK_WORD(SP - 2); - PUSH(PC); - PCQ_ENTRY(PC - 1); - PC = 0x28; - break; - - case 0xf0: /* RET P */ - if (TSTFLAG(S)) { - sim_brk_pend[0] = FALSE; - tStates += 5; - } - else { - CHECK_BREAK_WORD(SP); - PCQ_ENTRY(PC - 1); - POP(PC); - tStates += 11; - } - break; - - case 0xf1: /* POP AF */ - tStates += 10; - CHECK_BREAK_WORD(SP); - POP(AF); - break; - - case 0xf2: /* JP P,nnnn */ - sim_brk_pend[0] = FALSE; - JPC(!TSTFLAG(S)); /* also updates tStates */ - break; - - case 0xf3: /* DI */ - tStates += 4; - sim_brk_pend[0] = FALSE; - IFF_S = 0; - break; - - case 0xf4: /* CALL P,nnnn */ - CALLC(!TSTFLAG(S)); /* also updates tStates */ - break; - - case 0xf5: /* PUSH AF */ - tStates += 11; - CHECK_BREAK_WORD(SP - 2); - PUSH(AF); - break; - - case 0xf6: /* OR nn */ - tStates += 7; - sim_brk_pend[0] = FALSE; - AF = xororTable[((AF >> 8) | RAM_PP(PC)) & 0xff]; - break; - - case 0xf7: /* RST 30H */ - tStates += 11; - CHECK_BREAK_WORD(SP - 2); - PUSH(PC); - PCQ_ENTRY(PC - 1); - PC = 0x30; - break; - - case 0xf8: /* RET M */ - if (TSTFLAG(S)) { - CHECK_BREAK_WORD(SP); - PCQ_ENTRY(PC - 1); - POP(PC); - tStates += 11; - } - else { - sim_brk_pend[0] = FALSE; - tStates += 5; - } - break; - - case 0xf9: /* LD SP,HL */ - tStates += 6; - sim_brk_pend[0] = FALSE; - SP = HL; - break; - - case 0xfa: /* JP M,nnnn */ - sim_brk_pend[0] = FALSE; - JPC(TSTFLAG(S)); /* also updates tStates */ - break; - - case 0xfb: /* EI */ - tStates += 4; - sim_brk_pend[0] = FALSE; - IFF_S = 3; - break; - - case 0xfc: /* CALL M,nnnn */ - CALLC(TSTFLAG(S)); /* also updates tStates */ - break; - - case 0xfd: /* FD prefix */ - CHECK_CPU_8080; - switch (op = RAM_PP(PC)) { - - case 0x09: /* ADD IY,BC */ - tStates += 15; - sim_brk_pend[0] = FALSE; - IY &= ADDRMASK; - BC &= ADDRMASK; - sum = IY + BC; - AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IY ^ BC ^ sum) >> 8]; - IY = sum; - break; - - case 0x19: /* ADD IY,DE */ - tStates += 15; - sim_brk_pend[0] = FALSE; - IY &= ADDRMASK; - DE &= ADDRMASK; - sum = IY + DE; - AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IY ^ DE ^ sum) >> 8]; - IY = sum; - break; - - case 0x21: /* LD IY,nnnn */ - tStates += 14; - sim_brk_pend[0] = FALSE; - IY = GET_WORD(PC); - PC += 2; - break; - - case 0x22: /* LD (nnnn),IY */ - tStates += 20; - temp = GET_WORD(PC); - CHECK_BREAK_WORD(temp); - PutWORD(temp, IY); - PC += 2; - break; - - case 0x23: /* INC IY */ - tStates += 10; - sim_brk_pend[0] = FALSE; - ++IY; - break; - - case 0x24: /* INC IYH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - IY += 0x100; - AF = (AF & ~0xfe) | incZ80Table[HIGH_REGISTER(IY)]; - break; - - case 0x25: /* DEC IYH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - IY -= 0x100; - AF = (AF & ~0xfe) | decZ80Table[HIGH_REGISTER(IY)]; - break; - - case 0x26: /* LD IYH,nn */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(IY, RAM_PP(PC)); - break; - - case 0x29: /* ADD IY,IY */ - tStates += 15; - sim_brk_pend[0] = FALSE; - IY &= ADDRMASK; - sum = IY + IY; - AF = (AF & ~0x3b) | cbitsDup16Table[sum >> 8]; - IY = sum; - break; - - case 0x2a: /* LD IY,(nnnn) */ - tStates += 20; - temp = GET_WORD(PC); - CHECK_BREAK_WORD(temp); - IY = GET_WORD(temp); - PC += 2; - break; - - case 0x2b: /* DEC IY */ - tStates += 10; - sim_brk_pend[0] = FALSE; - --IY; - break; - - case 0x2c: /* INC IYL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(IY) + 1; - SET_LOW_REGISTER(IY, temp); - AF = (AF & ~0xfe) | incZ80Table[temp]; - break; - - case 0x2d: /* DEC IYL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(IY) - 1; - SET_LOW_REGISTER(IY, temp); - AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; - break; - - case 0x2e: /* LD IYL,nn */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(IY, RAM_PP(PC)); - break; - - case 0x34: /* INC (IY+dd) */ - tStates += 23; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - temp = GET_BYTE(adr) + 1; - PutBYTE(adr, temp); - AF = (AF & ~0xfe) | incZ80Table[temp]; - break; - - case 0x35: /* DEC (IY+dd) */ - tStates += 23; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - temp = GET_BYTE(adr) - 1; - PutBYTE(adr, temp); - AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; - break; - - case 0x36: /* LD (IY+dd),nn */ - tStates += 19; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - PutBYTE(adr, RAM_PP(PC)); - break; - - case 0x39: /* ADD IY,SP */ - tStates += 15; - sim_brk_pend[0] = FALSE; - IY &= ADDRMASK; - SP &= ADDRMASK; - sum = IY + SP; - AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IY ^ SP ^ sum) >> 8]; - IY = sum; - break; - - case 0x44: /* LD B,IYH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(BC, HIGH_REGISTER(IY)); - break; - - case 0x45: /* LD B,IYL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(BC, LOW_REGISTER(IY)); - break; - - case 0x46: /* LD B,(IY+dd) */ - tStates += 19; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - SET_HIGH_REGISTER(BC, GET_BYTE(adr)); - break; - - case 0x4c: /* LD C,IYH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(BC, HIGH_REGISTER(IY)); - break; - - case 0x4d: /* LD C,IYL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(BC, LOW_REGISTER(IY)); - break; - - case 0x4e: /* LD C,(IY+dd) */ - tStates += 19; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - SET_LOW_REGISTER(BC, GET_BYTE(adr)); - break; - - case 0x54: /* LD D,IYH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(DE, HIGH_REGISTER(IY)); - break; - - case 0x55: /* LD D,IYL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(DE, LOW_REGISTER(IY)); - break; - - case 0x56: /* LD D,(IY+dd) */ - tStates += 19; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - SET_HIGH_REGISTER(DE, GET_BYTE(adr)); - break; - - case 0x5c: /* LD E,IYH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(DE, HIGH_REGISTER(IY)); - break; - - case 0x5d: /* LD E,IYL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(DE, LOW_REGISTER(IY)); - break; - - case 0x5e: /* LD E,(IY+dd) */ - tStates += 19; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - SET_LOW_REGISTER(DE, GET_BYTE(adr)); - break; - - case 0x60: /* LD IYH,B */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(IY, HIGH_REGISTER(BC)); - break; - - case 0x61: /* LD IYH,C */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(IY, LOW_REGISTER(BC)); - break; - - case 0x62: /* LD IYH,D */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(IY, HIGH_REGISTER(DE)); - break; - - case 0x63: /* LD IYH,E */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(IY, LOW_REGISTER(DE)); - break; - - case 0x64: /* LD IYH,IYH */ - tStates += 9; - sim_brk_pend[0] = FALSE; /* nop */ - break; - - case 0x65: /* LD IYH,IYL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(IY, LOW_REGISTER(IY)); - break; - - case 0x66: /* LD H,(IY+dd) */ - tStates += 19; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - SET_HIGH_REGISTER(HL, GET_BYTE(adr)); - break; - - case 0x67: /* LD IYH,A */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(IY, HIGH_REGISTER(AF)); - break; - - case 0x68: /* LD IYL,B */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(IY, HIGH_REGISTER(BC)); - break; - - case 0x69: /* LD IYL,C */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(IY, LOW_REGISTER(BC)); - break; - - case 0x6a: /* LD IYL,D */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(IY, HIGH_REGISTER(DE)); - break; - - case 0x6b: /* LD IYL,E */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(IY, LOW_REGISTER(DE)); - break; - - case 0x6c: /* LD IYL,IYH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(IY, HIGH_REGISTER(IY)); - break; - - case 0x6d: /* LD IYL,IYL */ - tStates += 9; - sim_brk_pend[0] = FALSE; /* nop */ - break; - - case 0x6e: /* LD L,(IY+dd) */ - tStates += 19; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - SET_LOW_REGISTER(HL, GET_BYTE(adr)); - break; - - case 0x6f: /* LD IYL,A */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_LOW_REGISTER(IY, HIGH_REGISTER(AF)); - break; - - case 0x70: /* LD (IY+dd),B */ - tStates += 19; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - PutBYTE(adr, HIGH_REGISTER(BC)); - break; - - case 0x71: /* LD (IY+dd),C */ - tStates += 19; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - PutBYTE(adr, LOW_REGISTER(BC)); - break; - - case 0x72: /* LD (IY+dd),D */ - tStates += 19; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - PutBYTE(adr, HIGH_REGISTER(DE)); - break; - - case 0x73: /* LD (IY+dd),E */ - tStates += 19; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - PutBYTE(adr, LOW_REGISTER(DE)); - break; - - case 0x74: /* LD (IY+dd),H */ - tStates += 19; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - PutBYTE(adr, HIGH_REGISTER(HL)); - break; - - case 0x75: /* LD (IY+dd),L */ - tStates += 19; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - PutBYTE(adr, LOW_REGISTER(HL)); - break; - - case 0x77: /* LD (IY+dd),A */ - tStates += 19; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - PutBYTE(adr, HIGH_REGISTER(AF)); - break; - - case 0x7c: /* LD A,IYH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(AF, HIGH_REGISTER(IY)); - break; - - case 0x7d: /* LD A,IYL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - SET_HIGH_REGISTER(AF, LOW_REGISTER(IY)); - break; - - case 0x7e: /* LD A,(IY+dd) */ - tStates += 19; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - SET_HIGH_REGISTER(AF, GET_BYTE(adr)); - break; - - case 0x84: /* ADD A,IYH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - temp = HIGH_REGISTER(IY); - acu = HIGH_REGISTER(AF); - sum = acu + temp; - AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; - break; - - case 0x85: /* ADD A,IYL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(IY); - acu = HIGH_REGISTER(AF); - sum = acu + temp; - AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; - break; - - case 0x86: /* ADD A,(IY+dd) */ - tStates += 19; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - temp = GET_BYTE(adr); - acu = HIGH_REGISTER(AF); - sum = acu + temp; - AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; - break; - - case 0x8c: /* ADC A,IYH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - temp = HIGH_REGISTER(IY); - acu = HIGH_REGISTER(AF); - sum = acu + temp + TSTFLAG(C); - AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; - break; - - case 0x8d: /* ADC A,IYL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(IY); - acu = HIGH_REGISTER(AF); - sum = acu + temp + TSTFLAG(C); - AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; - break; - - case 0x8e: /* ADC A,(IY+dd) */ - tStates += 19; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - temp = GET_BYTE(adr); - acu = HIGH_REGISTER(AF); - sum = acu + temp + TSTFLAG(C); - AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; - break; - - case 0x96: /* SUB (IY+dd) */ - tStates += 19; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - temp = GET_BYTE(adr); - acu = HIGH_REGISTER(AF); - sum = acu - temp; - AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - - case 0x94: /* SUB IYH */ - SETFLAG(C, 0);/* fall through, a bit less efficient but smaller code */ - - case 0x9c: /* SBC A,IYH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - temp = HIGH_REGISTER(IY); - acu = HIGH_REGISTER(AF); - sum = acu - temp - TSTFLAG(C); - AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - - case 0x95: /* SUB IYL */ - SETFLAG(C, 0);/* fall through, a bit less efficient but smaller code */ - - case 0x9d: /* SBC A,IYL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(IY); - acu = HIGH_REGISTER(AF); - sum = acu - temp - TSTFLAG(C); - AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - - case 0x9e: /* SBC A,(IY+dd) */ - tStates += 19; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - temp = GET_BYTE(adr); - acu = HIGH_REGISTER(AF); - sum = acu - temp - TSTFLAG(C); - AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - - case 0xa4: /* AND IYH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - AF = andTable[((AF & IY) >> 8) & 0xff]; - break; - - case 0xa5: /* AND IYL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - AF = andTable[((AF >> 8) & IY) & 0xff]; - break; - - case 0xa6: /* AND (IY+dd) */ - tStates += 19; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - AF = andTable[((AF >> 8) & GET_BYTE(adr)) & 0xff]; - break; - - case 0xac: /* XOR IYH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - AF = xororTable[((AF ^ IY) >> 8) & 0xff]; - break; - - case 0xad: /* XOR IYL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - AF = xororTable[((AF >> 8) ^ IY) & 0xff]; - break; - - case 0xae: /* XOR (IY+dd) */ - tStates += 19; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - AF = xororTable[((AF >> 8) ^ GET_BYTE(adr)) & 0xff]; - break; - - case 0xb4: /* OR IYH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - AF = xororTable[((AF | IY) >> 8) & 0xff]; - break; - - case 0xb5: /* OR IYL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - AF = xororTable[((AF >> 8) | IY) & 0xff]; - break; - - case 0xb6: /* OR (IY+dd) */ - tStates += 19; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - AF = xororTable[((AF >> 8) | GET_BYTE(adr)) & 0xff]; - break; - - case 0xbc: /* CP IYH */ - tStates += 9; - sim_brk_pend[0] = FALSE; - temp = HIGH_REGISTER(IY); - AF = (AF & ~0x28) | (temp & 0x28); - acu = HIGH_REGISTER(AF); - sum = acu - temp; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - - case 0xbd: /* CP IYL */ - tStates += 9; - sim_brk_pend[0] = FALSE; - temp = LOW_REGISTER(IY); - AF = (AF & ~0x28) | (temp & 0x28); - acu = HIGH_REGISTER(AF); - sum = acu - temp; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - - case 0xbe: /* CP (IY+dd) */ - tStates += 19; - adr = IY + (int8) RAM_PP(PC); - CHECK_BREAK_BYTE(adr); - temp = GET_BYTE(adr); - AF = (AF & ~0x28) | (temp & 0x28); - acu = HIGH_REGISTER(AF); - sum = acu - temp; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; - break; - - case 0xcb: /* CB prefix */ - adr = IY + (int8) RAM_PP(PC); - switch ((op = GET_BYTE(PC)) & 7) { - - case 0: - sim_brk_pend[0] = FALSE; - ++PC; - acu = HIGH_REGISTER(BC); - break; - - case 1: - sim_brk_pend[0] = FALSE; - ++PC; - acu = LOW_REGISTER(BC); - break; - - case 2: - sim_brk_pend[0] = FALSE; - ++PC; - acu = HIGH_REGISTER(DE); - break; - - case 3: - sim_brk_pend[0] = FALSE; - ++PC; - acu = LOW_REGISTER(DE); - break; - - case 4: - sim_brk_pend[0] = FALSE; - ++PC; - acu = HIGH_REGISTER(HL); - break; - - case 5: - sim_brk_pend[0] = FALSE; - ++PC; - acu = LOW_REGISTER(HL); - break; - - case 6: - CHECK_BREAK_BYTE(adr); - ++PC; - acu = GET_BYTE(adr); - break; - - case 7: - sim_brk_pend[0] = FALSE; - ++PC; - acu = HIGH_REGISTER(AF); - break; - } - switch (op & 0xc0) { - - case 0x00: /* shift/rotate */ - tStates += 23; - switch (op & 0x38) { - - case 0x00: /* RLC */ - temp = (acu << 1) | (acu >> 7); - cbits = temp & 1; - goto cbshflg3; - - case 0x08: /* RRC */ - temp = (acu >> 1) | (acu << 7); - cbits = temp & 0x80; - goto cbshflg3; - - case 0x10: /* RL */ - temp = (acu << 1) | TSTFLAG(C); - cbits = acu & 0x80; - goto cbshflg3; - - case 0x18: /* RR */ - temp = (acu >> 1) | (TSTFLAG(C) << 7); - cbits = acu & 1; - goto cbshflg3; - - case 0x20: /* SLA */ - temp = acu << 1; - cbits = acu & 0x80; - goto cbshflg3; - - case 0x28: /* SRA */ - temp = (acu >> 1) | (acu & 0x80); - cbits = acu & 1; - goto cbshflg3; - - case 0x30: /* SLIA */ - temp = (acu << 1) | 1; - cbits = acu & 0x80; - goto cbshflg3; - - case 0x38: /* SRL */ - temp = acu >> 1; - cbits = acu & 1; - cbshflg3: - AF = (AF & ~0xff) | rotateShiftTable[temp & 0xff] | !!cbits; - } - break; - - case 0x40: /* BIT */ - tStates += 20; - if (acu & (1 << ((op >> 3) & 7))) { - AF = (AF & ~0xfe) | 0x10 | (((op & 0x38) == 0x38) << 7); - } - else { - AF = (AF & ~0xfe) | 0x54; - } - if ((op & 7) != 6) { - AF |= (acu & 0x28); - } - temp = acu; - break; - - case 0x80: /* RES */ - tStates += 23; - temp = acu & ~(1 << ((op >> 3) & 7)); - break; - - case 0xc0: /* SET */ - tStates += 23; - temp = acu | (1 << ((op >> 3) & 7)); - break; - } - switch (op & 7) { - - case 0: - SET_HIGH_REGISTER(BC, temp); - break; - - case 1: - SET_LOW_REGISTER(BC, temp); - break; - - case 2: - SET_HIGH_REGISTER(DE, temp); - break; - - case 3: - SET_LOW_REGISTER(DE, temp); - break; - - case 4: - SET_HIGH_REGISTER(HL, temp); - break; - - case 5: - SET_LOW_REGISTER(HL, temp); - break; - - case 6: - PutBYTE(adr, temp); - break; - - case 7: - SET_HIGH_REGISTER(AF, temp); - break; - } - break; - - case 0xe1: /* POP IY */ - tStates += 14; - CHECK_BREAK_WORD(SP); - POP(IY); - break; - - case 0xe3: /* EX (SP),IY */ - tStates += 23; - CHECK_BREAK_WORD(SP); - temp = IY; - POP(IY); - PUSH(temp); - break; - - case 0xe5: /* PUSH IY */ - tStates += 15; - CHECK_BREAK_WORD(SP - 2); - PUSH(IY); - break; - - case 0xe9: /* JP (IY) */ - tStates += 8; - sim_brk_pend[0] = FALSE; - PCQ_ENTRY(PC - 2); - PC = IY; - break; - - case 0xf9: /* LD SP,IY */ - tStates += 10; - sim_brk_pend[0] = FALSE; - SP = IY; - break; - - default: /* ignore FD */ - sim_brk_pend[0] = FALSE; - CHECK_CPU_Z80; - PC--; - } - break; - - case 0xfe: /* CP nn */ - tStates += 7; - sim_brk_pend[0] = FALSE; - temp = RAM_PP(PC); - AF = (AF & ~0x28) | (temp & 0x28); - acu = HIGH_REGISTER(AF); - sum = acu - temp; - cbits = acu ^ temp ^ sum; - AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | - (SET_PV) | cbits2Table[cbits & 0x1ff]; - break; - - case 0xff: /* RST 38H */ - tStates += 11; - CHECK_BREAK_WORD(SP - 2); - PUSH(PC); - PCQ_ENTRY(PC - 1); - PC = 0x38; - } - } - end_decode: - - /* simulation halted */ - saved_PC = ((reason == STOP_OPCODE) || (reason == STOP_MEM)) ? PCX : PC; - pcq_r -> qptr = pcq_p; /* update pc q ptr */ - AF_S = AF; - BC_S = BC; - DE_S = DE; - HL_S = HL; - IX_S = IX; - IY_S = IY; - SP_S = SP; - executedTStates = tStates; - return reason; -} - -static void checkROMBoundaries(void) { - uint32 temp; - if (ROMLow > ROMHigh) { - printf("ROMLOW [%04X] must be less than or equal to ROMHIGH [%04X]. Values exchanged.\n", - ROMLow, ROMHigh); - temp = ROMLow; - ROMLow = ROMHigh; - ROMHigh = temp; - } - if (cpu_unit.flags & UNIT_ALTAIRROM) { - if (DEFAULT_ROM_LOW < ROMLow) { - printf("ROMLOW [%04X] reset to %04X since Altair ROM was desired.\n", ROMLow, DEFAULT_ROM_LOW); - ROMLow = DEFAULT_ROM_LOW; - } - if (ROMHigh < DEFAULT_ROM_HIGH) { - printf("ROMHIGH [%04X] reset to %04X since Altair ROM was desired.\n", ROMHigh, DEFAULT_ROM_HIGH); - ROMHigh = DEFAULT_ROM_HIGH; - } - } -} - -static void reset_memory(void) { - uint32 i, j; - checkROMBoundaries(); - if (cpu_unit.flags & UNIT_BANKED) { - for (i = 0; i < MAXMEMSIZE; i++) { - for (j = 0; j < MAXBANKS; j++) { - resetCell(i, j); - } - } - } - else if (cpu_unit.flags & UNIT_ROM) { - for (i = 0; i < ROMLow; i++) { - resetCell(i, 0); - } - for (i = ROMHigh + 1; i < MAXMEMSIZE; i++) { - resetCell(i, 0); - } - } - else { - for (i = 0; i < MAXMEMSIZE; i++) { - resetCell(i, 0); - } - } - if (cpu_unit.flags & (UNIT_ALTAIRROM | UNIT_BANKED)) { - install_bootrom(); - } - isProtected = FALSE; -} - -static void printROMMessage(const uint32 cntROM) { - if (cntROM) { - printf("Warning: %d bytes written to ROM [%04X - %04X].\n", cntROM, ROMLow, ROMHigh); - } -} - -/* reset routine */ - -t_stat cpu_reset(DEVICE *dptr) { - extern uint32 sim_brk_types, sim_brk_dflt; /* breakpoint info */ - int32 i; - AF_S = AF1_S = 0; - BC_S = DE_S = HL_S = 0; - BC1_S = DE1_S = HL1_S = 0; - IR_S = IX_S = IY_S = SP_S = 0; - IFF_S = 3; - setBankSelect(0); - reset_memory(); - sim_brk_types = (SWMASK('E') | SWMASK('M')); - sim_brk_dflt = SWMASK('E'); - for (i = 0; i < PCQ_SIZE; i++) { - pcq[i] = 0; - } - pcq_p = 0; - pcq_r = find_reg("PCQ", NULL, dptr); - if (pcq_r) { - pcq_r -> qptr = 0; - } - else { - return SCPE_IERR; - } - return SCPE_OK; -} - -static t_stat cpu_set_rom(UNIT *uptr, int32 value, char *cptr, void *desc) { - checkROMBoundaries(); - return SCPE_OK; -} - -static t_stat cpu_set_norom(UNIT *uptr, int32 value, char *cptr, void *desc) { - if (cpu_unit.flags & UNIT_ALTAIRROM) { - printf("\"SET CPU NOALTAIRROM\" also executed.\n"); - cpu_unit.flags &= ~UNIT_ALTAIRROM; - } - return SCPE_OK; -} - -static t_stat cpu_set_altairrom(UNIT *uptr, int32 value, char *cptr, void *desc) { - install_bootrom(); - if (ROMLow != DEFAULT_ROM_LOW) { - printf("\"D ROMLOW %04X\" also executed.\n", DEFAULT_ROM_LOW); - ROMLow = DEFAULT_ROM_LOW; - } - if (ROMHigh != DEFAULT_ROM_HIGH) { - printf("\"D ROMHIGH %04X\" also executed.\n", DEFAULT_ROM_HIGH); - ROMHigh = DEFAULT_ROM_HIGH; - } - if (!(cpu_unit.flags & UNIT_ROM)) { - printf("\"SET CPU ROM\" also executed.\n"); - cpu_unit.flags |= UNIT_ROM; - } - return SCPE_OK; -} - -static t_stat cpu_set_warnrom(UNIT *uptr, int32 value, char *cptr, void *desc) { - if ((!(cpu_unit.flags & UNIT_ROM)) && (MEMSIZE >= 64*KB)) { - printf("CPU has currently no ROM - no warning to be expected.\n"); - } - return SCPE_OK; -} - -static t_stat cpu_set_banked(UNIT *uptr, int32 value, char *cptr, void *desc) { - if (common > DEFAULT_ROM_LOW) { - printf("Warning: COMMON [%04X] must not be greater than %04X. Reset to %04X.\n", - common, DEFAULT_ROM_LOW, DEFAULT_ROM_LOW); - common = DEFAULT_ROM_LOW; - } - if (MEMSIZE != (MAXBANKS * MAXMEMSIZE)) { - previousCapacity = MEMSIZE; - } - MEMSIZE = MAXBANKS * MAXMEMSIZE; - cpu_dev.awidth = 16 + MAXBANKSLOG2; - return SCPE_OK; -} - -static t_stat cpu_set_nonbanked(UNIT *uptr, int32 value, char *cptr, void *desc) { - if (MEMSIZE == (MAXBANKS * MAXMEMSIZE)) { - MEMSIZE = previousCapacity ? previousCapacity : 64*KB; - } - cpu_dev.awidth = 16; - return SCPE_OK; -} - -static t_stat cpu_set_size(UNIT *uptr, int32 value, char *cptr, void *desc) { - if (cpu_unit.flags & UNIT_BANKED) { - printf("\"SET CPU NONBANKED\" also executed.\n"); - cpu_unit.flags &= ~UNIT_BANKED; - } - MEMSIZE = value; - cpu_dev.awidth = 16; - reset_memory(); - return SCPE_OK; -} - -/* This is the binary loader. The input file is considered to be - a string of literal bytes with no format special format. The - load starts at the current value of the PC. ROM/NOROM and - ALTAIRROM/NOALTAIRROM settings are ignored. -*/ - -t_stat sim_load(FILE *fileref, char *cptr, char *fnam, int32 flag) { - int32 i, addr = 0, cnt = 0, org, cntROM = 0, cntNonExist = 0; - t_addr j, lo, hi; - char *result; - t_stat status; - if (flag) { - result = get_range(NULL, cptr, &lo, &hi, 16, ADDRMASK, 0); - if (result == NULL) { - return SCPE_ARG; - } - for (j = lo; j <= hi; j++) { - if (putc(GET_BYTE(j), fileref) == EOF) { - return SCPE_IOERR; - } - } - printf("%d byte%s dumped [%x - %x].\n", hi + 1 - lo, hi == lo ? "" : "s", lo, hi); - } - else { - if (*cptr == 0) { - addr = saved_PC; - } - else { - addr = get_uint(cptr, 16, ADDRMASK, &status); - if (status != SCPE_OK) { - return status; - } - } - org = addr; - while ((addr < MAXMEMSIZE) && ((i = getc(fileref)) != EOF)) { - PutBYTEForced(addr, i); - if (addressIsInROM(addr)) { - cntROM++; - } - if (!addressExists(addr)) { - cntNonExist++; - } - addr++; - cnt++; - } /* end while */ - printf("%d bytes [%d page%s] loaded at %x.\n", cnt, (cnt + 255) >> 8, - ((cnt + 255) >> 8) == 1 ? "" : "s", org); - printROMMessage(cntROM); - if (cntNonExist) { - printf("Warning: %d bytes written to non-existing memory (for this configuration).\n", cntNonExist); - } - } - return SCPE_OK; -} +/* altairz80_cpu.c: MITS Altair CPU (8080 and Z80) + + Copyright (c) 2002-2008, Peter Schorn + + 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 + PETER SCHORN 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 Peter Schorn shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Peter Schorn. + + Based on work by Charles E Owen (c) 1997 + Code for Z80 CPU from Frank D. Cringle ((c) 1995 under GNU license) +*/ + +#include "altairz80_defs.h" +#include +#define SWITCHCPU_DEFAULT 0xfd + +#if defined (_WIN32) +#include +#else +#include +#endif + +#define PCQ_SIZE 64 /* must be 2**n */ +#define PCQ_SIZE_LOG2 6 /* log2 of PCQ_SIZE */ +#define PCQ_MASK (PCQ_SIZE - 1) +#define PCQ_ENTRY(PC) if (pcq[pcq_p] != (PC)) { pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = (PC); } + +#define FLAG_C 1 +#define FLAG_N 2 +#define FLAG_P 4 +#define FLAG_H 16 +#define FLAG_Z 64 +#define FLAG_S 128 + +#define SETFLAG(f,c) AF = (c) ? AF | FLAG_ ## f : AF & ~FLAG_ ## f +#define TSTFLAG(f) ((AF & FLAG_ ## f) != 0) + +#define LOW_DIGIT(x) ((x) & 0xf) +#define HIGH_DIGIT(x) (((x) >> 4) & 0xf) +#define LOW_REGISTER(x) ((x) & 0xff) +#define HIGH_REGISTER(x) (((x) >> 8) & 0xff) + +#define SET_LOW_REGISTER(x, v) x = (((x) & 0xff00) | ((v) & 0xff)) +#define SET_HIGH_REGISTER(x, v) x = (((x) & 0xff) | (((v) & 0xff) << 8)) + +#define PARITY(x) parityTable[(x) & 0xff] +/* SET_PV and SET_PV2 are used to provide correct PARITY flag semantics for the 8080 in cases + where the Z80 uses the overflow flag +*/ +#define SET_PVS(s) ((chiptype == CHIP_TYPE_Z80) ? (((cbits >> 6) ^ (cbits >> 5)) & 4) : (PARITY(s))) +#define SET_PV (SET_PVS(sum)) +#define SET_PV2(x) ((chiptype == CHIP_TYPE_Z80) ? (((temp == (x)) << 2)) : (PARITY(temp))) + +/* CHECK_CPU_8080 must be invoked whenever a Z80 only instruction is executed + In case a Z80 instruction is executed on an 8080 the following two cases exist: + 1) Trapping is enabled: execution stops + 2) Trapping is not enabled: decoding continues with the next byte +*/ +#define CHECK_CPU_8080 \ + if (chiptype == CHIP_TYPE_8080) { \ + if (cpu_unit.flags & UNIT_CPU_OPSTOP) { \ + reason = STOP_OPCODE; \ + goto end_decode; \ + } \ + else { \ + sim_brk_pend[0] = FALSE; \ + continue; \ + } \ + } + +/* CHECK_CPU_Z80 must be invoked whenever a non Z80 instruction is executed */ +#define CHECK_CPU_Z80 \ + if (cpu_unit.flags & UNIT_CPU_OPSTOP) { \ + reason = STOP_OPCODE; \ + goto end_decode; \ + } + +#define POP(x) { \ + register uint32 y = RAM_PP(SP); \ + x = y + (RAM_PP(SP) << 8); \ +} + +#define JPC(cond) { \ + tStates += 10; \ + if (cond) { \ + PCQ_ENTRY(PCX); \ + PC = GET_WORD(PC); \ + } \ + else { \ + PC += 2; \ + } \ +} + +#define CALLC(cond) { \ + if (cond) { \ + register uint32 adrr = GET_WORD(PC); \ + CHECK_BREAK_WORD(SP - 2); \ + PUSH(PC + 2); \ + PCQ_ENTRY(PCX); \ + PC = adrr; \ + tStates += 17; \ + } \ + else { \ + sim_brk_pend[0] = FALSE; \ + PC += 2; \ + tStates += 10; \ + } \ +} + +extern int32 sim_int_char; +extern int32 sio0s (const int32 port, const int32 io, const int32 data); +extern int32 sio0d (const int32 port, const int32 io, const int32 data); +extern int32 sio1s (const int32 port, const int32 io, const int32 data); +extern int32 sio1d (const int32 port, const int32 io, const int32 data); +extern int32 dsk10 (const int32 port, const int32 io, const int32 data); +extern int32 dsk11 (const int32 port, const int32 io, const int32 data); +extern int32 dsk12 (const int32 port, const int32 io, const int32 data); +extern int32 netStatus (const int32 port, const int32 io, const int32 data); +extern int32 netData (const int32 port, const int32 io, const int32 data); +extern int32 nulldev (const int32 port, const int32 io, const int32 data); +extern int32 hdsk_io (const int32 port, const int32 io, const int32 data); +extern int32 simh_dev (const int32 port, const int32 io, const int32 data); +extern int32 sr_dev (const int32 port, const int32 io, const int32 data); +extern void install_ALTAIRbootROM(void); +extern char messageBuffer[]; +extern void printMessage(void); +extern void do_SIMH_sleep(void); + +extern t_stat sim_instr_nommu(void); +extern uint8 MOPT[MAXBANKSIZE]; +extern t_stat sim_instr_8086(void); +extern t_stat sim_instr_8086(void); +extern void cpu8086reset(void); + +/* function prototypes */ +#ifdef CPUSWITCHER +static t_stat cpu_set_switcher (UNIT *uptr, int32 value, char *cptr, void *desc); +static t_stat cpu_reset_switcher(UNIT *uptr, int32 value, char *cptr, void *desc); +static t_stat cpu_show_switcher (FILE *st, UNIT *uptr, int32 val, void *desc); +static int32 switchcpu_io (const int32 port, const int32 io, const int32 data); +#endif + +static t_stat cpu_set_altairrom (UNIT *uptr, int32 value, char *cptr, void *desc); +static t_stat cpu_set_noaltairrom (UNIT *uptr, int32 value, char *cptr, void *desc); +static t_stat cpu_set_nommu (UNIT *uptr, int32 value, char *cptr, void *desc); +static t_stat cpu_set_banked (UNIT *uptr, int32 value, char *cptr, void *desc); +static t_stat cpu_set_nonbanked (UNIT *uptr, int32 value, char *cptr, void *desc); +static t_stat cpu_set_ramtype (UNIT *uptr, int32 value, char *cptr, void *desc); +static t_stat cpu_set_chiptype (UNIT *uptr, int32 value, char *cptr, void *desc); +static t_stat cpu_set_size (UNIT *uptr, int32 value, char *cptr, void *desc); +static t_stat cpu_set_memory (UNIT *uptr, int32 value, char *cptr, void *desc); +static t_stat cpu_clear_command (UNIT *uptr, int32 value, char *cptr, void *desc); +static void cpu_clear(void); +static t_stat cpu_show (FILE *st, UNIT *uptr, int32 val, void *desc); +static t_stat chip_show (FILE *st, UNIT *uptr, int32 val, void *desc); +static t_stat cpu_ex(t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +static t_stat cpu_dep(t_value val, t_addr addr, UNIT *uptr, int32 sw); +static t_stat cpu_reset(DEVICE *dptr); +static t_stat sim_instr_mmu(void); +static uint32 GetBYTE(register uint32 Addr); +static void PutWORD(register uint32 Addr, const register uint32 Value); +static void PutBYTE(register uint32 Addr, const register uint32 Value); +void out(const uint32 Port, const uint32 Value); +uint32 in(const uint32 Port); +void altairz80_init(void); +t_stat sim_instr(void); +t_stat install_bootrom(int32 bootrom[], int32 size, int32 addr, int32 makeROM); +uint8 GetBYTEWrapper(const uint32 Addr); +void PutBYTEWrapper(const uint32 Addr, const uint32 Value); +int32 getBankSelect(void); +void setBankSelect(const int32 b); +uint32 getCommon(void); +t_stat sim_load(FILE *fileref, char *cptr, char *fnam, int32 flag); +uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, + int32 (*routine)(const int32, const int32, const int32), uint8 unmap); + +void PutBYTEExtended(register uint32 Addr, const register uint32 Value); +uint32 GetBYTEExtended(register uint32 Addr); + +/* CPU data structures + cpu_dev CPU device descriptor + cpu_unit CPU unit descriptor + cpu_reg CPU register list + cpu_mod CPU modifiers list +*/ + +UNIT cpu_unit = { + UDATA (NULL, UNIT_FIX | UNIT_BINK | UNIT_CPU_ALTAIRROM | + UNIT_CPU_STOPONHALT | UNIT_CPU_MMU, MAXBANKSIZE) +}; + + uint32 PCX = 0; /* external view of PC */ + int32 AF_S; /* AF register */ + int32 BC_S; /* BC register */ + int32 DE_S; /* DE register */ + int32 HL_S; /* HL register */ + int32 IX_S; /* IX register */ + int32 IY_S; /* IY register */ + int32 PC_S = 0; /* program counter */ + int32 SP_S; /* SP register */ + int32 AF1_S; /* alternate AF register */ + int32 BC1_S; /* alternate BC register */ + int32 DE1_S; /* alternate DE register */ + int32 HL1_S; /* alternate HL register */ + int32 IFF_S; /* Interrupt Flip Flop */ + int32 IR_S; /* Interrupt (upper) / Refresh (lower) register */ + int32 AX_S; /* AX register (8086) */ + int32 BX_S; /* BX register (8086) */ + int32 CX_S; /* CX register (8086) */ + int32 DX_S; /* DX register (8086) */ + int32 CS_S; /* CS register (8086) */ + int32 DS_S; /* DS register (8086) */ + int32 ES_S; /* ES register (8086) */ + int32 SS_S; /* SS register (8086) */ + int32 DI_S; /* DI register (8086) */ + int32 SI_S; /* SI register (8086) */ + int32 BP_S; /* BP register (8086) */ + int32 SP8086_S; /* SP register (8086) */ + int32 IP_S; /* IP register (8086) */ + int32 FLAGS_S; /* flags register (8086) */ + int32 SR = 0; /* switch register */ +static int32 bankSelect = 0; /* determines selected memory bank */ +static uint32 common = 0xc000; /* addresses >= 'common' are in common memory */ +static uint32 previousCapacity = MAXBANKSIZE; /* safe for previous memory capacity */ +static uint32 clockFrequency = 0; /* in kHz, 0 means as fast as possible */ +static uint32 sliceLength = 10; /* length of time-slice for CPU speed */ + /* adjustment in milliseconds */ +static uint32 executedTStates = 0; /* executed t-states */ +static uint16 pcq[PCQ_SIZE] = { /* PC queue */ + 0 +}; +static int32 pcq_p = 0; /* PC queue ptr */ +static REG *pcq_r = NULL; /* PC queue reg ptr */ + +/* data structure for IN/OUT instructions */ +struct idev { + int32 (*routine)(const int32, const int32, const int32); +}; + +#ifdef CPUSWITCHER +static int32 switcherPort = SWITCHCPU_DEFAULT; +static struct idev oldSwitcherDevice = { NULL }; +#endif + +REG cpu_reg[] = { + { HRDATA (AF, AF_S, 16) }, + { HRDATA (BC, BC_S, 16) }, + { HRDATA (DE, DE_S, 16) }, + { HRDATA (HL, HL_S, 16) }, + { HRDATA (IX, IX_S, 16) }, + { HRDATA (IY, IY_S, 16) }, + { HRDATA (PC, PC_S, 16 + MAXBANKSLOG2) }, + { HRDATA (SP, SP_S, 16) }, + { HRDATA (AF1, AF1_S, 16) }, + { HRDATA (BC1, BC1_S, 16) }, + { HRDATA (DE1, DE1_S, 16) }, + { HRDATA (HL1, HL1_S, 16) }, + { GRDATA (IFF, IFF_S, 2, 2, 0) }, + { FLDATA (IR, IR_S, 8) }, + { HRDATA (AX, AX_S, 16) }, /* 8086 */ + { GRDATA (AL, AX_S, 16, 8, 0) }, /* 8086, low 8 bits of AX */ + { GRDATA (AH, AX_S, 16, 8, 8) }, /* 8086, high 8 bits of AX */ + { HRDATA (BX, BX_S, 16) }, /* 8086 */ + { GRDATA (BL, BX_S, 16, 8, 0) }, /* 8086, low 8 bits of BX */ + { GRDATA (BH, BX_S, 16, 8, 8) }, /* 8086, high 8 bits of BX */ + { HRDATA (CX, CX_S, 16) }, /* 8086 */ + { GRDATA (CL, CX_S, 16, 8, 0) }, /* 8086, low 8 bits of CX */ + { GRDATA (CH, CX_S, 16, 8, 8) }, /* 8086, high 8 bits of CX */ + { HRDATA (DX, DX_S, 16) }, /* 8086 */ + { GRDATA (DL, DX_S, 16, 8, 0) }, /* 8086, low 8 bits of DX */ + { GRDATA (DH, DX_S, 16, 8, 8) }, /* 8086, high 8 bits of DX */ + { HRDATA (SP86, SP8086_S, 16) }, /* 8086 */ + { HRDATA (BP, BP_S, 16) }, /* 8086, Base Pointer */ + { HRDATA (SI, SI_S, 16) }, /* 8086, Source Index */ + { HRDATA (DI, DI_S, 16) }, /* 8086, Destination Index */ + { HRDATA (CS, CS_S, 16) }, /* 8086, Code Segment */ + { HRDATA (DS, DS_S, 16) }, /* 8086, Data Segment */ + { HRDATA (ES, ES_S, 16) }, /* 8086, Extra Segment */ + { HRDATA (SS, SS_S, 16) }, /* 8086, Stack Segment */ + { HRDATA (FLAGS, FLAGS_S, 16) }, /* 8086, FLAGS */ + { HRDATA (IP, IP_S, 16), REG_RO }, /* 8086, set via PC */ + { FLDATA (OPSTOP, cpu_unit.flags, UNIT_CPU_V_OPSTOP), REG_HRO }, + { HRDATA (SR, SR, 8) }, + { HRDATA (BANK, bankSelect, MAXBANKSLOG2) }, + { HRDATA (COMMON, common, 32) }, +#ifdef CPUSWITCHER + { HRDATA (SWITCHERPORT, switcherPort, 8), }, +#endif + { DRDATA (CLOCK, clockFrequency, 32) }, + { DRDATA (SLICE, sliceLength, 16) }, + { DRDATA (TSTATES, executedTStates, 32), REG_RO }, + { HRDATA (CAPACITY, cpu_unit.capac, 32), REG_RO }, + { HRDATA (PREVCAP, previousCapacity, 32), REG_RO }, + { BRDATA (PCQ, pcq, 16, 16, PCQ_SIZE), REG_RO + REG_CIRC }, + { DRDATA (PCQP, pcq_p, PCQ_SIZE_LOG2), REG_HRO }, + { HRDATA (WRU, sim_int_char, 8) }, + { NULL } +}; + +static MTAB cpu_mod[] = { + { MTAB_XTD | MTAB_VDV, CHIP_TYPE_8080, NULL, "8080", &cpu_set_chiptype }, + { MTAB_XTD | MTAB_VDV, CHIP_TYPE_Z80, NULL, "Z80", &cpu_set_chiptype }, + { MTAB_XTD | MTAB_VDV, CHIP_TYPE_8086, NULL, "8086", &cpu_set_chiptype }, + { UNIT_CPU_OPSTOP, UNIT_CPU_OPSTOP, "ITRAP", "ITRAP", NULL, &chip_show }, + { UNIT_CPU_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL, &chip_show }, + { UNIT_CPU_STOPONHALT, UNIT_CPU_STOPONHALT,"STOPONHALT", "STOPONHALT", NULL }, + { UNIT_CPU_STOPONHALT, 0, "LOOPONHALT", "LOOPONHALT", NULL }, + { UNIT_CPU_BANKED, UNIT_CPU_BANKED, "BANKED", "BANKED", &cpu_set_banked }, + { UNIT_CPU_BANKED, 0, "NONBANKED", "NONBANKED", &cpu_set_nonbanked }, + { UNIT_CPU_ALTAIRROM, UNIT_CPU_ALTAIRROM, "ALTAIRROM", "ALTAIRROM", &cpu_set_altairrom }, + { UNIT_CPU_ALTAIRROM, 0, "NOALTAIRROM", "NOALTAIRROM", &cpu_set_noaltairrom}, + { UNIT_CPU_VERBOSE, UNIT_CPU_VERBOSE, "VERBOSE", "VERBOSE", NULL, &cpu_show }, + { UNIT_CPU_VERBOSE, 0, "QUIET", "QUIET", NULL }, + { MTAB_VDV, 0, NULL, "CLEARMEMORY", &cpu_clear_command }, + { UNIT_CPU_MMU, UNIT_CPU_MMU, "MMU", "MMU", NULL }, + { UNIT_CPU_MMU, 0, "NOMMU", "NOMMU", &cpu_set_nommu }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "MEMORY", &cpu_set_memory }, +#ifdef CPUSWITCHER + { UNIT_CPU_SWITCHER, UNIT_CPU_SWITCHER, "SWITCHER", "SWITCHER", &cpu_set_switcher, &cpu_show_switcher }, + { UNIT_CPU_SWITCHER, 0, "NOSWITCHER", "NOSWITCHER", &cpu_reset_switcher, &cpu_show_switcher }, +#endif + { MTAB_XTD | MTAB_VDV, 0, NULL, "AZ80", &cpu_set_ramtype }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "HRAM", &cpu_set_ramtype }, + { MTAB_XTD | MTAB_VDV, 2, NULL, "VRAM", &cpu_set_ramtype }, + { MTAB_XTD | MTAB_VDV, 3, NULL, "CRAM", &cpu_set_ramtype }, + { MTAB_VDV, 4, NULL, "4KB", &cpu_set_size }, + { MTAB_VDV, 8, NULL, "8KB", &cpu_set_size }, + { MTAB_VDV, 12, NULL, "12KB", &cpu_set_size }, + { MTAB_VDV, 16, NULL, "16KB", &cpu_set_size }, + { MTAB_VDV, 20, NULL, "20KB", &cpu_set_size }, + { MTAB_VDV, 24, NULL, "24KB", &cpu_set_size }, + { MTAB_VDV, 28, NULL, "28KB", &cpu_set_size }, + { MTAB_VDV, 32, NULL, "32KB", &cpu_set_size }, + { MTAB_VDV, 36, NULL, "36KB", &cpu_set_size }, + { MTAB_VDV, 40, NULL, "40KB", &cpu_set_size }, + { MTAB_VDV, 44, NULL, "44KB", &cpu_set_size }, + { MTAB_VDV, 48, NULL, "48KB", &cpu_set_size }, + { MTAB_VDV, 52, NULL, "52KB", &cpu_set_size }, + { MTAB_VDV, 56, NULL, "56KB", &cpu_set_size }, + { MTAB_VDV, 60, NULL, "60KB", &cpu_set_size }, + { MTAB_VDV, 64, NULL, "64KB", &cpu_set_size }, + { 0 } +}; + +DEVICE cpu_dev = { + "CPU", &cpu_unit, cpu_reg, cpu_mod, + 1, 16, 16, 1, 16, 8, + &cpu_ex, &cpu_dep, &cpu_reset, + NULL, NULL, NULL, + NULL, 0, 0, + NULL, NULL, NULL +}; + +/* This is the I/O configuration table. There are 255 possible + device addresses, if a device is plugged to a port it's routine + address is here, 'nulldev' means no device is available +*/ +static struct idev dev_table[256] = { + {&nulldev}, {&nulldev}, {&sio0d}, {&sio0s}, /* 00 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 04 */ + {&dsk10}, {&dsk11}, {&dsk12}, {&nulldev}, /* 08 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0C */ + {&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /* 10 */ + {&sio0s}, {&sio0d}, {&sio0s}, {&sio0d}, /* 14 */ + {&sio0s}, {&sio0d}, {&nulldev}, {&nulldev}, /* 18 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1C */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 20 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 24 */ + {&netStatus},{&netData},{&netStatus},{&netData}, /* 28 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2C */ + {&nulldev}, {&nulldev}, {&netStatus},{&netData}, /* 30 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 34 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 38 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3C */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 40 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 44 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 48 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 4C */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 50 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 54 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 58 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 5C */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 60 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 64 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 68 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 6C */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 70 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 74 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 78 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 7C */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 80 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 84 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 88 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 8C */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 90 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 94 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 98 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 9C */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* A0 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* A4 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* A8 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* AC */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* B0 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* B4 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* B8 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* BC */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* C0 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* C4 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* C8 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* CC */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D0 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D4 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D8 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* DC */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D0 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* E4 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* E8 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* EC */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F0 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F4 */ + {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F8 */ + {&nulldev}, {&hdsk_io}, {&simh_dev}, {&sr_dev} /* FC */ +}; + +static int32 ramtype = 0; +int32 chiptype = CHIP_TYPE_8080; + +void out(const uint32 Port, const uint32 Value) { + dev_table[Port & 0xff].routine(Port, 1, Value); +} + +uint32 in(const uint32 Port) { + return dev_table[Port & 0xff].routine(Port, 0, 0); +} + +/* the following tables precompute some common subexpressions + parityTable[i] 0..255 (number of 1's in i is odd) ? 0 : 4 + incTable[i] 0..256! (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0) << 4) + decTable[i] 0..255 (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0xf) << 4) | 2 + cbitsTable[i] 0..511 (i & 0x10) | ((i >> 8) & 1) + cbitsDup8Table[i] 0..511 (i & 0x10) | ((i >> 8) & 1) | ((i & 0xff) << 8) | (i & 0xa8) | + (((i & 0xff) == 0) << 6) + cbitsDup16Table[i] 0..511 (i & 0x10) | ((i >> 8) & 1) | (i & 0x28) + cbits2Table[i] 0..511 (i & 0x10) | ((i >> 8) & 1) | 2 + rrcaTable[i] 0..255 ((i & 1) << 15) | ((i >> 1) << 8) | ((i >> 1) & 0x28) | (i & 1) + rraTable[i] 0..255 ((i >> 1) << 8) | ((i >> 1) & 0x28) | (i & 1) + addTable[i] 0..511 ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) + subTable[i] 0..255 ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) | 2 + andTable[i] 0..255 (i << 8) | (i & 0xa8) | ((i == 0) << 6) | 0x10 | parityTable[i] + xororTable[i] 0..255 (i << 8) | (i & 0xa8) | ((i == 0) << 6) | parityTable[i] + rotateShiftTable[i] 0..255 (i & 0xa8) | (((i & 0xff) == 0) << 6) | parityTable[i & 0xff] + incZ80Table[i] 0..256! (i & 0xa8) | (((i & 0xff) == 0) << 6) | + (((i & 0xf) == 0) << 4) | ((i == 0x80) << 2) + decZ80Table[i] 0..255 (i & 0xa8) | (((i & 0xff) == 0) << 6) | + (((i & 0xf) == 0xf) << 4) | ((i == 0x7f) << 2) | 2 + cbitsZ80Table[i] 0..511 (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) + cbitsZ80DupTable[i] 0..511 (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | + ((i >> 8) & 1) | (i & 0xa8) + cbits2Z80Table[i] 0..511 (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | 2 + cbits2Z80DupTable[i] 0..511 (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | 2 | + (i & 0xa8) + negTable[i] 0..255 (((i & 0x0f) != 0) << 4) | ((i == 0x80) << 2) | 2 | (i != 0) + rrdrldTable[i] 0..255 (i << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) | parityTable[i] + cpTable[i] 0..255 (i & 0x80) | (((i & 0xff) == 0) << 6) +*/ + +/* parityTable[i] = (number of 1's in i is odd) ? 0 : 4, i = 0..255 */ +static const uint8 parityTable[256] = { + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, +}; + +/* incTable[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0) << 4), i = 0..256 */ +static const uint8 incTable[257] = { + 80, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, 80 +}; + +/* decTable[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0xf) << 4) | 2, i = 0..255 */ +static const uint8 decTable[256] = { + 66, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, +}; + +/* cbitsTable[i] = (i & 0x10) | ((i >> 8) & 1), i = 0..511 */ +static const uint8 cbitsTable[512] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +}; + +/* cbitsDup8Table[i] = (i & 0x10) | ((i >> 8) & 1) | ((i & 0xff) << 8) | (i & 0xa8) | + (((i & 0xff) == 0) << 6), i = 0..511 */ +static const uint16 cbitsDup8Table[512] = { + 0x0040,0x0100,0x0200,0x0300,0x0400,0x0500,0x0600,0x0700, + 0x0808,0x0908,0x0a08,0x0b08,0x0c08,0x0d08,0x0e08,0x0f08, + 0x1010,0x1110,0x1210,0x1310,0x1410,0x1510,0x1610,0x1710, + 0x1818,0x1918,0x1a18,0x1b18,0x1c18,0x1d18,0x1e18,0x1f18, + 0x2020,0x2120,0x2220,0x2320,0x2420,0x2520,0x2620,0x2720, + 0x2828,0x2928,0x2a28,0x2b28,0x2c28,0x2d28,0x2e28,0x2f28, + 0x3030,0x3130,0x3230,0x3330,0x3430,0x3530,0x3630,0x3730, + 0x3838,0x3938,0x3a38,0x3b38,0x3c38,0x3d38,0x3e38,0x3f38, + 0x4000,0x4100,0x4200,0x4300,0x4400,0x4500,0x4600,0x4700, + 0x4808,0x4908,0x4a08,0x4b08,0x4c08,0x4d08,0x4e08,0x4f08, + 0x5010,0x5110,0x5210,0x5310,0x5410,0x5510,0x5610,0x5710, + 0x5818,0x5918,0x5a18,0x5b18,0x5c18,0x5d18,0x5e18,0x5f18, + 0x6020,0x6120,0x6220,0x6320,0x6420,0x6520,0x6620,0x6720, + 0x6828,0x6928,0x6a28,0x6b28,0x6c28,0x6d28,0x6e28,0x6f28, + 0x7030,0x7130,0x7230,0x7330,0x7430,0x7530,0x7630,0x7730, + 0x7838,0x7938,0x7a38,0x7b38,0x7c38,0x7d38,0x7e38,0x7f38, + 0x8080,0x8180,0x8280,0x8380,0x8480,0x8580,0x8680,0x8780, + 0x8888,0x8988,0x8a88,0x8b88,0x8c88,0x8d88,0x8e88,0x8f88, + 0x9090,0x9190,0x9290,0x9390,0x9490,0x9590,0x9690,0x9790, + 0x9898,0x9998,0x9a98,0x9b98,0x9c98,0x9d98,0x9e98,0x9f98, + 0xa0a0,0xa1a0,0xa2a0,0xa3a0,0xa4a0,0xa5a0,0xa6a0,0xa7a0, + 0xa8a8,0xa9a8,0xaaa8,0xaba8,0xaca8,0xada8,0xaea8,0xafa8, + 0xb0b0,0xb1b0,0xb2b0,0xb3b0,0xb4b0,0xb5b0,0xb6b0,0xb7b0, + 0xb8b8,0xb9b8,0xbab8,0xbbb8,0xbcb8,0xbdb8,0xbeb8,0xbfb8, + 0xc080,0xc180,0xc280,0xc380,0xc480,0xc580,0xc680,0xc780, + 0xc888,0xc988,0xca88,0xcb88,0xcc88,0xcd88,0xce88,0xcf88, + 0xd090,0xd190,0xd290,0xd390,0xd490,0xd590,0xd690,0xd790, + 0xd898,0xd998,0xda98,0xdb98,0xdc98,0xdd98,0xde98,0xdf98, + 0xe0a0,0xe1a0,0xe2a0,0xe3a0,0xe4a0,0xe5a0,0xe6a0,0xe7a0, + 0xe8a8,0xe9a8,0xeaa8,0xeba8,0xeca8,0xeda8,0xeea8,0xefa8, + 0xf0b0,0xf1b0,0xf2b0,0xf3b0,0xf4b0,0xf5b0,0xf6b0,0xf7b0, + 0xf8b8,0xf9b8,0xfab8,0xfbb8,0xfcb8,0xfdb8,0xfeb8,0xffb8, + 0x0041,0x0101,0x0201,0x0301,0x0401,0x0501,0x0601,0x0701, + 0x0809,0x0909,0x0a09,0x0b09,0x0c09,0x0d09,0x0e09,0x0f09, + 0x1011,0x1111,0x1211,0x1311,0x1411,0x1511,0x1611,0x1711, + 0x1819,0x1919,0x1a19,0x1b19,0x1c19,0x1d19,0x1e19,0x1f19, + 0x2021,0x2121,0x2221,0x2321,0x2421,0x2521,0x2621,0x2721, + 0x2829,0x2929,0x2a29,0x2b29,0x2c29,0x2d29,0x2e29,0x2f29, + 0x3031,0x3131,0x3231,0x3331,0x3431,0x3531,0x3631,0x3731, + 0x3839,0x3939,0x3a39,0x3b39,0x3c39,0x3d39,0x3e39,0x3f39, + 0x4001,0x4101,0x4201,0x4301,0x4401,0x4501,0x4601,0x4701, + 0x4809,0x4909,0x4a09,0x4b09,0x4c09,0x4d09,0x4e09,0x4f09, + 0x5011,0x5111,0x5211,0x5311,0x5411,0x5511,0x5611,0x5711, + 0x5819,0x5919,0x5a19,0x5b19,0x5c19,0x5d19,0x5e19,0x5f19, + 0x6021,0x6121,0x6221,0x6321,0x6421,0x6521,0x6621,0x6721, + 0x6829,0x6929,0x6a29,0x6b29,0x6c29,0x6d29,0x6e29,0x6f29, + 0x7031,0x7131,0x7231,0x7331,0x7431,0x7531,0x7631,0x7731, + 0x7839,0x7939,0x7a39,0x7b39,0x7c39,0x7d39,0x7e39,0x7f39, + 0x8081,0x8181,0x8281,0x8381,0x8481,0x8581,0x8681,0x8781, + 0x8889,0x8989,0x8a89,0x8b89,0x8c89,0x8d89,0x8e89,0x8f89, + 0x9091,0x9191,0x9291,0x9391,0x9491,0x9591,0x9691,0x9791, + 0x9899,0x9999,0x9a99,0x9b99,0x9c99,0x9d99,0x9e99,0x9f99, + 0xa0a1,0xa1a1,0xa2a1,0xa3a1,0xa4a1,0xa5a1,0xa6a1,0xa7a1, + 0xa8a9,0xa9a9,0xaaa9,0xaba9,0xaca9,0xada9,0xaea9,0xafa9, + 0xb0b1,0xb1b1,0xb2b1,0xb3b1,0xb4b1,0xb5b1,0xb6b1,0xb7b1, + 0xb8b9,0xb9b9,0xbab9,0xbbb9,0xbcb9,0xbdb9,0xbeb9,0xbfb9, + 0xc081,0xc181,0xc281,0xc381,0xc481,0xc581,0xc681,0xc781, + 0xc889,0xc989,0xca89,0xcb89,0xcc89,0xcd89,0xce89,0xcf89, + 0xd091,0xd191,0xd291,0xd391,0xd491,0xd591,0xd691,0xd791, + 0xd899,0xd999,0xda99,0xdb99,0xdc99,0xdd99,0xde99,0xdf99, + 0xe0a1,0xe1a1,0xe2a1,0xe3a1,0xe4a1,0xe5a1,0xe6a1,0xe7a1, + 0xe8a9,0xe9a9,0xeaa9,0xeba9,0xeca9,0xeda9,0xeea9,0xefa9, + 0xf0b1,0xf1b1,0xf2b1,0xf3b1,0xf4b1,0xf5b1,0xf6b1,0xf7b1, + 0xf8b9,0xf9b9,0xfab9,0xfbb9,0xfcb9,0xfdb9,0xfeb9,0xffb9, +}; + +/* cbitsDup16Table[i] = (i & 0x10) | ((i >> 8) & 1) | (i & 0x28), i = 0..511 */ +static const uint8 cbitsDup16Table[512] = { + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24, + 32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40, + 48,48,48,48,48,48,48,48,56,56,56,56,56,56,56,56, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24, + 32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40, + 48,48,48,48,48,48,48,48,56,56,56,56,56,56,56,56, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24, + 32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40, + 48,48,48,48,48,48,48,48,56,56,56,56,56,56,56,56, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24, + 32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40, + 48,48,48,48,48,48,48,48,56,56,56,56,56,56,56,56, + 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, + 17,17,17,17,17,17,17,17,25,25,25,25,25,25,25,25, + 33,33,33,33,33,33,33,33,41,41,41,41,41,41,41,41, + 49,49,49,49,49,49,49,49,57,57,57,57,57,57,57,57, + 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, + 17,17,17,17,17,17,17,17,25,25,25,25,25,25,25,25, + 33,33,33,33,33,33,33,33,41,41,41,41,41,41,41,41, + 49,49,49,49,49,49,49,49,57,57,57,57,57,57,57,57, + 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, + 17,17,17,17,17,17,17,17,25,25,25,25,25,25,25,25, + 33,33,33,33,33,33,33,33,41,41,41,41,41,41,41,41, + 49,49,49,49,49,49,49,49,57,57,57,57,57,57,57,57, + 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, + 17,17,17,17,17,17,17,17,25,25,25,25,25,25,25,25, + 33,33,33,33,33,33,33,33,41,41,41,41,41,41,41,41, + 49,49,49,49,49,49,49,49,57,57,57,57,57,57,57,57, +}; + +/* cbits2Table[i] = (i & 0x10) | ((i >> 8) & 1) | 2, i = 0..511 */ +static const uint8 cbits2Table[512] = { + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, +}; + +/* rrcaTable[i] = ((i & 1) << 15) | ((i >> 1) << 8) | ((i >> 1) & 0x28) | (i & 1), i = 0..255 */ +static const uint16 rrcaTable[256] = { + 0x0000,0x8001,0x0100,0x8101,0x0200,0x8201,0x0300,0x8301, + 0x0400,0x8401,0x0500,0x8501,0x0600,0x8601,0x0700,0x8701, + 0x0808,0x8809,0x0908,0x8909,0x0a08,0x8a09,0x0b08,0x8b09, + 0x0c08,0x8c09,0x0d08,0x8d09,0x0e08,0x8e09,0x0f08,0x8f09, + 0x1000,0x9001,0x1100,0x9101,0x1200,0x9201,0x1300,0x9301, + 0x1400,0x9401,0x1500,0x9501,0x1600,0x9601,0x1700,0x9701, + 0x1808,0x9809,0x1908,0x9909,0x1a08,0x9a09,0x1b08,0x9b09, + 0x1c08,0x9c09,0x1d08,0x9d09,0x1e08,0x9e09,0x1f08,0x9f09, + 0x2020,0xa021,0x2120,0xa121,0x2220,0xa221,0x2320,0xa321, + 0x2420,0xa421,0x2520,0xa521,0x2620,0xa621,0x2720,0xa721, + 0x2828,0xa829,0x2928,0xa929,0x2a28,0xaa29,0x2b28,0xab29, + 0x2c28,0xac29,0x2d28,0xad29,0x2e28,0xae29,0x2f28,0xaf29, + 0x3020,0xb021,0x3120,0xb121,0x3220,0xb221,0x3320,0xb321, + 0x3420,0xb421,0x3520,0xb521,0x3620,0xb621,0x3720,0xb721, + 0x3828,0xb829,0x3928,0xb929,0x3a28,0xba29,0x3b28,0xbb29, + 0x3c28,0xbc29,0x3d28,0xbd29,0x3e28,0xbe29,0x3f28,0xbf29, + 0x4000,0xc001,0x4100,0xc101,0x4200,0xc201,0x4300,0xc301, + 0x4400,0xc401,0x4500,0xc501,0x4600,0xc601,0x4700,0xc701, + 0x4808,0xc809,0x4908,0xc909,0x4a08,0xca09,0x4b08,0xcb09, + 0x4c08,0xcc09,0x4d08,0xcd09,0x4e08,0xce09,0x4f08,0xcf09, + 0x5000,0xd001,0x5100,0xd101,0x5200,0xd201,0x5300,0xd301, + 0x5400,0xd401,0x5500,0xd501,0x5600,0xd601,0x5700,0xd701, + 0x5808,0xd809,0x5908,0xd909,0x5a08,0xda09,0x5b08,0xdb09, + 0x5c08,0xdc09,0x5d08,0xdd09,0x5e08,0xde09,0x5f08,0xdf09, + 0x6020,0xe021,0x6120,0xe121,0x6220,0xe221,0x6320,0xe321, + 0x6420,0xe421,0x6520,0xe521,0x6620,0xe621,0x6720,0xe721, + 0x6828,0xe829,0x6928,0xe929,0x6a28,0xea29,0x6b28,0xeb29, + 0x6c28,0xec29,0x6d28,0xed29,0x6e28,0xee29,0x6f28,0xef29, + 0x7020,0xf021,0x7120,0xf121,0x7220,0xf221,0x7320,0xf321, + 0x7420,0xf421,0x7520,0xf521,0x7620,0xf621,0x7720,0xf721, + 0x7828,0xf829,0x7928,0xf929,0x7a28,0xfa29,0x7b28,0xfb29, + 0x7c28,0xfc29,0x7d28,0xfd29,0x7e28,0xfe29,0x7f28,0xff29, +}; + +/* rraTable[i] = ((i >> 1) << 8) | ((i >> 1) & 0x28) | (i & 1), i = 0..255 */ +static const uint16 rraTable[256] = { + 0x0000,0x0001,0x0100,0x0101,0x0200,0x0201,0x0300,0x0301, + 0x0400,0x0401,0x0500,0x0501,0x0600,0x0601,0x0700,0x0701, + 0x0808,0x0809,0x0908,0x0909,0x0a08,0x0a09,0x0b08,0x0b09, + 0x0c08,0x0c09,0x0d08,0x0d09,0x0e08,0x0e09,0x0f08,0x0f09, + 0x1000,0x1001,0x1100,0x1101,0x1200,0x1201,0x1300,0x1301, + 0x1400,0x1401,0x1500,0x1501,0x1600,0x1601,0x1700,0x1701, + 0x1808,0x1809,0x1908,0x1909,0x1a08,0x1a09,0x1b08,0x1b09, + 0x1c08,0x1c09,0x1d08,0x1d09,0x1e08,0x1e09,0x1f08,0x1f09, + 0x2020,0x2021,0x2120,0x2121,0x2220,0x2221,0x2320,0x2321, + 0x2420,0x2421,0x2520,0x2521,0x2620,0x2621,0x2720,0x2721, + 0x2828,0x2829,0x2928,0x2929,0x2a28,0x2a29,0x2b28,0x2b29, + 0x2c28,0x2c29,0x2d28,0x2d29,0x2e28,0x2e29,0x2f28,0x2f29, + 0x3020,0x3021,0x3120,0x3121,0x3220,0x3221,0x3320,0x3321, + 0x3420,0x3421,0x3520,0x3521,0x3620,0x3621,0x3720,0x3721, + 0x3828,0x3829,0x3928,0x3929,0x3a28,0x3a29,0x3b28,0x3b29, + 0x3c28,0x3c29,0x3d28,0x3d29,0x3e28,0x3e29,0x3f28,0x3f29, + 0x4000,0x4001,0x4100,0x4101,0x4200,0x4201,0x4300,0x4301, + 0x4400,0x4401,0x4500,0x4501,0x4600,0x4601,0x4700,0x4701, + 0x4808,0x4809,0x4908,0x4909,0x4a08,0x4a09,0x4b08,0x4b09, + 0x4c08,0x4c09,0x4d08,0x4d09,0x4e08,0x4e09,0x4f08,0x4f09, + 0x5000,0x5001,0x5100,0x5101,0x5200,0x5201,0x5300,0x5301, + 0x5400,0x5401,0x5500,0x5501,0x5600,0x5601,0x5700,0x5701, + 0x5808,0x5809,0x5908,0x5909,0x5a08,0x5a09,0x5b08,0x5b09, + 0x5c08,0x5c09,0x5d08,0x5d09,0x5e08,0x5e09,0x5f08,0x5f09, + 0x6020,0x6021,0x6120,0x6121,0x6220,0x6221,0x6320,0x6321, + 0x6420,0x6421,0x6520,0x6521,0x6620,0x6621,0x6720,0x6721, + 0x6828,0x6829,0x6928,0x6929,0x6a28,0x6a29,0x6b28,0x6b29, + 0x6c28,0x6c29,0x6d28,0x6d29,0x6e28,0x6e29,0x6f28,0x6f29, + 0x7020,0x7021,0x7120,0x7121,0x7220,0x7221,0x7320,0x7321, + 0x7420,0x7421,0x7520,0x7521,0x7620,0x7621,0x7720,0x7721, + 0x7828,0x7829,0x7928,0x7929,0x7a28,0x7a29,0x7b28,0x7b29, + 0x7c28,0x7c29,0x7d28,0x7d29,0x7e28,0x7e29,0x7f28,0x7f29, +}; + +/* addTable[i] = ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6), i = 0..511 */ +static const uint16 addTable[512] = { + 0x0040,0x0100,0x0200,0x0300,0x0400,0x0500,0x0600,0x0700, + 0x0808,0x0908,0x0a08,0x0b08,0x0c08,0x0d08,0x0e08,0x0f08, + 0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700, + 0x1808,0x1908,0x1a08,0x1b08,0x1c08,0x1d08,0x1e08,0x1f08, + 0x2020,0x2120,0x2220,0x2320,0x2420,0x2520,0x2620,0x2720, + 0x2828,0x2928,0x2a28,0x2b28,0x2c28,0x2d28,0x2e28,0x2f28, + 0x3020,0x3120,0x3220,0x3320,0x3420,0x3520,0x3620,0x3720, + 0x3828,0x3928,0x3a28,0x3b28,0x3c28,0x3d28,0x3e28,0x3f28, + 0x4000,0x4100,0x4200,0x4300,0x4400,0x4500,0x4600,0x4700, + 0x4808,0x4908,0x4a08,0x4b08,0x4c08,0x4d08,0x4e08,0x4f08, + 0x5000,0x5100,0x5200,0x5300,0x5400,0x5500,0x5600,0x5700, + 0x5808,0x5908,0x5a08,0x5b08,0x5c08,0x5d08,0x5e08,0x5f08, + 0x6020,0x6120,0x6220,0x6320,0x6420,0x6520,0x6620,0x6720, + 0x6828,0x6928,0x6a28,0x6b28,0x6c28,0x6d28,0x6e28,0x6f28, + 0x7020,0x7120,0x7220,0x7320,0x7420,0x7520,0x7620,0x7720, + 0x7828,0x7928,0x7a28,0x7b28,0x7c28,0x7d28,0x7e28,0x7f28, + 0x8080,0x8180,0x8280,0x8380,0x8480,0x8580,0x8680,0x8780, + 0x8888,0x8988,0x8a88,0x8b88,0x8c88,0x8d88,0x8e88,0x8f88, + 0x9080,0x9180,0x9280,0x9380,0x9480,0x9580,0x9680,0x9780, + 0x9888,0x9988,0x9a88,0x9b88,0x9c88,0x9d88,0x9e88,0x9f88, + 0xa0a0,0xa1a0,0xa2a0,0xa3a0,0xa4a0,0xa5a0,0xa6a0,0xa7a0, + 0xa8a8,0xa9a8,0xaaa8,0xaba8,0xaca8,0xada8,0xaea8,0xafa8, + 0xb0a0,0xb1a0,0xb2a0,0xb3a0,0xb4a0,0xb5a0,0xb6a0,0xb7a0, + 0xb8a8,0xb9a8,0xbaa8,0xbba8,0xbca8,0xbda8,0xbea8,0xbfa8, + 0xc080,0xc180,0xc280,0xc380,0xc480,0xc580,0xc680,0xc780, + 0xc888,0xc988,0xca88,0xcb88,0xcc88,0xcd88,0xce88,0xcf88, + 0xd080,0xd180,0xd280,0xd380,0xd480,0xd580,0xd680,0xd780, + 0xd888,0xd988,0xda88,0xdb88,0xdc88,0xdd88,0xde88,0xdf88, + 0xe0a0,0xe1a0,0xe2a0,0xe3a0,0xe4a0,0xe5a0,0xe6a0,0xe7a0, + 0xe8a8,0xe9a8,0xeaa8,0xeba8,0xeca8,0xeda8,0xeea8,0xefa8, + 0xf0a0,0xf1a0,0xf2a0,0xf3a0,0xf4a0,0xf5a0,0xf6a0,0xf7a0, + 0xf8a8,0xf9a8,0xfaa8,0xfba8,0xfca8,0xfda8,0xfea8,0xffa8, + 0x0040,0x0100,0x0200,0x0300,0x0400,0x0500,0x0600,0x0700, + 0x0808,0x0908,0x0a08,0x0b08,0x0c08,0x0d08,0x0e08,0x0f08, + 0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700, + 0x1808,0x1908,0x1a08,0x1b08,0x1c08,0x1d08,0x1e08,0x1f08, + 0x2020,0x2120,0x2220,0x2320,0x2420,0x2520,0x2620,0x2720, + 0x2828,0x2928,0x2a28,0x2b28,0x2c28,0x2d28,0x2e28,0x2f28, + 0x3020,0x3120,0x3220,0x3320,0x3420,0x3520,0x3620,0x3720, + 0x3828,0x3928,0x3a28,0x3b28,0x3c28,0x3d28,0x3e28,0x3f28, + 0x4000,0x4100,0x4200,0x4300,0x4400,0x4500,0x4600,0x4700, + 0x4808,0x4908,0x4a08,0x4b08,0x4c08,0x4d08,0x4e08,0x4f08, + 0x5000,0x5100,0x5200,0x5300,0x5400,0x5500,0x5600,0x5700, + 0x5808,0x5908,0x5a08,0x5b08,0x5c08,0x5d08,0x5e08,0x5f08, + 0x6020,0x6120,0x6220,0x6320,0x6420,0x6520,0x6620,0x6720, + 0x6828,0x6928,0x6a28,0x6b28,0x6c28,0x6d28,0x6e28,0x6f28, + 0x7020,0x7120,0x7220,0x7320,0x7420,0x7520,0x7620,0x7720, + 0x7828,0x7928,0x7a28,0x7b28,0x7c28,0x7d28,0x7e28,0x7f28, + 0x8080,0x8180,0x8280,0x8380,0x8480,0x8580,0x8680,0x8780, + 0x8888,0x8988,0x8a88,0x8b88,0x8c88,0x8d88,0x8e88,0x8f88, + 0x9080,0x9180,0x9280,0x9380,0x9480,0x9580,0x9680,0x9780, + 0x9888,0x9988,0x9a88,0x9b88,0x9c88,0x9d88,0x9e88,0x9f88, + 0xa0a0,0xa1a0,0xa2a0,0xa3a0,0xa4a0,0xa5a0,0xa6a0,0xa7a0, + 0xa8a8,0xa9a8,0xaaa8,0xaba8,0xaca8,0xada8,0xaea8,0xafa8, + 0xb0a0,0xb1a0,0xb2a0,0xb3a0,0xb4a0,0xb5a0,0xb6a0,0xb7a0, + 0xb8a8,0xb9a8,0xbaa8,0xbba8,0xbca8,0xbda8,0xbea8,0xbfa8, + 0xc080,0xc180,0xc280,0xc380,0xc480,0xc580,0xc680,0xc780, + 0xc888,0xc988,0xca88,0xcb88,0xcc88,0xcd88,0xce88,0xcf88, + 0xd080,0xd180,0xd280,0xd380,0xd480,0xd580,0xd680,0xd780, + 0xd888,0xd988,0xda88,0xdb88,0xdc88,0xdd88,0xde88,0xdf88, + 0xe0a0,0xe1a0,0xe2a0,0xe3a0,0xe4a0,0xe5a0,0xe6a0,0xe7a0, + 0xe8a8,0xe9a8,0xeaa8,0xeba8,0xeca8,0xeda8,0xeea8,0xefa8, + 0xf0a0,0xf1a0,0xf2a0,0xf3a0,0xf4a0,0xf5a0,0xf6a0,0xf7a0, + 0xf8a8,0xf9a8,0xfaa8,0xfba8,0xfca8,0xfda8,0xfea8,0xffa8, +}; + +/* subTable[i] = ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) | 2, i = 0..255 */ +static const uint16 subTable[256] = { + 0x0042,0x0102,0x0202,0x0302,0x0402,0x0502,0x0602,0x0702, + 0x080a,0x090a,0x0a0a,0x0b0a,0x0c0a,0x0d0a,0x0e0a,0x0f0a, + 0x1002,0x1102,0x1202,0x1302,0x1402,0x1502,0x1602,0x1702, + 0x180a,0x190a,0x1a0a,0x1b0a,0x1c0a,0x1d0a,0x1e0a,0x1f0a, + 0x2022,0x2122,0x2222,0x2322,0x2422,0x2522,0x2622,0x2722, + 0x282a,0x292a,0x2a2a,0x2b2a,0x2c2a,0x2d2a,0x2e2a,0x2f2a, + 0x3022,0x3122,0x3222,0x3322,0x3422,0x3522,0x3622,0x3722, + 0x382a,0x392a,0x3a2a,0x3b2a,0x3c2a,0x3d2a,0x3e2a,0x3f2a, + 0x4002,0x4102,0x4202,0x4302,0x4402,0x4502,0x4602,0x4702, + 0x480a,0x490a,0x4a0a,0x4b0a,0x4c0a,0x4d0a,0x4e0a,0x4f0a, + 0x5002,0x5102,0x5202,0x5302,0x5402,0x5502,0x5602,0x5702, + 0x580a,0x590a,0x5a0a,0x5b0a,0x5c0a,0x5d0a,0x5e0a,0x5f0a, + 0x6022,0x6122,0x6222,0x6322,0x6422,0x6522,0x6622,0x6722, + 0x682a,0x692a,0x6a2a,0x6b2a,0x6c2a,0x6d2a,0x6e2a,0x6f2a, + 0x7022,0x7122,0x7222,0x7322,0x7422,0x7522,0x7622,0x7722, + 0x782a,0x792a,0x7a2a,0x7b2a,0x7c2a,0x7d2a,0x7e2a,0x7f2a, + 0x8082,0x8182,0x8282,0x8382,0x8482,0x8582,0x8682,0x8782, + 0x888a,0x898a,0x8a8a,0x8b8a,0x8c8a,0x8d8a,0x8e8a,0x8f8a, + 0x9082,0x9182,0x9282,0x9382,0x9482,0x9582,0x9682,0x9782, + 0x988a,0x998a,0x9a8a,0x9b8a,0x9c8a,0x9d8a,0x9e8a,0x9f8a, + 0xa0a2,0xa1a2,0xa2a2,0xa3a2,0xa4a2,0xa5a2,0xa6a2,0xa7a2, + 0xa8aa,0xa9aa,0xaaaa,0xabaa,0xacaa,0xadaa,0xaeaa,0xafaa, + 0xb0a2,0xb1a2,0xb2a2,0xb3a2,0xb4a2,0xb5a2,0xb6a2,0xb7a2, + 0xb8aa,0xb9aa,0xbaaa,0xbbaa,0xbcaa,0xbdaa,0xbeaa,0xbfaa, + 0xc082,0xc182,0xc282,0xc382,0xc482,0xc582,0xc682,0xc782, + 0xc88a,0xc98a,0xca8a,0xcb8a,0xcc8a,0xcd8a,0xce8a,0xcf8a, + 0xd082,0xd182,0xd282,0xd382,0xd482,0xd582,0xd682,0xd782, + 0xd88a,0xd98a,0xda8a,0xdb8a,0xdc8a,0xdd8a,0xde8a,0xdf8a, + 0xe0a2,0xe1a2,0xe2a2,0xe3a2,0xe4a2,0xe5a2,0xe6a2,0xe7a2, + 0xe8aa,0xe9aa,0xeaaa,0xebaa,0xecaa,0xedaa,0xeeaa,0xefaa, + 0xf0a2,0xf1a2,0xf2a2,0xf3a2,0xf4a2,0xf5a2,0xf6a2,0xf7a2, + 0xf8aa,0xf9aa,0xfaaa,0xfbaa,0xfcaa,0xfdaa,0xfeaa,0xffaa, +}; + +/* andTable[i] = (i << 8) | (i & 0xa8) | ((i == 0) << 6) | 0x10 | parityTable[i], i = 0..255 */ +static const uint16 andTable[256] = { + 0x0054,0x0110,0x0210,0x0314,0x0410,0x0514,0x0614,0x0710, + 0x0818,0x091c,0x0a1c,0x0b18,0x0c1c,0x0d18,0x0e18,0x0f1c, + 0x1010,0x1114,0x1214,0x1310,0x1414,0x1510,0x1610,0x1714, + 0x181c,0x1918,0x1a18,0x1b1c,0x1c18,0x1d1c,0x1e1c,0x1f18, + 0x2030,0x2134,0x2234,0x2330,0x2434,0x2530,0x2630,0x2734, + 0x283c,0x2938,0x2a38,0x2b3c,0x2c38,0x2d3c,0x2e3c,0x2f38, + 0x3034,0x3130,0x3230,0x3334,0x3430,0x3534,0x3634,0x3730, + 0x3838,0x393c,0x3a3c,0x3b38,0x3c3c,0x3d38,0x3e38,0x3f3c, + 0x4010,0x4114,0x4214,0x4310,0x4414,0x4510,0x4610,0x4714, + 0x481c,0x4918,0x4a18,0x4b1c,0x4c18,0x4d1c,0x4e1c,0x4f18, + 0x5014,0x5110,0x5210,0x5314,0x5410,0x5514,0x5614,0x5710, + 0x5818,0x591c,0x5a1c,0x5b18,0x5c1c,0x5d18,0x5e18,0x5f1c, + 0x6034,0x6130,0x6230,0x6334,0x6430,0x6534,0x6634,0x6730, + 0x6838,0x693c,0x6a3c,0x6b38,0x6c3c,0x6d38,0x6e38,0x6f3c, + 0x7030,0x7134,0x7234,0x7330,0x7434,0x7530,0x7630,0x7734, + 0x783c,0x7938,0x7a38,0x7b3c,0x7c38,0x7d3c,0x7e3c,0x7f38, + 0x8090,0x8194,0x8294,0x8390,0x8494,0x8590,0x8690,0x8794, + 0x889c,0x8998,0x8a98,0x8b9c,0x8c98,0x8d9c,0x8e9c,0x8f98, + 0x9094,0x9190,0x9290,0x9394,0x9490,0x9594,0x9694,0x9790, + 0x9898,0x999c,0x9a9c,0x9b98,0x9c9c,0x9d98,0x9e98,0x9f9c, + 0xa0b4,0xa1b0,0xa2b0,0xa3b4,0xa4b0,0xa5b4,0xa6b4,0xa7b0, + 0xa8b8,0xa9bc,0xaabc,0xabb8,0xacbc,0xadb8,0xaeb8,0xafbc, + 0xb0b0,0xb1b4,0xb2b4,0xb3b0,0xb4b4,0xb5b0,0xb6b0,0xb7b4, + 0xb8bc,0xb9b8,0xbab8,0xbbbc,0xbcb8,0xbdbc,0xbebc,0xbfb8, + 0xc094,0xc190,0xc290,0xc394,0xc490,0xc594,0xc694,0xc790, + 0xc898,0xc99c,0xca9c,0xcb98,0xcc9c,0xcd98,0xce98,0xcf9c, + 0xd090,0xd194,0xd294,0xd390,0xd494,0xd590,0xd690,0xd794, + 0xd89c,0xd998,0xda98,0xdb9c,0xdc98,0xdd9c,0xde9c,0xdf98, + 0xe0b0,0xe1b4,0xe2b4,0xe3b0,0xe4b4,0xe5b0,0xe6b0,0xe7b4, + 0xe8bc,0xe9b8,0xeab8,0xebbc,0xecb8,0xedbc,0xeebc,0xefb8, + 0xf0b4,0xf1b0,0xf2b0,0xf3b4,0xf4b0,0xf5b4,0xf6b4,0xf7b0, + 0xf8b8,0xf9bc,0xfabc,0xfbb8,0xfcbc,0xfdb8,0xfeb8,0xffbc, +}; + +/* xororTable[i] = (i << 8) | (i & 0xa8) | ((i == 0) << 6) | parityTable[i], i = 0..255 */ +static const uint16 xororTable[256] = { + 0x0044,0x0100,0x0200,0x0304,0x0400,0x0504,0x0604,0x0700, + 0x0808,0x090c,0x0a0c,0x0b08,0x0c0c,0x0d08,0x0e08,0x0f0c, + 0x1000,0x1104,0x1204,0x1300,0x1404,0x1500,0x1600,0x1704, + 0x180c,0x1908,0x1a08,0x1b0c,0x1c08,0x1d0c,0x1e0c,0x1f08, + 0x2020,0x2124,0x2224,0x2320,0x2424,0x2520,0x2620,0x2724, + 0x282c,0x2928,0x2a28,0x2b2c,0x2c28,0x2d2c,0x2e2c,0x2f28, + 0x3024,0x3120,0x3220,0x3324,0x3420,0x3524,0x3624,0x3720, + 0x3828,0x392c,0x3a2c,0x3b28,0x3c2c,0x3d28,0x3e28,0x3f2c, + 0x4000,0x4104,0x4204,0x4300,0x4404,0x4500,0x4600,0x4704, + 0x480c,0x4908,0x4a08,0x4b0c,0x4c08,0x4d0c,0x4e0c,0x4f08, + 0x5004,0x5100,0x5200,0x5304,0x5400,0x5504,0x5604,0x5700, + 0x5808,0x590c,0x5a0c,0x5b08,0x5c0c,0x5d08,0x5e08,0x5f0c, + 0x6024,0x6120,0x6220,0x6324,0x6420,0x6524,0x6624,0x6720, + 0x6828,0x692c,0x6a2c,0x6b28,0x6c2c,0x6d28,0x6e28,0x6f2c, + 0x7020,0x7124,0x7224,0x7320,0x7424,0x7520,0x7620,0x7724, + 0x782c,0x7928,0x7a28,0x7b2c,0x7c28,0x7d2c,0x7e2c,0x7f28, + 0x8080,0x8184,0x8284,0x8380,0x8484,0x8580,0x8680,0x8784, + 0x888c,0x8988,0x8a88,0x8b8c,0x8c88,0x8d8c,0x8e8c,0x8f88, + 0x9084,0x9180,0x9280,0x9384,0x9480,0x9584,0x9684,0x9780, + 0x9888,0x998c,0x9a8c,0x9b88,0x9c8c,0x9d88,0x9e88,0x9f8c, + 0xa0a4,0xa1a0,0xa2a0,0xa3a4,0xa4a0,0xa5a4,0xa6a4,0xa7a0, + 0xa8a8,0xa9ac,0xaaac,0xaba8,0xacac,0xada8,0xaea8,0xafac, + 0xb0a0,0xb1a4,0xb2a4,0xb3a0,0xb4a4,0xb5a0,0xb6a0,0xb7a4, + 0xb8ac,0xb9a8,0xbaa8,0xbbac,0xbca8,0xbdac,0xbeac,0xbfa8, + 0xc084,0xc180,0xc280,0xc384,0xc480,0xc584,0xc684,0xc780, + 0xc888,0xc98c,0xca8c,0xcb88,0xcc8c,0xcd88,0xce88,0xcf8c, + 0xd080,0xd184,0xd284,0xd380,0xd484,0xd580,0xd680,0xd784, + 0xd88c,0xd988,0xda88,0xdb8c,0xdc88,0xdd8c,0xde8c,0xdf88, + 0xe0a0,0xe1a4,0xe2a4,0xe3a0,0xe4a4,0xe5a0,0xe6a0,0xe7a4, + 0xe8ac,0xe9a8,0xeaa8,0xebac,0xeca8,0xedac,0xeeac,0xefa8, + 0xf0a4,0xf1a0,0xf2a0,0xf3a4,0xf4a0,0xf5a4,0xf6a4,0xf7a0, + 0xf8a8,0xf9ac,0xfaac,0xfba8,0xfcac,0xfda8,0xfea8,0xffac, +}; + +/* rotateShiftTable[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | parityTable[i & 0xff], i = 0..255 */ +static const uint8 rotateShiftTable[256] = { + 68, 0, 0, 4, 0, 4, 4, 0, 8, 12, 12, 8, 12, 8, 8, 12, + 0, 4, 4, 0, 4, 0, 0, 4, 12, 8, 8, 12, 8, 12, 12, 8, + 32, 36, 36, 32, 36, 32, 32, 36, 44, 40, 40, 44, 40, 44, 44, 40, + 36, 32, 32, 36, 32, 36, 36, 32, 40, 44, 44, 40, 44, 40, 40, 44, + 0, 4, 4, 0, 4, 0, 0, 4, 12, 8, 8, 12, 8, 12, 12, 8, + 4, 0, 0, 4, 0, 4, 4, 0, 8, 12, 12, 8, 12, 8, 8, 12, + 36, 32, 32, 36, 32, 36, 36, 32, 40, 44, 44, 40, 44, 40, 40, 44, + 32, 36, 36, 32, 36, 32, 32, 36, 44, 40, 40, 44, 40, 44, 44, 40, + 128,132,132,128,132,128,128,132,140,136,136,140,136,140,140,136, + 132,128,128,132,128,132,132,128,136,140,140,136,140,136,136,140, + 164,160,160,164,160,164,164,160,168,172,172,168,172,168,168,172, + 160,164,164,160,164,160,160,164,172,168,168,172,168,172,172,168, + 132,128,128,132,128,132,132,128,136,140,140,136,140,136,136,140, + 128,132,132,128,132,128,128,132,140,136,136,140,136,140,140,136, + 160,164,164,160,164,160,160,164,172,168,168,172,168,172,172,168, + 164,160,160,164,160,164,164,160,168,172,172,168,172,168,168,172, +}; + +/* incZ80Table[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | + (((i & 0xf) == 0) << 4) | ((i == 0x80) << 2), i = 0..256 */ +static const uint8 incZ80Table[257] = { + 80, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 148,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, 80, +}; + +/* decZ80Table[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | + (((i & 0xf) == 0xf) << 4) | ((i == 0x7f) << 2) | 2, i = 0..255 */ +static const uint8 decZ80Table[256] = { + 66, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 62, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, +}; + +/* cbitsZ80Table[i] = (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1), i = 0..511 */ +static const uint8 cbitsZ80Table[512] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +}; + +/* cbitsZ80DupTable[i] = (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | + ((i >> 8) & 1) | (i & 0xa8), i = 0..511 */ +static const uint8 cbitsZ80DupTable[512] = { + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 16, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, + 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 48, 48, 48, 48, 48, 48, 48, 56, 56, 56, 56, 56, 56, 56, 56, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 16, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, + 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 48, 48, 48, 48, 48, 48, 48, 56, 56, 56, 56, 56, 56, 56, 56, + 132,132,132,132,132,132,132,132,140,140,140,140,140,140,140,140, + 148,148,148,148,148,148,148,148,156,156,156,156,156,156,156,156, + 164,164,164,164,164,164,164,164,172,172,172,172,172,172,172,172, + 180,180,180,180,180,180,180,180,188,188,188,188,188,188,188,188, + 132,132,132,132,132,132,132,132,140,140,140,140,140,140,140,140, + 148,148,148,148,148,148,148,148,156,156,156,156,156,156,156,156, + 164,164,164,164,164,164,164,164,172,172,172,172,172,172,172,172, + 180,180,180,180,180,180,180,180,188,188,188,188,188,188,188,188, + 5, 5, 5, 5, 5, 5, 5, 5, 13, 13, 13, 13, 13, 13, 13, 13, + 21, 21, 21, 21, 21, 21, 21, 21, 29, 29, 29, 29, 29, 29, 29, 29, + 37, 37, 37, 37, 37, 37, 37, 37, 45, 45, 45, 45, 45, 45, 45, 45, + 53, 53, 53, 53, 53, 53, 53, 53, 61, 61, 61, 61, 61, 61, 61, 61, + 5, 5, 5, 5, 5, 5, 5, 5, 13, 13, 13, 13, 13, 13, 13, 13, + 21, 21, 21, 21, 21, 21, 21, 21, 29, 29, 29, 29, 29, 29, 29, 29, + 37, 37, 37, 37, 37, 37, 37, 37, 45, 45, 45, 45, 45, 45, 45, 45, + 53, 53, 53, 53, 53, 53, 53, 53, 61, 61, 61, 61, 61, 61, 61, 61, + 129,129,129,129,129,129,129,129,137,137,137,137,137,137,137,137, + 145,145,145,145,145,145,145,145,153,153,153,153,153,153,153,153, + 161,161,161,161,161,161,161,161,169,169,169,169,169,169,169,169, + 177,177,177,177,177,177,177,177,185,185,185,185,185,185,185,185, + 129,129,129,129,129,129,129,129,137,137,137,137,137,137,137,137, + 145,145,145,145,145,145,145,145,153,153,153,153,153,153,153,153, + 161,161,161,161,161,161,161,161,169,169,169,169,169,169,169,169, + 177,177,177,177,177,177,177,177,185,185,185,185,185,185,185,185, +}; + +/* cbits2Z80Table[i] = (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | 2, i = 0..511 */ +static const uint8 cbits2Z80Table[512] = { + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, +}; + +/* cbits2Z80DupTable[i] = (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | 2 | + (i & 0xa8), i = 0..511 */ +static const uint8 cbits2Z80DupTable[512] = { + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 10, + 18, 18, 18, 18, 18, 18, 18, 18, 26, 26, 26, 26, 26, 26, 26, 26, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 42, + 50, 50, 50, 50, 50, 50, 50, 50, 58, 58, 58, 58, 58, 58, 58, 58, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 10, + 18, 18, 18, 18, 18, 18, 18, 18, 26, 26, 26, 26, 26, 26, 26, 26, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 42, + 50, 50, 50, 50, 50, 50, 50, 50, 58, 58, 58, 58, 58, 58, 58, 58, + 134,134,134,134,134,134,134,134,142,142,142,142,142,142,142,142, + 150,150,150,150,150,150,150,150,158,158,158,158,158,158,158,158, + 166,166,166,166,166,166,166,166,174,174,174,174,174,174,174,174, + 182,182,182,182,182,182,182,182,190,190,190,190,190,190,190,190, + 134,134,134,134,134,134,134,134,142,142,142,142,142,142,142,142, + 150,150,150,150,150,150,150,150,158,158,158,158,158,158,158,158, + 166,166,166,166,166,166,166,166,174,174,174,174,174,174,174,174, + 182,182,182,182,182,182,182,182,190,190,190,190,190,190,190,190, + 7, 7, 7, 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 15, 15, + 23, 23, 23, 23, 23, 23, 23, 23, 31, 31, 31, 31, 31, 31, 31, 31, + 39, 39, 39, 39, 39, 39, 39, 39, 47, 47, 47, 47, 47, 47, 47, 47, + 55, 55, 55, 55, 55, 55, 55, 55, 63, 63, 63, 63, 63, 63, 63, 63, + 7, 7, 7, 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 15, 15, + 23, 23, 23, 23, 23, 23, 23, 23, 31, 31, 31, 31, 31, 31, 31, 31, + 39, 39, 39, 39, 39, 39, 39, 39, 47, 47, 47, 47, 47, 47, 47, 47, + 55, 55, 55, 55, 55, 55, 55, 55, 63, 63, 63, 63, 63, 63, 63, 63, + 131,131,131,131,131,131,131,131,139,139,139,139,139,139,139,139, + 147,147,147,147,147,147,147,147,155,155,155,155,155,155,155,155, + 163,163,163,163,163,163,163,163,171,171,171,171,171,171,171,171, + 179,179,179,179,179,179,179,179,187,187,187,187,187,187,187,187, + 131,131,131,131,131,131,131,131,139,139,139,139,139,139,139,139, + 147,147,147,147,147,147,147,147,155,155,155,155,155,155,155,155, + 163,163,163,163,163,163,163,163,171,171,171,171,171,171,171,171, + 179,179,179,179,179,179,179,179,187,187,187,187,187,187,187,187, +}; + +/* negTable[i] = (((i & 0x0f) != 0) << 4) | ((i == 0x80) << 2) | 2 | (i != 0), i = 0..255 */ +static const uint8 negTable[256] = { + 2,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 7,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, +}; + +/* rrdrldTable[i] = (i << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) | parityTable[i], i = 0..255 */ +static const uint16 rrdrldTable[256] = { + 0x0044,0x0100,0x0200,0x0304,0x0400,0x0504,0x0604,0x0700, + 0x0808,0x090c,0x0a0c,0x0b08,0x0c0c,0x0d08,0x0e08,0x0f0c, + 0x1000,0x1104,0x1204,0x1300,0x1404,0x1500,0x1600,0x1704, + 0x180c,0x1908,0x1a08,0x1b0c,0x1c08,0x1d0c,0x1e0c,0x1f08, + 0x2020,0x2124,0x2224,0x2320,0x2424,0x2520,0x2620,0x2724, + 0x282c,0x2928,0x2a28,0x2b2c,0x2c28,0x2d2c,0x2e2c,0x2f28, + 0x3024,0x3120,0x3220,0x3324,0x3420,0x3524,0x3624,0x3720, + 0x3828,0x392c,0x3a2c,0x3b28,0x3c2c,0x3d28,0x3e28,0x3f2c, + 0x4000,0x4104,0x4204,0x4300,0x4404,0x4500,0x4600,0x4704, + 0x480c,0x4908,0x4a08,0x4b0c,0x4c08,0x4d0c,0x4e0c,0x4f08, + 0x5004,0x5100,0x5200,0x5304,0x5400,0x5504,0x5604,0x5700, + 0x5808,0x590c,0x5a0c,0x5b08,0x5c0c,0x5d08,0x5e08,0x5f0c, + 0x6024,0x6120,0x6220,0x6324,0x6420,0x6524,0x6624,0x6720, + 0x6828,0x692c,0x6a2c,0x6b28,0x6c2c,0x6d28,0x6e28,0x6f2c, + 0x7020,0x7124,0x7224,0x7320,0x7424,0x7520,0x7620,0x7724, + 0x782c,0x7928,0x7a28,0x7b2c,0x7c28,0x7d2c,0x7e2c,0x7f28, + 0x8080,0x8184,0x8284,0x8380,0x8484,0x8580,0x8680,0x8784, + 0x888c,0x8988,0x8a88,0x8b8c,0x8c88,0x8d8c,0x8e8c,0x8f88, + 0x9084,0x9180,0x9280,0x9384,0x9480,0x9584,0x9684,0x9780, + 0x9888,0x998c,0x9a8c,0x9b88,0x9c8c,0x9d88,0x9e88,0x9f8c, + 0xa0a4,0xa1a0,0xa2a0,0xa3a4,0xa4a0,0xa5a4,0xa6a4,0xa7a0, + 0xa8a8,0xa9ac,0xaaac,0xaba8,0xacac,0xada8,0xaea8,0xafac, + 0xb0a0,0xb1a4,0xb2a4,0xb3a0,0xb4a4,0xb5a0,0xb6a0,0xb7a4, + 0xb8ac,0xb9a8,0xbaa8,0xbbac,0xbca8,0xbdac,0xbeac,0xbfa8, + 0xc084,0xc180,0xc280,0xc384,0xc480,0xc584,0xc684,0xc780, + 0xc888,0xc98c,0xca8c,0xcb88,0xcc8c,0xcd88,0xce88,0xcf8c, + 0xd080,0xd184,0xd284,0xd380,0xd484,0xd580,0xd680,0xd784, + 0xd88c,0xd988,0xda88,0xdb8c,0xdc88,0xdd8c,0xde8c,0xdf88, + 0xe0a0,0xe1a4,0xe2a4,0xe3a0,0xe4a4,0xe5a0,0xe6a0,0xe7a4, + 0xe8ac,0xe9a8,0xeaa8,0xebac,0xeca8,0xedac,0xeeac,0xefa8, + 0xf0a4,0xf1a0,0xf2a0,0xf3a4,0xf4a0,0xf5a4,0xf6a4,0xf7a0, + 0xf8a8,0xf9ac,0xfaac,0xfba8,0xfcac,0xfda8,0xfea8,0xffac, +}; + +/* cpTable[i] = (i & 0x80) | (((i & 0xff) == 0) << 6), i = 0..255 */ +static const uint8 cpTable[256] = { + 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +}; + +/* remove comments to generate table contents and define globally NEED_SIM_VM_INIT +static void altairz80_init(void); +void (*sim_vm_init) (void) = &altairz80_init; +static void altairz80_init(void) { +*/ +/* parityTable */ +/* + uint32 i, v; + for (i = 0; i < 256; i++) { + v = ((i & 1) + ((i & 2) >> 1) + ((i & 4) >> 2) + ((i & 8) >> 3) + + ((i & 16) >> 4) + ((i & 32) >> 5) + ((i & 64) >> 6) + ((i & 128) >> 7)) % 2 ? 0 : 4; + printf("%1d,", v); + if ( ((i+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* incTable */ +/* + uint32 temp, v; + for (temp = 0; temp <= 256; temp++) { + v = (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | (((temp & 0xf) == 0) << 4); + printf("%3d,", v); + if ( ((temp+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* decTable */ +/* + uint32 temp, v; + for (temp = 0; temp < 256; temp++) { + v = (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | (((temp & 0xf) == 0xf) << 4) | 2; + printf("%3d,", v); + if ( ((temp+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* cbitsTable */ +/* + uint32 cbits, v; + for (cbits = 0; cbits < 512; cbits++) { + v = (cbits & 0x10) | ((cbits >> 8) & 1); + printf("%2d,", v); + if ( ((cbits+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* cbitsDup8Table */ +/* + uint32 cbits, v; + for (cbits = 0; cbits < 512; cbits++) { + v = (cbits & 0x10) | ((cbits >> 8) & 1) | ((cbits & 0xff) << 8) | (cbits & 0xa8) | (((cbits & 0xff) == 0) << 6); + printf("0x%04x,", v); + if ( ((cbits+1) & 0x7) == 0) { + printf("\n"); + } + } +*/ +/* cbitsDup16Table */ +/* + uint32 cbits, v; + for (cbits = 0; cbits < 512; cbits++) { + v = (cbits & 0x10) | ((cbits >> 8) & 1) | (cbits & 0x28); + printf("%2d,", v); + if ( ((cbits+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* cbits2Table */ +/* + uint32 cbits, v; + for (cbits = 0; cbits < 512; cbits++) { + v = (cbits & 0x10) | ((cbits >> 8) & 1) | 2; + printf("%2d,", v); + if ( ((cbits+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* rrcaTable */ +/* + uint32 temp, sum, v; + for (temp = 0; temp < 256; temp++) { + sum = temp >> 1; + v = ((temp & 1) << 15) | (sum << 8) | (sum & 0x28) | (temp & 1); + printf("0x%04x,", v); + if ( ((temp+1) & 0x7) == 0) { + printf("\n"); + } + } +*/ +/* rraTable */ +/* + uint32 temp, sum, v; + for (temp = 0; temp < 256; temp++) { + sum = temp >> 1; + v = (sum << 8) | (sum & 0x28) | (temp & 1); + printf("0x%04x,", v); + if ( ((temp+1) & 0x7) == 0) { + printf("\n"); + } + } +*/ +/* addTable */ +/* + uint32 sum, v; + for (sum = 0; sum < 512; sum++) { + v = ((sum & 0xff) << 8) | (sum & 0xa8) | (((sum & 0xff) == 0) << 6); + printf("0x%04x,", v); + if ( ((sum+1) & 0x7) == 0) { + printf("\n"); + } + } +*/ +/* subTable */ +/* + uint32 sum, v; + for (sum = 0; sum < 256; sum++) { + v = ((sum & 0xff) << 8) | (sum & 0xa8) | (((sum & 0xff) == 0) << 6) | 2; + printf("0x%04x,", v); + if ( ((sum+1) & 0x7) == 0) { + printf("\n"); + } + } +*/ +/* andTable */ +/* + uint32 sum, v; + for (sum = 0; sum < 256; sum++) { + v = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | 0x10 | parityTable[sum]; + printf("0x%04x,", v); + if ( ((sum+1) & 0x7) == 0) { + printf("\n"); + } + } +*/ +/* xororTable */ +/* + uint32 sum, v; + for (sum = 0; sum < 256; sum++) { + v = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | parityTable[sum]; + printf("0x%04x,", v); + if ( ((sum+1) & 0x7) == 0) { + printf("\n"); + } + } +*/ +/* rotateShiftTable */ +/* + uint32 temp, v; + for (temp = 0; temp < 256; temp++) { + v = (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | PARITY(temp); + printf("%3d,", v); + if ( ((temp+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* incZ80Table */ +/* + uint32 temp, v; + for (temp = 0; temp < 256; temp++) { + v = (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0) << 4) | ((temp == 0x80) << 2); + printf("%3d,", v); + if ( ((temp+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* decZ80Table */ +/* + uint32 temp, v; + for (temp = 0; temp < 256; temp++) { + v = (temp & 0xa8) | (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0xf) << 4) | ((temp == 0x7f) << 2) | 2; + printf("%3d,", v); + if ( ((temp+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* cbitsZ80Table */ +/* + uint32 cbits, v; + for (cbits = 0; cbits < 512; cbits++) { + v = (cbits & 0x10) | (((cbits >> 6) ^ (cbits >> 5)) & 4) | + ((cbits >> 8) & 1); + printf("%2d,", v); + if ( ((cbits+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* cbitsZ80DupTable */ +/* + uint32 cbits, v; + for (cbits = 0; cbits < 512; cbits++) { + v = (cbits & 0x10) | (((cbits >> 6) ^ (cbits >> 5)) & 4) | + ((cbits >> 8) & 1) | (cbits & 0xa8); + printf("%3d,", v); + if ( ((cbits+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* cbits2Z80Table */ +/* + uint32 cbits, v; + for (cbits = 0; cbits < 512; cbits++) { + v = (((cbits >> 6) ^ (cbits >> 5)) & 4) | (cbits & 0x10) | 2 | ((cbits >> 8) & 1); + printf("%2d,", v); + if ( ((cbits+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* cbits2Z80DupTable */ +/* + uint32 cbits, v; + for (cbits = 0; cbits < 512; cbits++) { + v = (((cbits >> 6) ^ (cbits >> 5)) & 4) | (cbits & 0x10) | 2 | ((cbits >> 8) & 1) | + (cbits & 0xa8); + printf("%3d,", v); + if ( ((cbits+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* negTable */ +/* + uint32 temp, v; + for (temp = 0; temp < 256; temp++) { + v = (((temp & 0x0f) != 0) << 4) | ((temp == 0x80) << 2) | 2 | (temp != 0); + printf("%2d,", v); + if ( ((temp+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* rrdrldTable */ +/* + uint32 acu, v; + for (acu = 0; acu < 256; acu++) { + v = (acu << 8) | (acu & 0xa8) | (((acu & 0xff) == 0) << 6) | parityTable[acu]; + printf("0x%04x,", v); + if ( ((acu+1) & 0x7) == 0) { + printf("\n"); + } + } +*/ +/* cpTable */ +/* + uint32 sum, v; + for (sum = 0; sum < 256; sum++) { + v = (sum & 0x80) | (((sum & 0xff) == 0) << 6); + printf("%3d,", v); + if ( ((sum+1) & 0xf) == 0) { + printf("\n"); + } + } +*/ +/* remove comments to generate table contents +} +*/ + +/* Memory management */ + +#define LOG2PAGESIZE 8 +#define PAGESIZE (1 << LOG2PAGESIZE) + +static uint8 M[MAXMEMORY]; /* RAM which is present */ + +struct mdev { /* Structure to describe a 2^LOG2PAGESIZE byte page of address space */ + /* There are four cases + isRAM isEmpty routine code + TRUE FALSE NULL W page is random access memory (RAM) + FALSE TRUE NULL U no memory at this location + FALSE FALSE NULL R page is read only memory (ROM) + FALSE FALSE not NULL M page is mapped to memory mapped I/O routine + other combinations are undefined! + */ + uint32 isRAM; + uint32 isEmpty; + int32 (*routine)(const int32, const int32, const int32); +}; + +typedef struct mdev MDEV; + +static MDEV ROM_PAGE = {FALSE, FALSE, NULL}; /* this makes a page ROM */ +static MDEV RAM_PAGE = {TRUE, FALSE, NULL}; /* this makes a page RAM */ +static MDEV EMPTY_PAGE = {FALSE, TRUE, NULL}; /* this is non-existing memory */ +static MDEV mmu_table[MAXMEMORY >> LOG2PAGESIZE]; + +/* Memory and I/O Resource Mapping and Unmapping routine. */ +uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, + int32 (*routine)(const int32, const int32, const int32), uint8 unmap) { + uint32 page, i, addr; + if (resource_type == RESOURCE_TYPE_MEMORY) { + for (i = 0; i < (size >> LOG2PAGESIZE); i++) { + addr = (baseaddr & 0xfff00) + (i << LOG2PAGESIZE); + if ((cpu_unit.flags & UNIT_CPU_BANKED) && (addr < common)) + addr |= bankSelect << MAXBANKSIZELOG2; + page = addr >> LOG2PAGESIZE; + if (cpu_unit.flags & UNIT_CPU_VERBOSE) + printf("%s memory 0x%05x, handler=%p\n", unmap ? "Unmapping" : " Mapping", + addr, routine); + if (unmap) { + if (mmu_table[page].routine == routine) /* unmap only if it was mapped */ + if (MEMORYSIZE < MAXBANKSIZE) + if (addr < MEMORYSIZE) + mmu_table[page] = RAM_PAGE; + else + mmu_table[page] = EMPTY_PAGE; + else + mmu_table[page] = RAM_PAGE; + } + else { + mmu_table[page] = ROM_PAGE; + mmu_table[page].routine = routine; + } + } + } else if (resource_type == RESOURCE_TYPE_IO) { + for (i = baseaddr; i < baseaddr + size; i++) + if (unmap) { + if (dev_table[i & 0xff].routine == routine) { + if (cpu_unit.flags & UNIT_CPU_VERBOSE) + printf("Unmapping IO %04x, handler=%p\n", i, routine); + dev_table[i & 0xff].routine = &nulldev; + } + } + else { + if (cpu_unit.flags & UNIT_CPU_VERBOSE) + printf(" Mapping IO %04x, handler=%p\n", i, routine); + dev_table[i & 0xff].routine = routine; + } + } else { + printf("%s: cannot map unknown resource type %d\n", __FUNCTION__, resource_type); + return -1; + } + return 0; +} + +static void PutBYTE(register uint32 Addr, const register uint32 Value) { + MDEV m; + + Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ + if ((cpu_unit.flags & UNIT_CPU_BANKED) && (Addr < common)) + Addr |= bankSelect << MAXBANKSIZELOG2; + m = mmu_table[Addr >> LOG2PAGESIZE]; + + if (m.isRAM) M[Addr] = Value; + else if (m.routine) m.routine(Addr, 1, Value); + else if (cpu_unit.flags & UNIT_CPU_VERBOSE) { + if (m.isEmpty) { + MESSAGE_2("Attempt to write to non existing memory " ADDRESS_FORMAT ".", Addr); + } + else { + MESSAGE_2("Attempt to write to ROM " ADDRESS_FORMAT ".", Addr); + } + } +} + +void PutBYTEExtended(register uint32 Addr, const register uint32 Value) { + MDEV m; + + Addr &= ADDRMASKEXTENDED; + m = mmu_table[Addr >> LOG2PAGESIZE]; + + if (m.isRAM) M[Addr] = Value; + else if (m.routine) m.routine(Addr, 1, Value); + else if (cpu_unit.flags & UNIT_CPU_VERBOSE) { + if (m.isEmpty) { + MESSAGE_2("Attempt to write to non existing memory " ADDRESS_FORMAT ".", Addr); + } + else { + MESSAGE_2("Attempt to write to ROM " ADDRESS_FORMAT ".", Addr); + } + } +} + +static void PutWORD(register uint32 Addr, const register uint32 Value) { + PutBYTE(Addr, Value); + PutBYTE(Addr + 1, Value >> 8); +} + +static uint32 GetBYTE(register uint32 Addr) { + MDEV m; + + Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ + if ((cpu_unit.flags & UNIT_CPU_BANKED) && (Addr < common)) + Addr |= bankSelect << MAXBANKSIZELOG2; + m = mmu_table[Addr >> LOG2PAGESIZE]; + + if (m.isRAM) return M[Addr]; /* RAM */ + if (m.routine) return m.routine(Addr, 0, 0); /* memory mapped I/O */ + if (m.isEmpty) { + if (cpu_unit.flags & UNIT_CPU_VERBOSE) { + MESSAGE_2("Attempt to read from non existing memory " ADDRESS_FORMAT ".", Addr); + } + return 0xff; + } + return M[Addr]; /* ROM */ +} + +uint32 GetBYTEExtended(register uint32 Addr) { + MDEV m; + + Addr &= ADDRMASKEXTENDED; + m = mmu_table[Addr >> LOG2PAGESIZE]; + + if (m.isRAM) return M[Addr]; + if (m.routine) return m.routine(Addr, 0, 0); + if (m.isEmpty) { + if (cpu_unit.flags & UNIT_CPU_VERBOSE) { + MESSAGE_2("Attempt to read from non existing memory " ADDRESS_FORMAT ".", Addr); + } + return 0xff; + } + return M[Addr]; +} + +int32 getBankSelect(void) { + return bankSelect; +} + +void setBankSelect(const int32 b) { + bankSelect = b; +} + +uint32 getCommon(void) { + return common; +} + +/* memory access during a simulation */ +uint8 GetBYTEWrapper(const uint32 Addr) { + if (chiptype == CHIP_TYPE_8086) + return GetBYTEExtended(Addr); + else if (cpu_unit.flags & UNIT_CPU_MMU) + return GetBYTE(Addr); + else + return MOPT[Addr & ADDRMASK]; +} + +/* memory access during a simulation */ +void PutBYTEWrapper(const uint32 Addr, const uint32 Value) { + if (chiptype == CHIP_TYPE_8086) + PutBYTEExtended(Addr, Value); + else if (cpu_unit.flags & UNIT_CPU_MMU) + PutBYTE(Addr, Value); + else + MOPT[Addr & ADDRMASK] = Value & 0xff; +} + +#define RAM_PP(Addr) GetBYTE(Addr++) +#define RAM_MM(Addr) GetBYTE(Addr--) +#define GET_WORD(Addr) (GetBYTE(Addr) | (GetBYTE(Addr + 1) << 8)) +#define PUT_BYTE_PP(a,v) PutBYTE(a++, v) +#define PUT_BYTE_MM(a,v) PutBYTE(a--, v) +#define MM_PUT_BYTE(a,v) PutBYTE(--a, v) + +#define MASK_BRK (TRUE + 1) + +/* this is a modified version of sim_brk_test with two differences: + 1) is does not set sim_brk_pend to FALSE (this is left to the instruction decode) + 2) it returns MASK_BRK if a breakpoint is found but should be ignored +*/ +static int32 sim_brk_lookup (const t_addr loc, const int32 btyp) { + extern t_bool sim_brk_pend[SIM_BKPT_N_SPC]; + extern t_addr sim_brk_ploc[SIM_BKPT_N_SPC]; + extern char *sim_brk_act; + BRKTAB *bp; + if ((bp = sim_brk_fnd (loc)) && /* entry in table? */ + (btyp & bp -> typ) && /* type match? */ + (!sim_brk_pend[0] || (loc != sim_brk_ploc[0])) && /* new location? */ + (--(bp -> cnt) <= 0)) { /* count reach 0? */ + bp -> cnt = 0; /* reset count */ + sim_brk_ploc[0] = loc; /* save location */ + sim_brk_act = bp -> act; /* set up actions */ + sim_brk_pend[0] = TRUE; /* don't do twice */ + return TRUE; + } + return (sim_brk_pend[0] && (loc == sim_brk_ploc[0])) ? MASK_BRK : FALSE; +} + +static void prepareMemoryAccessMessage(t_addr loc) { + extern char memoryAccessMessage[]; + sprintf(memoryAccessMessage, "Memory access breakpoint [%04xh]", loc); +} + +#define PUSH(x) { \ + MM_PUT_BYTE(SP, (x) >> 8); \ + MM_PUT_BYTE(SP, x); \ +} + +#define CHECK_BREAK_BYTE(a) \ + if (sim_brk_summ && sim_brk_test((a) & 0xffff, SWMASK('M'))) { \ + reason = STOP_MEM; \ + prepareMemoryAccessMessage((a) & 0xffff); \ + goto end_decode; \ + } + +#define CHECK_BREAK_TWO_BYTES_EXTENDED(a1, a2, iCode) \ + if (sim_brk_summ) { \ + br1 = sim_brk_lookup((a1) & 0xffff, SWMASK('M')); \ + br2 = br1 ? FALSE : sim_brk_lookup((a2) & 0xffff, SWMASK('M'));\ + if ((br1 == MASK_BRK) || (br2 == MASK_BRK)) { \ + sim_brk_pend[0] = FALSE; \ + } \ + else if (br1 || br2) { \ + reason = STOP_MEM; \ + if (br1) { \ + prepareMemoryAccessMessage((a1) & 0xffff); \ + } \ + else { \ + prepareMemoryAccessMessage((a2) & 0xffff); \ + } \ + iCode; \ + goto end_decode; \ + } \ + else { \ + sim_brk_pend[0] = FALSE; \ + } \ + } + +#define CHECK_BREAK_TWO_BYTES(a1, a2) CHECK_BREAK_TWO_BYTES_EXTENDED(a1, a2,;) + +#define CHECK_BREAK_WORD(a) CHECK_BREAK_TWO_BYTES(a, (a + 1)) + +#define HALTINSTRUCTION 0x76 + +/* Macros for the IN/OUT instructions INI/INIR/IND/INDR/OUTI/OTIR/OUTD/OTDR + + Pre condition + temp == value of register B at entry of the instruction + acu == value of transferred byte (IN or OUT) + Post condition + F is set correctly + + Use INOUTFLAGS_ZERO(x) for INIR/INDR/OTIR/OTDR where + x == (C + 1) & 0xff for INIR + x == L for OTIR and OTDR + x == (C - 1) & 0xff for INDR + Use INOUTFLAGS_NONZERO(x) for INI/IND/OUTI/OUTD where + x == (C + 1) & 0xff for INI + x == L for OUTI and OUTD + x == (C - 1) & 0xff for IND +*/ +#define INOUTFLAGS(syxz, x) \ + AF = (AF & 0xff00) | (syxz) | /* SF, YF, XF, ZF */ \ + ((acu & 0x80) >> 6) | /* NF */ \ + ((acu + (x)) > 0xff ? (FLAG_C | FLAG_H) : 0) | /* CF, HF */ \ + parityTable[((acu + (x)) & 7) ^ temp] /* PF */ + +#define INOUTFLAGS_ZERO(x) INOUTFLAGS(FLAG_Z, x) +#define INOUTFLAGS_NONZERO(x) \ + INOUTFLAGS((HIGH_REGISTER(BC) & 0xa8) | ((HIGH_REGISTER(BC) == 0) << 6), x) + +t_stat sim_instr (void) { + uint32 i; + t_stat result; + if (chiptype == CHIP_TYPE_8086) return sim_instr_8086(); + if (cpu_unit.flags & UNIT_CPU_MMU) return sim_instr_mmu(); + for (i = 0; i < MAXBANKSIZE; i++) MOPT[i] = M[i]; + result = sim_instr_nommu(); + for (i = 0; i < MAXBANKSIZE; i++) M[i] = MOPT[i]; + return result; +} + +static t_stat sim_instr_mmu (void) { + extern int32 sim_interval; + extern t_bool sim_brk_pend[SIM_BKPT_N_SPC]; + extern int32 timerInterrupt; + extern int32 timerInterruptHandler; + extern int32 keyboardInterrupt; + extern uint32 keyboardInterruptHandler; + extern uint32 sim_os_msec(void); + extern const t_bool rtc_avail; + extern uint32 sim_brk_summ; + int32 reason = 0; + register uint32 specialProcessing; + register uint32 AF; + register uint32 BC; + register uint32 DE; + register uint32 HL; + register uint32 PC; + register uint32 SP; + register uint32 IX; + register uint32 IY; + register uint32 temp = 0; + register uint32 acu = 0; + register uint32 sum; + register uint32 cbits; + register uint32 op; + register uint32 adr; + /* tStates contains the number of t-states executed. One t-state is executed + in one microsecond on a 1MHz CPU. tStates is used for real-time simulations. */ + register uint32 tStates; + uint32 tStatesInSlice; /* number of t-states in 10 mSec time-slice */ + uint32 startTime, now; + int32 br1, br2, tStateModifier = FALSE; + + AF = AF_S; + BC = BC_S; + DE = DE_S; + HL = HL_S; + PC = PC_S & ADDRMASK; + SP = SP_S; + IX = IX_S; + IY = IY_S; + specialProcessing = clockFrequency | timerInterrupt | keyboardInterrupt | sim_brk_summ; + tStates = 0; + if (rtc_avail) { + startTime = sim_os_msec(); + tStatesInSlice = sliceLength*clockFrequency; + } + else { /* make sure that sim_os_msec() is not called later */ + clockFrequency = startTime = tStatesInSlice = 0; + } + + /* main instruction fetch/decode loop */ + while (TRUE) { /* loop until halted */ + if (sim_interval <= 0) { /* check clock queue */ +#if !UNIX_PLATFORM + if ((reason = sim_os_poll_kbd()) == SCPE_STOP) { /* poll on platforms without reliable signalling */ + break; + } +#endif + if ( (reason = sim_process_event()) ) break; + else + specialProcessing = clockFrequency | timerInterrupt | keyboardInterrupt | sim_brk_summ; + } + + if (specialProcessing) { /* quick check for special processing */ + if (clockFrequency && (tStates >= tStatesInSlice)) { + /* clockFrequency != 0 implies that real time clock is available */ + startTime += sliceLength; + tStates -= tStatesInSlice; + if (startTime > (now = sim_os_msec())) { +#if defined (_WIN32) + Sleep(startTime - now); +#else + usleep(1000 * (startTime - now)); +#endif + } + } + + if (timerInterrupt && (IFF_S & 1)) { + timerInterrupt = FALSE; + specialProcessing = clockFrequency | sim_brk_summ; + IFF_S = 0; /* disable interrupts */ + CHECK_BREAK_TWO_BYTES_EXTENDED(SP - 2, SP - 1, (timerInterrupt = TRUE, IFF_S |= 1)); + if ((GetBYTE(PC) == HALTINSTRUCTION) && ((cpu_unit.flags & UNIT_CPU_STOPONHALT) == 0)) { + PUSH(PC + 1); + PCQ_ENTRY(PC); + } + else { + PUSH(PC); + PCQ_ENTRY(PC - 1); + } + PC = timerInterruptHandler & ADDRMASK; + } + + if (keyboardInterrupt && (IFF_S & 1)) { + keyboardInterrupt = FALSE; + specialProcessing = clockFrequency | sim_brk_summ; + IFF_S = 0; /* disable interrupts */ + CHECK_BREAK_TWO_BYTES_EXTENDED(SP - 2, SP - 1, (keyboardInterrupt = TRUE, IFF_S |= 1)); + if ((GetBYTE(PC) == HALTINSTRUCTION) && ((cpu_unit.flags & UNIT_CPU_STOPONHALT) == 0)) { + PUSH(PC + 1); + PCQ_ENTRY(PC); + } + else { + PUSH(PC); + PCQ_ENTRY(PC - 1); + } + PC = keyboardInterruptHandler & ADDRMASK; + } + + if (sim_brk_summ) { + if (sim_brk_lookup(PC, SWMASK('E')) == TRUE) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; + } + if (sim_brk_test(GetBYTE(PC), (1u << SIM_BKPT_V_SPC) | SWMASK('I'))) { /* instruction breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; + } + } + } + + PCX = PC; + sim_interval--; + + /* make sure that each instructions properly sets sim_brk_pend: + 1) Either directly to FALSE if no memory access takes place or + 2) through a call to a Check... routine + */ + switch(RAM_PP(PC)) { + + case 0x00: /* NOP */ + tStates += 4; + sim_brk_pend[0] = FALSE; + break; + + case 0x01: /* LD BC,nnnn */ + tStates += 10; + sim_brk_pend[0] = FALSE; + BC = GET_WORD(PC); + PC += 2; + break; + + case 0x02: /* LD (BC),A */ + tStates += 7; + CHECK_BREAK_BYTE(BC) + PutBYTE(BC, HIGH_REGISTER(AF)); + break; + + case 0x03: /* INC BC */ + tStates += 6; + sim_brk_pend[0] = FALSE; + ++BC; + break; + + case 0x04: /* INC B */ + tStates += 4; + sim_brk_pend[0] = FALSE; + BC += 0x100; + temp = HIGH_REGISTER(BC); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); /* SET_PV2 uses temp */ + break; + + case 0x05: /* DEC B */ + tStates += 4; + sim_brk_pend[0] = FALSE; + BC -= 0x100; + temp = HIGH_REGISTER(BC); + AF = (AF & ~0xfe) | decTable[temp] | SET_PV2(0x7f); /* SET_PV2 uses temp */ + break; + + case 0x06: /* LD B,nn */ + tStates += 7; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(BC, RAM_PP(PC)); + break; + + case 0x07: /* RLCA */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = ((AF >> 7) & 0x0128) | ((AF << 1) & ~0x1ff) | + (AF & 0xc4) | ((AF >> 15) & 1); + break; + + case 0x08: /* EX AF,AF' */ + tStates += 4; + sim_brk_pend[0] = FALSE; + CHECK_CPU_8080; + temp = AF; + AF = AF1_S; + AF1_S = temp; + break; + + case 0x09: /* ADD HL,BC */ + tStates += 11; + sim_brk_pend[0] = FALSE; + HL &= ADDRMASK; + BC &= ADDRMASK; + sum = HL + BC; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(HL ^ BC ^ sum) >> 8]; + HL = sum; + break; + + case 0x0a: /* LD A,(BC) */ + tStates += 7; + CHECK_BREAK_BYTE(BC) + SET_HIGH_REGISTER(AF, GetBYTE(BC)); + break; + + case 0x0b: /* DEC BC */ + tStates += 6; + sim_brk_pend[0] = FALSE; + --BC; + break; + + case 0x0c: /* INC C */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(BC) + 1; + SET_LOW_REGISTER(BC, temp); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); + break; + + case 0x0d: /* DEC C */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(BC) - 1; + SET_LOW_REGISTER(BC, temp); + AF = (AF & ~0xfe) | decTable[temp & 0xff] | SET_PV2(0x7f); + break; + + case 0x0e: /* LD C,nn */ + tStates += 7; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(BC, RAM_PP(PC)); + break; + + case 0x0f: /* RRCA */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = (AF & 0xc4) | rrcaTable[HIGH_REGISTER(AF)]; + break; + + case 0x10: /* DJNZ dd */ + sim_brk_pend[0] = FALSE; + CHECK_CPU_8080; + if ((BC -= 0x100) & 0xff00) { + PCQ_ENTRY(PCX); + PC += (int8) GetBYTE(PC) + 1; + tStates += 13; + } + else { + PC++; + tStates += 8; + } + break; + + case 0x11: /* LD DE,nnnn */ + tStates += 10; + sim_brk_pend[0] = FALSE; + DE = GET_WORD(PC); + PC += 2; + break; + + case 0x12: /* LD (DE),A */ + tStates += 7; + CHECK_BREAK_BYTE(DE) + PutBYTE(DE, HIGH_REGISTER(AF)); + break; + + case 0x13: /* INC DE */ + tStates += 6; + sim_brk_pend[0] = FALSE; + ++DE; + break; + + case 0x14: /* INC D */ + tStates += 4; + sim_brk_pend[0] = FALSE; + DE += 0x100; + temp = HIGH_REGISTER(DE); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); /* SET_PV2 uses temp */ + break; + + case 0x15: /* DEC D */ + tStates += 4; + sim_brk_pend[0] = FALSE; + DE -= 0x100; + temp = HIGH_REGISTER(DE); + AF = (AF & ~0xfe) | decTable[temp] | SET_PV2(0x7f); /* SET_PV2 uses temp */ + break; + + case 0x16: /* LD D,nn */ + tStates += 7; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(DE, RAM_PP(PC)); + break; + + case 0x17: /* RLA */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = ((AF << 8) & 0x0100) | ((AF >> 7) & 0x28) | ((AF << 1) & ~0x01ff) | + (AF & 0xc4) | ((AF >> 15) & 1); + break; + + case 0x18: /* JR dd */ + tStates += 12; + sim_brk_pend[0] = FALSE; + CHECK_CPU_8080; + PCQ_ENTRY(PCX); + PC += (int8) GetBYTE(PC) + 1; + break; + + case 0x19: /* ADD HL,DE */ + tStates += 11; + sim_brk_pend[0] = FALSE; + HL &= ADDRMASK; + DE &= ADDRMASK; + sum = HL + DE; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(HL ^ DE ^ sum) >> 8]; + HL = sum; + break; + + case 0x1a: /* LD A,(DE) */ + tStates += 7; + CHECK_BREAK_BYTE(DE) + SET_HIGH_REGISTER(AF, GetBYTE(DE)); + break; + + case 0x1b: /* DEC DE */ + tStates += 6; + sim_brk_pend[0] = FALSE; + --DE; + break; + + case 0x1c: /* INC E */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(DE) + 1; + SET_LOW_REGISTER(DE, temp); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); + break; + + case 0x1d: /* DEC E */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(DE) - 1; + SET_LOW_REGISTER(DE, temp); + AF = (AF & ~0xfe) | decTable[temp & 0xff] | SET_PV2(0x7f); + break; + + case 0x1e: /* LD E,nn */ + tStates += 7; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(DE, RAM_PP(PC)); + break; + + case 0x1f: /* RRA */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = ((AF & 1) << 15) | (AF & 0xc4) | rraTable[HIGH_REGISTER(AF)]; + break; + + case 0x20: /* JR NZ,dd */ + sim_brk_pend[0] = FALSE; + CHECK_CPU_8080; + if (TSTFLAG(Z)) { + PC++; + tStates += 7; + } + else { + PCQ_ENTRY(PCX); + PC += (int8) GetBYTE(PC) + 1; + tStates += 12; + } + break; + + case 0x21: /* LD HL,nnnn */ + tStates += 10; + sim_brk_pend[0] = FALSE; + HL = GET_WORD(PC); + PC += 2; + break; + + case 0x22: /* LD (nnnn),HL */ + tStates += 16; + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); + PutWORD(temp, HL); + PC += 2; + break; + + case 0x23: /* INC HL */ + tStates += 6; + sim_brk_pend[0] = FALSE; + ++HL; + break; + + case 0x24: /* INC H */ + tStates += 4; + sim_brk_pend[0] = FALSE; + HL += 0x100; + temp = HIGH_REGISTER(HL); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); /* SET_PV2 uses temp */ + break; + + case 0x25: /* DEC H */ + tStates += 4; + sim_brk_pend[0] = FALSE; + HL -= 0x100; + temp = HIGH_REGISTER(HL); + AF = (AF & ~0xfe) | decTable[temp] | SET_PV2(0x7f); /* SET_PV2 uses temp */ + break; + + case 0x26: /* LD H,nn */ + tStates += 7; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(HL, RAM_PP(PC)); + break; + + case 0x27: /* DAA */ + tStates += 4; + sim_brk_pend[0] = FALSE; + acu = HIGH_REGISTER(AF); + temp = LOW_DIGIT(acu); + cbits = TSTFLAG(C); + if (TSTFLAG(N)) { /* last operation was a subtract */ + int hd = cbits || acu > 0x99; + if (TSTFLAG(H) || (temp > 9)) { /* adjust low digit */ + if (temp > 5) { + SETFLAG(H, 0); + } + acu -= 6; + acu &= 0xff; + } + if (hd) acu -= 0x160; /* adjust high digit */ + } + else { /* last operation was an add */ + if (TSTFLAG(H) || (temp > 9)) { /* adjust low digit */ + SETFLAG(H, (temp > 9)); + acu += 6; + } + if (cbits || ((acu & 0x1f0) > 0x90)) acu += 0x60; /* adjust high digit */ + } + AF = (AF & 0x12) | rrdrldTable[acu & 0xff] | ((acu >> 8) & 1) | cbits; + break; + + case 0x28: /* JR Z,dd */ + sim_brk_pend[0] = FALSE; + CHECK_CPU_8080; + if (TSTFLAG(Z)) { + PCQ_ENTRY(PCX); + PC += (int8) GetBYTE(PC) + 1; + tStates += 12; + } + else { + PC++; + tStates += 7; + } + break; + + case 0x29: /* ADD HL,HL */ + tStates += 11; + sim_brk_pend[0] = FALSE; + HL &= ADDRMASK; + sum = HL + HL; + AF = (AF & ~0x3b) | cbitsDup16Table[sum >> 8]; + HL = sum; + break; + + case 0x2a: /* LD HL,(nnnn) */ + tStates += 16; + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); + HL = GET_WORD(temp); + PC += 2; + break; + + case 0x2b: /* DEC HL */ + tStates += 6; + sim_brk_pend[0] = FALSE; + --HL; + break; + + case 0x2c: /* INC L */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(HL) + 1; + SET_LOW_REGISTER(HL, temp); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); + break; + + case 0x2d: /* DEC L */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(HL) - 1; + SET_LOW_REGISTER(HL, temp); + AF = (AF & ~0xfe) | decTable[temp & 0xff] | SET_PV2(0x7f); + break; + + case 0x2e: /* LD L,nn */ + tStates += 7; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(HL, RAM_PP(PC)); + break; + + case 0x2f: /* CPL */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = (~AF & ~0xff) | (AF & 0xc5) | ((~AF >> 8) & 0x28) | 0x12; + break; + + case 0x30: /* JR NC,dd */ + sim_brk_pend[0] = FALSE; + CHECK_CPU_8080; + if (TSTFLAG(C)) { + PC++; + tStates += 7; + } + else { + PCQ_ENTRY(PCX); + PC += (int8) GetBYTE(PC) + 1; + tStates += 12; + } + break; + + case 0x31: /* LD SP,nnnn */ + tStates += 10; + sim_brk_pend[0] = FALSE; + SP = GET_WORD(PC); + PC += 2; + break; + + case 0x32: /* LD (nnnn),A */ + tStates += 13; + temp = GET_WORD(PC); + CHECK_BREAK_BYTE(temp); + PutBYTE(temp, HIGH_REGISTER(AF)); + PC += 2; + break; + + case 0x33: /* INC SP */ + tStates += 6; + sim_brk_pend[0] = FALSE; + ++SP; + break; + + case 0x34: /* INC (HL) */ + tStates += 11; + CHECK_BREAK_BYTE(HL); + temp = GetBYTE(HL) + 1; + PutBYTE(HL, temp); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); + break; + + case 0x35: /* DEC (HL) */ + tStates += 11; + CHECK_BREAK_BYTE(HL); + temp = GetBYTE(HL) - 1; + PutBYTE(HL, temp); + AF = (AF & ~0xfe) | decTable[temp & 0xff] | SET_PV2(0x7f); + break; + + case 0x36: /* LD (HL),nn */ + tStates += 10; + CHECK_BREAK_BYTE(HL); + PutBYTE(HL, RAM_PP(PC)); + break; + + case 0x37: /* SCF */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = (AF & ~0x3b) | ((AF >> 8) & 0x28) | 1; + break; + + case 0x38: /* JR C,dd */ + sim_brk_pend[0] = FALSE; + CHECK_CPU_8080; + if (TSTFLAG(C)) { + PCQ_ENTRY(PCX); + PC += (int8) GetBYTE(PC) + 1; + tStates += 12; + } + else { + PC++; + tStates += 7; + } + break; + + case 0x39: /* ADD HL,SP */ + tStates += 11; + sim_brk_pend[0] = FALSE; + HL &= ADDRMASK; + SP &= ADDRMASK; + sum = HL + SP; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(HL ^ SP ^ sum) >> 8]; + HL = sum; + break; + + case 0x3a: /* LD A,(nnnn) */ + tStates += 13; + temp = GET_WORD(PC); + CHECK_BREAK_BYTE(temp); + SET_HIGH_REGISTER(AF, GetBYTE(temp)); + PC += 2; + break; + + case 0x3b: /* DEC SP */ + tStates += 6; + sim_brk_pend[0] = FALSE; + --SP; + break; + + case 0x3c: /* INC A */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF += 0x100; + temp = HIGH_REGISTER(AF); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); /* SET_PV2 uses temp */ + break; + + case 0x3d: /* DEC A */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF -= 0x100; + temp = HIGH_REGISTER(AF); + AF = (AF & ~0xfe) | decTable[temp] | SET_PV2(0x7f); /* SET_PV2 uses temp */ + break; + + case 0x3e: /* LD A,nn */ + tStates += 7; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(AF, RAM_PP(PC)); + break; + + case 0x3f: /* CCF */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = (AF & ~0x3b) | ((AF >> 8) & 0x28) | ((AF & 1) << 4) | (~AF & 1); + break; + + case 0x40: /* LD B,B */ + tStates += 4; + sim_brk_pend[0] = FALSE; /* nop */ + break; + + case 0x41: /* LD B,C */ + tStates += 4; + sim_brk_pend[0] = FALSE; + BC = (BC & 0xff) | ((BC & 0xff) << 8); + break; + + case 0x42: /* LD B,D */ + tStates += 4; + sim_brk_pend[0] = FALSE; + BC = (BC & 0xff) | (DE & ~0xff); + break; + + case 0x43: /* LD B,E */ + tStates += 4; + sim_brk_pend[0] = FALSE; + BC = (BC & 0xff) | ((DE & 0xff) << 8); + break; + + case 0x44: /* LD B,H */ + tStates += 4; + sim_brk_pend[0] = FALSE; + BC = (BC & 0xff) | (HL & ~0xff); + break; + + case 0x45: /* LD B,L */ + tStates += 4; + sim_brk_pend[0] = FALSE; + BC = (BC & 0xff) | ((HL & 0xff) << 8); + break; + + case 0x46: /* LD B,(HL) */ + tStates += 7; + CHECK_BREAK_BYTE(HL); + SET_HIGH_REGISTER(BC, GetBYTE(HL)); + break; + + case 0x47: /* LD B,A */ + tStates += 4; + sim_brk_pend[0] = FALSE; + BC = (BC & 0xff) | (AF & ~0xff); + break; + + case 0x48: /* LD C,B */ + tStates += 4; + sim_brk_pend[0] = FALSE; + BC = (BC & ~0xff) | ((BC >> 8) & 0xff); + break; + + case 0x49: /* LD C,C */ + tStates += 4; + sim_brk_pend[0] = FALSE; /* nop */ + break; + + case 0x4a: /* LD C,D */ + tStates += 4; + sim_brk_pend[0] = FALSE; + BC = (BC & ~0xff) | ((DE >> 8) & 0xff); + break; + + case 0x4b: /* LD C,E */ + tStates += 4; + sim_brk_pend[0] = FALSE; + BC = (BC & ~0xff) | (DE & 0xff); + break; + + case 0x4c: /* LD C,H */ + tStates += 4; + sim_brk_pend[0] = FALSE; + BC = (BC & ~0xff) | ((HL >> 8) & 0xff); + break; + + case 0x4d: /* LD C,L */ + tStates += 4; + sim_brk_pend[0] = FALSE; + BC = (BC & ~0xff) | (HL & 0xff); + break; + + case 0x4e: /* LD C,(HL) */ + tStates += 7; + CHECK_BREAK_BYTE(HL); + SET_LOW_REGISTER(BC, GetBYTE(HL)); + break; + + case 0x4f: /* LD C,A */ + tStates += 4; + sim_brk_pend[0] = FALSE; + BC = (BC & ~0xff) | ((AF >> 8) & 0xff); + break; + + case 0x50: /* LD D,B */ + tStates += 4; + sim_brk_pend[0] = FALSE; + DE = (DE & 0xff) | (BC & ~0xff); + break; + + case 0x51: /* LD D,C */ + tStates += 4; + sim_brk_pend[0] = FALSE; + DE = (DE & 0xff) | ((BC & 0xff) << 8); + break; + + case 0x52: /* LD D,D */ + tStates += 4; + sim_brk_pend[0] = FALSE; /* nop */ + break; + + case 0x53: /* LD D,E */ + tStates += 4; + sim_brk_pend[0] = FALSE; + DE = (DE & 0xff) | ((DE & 0xff) << 8); + break; + + case 0x54: /* LD D,H */ + tStates += 4; + sim_brk_pend[0] = FALSE; + DE = (DE & 0xff) | (HL & ~0xff); + break; + + case 0x55: /* LD D,L */ + tStates += 4; + sim_brk_pend[0] = FALSE; + DE = (DE & 0xff) | ((HL & 0xff) << 8); + break; + + case 0x56: /* LD D,(HL) */ + tStates += 7; + CHECK_BREAK_BYTE(HL); + SET_HIGH_REGISTER(DE, GetBYTE(HL)); + break; + + case 0x57: /* LD D,A */ + tStates += 4; + sim_brk_pend[0] = FALSE; + DE = (DE & 0xff) | (AF & ~0xff); + break; + + case 0x58: /* LD E,B */ + tStates += 4; + sim_brk_pend[0] = FALSE; + DE = (DE & ~0xff) | ((BC >> 8) & 0xff); + break; + + case 0x59: /* LD E,C */ + tStates += 4; + sim_brk_pend[0] = FALSE; + DE = (DE & ~0xff) | (BC & 0xff); + break; + + case 0x5a: /* LD E,D */ + tStates += 4; + sim_brk_pend[0] = FALSE; + DE = (DE & ~0xff) | ((DE >> 8) & 0xff); + break; + + case 0x5b: /* LD E,E */ + tStates += 4; + sim_brk_pend[0] = FALSE; /* nop */ + break; + + case 0x5c: /* LD E,H */ + tStates += 4; + sim_brk_pend[0] = FALSE; + DE = (DE & ~0xff) | ((HL >> 8) & 0xff); + break; + + case 0x5d: /* LD E,L */ + tStates += 4; + sim_brk_pend[0] = FALSE; + DE = (DE & ~0xff) | (HL & 0xff); + break; + + case 0x5e: /* LD E,(HL) */ + tStates += 7; + CHECK_BREAK_BYTE(HL); + SET_LOW_REGISTER(DE, GetBYTE(HL)); + break; + + case 0x5f: /* LD E,A */ + tStates += 4; + sim_brk_pend[0] = FALSE; + DE = (DE & ~0xff) | ((AF >> 8) & 0xff); + break; + + case 0x60: /* LD H,B */ + tStates += 4; + sim_brk_pend[0] = FALSE; + HL = (HL & 0xff) | (BC & ~0xff); + break; + + case 0x61: /* LD H,C */ + tStates += 4; + sim_brk_pend[0] = FALSE; + HL = (HL & 0xff) | ((BC & 0xff) << 8); + break; + + case 0x62: /* LD H,D */ + tStates += 4; + sim_brk_pend[0] = FALSE; + HL = (HL & 0xff) | (DE & ~0xff); + break; + + case 0x63: /* LD H,E */ + tStates += 4; + sim_brk_pend[0] = FALSE; + HL = (HL & 0xff) | ((DE & 0xff) << 8); + break; + + case 0x64: /* LD H,H */ + tStates += 4; + sim_brk_pend[0] = FALSE; /* nop */ + break; + + case 0x65: /* LD H,L */ + tStates += 4; + sim_brk_pend[0] = FALSE; + HL = (HL & 0xff) | ((HL & 0xff) << 8); + break; + + case 0x66: /* LD H,(HL) */ + tStates += 7; + CHECK_BREAK_BYTE(HL); + SET_HIGH_REGISTER(HL, GetBYTE(HL)); + break; + + case 0x67: /* LD H,A */ + tStates += 4; + sim_brk_pend[0] = FALSE; + HL = (HL & 0xff) | (AF & ~0xff); + break; + + case 0x68: /* LD L,B */ + tStates += 4; + sim_brk_pend[0] = FALSE; + HL = (HL & ~0xff) | ((BC >> 8) & 0xff); + break; + + case 0x69: /* LD L,C */ + tStates += 4; + sim_brk_pend[0] = FALSE; + HL = (HL & ~0xff) | (BC & 0xff); + break; + + case 0x6a: /* LD L,D */ + tStates += 4; + sim_brk_pend[0] = FALSE; + HL = (HL & ~0xff) | ((DE >> 8) & 0xff); + break; + + case 0x6b: /* LD L,E */ + tStates += 4; + sim_brk_pend[0] = FALSE; + HL = (HL & ~0xff) | (DE & 0xff); + break; + + case 0x6c: /* LD L,H */ + tStates += 4; + sim_brk_pend[0] = FALSE; + HL = (HL & ~0xff) | ((HL >> 8) & 0xff); + break; + + case 0x6d: /* LD L,L */ + tStates += 4; + sim_brk_pend[0] = FALSE; /* nop */ + break; + + case 0x6e: /* LD L,(HL) */ + tStates += 7; + CHECK_BREAK_BYTE(HL); + SET_LOW_REGISTER(HL, GetBYTE(HL)); + break; + + case 0x6f: /* LD L,A */ + tStates += 4; + sim_brk_pend[0] = FALSE; + HL = (HL & ~0xff) | ((AF >> 8) & 0xff); + break; + + case 0x70: /* LD (HL),B */ + tStates += 7; + CHECK_BREAK_BYTE(HL); + PutBYTE(HL, HIGH_REGISTER(BC)); + break; + + case 0x71: /* LD (HL),C */ + tStates += 7; + CHECK_BREAK_BYTE(HL); + PutBYTE(HL, LOW_REGISTER(BC)); + break; + + case 0x72: /* LD (HL),D */ + tStates += 7; + CHECK_BREAK_BYTE(HL); + PutBYTE(HL, HIGH_REGISTER(DE)); + break; + + case 0x73: /* LD (HL),E */ + tStates += 7; + CHECK_BREAK_BYTE(HL); + PutBYTE(HL, LOW_REGISTER(DE)); + break; + + case 0x74: /* LD (HL),H */ + tStates += 7; + CHECK_BREAK_BYTE(HL); + PutBYTE(HL, HIGH_REGISTER(HL)); + break; + + case 0x75: /* LD (HL),L */ + tStates += 7; + CHECK_BREAK_BYTE(HL); + PutBYTE(HL, LOW_REGISTER(HL)); + break; + + case HALTINSTRUCTION: /* HALT */ + tStates += 4; + sim_brk_pend[0] = FALSE; + PC--; + if (cpu_unit.flags & UNIT_CPU_STOPONHALT) { + reason = STOP_HALT; + goto end_decode; + } + sim_interval = 0; + do_SIMH_sleep(); /* reduce CPU load in busy wait */ + break; + + case 0x77: /* LD (HL),A */ + tStates += 7; + CHECK_BREAK_BYTE(HL); + PutBYTE(HL, HIGH_REGISTER(AF)); + break; + + case 0x78: /* LD A,B */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = (AF & 0xff) | (BC & ~0xff); + break; + + case 0x79: /* LD A,C */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = (AF & 0xff) | ((BC & 0xff) << 8); + break; + + case 0x7a: /* LD A,D */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = (AF & 0xff) | (DE & ~0xff); + break; + + case 0x7b: /* LD A,E */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = (AF & 0xff) | ((DE & 0xff) << 8); + break; + + case 0x7c: /* LD A,H */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = (AF & 0xff) | (HL & ~0xff); + break; + + case 0x7d: /* LD A,L */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = (AF & 0xff) | ((HL & 0xff) << 8); + break; + + case 0x7e: /* LD A,(HL) */ + tStates += 7; + CHECK_BREAK_BYTE(HL); + SET_HIGH_REGISTER(AF, GetBYTE(HL)); + break; + + case 0x7f: /* LD A,A */ + tStates += 4; + sim_brk_pend[0] = FALSE; /* nop */ + break; + + case 0x80: /* ADD A,B */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = HIGH_REGISTER(BC); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x81: /* ADD A,C */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(BC); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x82: /* ADD A,D */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = HIGH_REGISTER(DE); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x83: /* ADD A,E */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(DE); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x84: /* ADD A,H */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = HIGH_REGISTER(HL); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x85: /* ADD A,L */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(HL); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x86: /* ADD A,(HL) */ + tStates += 7; + CHECK_BREAK_BYTE(HL); + temp = GetBYTE(HL); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x87: /* ADD A,A */ + tStates += 4; + sim_brk_pend[0] = FALSE; + cbits = 2 * HIGH_REGISTER(AF); + AF = cbitsDup8Table[cbits] | (SET_PVS(cbits)); + break; + + case 0x88: /* ADC A,B */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = HIGH_REGISTER(BC); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x89: /* ADC A,C */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(BC); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x8a: /* ADC A,D */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = HIGH_REGISTER(DE); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x8b: /* ADC A,E */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(DE); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x8c: /* ADC A,H */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = HIGH_REGISTER(HL); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x8d: /* ADC A,L */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(HL); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x8e: /* ADC A,(HL) */ + tStates += 7; + CHECK_BREAK_BYTE(HL); + temp = GetBYTE(HL); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x8f: /* ADC A,A */ + tStates += 4; + sim_brk_pend[0] = FALSE; + cbits = 2 * HIGH_REGISTER(AF) + TSTFLAG(C); + AF = cbitsDup8Table[cbits] | (SET_PVS(cbits)); + break; + + case 0x90: /* SUB B */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = HIGH_REGISTER(BC); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x91: /* SUB C */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(BC); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x92: /* SUB D */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = HIGH_REGISTER(DE); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x93: /* SUB E */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(DE); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x94: /* SUB H */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = HIGH_REGISTER(HL); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x95: /* SUB L */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(HL); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x96: /* SUB (HL) */ + tStates += 7; + CHECK_BREAK_BYTE(HL); + temp = GetBYTE(HL); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x97: /* SUB A */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = (chiptype == CHIP_TYPE_Z80) ? 0x42 : 0x46; + break; + + case 0x98: /* SBC A,B */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = HIGH_REGISTER(BC); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x99: /* SBC A,C */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(BC); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x9a: /* SBC A,D */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = HIGH_REGISTER(DE); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x9b: /* SBC A,E */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(DE); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x9c: /* SBC A,H */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = HIGH_REGISTER(HL); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x9d: /* SBC A,L */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(HL); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x9e: /* SBC A,(HL) */ + tStates += 7; + CHECK_BREAK_BYTE(HL); + temp = GetBYTE(HL); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x9f: /* SBC A,A */ + tStates += 4; + sim_brk_pend[0] = FALSE; + cbits = -TSTFLAG(C); + AF = subTable[cbits & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PVS(cbits)); + break; + + case 0xa0: /* AND B */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = andTable[((AF & BC) >> 8) & 0xff]; + break; + + case 0xa1: /* AND C */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = andTable[((AF >> 8) & BC) & 0xff]; + break; + + case 0xa2: /* AND D */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = andTable[((AF & DE) >> 8) & 0xff]; + break; + + case 0xa3: /* AND E */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = andTable[((AF >> 8) & DE) & 0xff]; + break; + + case 0xa4: /* AND H */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = andTable[((AF & HL) >> 8) & 0xff]; + break; + + case 0xa5: /* AND L */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = andTable[((AF >> 8) & HL) & 0xff]; + break; + + case 0xa6: /* AND (HL) */ + tStates += 7; + CHECK_BREAK_BYTE(HL); + AF = andTable[((AF >> 8) & GetBYTE(HL)) & 0xff]; + break; + + case 0xa7: /* AND A */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = andTable[(AF >> 8) & 0xff]; + break; + + case 0xa8: /* XOR B */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = xororTable[((AF ^ BC) >> 8) & 0xff]; + break; + + case 0xa9: /* XOR C */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = xororTable[((AF >> 8) ^ BC) & 0xff]; + break; + + case 0xaa: /* XOR D */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = xororTable[((AF ^ DE) >> 8) & 0xff]; + break; + + case 0xab: /* XOR E */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = xororTable[((AF >> 8) ^ DE) & 0xff]; + break; + + case 0xac: /* XOR H */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = xororTable[((AF ^ HL) >> 8) & 0xff]; + break; + + case 0xad: /* XOR L */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = xororTable[((AF >> 8) ^ HL) & 0xff]; + break; + + case 0xae: /* XOR (HL) */ + tStates += 7; + CHECK_BREAK_BYTE(HL); + AF = xororTable[((AF >> 8) ^ GetBYTE(HL)) & 0xff]; + break; + + case 0xaf: /* XOR A */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = 0x44; + break; + + case 0xb0: /* OR B */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = xororTable[((AF | BC) >> 8) & 0xff]; + break; + + case 0xb1: /* OR C */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = xororTable[((AF >> 8) | BC) & 0xff]; + break; + + case 0xb2: /* OR D */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = xororTable[((AF | DE) >> 8) & 0xff]; + break; + + case 0xb3: /* OR E */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = xororTable[((AF >> 8) | DE) & 0xff]; + break; + + case 0xb4: /* OR H */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = xororTable[((AF | HL) >> 8) & 0xff]; + break; + + case 0xb5: /* OR L */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = xororTable[((AF >> 8) | HL) & 0xff]; + break; + + case 0xb6: /* OR (HL) */ + tStates += 7; + CHECK_BREAK_BYTE(HL); + AF = xororTable[((AF >> 8) | GetBYTE(HL)) & 0xff]; + break; + + case 0xb7: /* OR A */ + tStates += 4; + sim_brk_pend[0] = FALSE; + AF = xororTable[(AF >> 8) & 0xff]; + break; + + case 0xb8: /* CP B */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = HIGH_REGISTER(BC); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SET_PV) | cbits2Table[cbits & 0x1ff]; + break; + + case 0xb9: /* CP C */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(BC); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SET_PV) | cbits2Table[cbits & 0x1ff]; + break; + + case 0xba: /* CP D */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = HIGH_REGISTER(DE); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SET_PV) | cbits2Table[cbits & 0x1ff]; + break; + + case 0xbb: /* CP E */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(DE); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SET_PV) | cbits2Table[cbits & 0x1ff]; + break; + + case 0xbc: /* CP H */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = HIGH_REGISTER(HL); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SET_PV) | cbits2Table[cbits & 0x1ff]; + break; + + case 0xbd: /* CP L */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(HL); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SET_PV) | cbits2Table[cbits & 0x1ff]; + break; + + case 0xbe: /* CP (HL) */ + tStates += 7; + CHECK_BREAK_BYTE(HL); + temp = GetBYTE(HL); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SET_PV) | cbits2Table[cbits & 0x1ff]; + break; + + case 0xbf: /* CP A */ + tStates += 4; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(AF, (HIGH_REGISTER(AF) & 0x28) | (chiptype == CHIP_TYPE_Z80 ? 0x42 : 0x46)); + break; + + case 0xc0: /* RET NZ */ + if (TSTFLAG(Z)) { + sim_brk_pend[0] = FALSE; + tStates += 5; + } + else { + CHECK_BREAK_WORD(SP); + PCQ_ENTRY(PCX); + POP(PC); + tStates += 11; + } + break; + + case 0xc1: /* POP BC */ + tStates += 10; + CHECK_BREAK_WORD(SP); + POP(BC); + break; + + case 0xc2: /* JP NZ,nnnn */ + sim_brk_pend[0] = FALSE; + JPC(!TSTFLAG(Z)); /* also updates tStates */ + break; + + case 0xc3: /* JP nnnn */ + sim_brk_pend[0] = FALSE; + JPC(1); /* also updates tStates */ + break; + + case 0xc4: /* CALL NZ,nnnn */ + CALLC(!TSTFLAG(Z)); /* also updates tStates */ + break; + + case 0xc5: /* PUSH BC */ + tStates += 11; + CHECK_BREAK_WORD(SP - 2); + PUSH(BC); + break; + + case 0xc6: /* ADD A,nn */ + tStates += 7; + sim_brk_pend[0] = FALSE; + temp = RAM_PP(PC); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0xc7: /* RST 0 */ + tStates += 11; + CHECK_BREAK_WORD(SP - 2); + PUSH(PC); + PCQ_ENTRY(PCX); + PC = 0; + break; + + case 0xc8: /* RET Z */ + if (TSTFLAG(Z)) { + CHECK_BREAK_WORD(SP); + PCQ_ENTRY(PCX); + POP(PC); + tStates += 11; + } + else { + sim_brk_pend[0] = FALSE; + tStates += 5; + } + break; + + case 0xc9: /* RET */ + tStates += 10; + CHECK_BREAK_WORD(SP); + PCQ_ENTRY(PCX); + POP(PC); + break; + + case 0xca: /* JP Z,nnnn */ + sim_brk_pend[0] = FALSE; + JPC(TSTFLAG(Z)); /* also updates tStates */ + break; + + case 0xcb: /* CB prefix */ + CHECK_CPU_8080; + adr = HL; + switch ((op = GetBYTE(PC)) & 7) { + + case 0: + sim_brk_pend[0] = tStateModifier = FALSE; + ++PC; + acu = HIGH_REGISTER(BC); + tStates += 8; + break; + + case 1: + sim_brk_pend[0] = tStateModifier = FALSE; + ++PC; + acu = LOW_REGISTER(BC); + tStates += 8; + break; + + case 2: + sim_brk_pend[0] = tStateModifier = FALSE; + ++PC; + acu = HIGH_REGISTER(DE); + tStates += 8; + break; + + case 3: + sim_brk_pend[0] = tStateModifier = FALSE; + ++PC; + acu = LOW_REGISTER(DE); + tStates += 8; + break; + + case 4: + sim_brk_pend[0] = tStateModifier = FALSE; + ++PC; + acu = HIGH_REGISTER(HL); + tStates += 8; + break; + + case 5: + sim_brk_pend[0] = tStateModifier = FALSE; + ++PC; + acu = LOW_REGISTER(HL); + tStates += 8; + break; + + case 6: + CHECK_BREAK_BYTE(adr); + ++PC; + acu = GetBYTE(adr); + tStateModifier = TRUE; + tStates += 15; + break; + + case 7: + sim_brk_pend[0] = tStateModifier = FALSE; + ++PC; + acu = HIGH_REGISTER(AF); + tStates += 8; + break; + } + switch (op & 0xc0) { + + case 0x00: /* shift/rotate */ + switch (op & 0x38) { + + case 0x00: /* RLC */ + temp = (acu << 1) | (acu >> 7); + cbits = temp & 1; + goto cbshflg1; + + case 0x08: /* RRC */ + temp = (acu >> 1) | (acu << 7); + cbits = temp & 0x80; + goto cbshflg1; + + case 0x10: /* RL */ + temp = (acu << 1) | TSTFLAG(C); + cbits = acu & 0x80; + goto cbshflg1; + + case 0x18: /* RR */ + temp = (acu >> 1) | (TSTFLAG(C) << 7); + cbits = acu & 1; + goto cbshflg1; + + case 0x20: /* SLA */ + temp = acu << 1; + cbits = acu & 0x80; + goto cbshflg1; + + case 0x28: /* SRA */ + temp = (acu >> 1) | (acu & 0x80); + cbits = acu & 1; + goto cbshflg1; + + case 0x30: /* SLIA */ + temp = (acu << 1) | 1; + cbits = acu & 0x80; + goto cbshflg1; + + case 0x38: /* SRL */ + temp = acu >> 1; + cbits = acu & 1; + cbshflg1: + AF = (AF & ~0xff) | rotateShiftTable[temp & 0xff] | !!cbits; + /* !!cbits == 0 if cbits == 0 !!cbits == 1 if cbits > 0 */ + } + break; + + case 0x40: /* BIT */ + if (tStateModifier) tStates -= 3; + if (acu & (1 << ((op >> 3) & 7))) + AF = (AF & ~0xfe) | 0x10 | (((op & 0x38) == 0x38) << 7); + else AF = (AF & ~0xfe) | 0x54; + if ((op & 7) != 6) AF |= (acu & 0x28); + temp = acu; + break; + + case 0x80: /* RES */ + temp = acu & ~(1 << ((op >> 3) & 7)); + break; + + case 0xc0: /* SET */ + temp = acu | (1 << ((op >> 3) & 7)); + break; + } + + switch (op & 7) { + + case 0: + SET_HIGH_REGISTER(BC, temp); + break; + + case 1: + SET_LOW_REGISTER(BC, temp); + break; + + case 2: + SET_HIGH_REGISTER(DE, temp); + break; + + case 3: + SET_LOW_REGISTER(DE, temp); + break; + + case 4: + SET_HIGH_REGISTER(HL, temp); + break; + + case 5: + SET_LOW_REGISTER(HL, temp); + break; + + case 6: + PutBYTE(adr, temp); + break; + + case 7: + SET_HIGH_REGISTER(AF, temp); + break; + } + break; + + case 0xcc: /* CALL Z,nnnn */ + CALLC(TSTFLAG(Z)); /* also updates tStates */ + break; + + case 0xcd: /* CALL nnnn */ + CALLC(1); /* also updates tStates */ + break; + + case 0xce: /* ADC A,nn */ + tStates += 7; + sim_brk_pend[0] = FALSE; + temp = RAM_PP(PC); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0xcf: /* RST 8 */ + tStates += 11; + CHECK_BREAK_WORD(SP - 2); + PUSH(PC); + PCQ_ENTRY(PCX); + PC = 8; + break; + + case 0xd0: /* RET NC */ + if (TSTFLAG(C)) { + sim_brk_pend[0] = FALSE; + tStates += 5; + } + else { + CHECK_BREAK_WORD(SP); + PCQ_ENTRY(PCX); + POP(PC); + tStates += 11; + } + break; + + case 0xd1: /* POP DE */ + tStates += 10; + CHECK_BREAK_WORD(SP); + POP(DE); + break; + + case 0xd2: /* JP NC,nnnn */ + sim_brk_pend[0] = FALSE; + JPC(!TSTFLAG(C)); /* also updates tStates */ + break; + + case 0xd3: /* OUT (nn),A */ + tStates += 11; + sim_brk_pend[0] = FALSE; + out(RAM_PP(PC), HIGH_REGISTER(AF)); + break; + + case 0xd4: /* CALL NC,nnnn */ + CALLC(!TSTFLAG(C)); /* also updates tStates */ + break; + + case 0xd5: /* PUSH DE */ + tStates += 11; + CHECK_BREAK_WORD(SP - 2); + PUSH(DE); + break; + + case 0xd6: /* SUB nn */ + tStates += 7; + sim_brk_pend[0] = FALSE; + temp = RAM_PP(PC); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0xd7: /* RST 10H */ + tStates += 11; + CHECK_BREAK_WORD(SP - 2); + PUSH(PC); + PCQ_ENTRY(PCX); + PC = 0x10; + break; + + case 0xd8: /* RET C */ + if (TSTFLAG(C)) { + CHECK_BREAK_WORD(SP); + PCQ_ENTRY(PCX); + POP(PC); + tStates += 11; + } + else { + sim_brk_pend[0] = FALSE; + tStates += 5; + } + break; + + case 0xd9: /* EXX */ + tStates += 4; + sim_brk_pend[0] = FALSE; + CHECK_CPU_8080; + temp = BC; + BC = BC1_S; + BC1_S = temp; + temp = DE; + DE = DE1_S; + DE1_S = temp; + temp = HL; + HL = HL1_S; + HL1_S = temp; + break; + + case 0xda: /* JP C,nnnn */ + sim_brk_pend[0] = FALSE; + JPC(TSTFLAG(C)); /* also updates tStates */ + break; + + case 0xdb: /* IN A,(nn) */ + tStates += 11; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(AF, in(RAM_PP(PC))); + break; + + case 0xdc: /* CALL C,nnnn */ + CALLC(TSTFLAG(C)); /* also updates tStates */ + break; + + case 0xdd: /* DD prefix */ + CHECK_CPU_8080; + switch (op = RAM_PP(PC)) { + + case 0x09: /* ADD IX,BC */ + tStates += 15; + sim_brk_pend[0] = FALSE; + IX &= ADDRMASK; + BC &= ADDRMASK; + sum = IX + BC; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IX ^ BC ^ sum) >> 8]; + IX = sum; + break; + + case 0x19: /* ADD IX,DE */ + tStates += 15; + sim_brk_pend[0] = FALSE; + IX &= ADDRMASK; + DE &= ADDRMASK; + sum = IX + DE; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IX ^ DE ^ sum) >> 8]; + IX = sum; + break; + + case 0x21: /* LD IX,nnnn */ + tStates += 14; + sim_brk_pend[0] = FALSE; + IX = GET_WORD(PC); + PC += 2; + break; + + case 0x22: /* LD (nnnn),IX */ + tStates += 20; + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); + PutWORD(temp, IX); + PC += 2; + break; + + case 0x23: /* INC IX */ + tStates += 10; + sim_brk_pend[0] = FALSE; + ++IX; + break; + + case 0x24: /* INC IXH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + IX += 0x100; + AF = (AF & ~0xfe) | incZ80Table[HIGH_REGISTER(IX)]; + break; + + case 0x25: /* DEC IXH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + IX -= 0x100; + AF = (AF & ~0xfe) | decZ80Table[HIGH_REGISTER(IX)]; + break; + + case 0x26: /* LD IXH,nn */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(IX, RAM_PP(PC)); + break; + + case 0x29: /* ADD IX,IX */ + tStates += 15; + sim_brk_pend[0] = FALSE; + IX &= ADDRMASK; + sum = IX + IX; + AF = (AF & ~0x3b) | cbitsDup16Table[sum >> 8]; + IX = sum; + break; + + case 0x2a: /* LD IX,(nnnn) */ + tStates += 20; + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); + IX = GET_WORD(temp); + PC += 2; + break; + + case 0x2b: /* DEC IX */ + tStates += 10; + sim_brk_pend[0] = FALSE; + --IX; + break; + + case 0x2c: /* INC IXL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(IX) + 1; + SET_LOW_REGISTER(IX, temp); + AF = (AF & ~0xfe) | incZ80Table[temp]; + break; + + case 0x2d: /* DEC IXL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(IX) - 1; + SET_LOW_REGISTER(IX, temp); + AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; + break; + + case 0x2e: /* LD IXL,nn */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(IX, RAM_PP(PC)); + break; + + case 0x34: /* INC (IX+dd) */ + tStates += 23; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GetBYTE(adr) + 1; + PutBYTE(adr, temp); + AF = (AF & ~0xfe) | incZ80Table[temp]; + break; + + case 0x35: /* DEC (IX+dd) */ + tStates += 23; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GetBYTE(adr) - 1; + PutBYTE(adr, temp); + AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; + break; + + case 0x36: /* LD (IX+dd),nn */ + tStates += 19; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, RAM_PP(PC)); + break; + + case 0x39: /* ADD IX,SP */ + tStates += 15; + sim_brk_pend[0] = FALSE; + IX &= ADDRMASK; + SP &= ADDRMASK; + sum = IX + SP; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IX ^ SP ^ sum) >> 8]; + IX = sum; + break; + + case 0x44: /* LD B,IXH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(BC, HIGH_REGISTER(IX)); + break; + + case 0x45: /* LD B,IXL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(BC, LOW_REGISTER(IX)); + break; + + case 0x46: /* LD B,(IX+dd) */ + tStates += 19; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_HIGH_REGISTER(BC, GetBYTE(adr)); + break; + + case 0x4c: /* LD C,IXH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(BC, HIGH_REGISTER(IX)); + break; + + case 0x4d: /* LD C,IXL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(BC, LOW_REGISTER(IX)); + break; + + case 0x4e: /* LD C,(IX+dd) */ + tStates += 19; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_LOW_REGISTER(BC, GetBYTE(adr)); + break; + + case 0x54: /* LD D,IXH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(DE, HIGH_REGISTER(IX)); + break; + + case 0x55: /* LD D,IXL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(DE, LOW_REGISTER(IX)); + break; + + case 0x56: /* LD D,(IX+dd) */ + tStates += 19; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_HIGH_REGISTER(DE, GetBYTE(adr)); + break; + + case 0x5c: /* LD E,IXH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(DE, HIGH_REGISTER(IX)); + break; + + case 0x5d: /* LD E,IXL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(DE, LOW_REGISTER(IX)); + break; + + case 0x5e: /* LD E,(IX+dd) */ + tStates += 19; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_LOW_REGISTER(DE, GetBYTE(adr)); + break; + + case 0x60: /* LD IXH,B */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(IX, HIGH_REGISTER(BC)); + break; + + case 0x61: /* LD IXH,C */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(IX, LOW_REGISTER(BC)); + break; + + case 0x62: /* LD IXH,D */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(IX, HIGH_REGISTER(DE)); + break; + + case 0x63: /* LD IXH,E */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(IX, LOW_REGISTER(DE)); + break; + + case 0x64: /* LD IXH,IXH */ + tStates += 9; + sim_brk_pend[0] = FALSE; /* nop */ + break; + + case 0x65: /* LD IXH,IXL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(IX, LOW_REGISTER(IX)); + break; + + case 0x66: /* LD H,(IX+dd) */ + tStates += 19; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_HIGH_REGISTER(HL, GetBYTE(adr)); + break; + + case 0x67: /* LD IXH,A */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(IX, HIGH_REGISTER(AF)); + break; + + case 0x68: /* LD IXL,B */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(IX, HIGH_REGISTER(BC)); + break; + + case 0x69: /* LD IXL,C */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(IX, LOW_REGISTER(BC)); + break; + + case 0x6a: /* LD IXL,D */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(IX, HIGH_REGISTER(DE)); + break; + + case 0x6b: /* LD IXL,E */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(IX, LOW_REGISTER(DE)); + break; + + case 0x6c: /* LD IXL,IXH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(IX, HIGH_REGISTER(IX)); + break; + + case 0x6d: /* LD IXL,IXL */ + tStates += 9; + sim_brk_pend[0] = FALSE; /* nop */ + break; + + case 0x6e: /* LD L,(IX+dd) */ + tStates += 19; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_LOW_REGISTER(HL, GetBYTE(adr)); + break; + + case 0x6f: /* LD IXL,A */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(IX, HIGH_REGISTER(AF)); + break; + + case 0x70: /* LD (IX+dd),B */ + tStates += 19; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, HIGH_REGISTER(BC)); + break; + + case 0x71: /* LD (IX+dd),C */ + tStates += 19; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, LOW_REGISTER(BC)); + break; + + case 0x72: /* LD (IX+dd),D */ + tStates += 19; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, HIGH_REGISTER(DE)); + break; + + case 0x73: /* LD (IX+dd),E */ + tStates += 19; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, LOW_REGISTER(DE)); + break; + + case 0x74: /* LD (IX+dd),H */ + tStates += 19; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, HIGH_REGISTER(HL)); + break; + + case 0x75: /* LD (IX+dd),L */ + tStates += 19; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, LOW_REGISTER(HL)); + break; + + case 0x77: /* LD (IX+dd),A */ + tStates += 19; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, HIGH_REGISTER(AF)); + break; + + case 0x7c: /* LD A,IXH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(AF, HIGH_REGISTER(IX)); + break; + + case 0x7d: /* LD A,IXL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(AF, LOW_REGISTER(IX)); + break; + + case 0x7e: /* LD A,(IX+dd) */ + tStates += 19; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_HIGH_REGISTER(AF, GetBYTE(adr)); + break; + + case 0x84: /* ADD A,IXH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + temp = HIGH_REGISTER(IX); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x85: /* ADD A,IXL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(IX); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x86: /* ADD A,(IX+dd) */ + tStates += 19; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GetBYTE(adr); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x8c: /* ADC A,IXH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + temp = HIGH_REGISTER(IX); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x8d: /* ADC A,IXL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(IX); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x8e: /* ADC A,(IX+dd) */ + tStates += 19; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GetBYTE(adr); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x96: /* SUB (IX+dd) */ + tStates += 19; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GetBYTE(adr); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0x94: /* SUB IXH */ + SETFLAG(C, 0);/* fall through, a bit less efficient but smaller code */ + + case 0x9c: /* SBC A,IXH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + temp = HIGH_REGISTER(IX); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0x95: /* SUB IXL */ + SETFLAG(C, 0);/* fall through, a bit less efficient but smaller code */ + + case 0x9d: /* SBC A,IXL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(IX); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0x9e: /* SBC A,(IX+dd) */ + tStates += 19; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GetBYTE(adr); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0xa4: /* AND IXH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + AF = andTable[((AF & IX) >> 8) & 0xff]; + break; + + case 0xa5: /* AND IXL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + AF = andTable[((AF >> 8) & IX) & 0xff]; + break; + + case 0xa6: /* AND (IX+dd) */ + tStates += 19; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + AF = andTable[((AF >> 8) & GetBYTE(adr)) & 0xff]; + break; + + case 0xac: /* XOR IXH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + AF = xororTable[((AF ^ IX) >> 8) & 0xff]; + break; + + case 0xad: /* XOR IXL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + AF = xororTable[((AF >> 8) ^ IX) & 0xff]; + break; + + case 0xae: /* XOR (IX+dd) */ + tStates += 19; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + AF = xororTable[((AF >> 8) ^ GetBYTE(adr)) & 0xff]; + break; + + case 0xb4: /* OR IXH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + AF = xororTable[((AF | IX) >> 8) & 0xff]; + break; + + case 0xb5: /* OR IXL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + AF = xororTable[((AF >> 8) | IX) & 0xff]; + break; + + case 0xb6: /* OR (IX+dd) */ + tStates += 19; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + AF = xororTable[((AF >> 8) | GetBYTE(adr)) & 0xff]; + break; + + case 0xbc: /* CP IXH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + temp = HIGH_REGISTER(IX); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0xbd: /* CP IXL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(IX); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0xbe: /* CP (IX+dd) */ + tStates += 19; + adr = IX + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GetBYTE(adr); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0xcb: /* CB prefix */ + adr = IX + (int8) RAM_PP(PC); + switch ((op = GetBYTE(PC)) & 7) { + + case 0: + sim_brk_pend[0] = FALSE; + ++PC; + acu = HIGH_REGISTER(BC); + break; + + case 1: + sim_brk_pend[0] = FALSE; + ++PC; + acu = LOW_REGISTER(BC); + break; + + case 2: + sim_brk_pend[0] = FALSE; + ++PC; + acu = HIGH_REGISTER(DE); + break; + + case 3: + sim_brk_pend[0] = FALSE; + ++PC; + acu = LOW_REGISTER(DE); + break; + + case 4: + sim_brk_pend[0] = FALSE; + ++PC; + acu = HIGH_REGISTER(HL); + break; + + case 5: + sim_brk_pend[0] = FALSE; + ++PC; + acu = LOW_REGISTER(HL); + break; + + case 6: + CHECK_BREAK_BYTE(adr); + ++PC; + acu = GetBYTE(adr); + break; + + case 7: + sim_brk_pend[0] = FALSE; + ++PC; + acu = HIGH_REGISTER(AF); + break; + } + switch (op & 0xc0) { + + case 0x00: /* shift/rotate */ + tStates += 23; + switch (op & 0x38) { + + case 0x00: /* RLC */ + temp = (acu << 1) | (acu >> 7); + cbits = temp & 1; + goto cbshflg2; + + case 0x08: /* RRC */ + temp = (acu >> 1) | (acu << 7); + cbits = temp & 0x80; + goto cbshflg2; + + case 0x10: /* RL */ + temp = (acu << 1) | TSTFLAG(C); + cbits = acu & 0x80; + goto cbshflg2; + + case 0x18: /* RR */ + temp = (acu >> 1) | (TSTFLAG(C) << 7); + cbits = acu & 1; + goto cbshflg2; + + case 0x20: /* SLA */ + temp = acu << 1; + cbits = acu & 0x80; + goto cbshflg2; + + case 0x28: /* SRA */ + temp = (acu >> 1) | (acu & 0x80); + cbits = acu & 1; + goto cbshflg2; + + case 0x30: /* SLIA */ + temp = (acu << 1) | 1; + cbits = acu & 0x80; + goto cbshflg2; + + case 0x38: /* SRL */ + temp = acu >> 1; + cbits = acu & 1; + cbshflg2: + AF = (AF & ~0xff) | rotateShiftTable[temp & 0xff] | !!cbits; + /* !!cbits == 0 if cbits == 0 !!cbits == 1 if cbits > 0 */ + } + break; + + case 0x40: /* BIT */ + tStates += 20; + if (acu & (1 << ((op >> 3) & 7))) + AF = (AF & ~0xfe) | 0x10 | (((op & 0x38) == 0x38) << 7); + else AF = (AF & ~0xfe) | 0x54; + if ((op & 7) != 6) AF |= (acu & 0x28); + temp = acu; + break; + + case 0x80: /* RES */ + tStates += 23; + temp = acu & ~(1 << ((op >> 3) & 7)); + break; + + case 0xc0: /* SET */ + tStates += 23; + temp = acu | (1 << ((op >> 3) & 7)); + break; + } + switch (op & 7) { + + case 0: + SET_HIGH_REGISTER(BC, temp); + break; + + case 1: + SET_LOW_REGISTER(BC, temp); + break; + + case 2: + SET_HIGH_REGISTER(DE, temp); + break; + + case 3: + SET_LOW_REGISTER(DE, temp); + break; + + case 4: + SET_HIGH_REGISTER(HL, temp); + break; + + case 5: + SET_LOW_REGISTER(HL, temp); + break; + + case 6: + PutBYTE(adr, temp); + break; + + case 7: + SET_HIGH_REGISTER(AF, temp); + break; + } + break; + + case 0xe1: /* POP IX */ + tStates += 14; + CHECK_BREAK_WORD(SP); + POP(IX); + break; + + case 0xe3: /* EX (SP),IX */ + tStates += 23; + CHECK_BREAK_WORD(SP); + temp = IX; + POP(IX); + PUSH(temp); + break; + + case 0xe5: /* PUSH IX */ + tStates += 15; + CHECK_BREAK_WORD(SP - 2); + PUSH(IX); + break; + + case 0xe9: /* JP (IX) */ + tStates += 8; + sim_brk_pend[0] = FALSE; + PCQ_ENTRY(PCX); + PC = IX; + break; + + case 0xf9: /* LD SP,IX */ + tStates += 10; + sim_brk_pend[0] = FALSE; + SP = IX; + break; + + default: /* ignore DD */ + sim_brk_pend[0] = FALSE; + CHECK_CPU_Z80; + PC--; + } + break; + + case 0xde: /* SBC A,nn */ + tStates += 7; + sim_brk_pend[0] = FALSE; + temp = RAM_PP(PC); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0xdf: /* RST 18H */ + tStates += 11; + CHECK_BREAK_WORD(SP - 2); + PUSH(PC); + PCQ_ENTRY(PCX); + PC = 0x18; + break; + + case 0xe0: /* RET PO */ + if (TSTFLAG(P)) { + sim_brk_pend[0] = FALSE; + tStates += 5; + } + else { + CHECK_BREAK_WORD(SP); + PCQ_ENTRY(PCX); + POP(PC); + tStates += 11; + } + break; + + case 0xe1: /* POP HL */ + tStates += 10; + CHECK_BREAK_WORD(SP); + POP(HL); + break; + + case 0xe2: /* JP PO,nnnn */ + sim_brk_pend[0] = FALSE; + JPC(!TSTFLAG(P)); /* also updates tStates */ + break; + + case 0xe3: /* EX (SP),HL */ + tStates += 19; + CHECK_BREAK_WORD(SP); + temp = HL; + POP(HL); + PUSH(temp); + break; + + case 0xe4: /* CALL PO,nnnn */ + CALLC(!TSTFLAG(P)); /* also updates tStates */ + break; + + case 0xe5: /* PUSH HL */ + tStates += 11; + CHECK_BREAK_WORD(SP - 2); + PUSH(HL); + break; + + case 0xe6: /* AND nn */ + tStates += 7; + sim_brk_pend[0] = FALSE; + AF = andTable[((AF >> 8) & RAM_PP(PC)) & 0xff]; + break; + + case 0xe7: /* RST 20H */ + tStates += 11; + CHECK_BREAK_WORD(SP - 2); + PUSH(PC); + PCQ_ENTRY(PCX); + PC = 0x20; + break; + + case 0xe8: /* RET PE */ + if (TSTFLAG(P)) { + CHECK_BREAK_WORD(SP); + PCQ_ENTRY(PCX); + POP(PC); + tStates += 11; + } + else { + sim_brk_pend[0] = FALSE; + tStates += 5; + } + break; + + case 0xe9: /* JP (HL) */ + tStates += 4; + sim_brk_pend[0] = FALSE; + PCQ_ENTRY(PCX); + PC = HL; + break; + + case 0xea: /* JP PE,nnnn */ + sim_brk_pend[0] = FALSE; + JPC(TSTFLAG(P)); /* also updates tStates */ + break; + + case 0xeb: /* EX DE,HL */ + tStates += 4; + sim_brk_pend[0] = FALSE; + temp = HL; + HL = DE; + DE = temp; + break; + + case 0xec: /* CALL PE,nnnn */ + CALLC(TSTFLAG(P)); /* also updates tStates */ + break; + + case 0xed: /* ED prefix */ + CHECK_CPU_8080; + switch (op = RAM_PP(PC)) { + + case 0x40: /* IN B,(C) */ + tStates += 12; + sim_brk_pend[0] = FALSE; + temp = in(LOW_REGISTER(BC)); + SET_HIGH_REGISTER(BC, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + + case 0x41: /* OUT (C),B */ + tStates += 12; + sim_brk_pend[0] = FALSE; + out(LOW_REGISTER(BC), HIGH_REGISTER(BC)); + break; + + case 0x42: /* SBC HL,BC */ + tStates += 15; + sim_brk_pend[0] = FALSE; + HL &= ADDRMASK; + BC &= ADDRMASK; + sum = HL - BC - TSTFLAG(C); + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | + cbits2Z80Table[((HL ^ BC ^ sum) >> 8) & 0x1ff]; + HL = sum; + break; + + case 0x43: /* LD (nnnn),BC */ + tStates += 20; + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); + PutWORD(temp, BC); + PC += 2; + break; + + case 0x44: /* NEG */ + + case 0x4C: /* NEG, unofficial */ + + case 0x54: /* NEG, unofficial */ + + case 0x5C: /* NEG, unofficial */ + + case 0x64: /* NEG, unofficial */ + + case 0x6C: /* NEG, unofficial */ + + case 0x74: /* NEG, unofficial */ + + case 0x7C: /* NEG, unofficial */ + tStates += 8; + sim_brk_pend[0] = FALSE; + temp = HIGH_REGISTER(AF); + AF = ((~(AF & 0xff00) + 1) & 0xff00); /* AF = (-(AF & 0xff00) & 0xff00); */ + AF |= ((AF >> 8) & 0xa8) | (((AF & 0xff00) == 0) << 6) | negTable[temp]; + break; + + case 0x45: /* RETN */ + + case 0x55: /* RETN, unofficial */ + + case 0x5D: /* RETN, unofficial */ + + case 0x65: /* RETN, unofficial */ + + case 0x6D: /* RETN, unofficial */ + + case 0x75: /* RETN, unofficial */ + + case 0x7D: /* RETN, unofficial */ + tStates += 14; + IFF_S |= IFF_S >> 1; + CHECK_BREAK_WORD(SP); + PCQ_ENTRY(PCX); + POP(PC); + break; + + case 0x46: /* IM 0 */ + tStates += 8; + sim_brk_pend[0] = FALSE; + /* interrupt mode 0 */ + break; + + case 0x47: /* LD I,A */ + tStates += 9; + sim_brk_pend[0] = FALSE; + IR_S = (IR_S & 0xff) | (AF & ~0xff); + break; + + case 0x48: /* IN C,(C) */ + tStates += 12; + sim_brk_pend[0] = FALSE; + temp = in(LOW_REGISTER(BC)); + SET_LOW_REGISTER(BC, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + + case 0x49: /* OUT (C),C */ + tStates += 12; + sim_brk_pend[0] = FALSE; + out(LOW_REGISTER(BC), LOW_REGISTER(BC)); + break; + + case 0x4a: /* ADC HL,BC */ + tStates += 15; + sim_brk_pend[0] = FALSE; + HL &= ADDRMASK; + BC &= ADDRMASK; + sum = HL + BC + TSTFLAG(C); + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | + cbitsZ80Table[(HL ^ BC ^ sum) >> 8]; + HL = sum; + break; + + case 0x4b: /* LD BC,(nnnn) */ + tStates += 20; + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); + BC = GET_WORD(temp); + PC += 2; + break; + + case 0x4d: /* RETI */ + tStates += 14; + IFF_S |= IFF_S >> 1; + CHECK_BREAK_WORD(SP); + PCQ_ENTRY(PCX); + POP(PC); + break; + + case 0x4f: /* LD R,A */ + tStates += 9; + sim_brk_pend[0] = FALSE; + IR_S = (IR_S & ~0xff) | ((AF >> 8) & 0xff); + break; + + case 0x50: /* IN D,(C) */ + tStates += 12; + sim_brk_pend[0] = FALSE; + temp = in(LOW_REGISTER(BC)); + SET_HIGH_REGISTER(DE, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + + case 0x51: /* OUT (C),D */ + tStates += 12; + sim_brk_pend[0] = FALSE; + out(LOW_REGISTER(BC), HIGH_REGISTER(DE)); + break; + + case 0x52: /* SBC HL,DE */ + tStates += 15; + sim_brk_pend[0] = FALSE; + HL &= ADDRMASK; + DE &= ADDRMASK; + sum = HL - DE - TSTFLAG(C); + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | + cbits2Z80Table[((HL ^ DE ^ sum) >> 8) & 0x1ff]; + HL = sum; + break; + + case 0x53: /* LD (nnnn),DE */ + tStates += 20; + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); + PutWORD(temp, DE); + PC += 2; + break; + + case 0x56: /* IM 1 */ + tStates += 8; + sim_brk_pend[0] = FALSE; + /* interrupt mode 1 */ + break; + + case 0x57: /* LD A,I */ + tStates += 9; + sim_brk_pend[0] = FALSE; + AF = (AF & 0x29) | (IR_S & ~0xff) | ((IR_S >> 8) & 0x80) | (((IR_S & ~0xff) == 0) << 6) | ((IFF_S & 2) << 1); + break; + + case 0x58: /* IN E,(C) */ + tStates += 12; + sim_brk_pend[0] = FALSE; + temp = in(LOW_REGISTER(BC)); + SET_LOW_REGISTER(DE, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + + case 0x59: /* OUT (C),E */ + tStates += 12; + sim_brk_pend[0] = FALSE; + out(LOW_REGISTER(BC), LOW_REGISTER(DE)); + break; + + case 0x5a: /* ADC HL,DE */ + tStates += 15; + sim_brk_pend[0] = FALSE; + HL &= ADDRMASK; + DE &= ADDRMASK; + sum = HL + DE + TSTFLAG(C); + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | + cbitsZ80Table[(HL ^ DE ^ sum) >> 8]; + HL = sum; + break; + + case 0x5b: /* LD DE,(nnnn) */ + tStates += 20; + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); + DE = GET_WORD(temp); + PC += 2; + break; + + case 0x5e: /* IM 2 */ + tStates += 8; + sim_brk_pend[0] = FALSE; + /* interrupt mode 2 */ + break; + + case 0x5f: /* LD A,R */ + tStates += 9; + sim_brk_pend[0] = FALSE; + AF = (AF & 0x29) | ((IR_S & 0xff) << 8) | (IR_S & 0x80) | + (((IR_S & 0xff) == 0) << 6) | ((IFF_S & 2) << 1); + break; + + case 0x60: /* IN H,(C) */ + tStates += 12; + sim_brk_pend[0] = FALSE; + temp = in(LOW_REGISTER(BC)); + SET_HIGH_REGISTER(HL, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + + case 0x61: /* OUT (C),H */ + tStates += 12; + sim_brk_pend[0] = FALSE; + out(LOW_REGISTER(BC), HIGH_REGISTER(HL)); + break; + + case 0x62: /* SBC HL,HL */ + tStates += 15; + sim_brk_pend[0] = FALSE; + HL &= ADDRMASK; + sum = HL - HL - TSTFLAG(C); + AF = (AF & ~0xff) | (((sum & ADDRMASK) == 0) << 6) | + cbits2Z80DupTable[(sum >> 8) & 0x1ff]; + HL = sum; + break; + + case 0x63: /* LD (nnnn),HL */ + tStates += 20; + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); + PutWORD(temp, HL); + PC += 2; + break; + + case 0x67: /* RRD */ + tStates += 18; + sim_brk_pend[0] = FALSE; + temp = GetBYTE(HL); + acu = HIGH_REGISTER(AF); + PutBYTE(HL, HIGH_DIGIT(temp) | (LOW_DIGIT(acu) << 4)); + AF = rrdrldTable[(acu & 0xf0) | LOW_DIGIT(temp)] | (AF & 1); + break; + + case 0x68: /* IN L,(C) */ + tStates += 12; + sim_brk_pend[0] = FALSE; + temp = in(LOW_REGISTER(BC)); + SET_LOW_REGISTER(HL, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + + case 0x69: /* OUT (C),L */ + tStates += 12; + sim_brk_pend[0] = FALSE; + out(LOW_REGISTER(BC), LOW_REGISTER(HL)); + break; + + case 0x6a: /* ADC HL,HL */ + tStates += 15; + sim_brk_pend[0] = FALSE; + HL &= ADDRMASK; + sum = HL + HL + TSTFLAG(C); + AF = (AF & ~0xff) | (((sum & ADDRMASK) == 0) << 6) | + cbitsZ80DupTable[sum >> 8]; + HL = sum; + break; + + case 0x6b: /* LD HL,(nnnn) */ + tStates += 20; + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); + HL = GET_WORD(temp); + PC += 2; + break; + + case 0x6f: /* RLD */ + tStates += 18; + sim_brk_pend[0] = FALSE; + temp = GetBYTE(HL); + acu = HIGH_REGISTER(AF); + PutBYTE(HL, (LOW_DIGIT(temp) << 4) | LOW_DIGIT(acu)); + AF = rrdrldTable[(acu & 0xf0) | HIGH_DIGIT(temp)] | (AF & 1); + break; + + case 0x70: /* IN (C) */ + tStates += 12; + sim_brk_pend[0] = FALSE; + temp = in(LOW_REGISTER(BC)); + SET_LOW_REGISTER(temp, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + + case 0x71: /* OUT (C),0 */ + tStates += 12; + sim_brk_pend[0] = FALSE; + out(LOW_REGISTER(BC), 0); + break; + + case 0x72: /* SBC HL,SP */ + tStates += 15; + sim_brk_pend[0] = FALSE; + HL &= ADDRMASK; + SP &= ADDRMASK; + sum = HL - SP - TSTFLAG(C); + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | + cbits2Z80Table[((HL ^ SP ^ sum) >> 8) & 0x1ff]; + HL = sum; + break; + + case 0x73: /* LD (nnnn),SP */ + tStates += 20; + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); + PutWORD(temp, SP); + PC += 2; + break; + + case 0x78: /* IN A,(C) */ + tStates += 12; + sim_brk_pend[0] = FALSE; + temp = in(LOW_REGISTER(BC)); + SET_HIGH_REGISTER(AF, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + + case 0x79: /* OUT (C),A */ + tStates += 12; + sim_brk_pend[0] = FALSE; + out(LOW_REGISTER(BC), HIGH_REGISTER(AF)); + break; + + case 0x7a: /* ADC HL,SP */ + tStates += 15; + sim_brk_pend[0] = FALSE; + HL &= ADDRMASK; + SP &= ADDRMASK; + sum = HL + SP + TSTFLAG(C); + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | + cbitsZ80Table[(HL ^ SP ^ sum) >> 8]; + HL = sum; + break; + + case 0x7b: /* LD SP,(nnnn) */ + tStates += 20; + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); + SP = GET_WORD(temp); + PC += 2; + break; + + case 0xa0: /* LDI */ + tStates += 16; + CHECK_BREAK_TWO_BYTES(HL, DE); + acu = RAM_PP(HL); + PUT_BYTE_PP(DE, acu); + acu += HIGH_REGISTER(AF); + AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4) | + (((--BC & ADDRMASK) != 0) << 2); + break; + + case 0xa1: /* CPI */ + tStates += 16; + CHECK_BREAK_BYTE(HL); + acu = HIGH_REGISTER(AF); + temp = RAM_PP(HL); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | + (((sum - ((cbits & 16) >> 4)) & 2) << 4) | (cbits & 16) | + ((sum - ((cbits >> 4) & 1)) & 8) | + ((--BC & ADDRMASK) != 0) << 2 | 2; + if ((sum & 15) == 8 && (cbits & 16) != 0) AF &= ~8; + break; + +/* SF, ZF, YF, XF flags are affected by decreasing register B, as in DEC B. + NF flag A is copy of bit 7 of the value read from or written to an I/O port. + INI/INIR/IND/INDR use the C flag in stead of the L register. There is a + catch though, because not the value of C is used, but C + 1 if it's INI/INIR or + C - 1 if it's IND/INDR. So, first of all INI/INIR: + HF and CF Both set if ((HL) + ((C + 1) & 255) > 255) + PF The parity of (((HL) + ((C + 1) & 255)) & 7) xor B) */ + case 0xa2: /* INI */ + tStates += 16; + CHECK_BREAK_BYTE(HL); + acu = in(LOW_REGISTER(BC)); + PutBYTE(HL, acu); + ++HL; + temp = HIGH_REGISTER(BC); + BC -= 0x100; + INOUTFLAGS_NONZERO((LOW_REGISTER(BC) + 1) & 0xff); + break; + +/* SF, ZF, YF, XF flags are affected by decreasing register B, as in DEC B. + NF flag A is copy of bit 7 of the value read from or written to an I/O port. + And now the for OUTI/OTIR/OUTD/OTDR instructions. Take state of the L + after the increment or decrement of HL; add the value written to the I/O port + to; call that k for now. If k > 255, then the CF and HF flags are set. The PF + flags is set like the parity of k bitwise and'ed with 7, bitwise xor'ed with B. + HF and CF Both set if ((HL) + L > 255) + PF The parity of ((((HL) + L) & 7) xor B) */ + case 0xa3: /* OUTI */ + tStates += 16; + CHECK_BREAK_BYTE(HL); + acu = GetBYTE(HL); + out(LOW_REGISTER(BC), acu); + ++HL; + temp = HIGH_REGISTER(BC); + BC -= 0x100; + INOUTFLAGS_NONZERO(LOW_REGISTER(HL)); + break; + + case 0xa8: /* LDD */ + tStates += 16; + CHECK_BREAK_TWO_BYTES(HL, DE); + acu = RAM_MM(HL); + PUT_BYTE_MM(DE, acu); + acu += HIGH_REGISTER(AF); + AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4) | + (((--BC & ADDRMASK) != 0) << 2); + break; + + case 0xa9: /* CPD */ + tStates += 16; + CHECK_BREAK_BYTE(HL); + acu = HIGH_REGISTER(AF); + temp = RAM_MM(HL); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | + (((sum - ((cbits & 16) >> 4)) & 2) << 4) | (cbits & 16) | + ((sum - ((cbits >> 4) & 1)) & 8) | + ((--BC & ADDRMASK) != 0) << 2 | 2; + if ((sum & 15) == 8 && (cbits & 16) != 0) AF &= ~8; + break; + +/* SF, ZF, YF, XF flags are affected by decreasing register B, as in DEC B. + NF flag A is copy of bit 7 of the value read from or written to an I/O port. + INI/INIR/IND/INDR use the C flag in stead of the L register. There is a + catch though, because not the value of C is used, but C + 1 if it's INI/INIR or + C - 1 if it's IND/INDR. And last IND/INDR: + HF and CF Both set if ((HL) + ((C - 1) & 255) > 255) + PF The parity of (((HL) + ((C - 1) & 255)) & 7) xor B) */ + case 0xaa: /* IND */ + tStates += 16; + CHECK_BREAK_BYTE(HL); + acu = in(LOW_REGISTER(BC)); + PutBYTE(HL, acu); + --HL; + temp = HIGH_REGISTER(BC); + BC -= 0x100; + INOUTFLAGS_NONZERO((LOW_REGISTER(BC) - 1) & 0xff); + break; + + case 0xab: /* OUTD */ + tStates += 16; + CHECK_BREAK_BYTE(HL); + acu = GetBYTE(HL); + out(LOW_REGISTER(BC), acu); + --HL; + temp = HIGH_REGISTER(BC); + BC -= 0x100; + INOUTFLAGS_NONZERO(LOW_REGISTER(HL)); + break; + + case 0xb0: /* LDIR */ + tStates -= 5; + acu = HIGH_REGISTER(AF); + BC &= ADDRMASK; + if (BC == 0) BC = 0x10000; + do { + tStates += 21; + CHECK_BREAK_TWO_BYTES(HL, DE); + acu = RAM_PP(HL); + PUT_BYTE_PP(DE, acu); + } while (--BC); + acu += HIGH_REGISTER(AF); + AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4); + break; + + case 0xb1: /* CPIR */ + tStates -= 5; + acu = HIGH_REGISTER(AF); + BC &= ADDRMASK; + if (BC == 0) BC = 0x10000; + do { + tStates += 21; + CHECK_BREAK_BYTE(HL); + temp = RAM_PP(HL); + op = --BC != 0; + sum = acu - temp; + } while (op && sum != 0); + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | + (((sum - ((cbits & 16) >> 4)) & 2) << 4) | + (cbits & 16) | ((sum - ((cbits >> 4) & 1)) & 8) | + op << 2 | 2; + if ((sum & 15) == 8 && (cbits & 16) != 0) AF &= ~8; + break; + + case 0xb2: /* INIR */ + tStates -= 5; + temp = HIGH_REGISTER(BC); + if (temp == 0) temp = 0x100; + do { + tStates += 21; + CHECK_BREAK_BYTE(HL); + acu = in(LOW_REGISTER(BC)); + PutBYTE(HL, acu); + ++HL; + } while (--temp); + temp = HIGH_REGISTER(BC); + SET_HIGH_REGISTER(BC, 0); + INOUTFLAGS_ZERO((LOW_REGISTER(BC) + 1) & 0xff); + break; + + case 0xb3: /* OTIR */ + tStates -= 5; + temp = HIGH_REGISTER(BC); + if (temp == 0) temp = 0x100; + do { + tStates += 21; + CHECK_BREAK_BYTE(HL); + acu = GetBYTE(HL); + out(LOW_REGISTER(BC), acu); + ++HL; + } while (--temp); + temp = HIGH_REGISTER(BC); + SET_HIGH_REGISTER(BC, 0); + INOUTFLAGS_ZERO(LOW_REGISTER(HL)); + break; + + case 0xb8: /* LDDR */ + tStates -= 5; + BC &= ADDRMASK; + if (BC == 0) BC = 0x10000; + do { + tStates += 21; + CHECK_BREAK_TWO_BYTES(HL, DE); + acu = RAM_MM(HL); + PUT_BYTE_MM(DE, acu); + } while (--BC); + acu += HIGH_REGISTER(AF); + AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4); + break; + + case 0xb9: /* CPDR */ + tStates -= 5; + acu = HIGH_REGISTER(AF); + BC &= ADDRMASK; + if (BC == 0) BC = 0x10000; + do { + tStates += 21; + CHECK_BREAK_BYTE(HL); + temp = RAM_MM(HL); + op = --BC != 0; + sum = acu - temp; + } while (op && sum != 0); + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | + (((sum - ((cbits & 16) >> 4)) & 2) << 4) | + (cbits & 16) | ((sum - ((cbits >> 4) & 1)) & 8) | + op << 2 | 2; + if ((sum & 15) == 8 && (cbits & 16) != 0) AF &= ~8; + break; + + case 0xba: /* INDR */ + tStates -= 5; + temp = HIGH_REGISTER(BC); + if (temp == 0) temp = 0x100; + do { + tStates += 21; + CHECK_BREAK_BYTE(HL); + acu = in(LOW_REGISTER(BC)); + PutBYTE(HL, acu); + --HL; + } while (--temp); + temp = HIGH_REGISTER(BC); + SET_HIGH_REGISTER(BC, 0); + INOUTFLAGS_ZERO((LOW_REGISTER(BC) - 1) & 0xff); + break; + + case 0xbb: /* OTDR */ + tStates -= 5; + temp = HIGH_REGISTER(BC); + if (temp == 0) temp = 0x100; + do { + tStates += 21; + CHECK_BREAK_BYTE(HL); + acu = GetBYTE(HL); + out(LOW_REGISTER(BC), acu); + --HL; + } while (--temp); + temp = HIGH_REGISTER(BC); + SET_HIGH_REGISTER(BC, 0); + INOUTFLAGS_ZERO(LOW_REGISTER(HL)); + break; + + default: /* ignore ED and following byte */ + sim_brk_pend[0] = FALSE; + CHECK_CPU_Z80; + } + break; + + case 0xee: /* XOR nn */ + tStates += 7; + sim_brk_pend[0] = FALSE; + AF = xororTable[((AF >> 8) ^ RAM_PP(PC)) & 0xff]; + break; + + case 0xef: /* RST 28H */ + tStates += 11; + CHECK_BREAK_WORD(SP - 2); + PUSH(PC); + PCQ_ENTRY(PCX); + PC = 0x28; + break; + + case 0xf0: /* RET P */ + if (TSTFLAG(S)) { + sim_brk_pend[0] = FALSE; + tStates += 5; + } + else { + CHECK_BREAK_WORD(SP); + PCQ_ENTRY(PCX); + POP(PC); + tStates += 11; + } + break; + + case 0xf1: /* POP AF */ + tStates += 10; + CHECK_BREAK_WORD(SP); + POP(AF); + break; + + case 0xf2: /* JP P,nnnn */ + sim_brk_pend[0] = FALSE; + JPC(!TSTFLAG(S)); /* also updates tStates */ + break; + + case 0xf3: /* DI */ + tStates += 4; + sim_brk_pend[0] = FALSE; + IFF_S = 0; + break; + + case 0xf4: /* CALL P,nnnn */ + CALLC(!TSTFLAG(S)); /* also updates tStates */ + break; + + case 0xf5: /* PUSH AF */ + tStates += 11; + CHECK_BREAK_WORD(SP - 2); + PUSH(AF); + break; + + case 0xf6: /* OR nn */ + tStates += 7; + sim_brk_pend[0] = FALSE; + AF = xororTable[((AF >> 8) | RAM_PP(PC)) & 0xff]; + break; + + case 0xf7: /* RST 30H */ + tStates += 11; + CHECK_BREAK_WORD(SP - 2); + PUSH(PC); + PCQ_ENTRY(PCX); + PC = 0x30; + break; + + case 0xf8: /* RET M */ + if (TSTFLAG(S)) { + CHECK_BREAK_WORD(SP); + PCQ_ENTRY(PCX); + POP(PC); + tStates += 11; + } + else { + sim_brk_pend[0] = FALSE; + tStates += 5; + } + break; + + case 0xf9: /* LD SP,HL */ + tStates += 6; + sim_brk_pend[0] = FALSE; + SP = HL; + break; + + case 0xfa: /* JP M,nnnn */ + sim_brk_pend[0] = FALSE; + JPC(TSTFLAG(S)); /* also updates tStates */ + break; + + case 0xfb: /* EI */ + tStates += 4; + sim_brk_pend[0] = FALSE; + IFF_S = 3; + break; + + case 0xfc: /* CALL M,nnnn */ + CALLC(TSTFLAG(S)); /* also updates tStates */ + break; + + case 0xfd: /* FD prefix */ + CHECK_CPU_8080; + switch (op = RAM_PP(PC)) { + + case 0x09: /* ADD IY,BC */ + tStates += 15; + sim_brk_pend[0] = FALSE; + IY &= ADDRMASK; + BC &= ADDRMASK; + sum = IY + BC; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IY ^ BC ^ sum) >> 8]; + IY = sum; + break; + + case 0x19: /* ADD IY,DE */ + tStates += 15; + sim_brk_pend[0] = FALSE; + IY &= ADDRMASK; + DE &= ADDRMASK; + sum = IY + DE; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IY ^ DE ^ sum) >> 8]; + IY = sum; + break; + + case 0x21: /* LD IY,nnnn */ + tStates += 14; + sim_brk_pend[0] = FALSE; + IY = GET_WORD(PC); + PC += 2; + break; + + case 0x22: /* LD (nnnn),IY */ + tStates += 20; + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); + PutWORD(temp, IY); + PC += 2; + break; + + case 0x23: /* INC IY */ + tStates += 10; + sim_brk_pend[0] = FALSE; + ++IY; + break; + + case 0x24: /* INC IYH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + IY += 0x100; + AF = (AF & ~0xfe) | incZ80Table[HIGH_REGISTER(IY)]; + break; + + case 0x25: /* DEC IYH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + IY -= 0x100; + AF = (AF & ~0xfe) | decZ80Table[HIGH_REGISTER(IY)]; + break; + + case 0x26: /* LD IYH,nn */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(IY, RAM_PP(PC)); + break; + + case 0x29: /* ADD IY,IY */ + tStates += 15; + sim_brk_pend[0] = FALSE; + IY &= ADDRMASK; + sum = IY + IY; + AF = (AF & ~0x3b) | cbitsDup16Table[sum >> 8]; + IY = sum; + break; + + case 0x2a: /* LD IY,(nnnn) */ + tStates += 20; + temp = GET_WORD(PC); + CHECK_BREAK_WORD(temp); + IY = GET_WORD(temp); + PC += 2; + break; + + case 0x2b: /* DEC IY */ + tStates += 10; + sim_brk_pend[0] = FALSE; + --IY; + break; + + case 0x2c: /* INC IYL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(IY) + 1; + SET_LOW_REGISTER(IY, temp); + AF = (AF & ~0xfe) | incZ80Table[temp]; + break; + + case 0x2d: /* DEC IYL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(IY) - 1; + SET_LOW_REGISTER(IY, temp); + AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; + break; + + case 0x2e: /* LD IYL,nn */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(IY, RAM_PP(PC)); + break; + + case 0x34: /* INC (IY+dd) */ + tStates += 23; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GetBYTE(adr) + 1; + PutBYTE(adr, temp); + AF = (AF & ~0xfe) | incZ80Table[temp]; + break; + + case 0x35: /* DEC (IY+dd) */ + tStates += 23; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GetBYTE(adr) - 1; + PutBYTE(adr, temp); + AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; + break; + + case 0x36: /* LD (IY+dd),nn */ + tStates += 19; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, RAM_PP(PC)); + break; + + case 0x39: /* ADD IY,SP */ + tStates += 15; + sim_brk_pend[0] = FALSE; + IY &= ADDRMASK; + SP &= ADDRMASK; + sum = IY + SP; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IY ^ SP ^ sum) >> 8]; + IY = sum; + break; + + case 0x44: /* LD B,IYH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(BC, HIGH_REGISTER(IY)); + break; + + case 0x45: /* LD B,IYL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(BC, LOW_REGISTER(IY)); + break; + + case 0x46: /* LD B,(IY+dd) */ + tStates += 19; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_HIGH_REGISTER(BC, GetBYTE(adr)); + break; + + case 0x4c: /* LD C,IYH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(BC, HIGH_REGISTER(IY)); + break; + + case 0x4d: /* LD C,IYL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(BC, LOW_REGISTER(IY)); + break; + + case 0x4e: /* LD C,(IY+dd) */ + tStates += 19; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_LOW_REGISTER(BC, GetBYTE(adr)); + break; + + case 0x54: /* LD D,IYH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(DE, HIGH_REGISTER(IY)); + break; + + case 0x55: /* LD D,IYL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(DE, LOW_REGISTER(IY)); + break; + + case 0x56: /* LD D,(IY+dd) */ + tStates += 19; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_HIGH_REGISTER(DE, GetBYTE(adr)); + break; + + case 0x5c: /* LD E,IYH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(DE, HIGH_REGISTER(IY)); + break; + + case 0x5d: /* LD E,IYL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(DE, LOW_REGISTER(IY)); + break; + + case 0x5e: /* LD E,(IY+dd) */ + tStates += 19; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_LOW_REGISTER(DE, GetBYTE(adr)); + break; + + case 0x60: /* LD IYH,B */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(IY, HIGH_REGISTER(BC)); + break; + + case 0x61: /* LD IYH,C */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(IY, LOW_REGISTER(BC)); + break; + + case 0x62: /* LD IYH,D */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(IY, HIGH_REGISTER(DE)); + break; + + case 0x63: /* LD IYH,E */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(IY, LOW_REGISTER(DE)); + break; + + case 0x64: /* LD IYH,IYH */ + tStates += 9; + sim_brk_pend[0] = FALSE; /* nop */ + break; + + case 0x65: /* LD IYH,IYL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(IY, LOW_REGISTER(IY)); + break; + + case 0x66: /* LD H,(IY+dd) */ + tStates += 19; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_HIGH_REGISTER(HL, GetBYTE(adr)); + break; + + case 0x67: /* LD IYH,A */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(IY, HIGH_REGISTER(AF)); + break; + + case 0x68: /* LD IYL,B */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(IY, HIGH_REGISTER(BC)); + break; + + case 0x69: /* LD IYL,C */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(IY, LOW_REGISTER(BC)); + break; + + case 0x6a: /* LD IYL,D */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(IY, HIGH_REGISTER(DE)); + break; + + case 0x6b: /* LD IYL,E */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(IY, LOW_REGISTER(DE)); + break; + + case 0x6c: /* LD IYL,IYH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(IY, HIGH_REGISTER(IY)); + break; + + case 0x6d: /* LD IYL,IYL */ + tStates += 9; + sim_brk_pend[0] = FALSE; /* nop */ + break; + + case 0x6e: /* LD L,(IY+dd) */ + tStates += 19; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_LOW_REGISTER(HL, GetBYTE(adr)); + break; + + case 0x6f: /* LD IYL,A */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_LOW_REGISTER(IY, HIGH_REGISTER(AF)); + break; + + case 0x70: /* LD (IY+dd),B */ + tStates += 19; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, HIGH_REGISTER(BC)); + break; + + case 0x71: /* LD (IY+dd),C */ + tStates += 19; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, LOW_REGISTER(BC)); + break; + + case 0x72: /* LD (IY+dd),D */ + tStates += 19; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, HIGH_REGISTER(DE)); + break; + + case 0x73: /* LD (IY+dd),E */ + tStates += 19; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, LOW_REGISTER(DE)); + break; + + case 0x74: /* LD (IY+dd),H */ + tStates += 19; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, HIGH_REGISTER(HL)); + break; + + case 0x75: /* LD (IY+dd),L */ + tStates += 19; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, LOW_REGISTER(HL)); + break; + + case 0x77: /* LD (IY+dd),A */ + tStates += 19; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + PutBYTE(adr, HIGH_REGISTER(AF)); + break; + + case 0x7c: /* LD A,IYH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(AF, HIGH_REGISTER(IY)); + break; + + case 0x7d: /* LD A,IYL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + SET_HIGH_REGISTER(AF, LOW_REGISTER(IY)); + break; + + case 0x7e: /* LD A,(IY+dd) */ + tStates += 19; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + SET_HIGH_REGISTER(AF, GetBYTE(adr)); + break; + + case 0x84: /* ADD A,IYH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + temp = HIGH_REGISTER(IY); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x85: /* ADD A,IYL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(IY); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x86: /* ADD A,(IY+dd) */ + tStates += 19; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GetBYTE(adr); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x8c: /* ADC A,IYH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + temp = HIGH_REGISTER(IY); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x8d: /* ADC A,IYL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(IY); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x8e: /* ADC A,(IY+dd) */ + tStates += 19; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GetBYTE(adr); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x96: /* SUB (IY+dd) */ + tStates += 19; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GetBYTE(adr); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0x94: /* SUB IYH */ + SETFLAG(C, 0);/* fall through, a bit less efficient but smaller code */ + + case 0x9c: /* SBC A,IYH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + temp = HIGH_REGISTER(IY); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0x95: /* SUB IYL */ + SETFLAG(C, 0);/* fall through, a bit less efficient but smaller code */ + + case 0x9d: /* SBC A,IYL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(IY); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0x9e: /* SBC A,(IY+dd) */ + tStates += 19; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GetBYTE(adr); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0xa4: /* AND IYH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + AF = andTable[((AF & IY) >> 8) & 0xff]; + break; + + case 0xa5: /* AND IYL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + AF = andTable[((AF >> 8) & IY) & 0xff]; + break; + + case 0xa6: /* AND (IY+dd) */ + tStates += 19; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + AF = andTable[((AF >> 8) & GetBYTE(adr)) & 0xff]; + break; + + case 0xac: /* XOR IYH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + AF = xororTable[((AF ^ IY) >> 8) & 0xff]; + break; + + case 0xad: /* XOR IYL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + AF = xororTable[((AF >> 8) ^ IY) & 0xff]; + break; + + case 0xae: /* XOR (IY+dd) */ + tStates += 19; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + AF = xororTable[((AF >> 8) ^ GetBYTE(adr)) & 0xff]; + break; + + case 0xb4: /* OR IYH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + AF = xororTable[((AF | IY) >> 8) & 0xff]; + break; + + case 0xb5: /* OR IYL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + AF = xororTable[((AF >> 8) | IY) & 0xff]; + break; + + case 0xb6: /* OR (IY+dd) */ + tStates += 19; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + AF = xororTable[((AF >> 8) | GetBYTE(adr)) & 0xff]; + break; + + case 0xbc: /* CP IYH */ + tStates += 9; + sim_brk_pend[0] = FALSE; + temp = HIGH_REGISTER(IY); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0xbd: /* CP IYL */ + tStates += 9; + sim_brk_pend[0] = FALSE; + temp = LOW_REGISTER(IY); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0xbe: /* CP (IY+dd) */ + tStates += 19; + adr = IY + (int8) RAM_PP(PC); + CHECK_BREAK_BYTE(adr); + temp = GetBYTE(adr); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0xcb: /* CB prefix */ + adr = IY + (int8) RAM_PP(PC); + switch ((op = GetBYTE(PC)) & 7) { + + case 0: + sim_brk_pend[0] = FALSE; + ++PC; + acu = HIGH_REGISTER(BC); + break; + + case 1: + sim_brk_pend[0] = FALSE; + ++PC; + acu = LOW_REGISTER(BC); + break; + + case 2: + sim_brk_pend[0] = FALSE; + ++PC; + acu = HIGH_REGISTER(DE); + break; + + case 3: + sim_brk_pend[0] = FALSE; + ++PC; + acu = LOW_REGISTER(DE); + break; + + case 4: + sim_brk_pend[0] = FALSE; + ++PC; + acu = HIGH_REGISTER(HL); + break; + + case 5: + sim_brk_pend[0] = FALSE; + ++PC; + acu = LOW_REGISTER(HL); + break; + + case 6: + CHECK_BREAK_BYTE(adr); + ++PC; + acu = GetBYTE(adr); + break; + + case 7: + sim_brk_pend[0] = FALSE; + ++PC; + acu = HIGH_REGISTER(AF); + break; + } + switch (op & 0xc0) { + + case 0x00: /* shift/rotate */ + tStates += 23; + switch (op & 0x38) { + + case 0x00: /* RLC */ + temp = (acu << 1) | (acu >> 7); + cbits = temp & 1; + goto cbshflg3; + + case 0x08: /* RRC */ + temp = (acu >> 1) | (acu << 7); + cbits = temp & 0x80; + goto cbshflg3; + + case 0x10: /* RL */ + temp = (acu << 1) | TSTFLAG(C); + cbits = acu & 0x80; + goto cbshflg3; + + case 0x18: /* RR */ + temp = (acu >> 1) | (TSTFLAG(C) << 7); + cbits = acu & 1; + goto cbshflg3; + + case 0x20: /* SLA */ + temp = acu << 1; + cbits = acu & 0x80; + goto cbshflg3; + + case 0x28: /* SRA */ + temp = (acu >> 1) | (acu & 0x80); + cbits = acu & 1; + goto cbshflg3; + + case 0x30: /* SLIA */ + temp = (acu << 1) | 1; + cbits = acu & 0x80; + goto cbshflg3; + + case 0x38: /* SRL */ + temp = acu >> 1; + cbits = acu & 1; + cbshflg3: + AF = (AF & ~0xff) | rotateShiftTable[temp & 0xff] | !!cbits; + /* !!cbits == 0 if cbits == 0 !!cbits == 1 if cbits > 0 */ + } + break; + + case 0x40: /* BIT */ + tStates += 20; + if (acu & (1 << ((op >> 3) & 7))) + AF = (AF & ~0xfe) | 0x10 | (((op & 0x38) == 0x38) << 7); + else AF = (AF & ~0xfe) | 0x54; + if ((op & 7) != 6) AF |= (acu & 0x28); + temp = acu; + break; + + case 0x80: /* RES */ + tStates += 23; + temp = acu & ~(1 << ((op >> 3) & 7)); + break; + + case 0xc0: /* SET */ + tStates += 23; + temp = acu | (1 << ((op >> 3) & 7)); + break; + } + switch (op & 7) { + + case 0: + SET_HIGH_REGISTER(BC, temp); + break; + + case 1: + SET_LOW_REGISTER(BC, temp); + break; + + case 2: + SET_HIGH_REGISTER(DE, temp); + break; + + case 3: + SET_LOW_REGISTER(DE, temp); + break; + + case 4: + SET_HIGH_REGISTER(HL, temp); + break; + + case 5: + SET_LOW_REGISTER(HL, temp); + break; + + case 6: + PutBYTE(adr, temp); + break; + + case 7: + SET_HIGH_REGISTER(AF, temp); + break; + } + break; + + case 0xe1: /* POP IY */ + tStates += 14; + CHECK_BREAK_WORD(SP); + POP(IY); + break; + + case 0xe3: /* EX (SP),IY */ + tStates += 23; + CHECK_BREAK_WORD(SP); + temp = IY; + POP(IY); + PUSH(temp); + break; + + case 0xe5: /* PUSH IY */ + tStates += 15; + CHECK_BREAK_WORD(SP - 2); + PUSH(IY); + break; + + case 0xe9: /* JP (IY) */ + tStates += 8; + sim_brk_pend[0] = FALSE; + PCQ_ENTRY(PCX); + PC = IY; + break; + + case 0xf9: /* LD SP,IY */ + tStates += 10; + sim_brk_pend[0] = FALSE; + SP = IY; + break; + + default: /* ignore FD */ + sim_brk_pend[0] = FALSE; + CHECK_CPU_Z80; + PC--; + } + break; + + case 0xfe: /* CP nn */ + tStates += 7; + sim_brk_pend[0] = FALSE; + temp = RAM_PP(PC); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SET_PV) | cbits2Table[cbits & 0x1ff]; + break; + + case 0xff: /* RST 38H */ + tStates += 11; + CHECK_BREAK_WORD(SP - 2); + PUSH(PC); + PCQ_ENTRY(PCX); + PC = 0x38; + } + } + end_decode: + + /* simulation halted */ + PC_S = ((reason == STOP_OPCODE) || (reason == STOP_MEM)) ? PCX : (PC & ADDRMASK); + pcq_r -> qptr = pcq_p; /* update pc q ptr */ + AF_S = AF; + BC_S = BC; + DE_S = DE; + HL_S = HL; + IX_S = IX; + IY_S = IY; + SP_S = SP; + executedTStates = tStates; + return reason; +} + +/* reset routine */ + +static t_stat cpu_reset(DEVICE *dptr) { + extern uint32 sim_brk_types, sim_brk_dflt; /* breakpoint info */ + int32 i; + AF_S = AF1_S = 0; + BC_S = DE_S = HL_S = 0; + BC1_S = DE1_S = HL1_S = 0; + IR_S = IX_S = IY_S = SP_S = 0; + IFF_S = 3; + setBankSelect(0); + cpu8086reset(); + sim_brk_types = (SWMASK('E') | SWMASK('I') | SWMASK('M')); + sim_brk_dflt = SWMASK('E'); + for (i = 0; i < PCQ_SIZE; i++) pcq[i] = 0; + pcq_p = 0; + pcq_r = find_reg("PCQ", NULL, dptr); + if (pcq_r) pcq_r -> qptr = 0; + else return SCPE_IERR; + return SCPE_OK; +} + +t_stat install_bootrom(int32 bootrom[], int32 size, int32 addr, int32 makeROM) { + int32 i; + if (addr & (PAGESIZE - 1)) return SCPE_IERR; + for (i = 0; i < size; i++) { + if (makeROM && ((i & (PAGESIZE - 1)) == 0)) + mmu_table[(i + addr) >> LOG2PAGESIZE] = ROM_PAGE; + M[i + addr] = bootrom[i] & 0xff; + } + return SCPE_OK; +} + +/* memory examine */ +static t_stat cpu_ex(t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) { + int32 oldBankSelect; + if (chiptype == CHIP_TYPE_8086) *vptr = GetBYTEExtended(addr); + else { + oldBankSelect = getBankSelect(); + setBankSelect((addr >> MAXBANKSIZELOG2) & BANKMASK); + *vptr = GetBYTE(addr & ADDRMASK); + setBankSelect(oldBankSelect); + } + return SCPE_OK; +} + +/* memory deposit */ +static t_stat cpu_dep(t_value val, t_addr addr, UNIT *uptr, int32 sw) { + int32 oldBankSelect; + if (chiptype == CHIP_TYPE_8086) PutBYTEExtended(addr, val); + else { + oldBankSelect = getBankSelect(); + setBankSelect((addr >> MAXBANKSIZELOG2) & BANKMASK); + PutBYTE(addr & ADDRMASK, val); + setBankSelect(oldBankSelect); + } + return SCPE_OK; +} + +static t_stat chip_show(FILE *st, UNIT *uptr, int32 val, void *desc) { + fprintf(st, cpu_unit.flags & UNIT_CPU_OPSTOP ? "ITRAP, " : "NOITRAP, "); + if (chiptype == CHIP_TYPE_8080) fprintf(st, "8080"); + else if (chiptype == CHIP_TYPE_Z80) fprintf(st, "Z80"); + else if (chiptype == CHIP_TYPE_8086) fprintf(st, "8086"); + fprintf(st, ", "); + if (ramtype == 0) fprintf(st, "AZ80"); + else if (ramtype == 1) fprintf(st, "HRAM"); + else if (ramtype == 2) fprintf(st, "VRAM"); + else if (ramtype == 3) fprintf(st, "CRAM"); + return SCPE_OK; +} + +static t_stat cpu_show(FILE *st, UNIT *uptr, int32 val, void *desc) { + uint32 i, maxBanks; + MDEV m; + maxBanks = ((cpu_unit.flags & UNIT_CPU_BANKED) || + (chiptype == CHIP_TYPE_8086)) ? MAXBANKS : 1; + fprintf(st, "VERBOSE,\n "); + for (i = 0; i < 4; i++) fprintf(st, "0123456789ABCDEF"); + fprintf(st, " [16k]"); + for (i = 0; i < (maxBanks * (MAXBANKSIZE >> LOG2PAGESIZE)); i++) { + if ((i & 0x3f) == 0) fprintf(st, "\n%05X: ", (i << LOG2PAGESIZE)); + m = mmu_table[i]; + if (m.isRAM) fprintf(st, "W"); + else if (m.isEmpty) fprintf(st, "U"); + else if (m.routine) fprintf(st, "M"); + else fprintf(st, "R"); + } + return SCPE_OK; +} + +static void cpu_clear(void) { + uint32 i; + for (i = 0; i < MAXMEMORY; i++) M[i] = 0; + for (i = 0; i < (MAXMEMORY >> LOG2PAGESIZE); i++) mmu_table[i] = RAM_PAGE; + for (i = (MEMORYSIZE >> LOG2PAGESIZE); i < (MAXMEMORY >> LOG2PAGESIZE); i++) + mmu_table[i] = EMPTY_PAGE; + if (cpu_unit.flags & UNIT_CPU_ALTAIRROM) install_ALTAIRbootROM(); +} + +static t_stat cpu_clear_command(UNIT *uptr, int32 value, char *cptr, void *desc) { + cpu_clear(); + return SCPE_OK; +} + +static t_stat cpu_set_altairrom(UNIT *uptr, int32 value, char *cptr, void *desc) { + install_ALTAIRbootROM(); + return SCPE_OK; +} + +static t_stat cpu_set_noaltairrom(UNIT *uptr, int32 value, char *cptr, void *desc) { + mmu_table[ALTAIR_ROM_LOW >> LOG2PAGESIZE] = MEMORYSIZE < MAXBANKSIZE ? + EMPTY_PAGE : RAM_PAGE; + return SCPE_OK; +} + +static t_stat cpu_set_nommu(UNIT *uptr, int32 value, char *cptr, void *desc) { + if (chiptype == CHIP_TYPE_8086) { + printf("Cannot switch off MMU for 8086 CPU.\n"); + return SCPE_ARG; + } + if (cpu_unit.flags & UNIT_CPU_BANKED) { + printf("Cannot switch off MMU for banked memory.\n"); + return SCPE_ARG; + } + if (((chiptype == CHIP_TYPE_8080) || (chiptype == CHIP_TYPE_Z80)) && + (MEMORYSIZE < MAXBANKSIZE)) { + printf("Cannot switch off MMU when memory is %iKB < %iKB.\n", + MEMORYSIZE >> KBLOG2, MAXBANKSIZE >> KBLOG2); + return SCPE_ARG; + } + return SCPE_OK; +} + +static t_stat cpu_set_banked(UNIT *uptr, int32 value, char *cptr, void *desc) { + if ((chiptype == CHIP_TYPE_8080) || (chiptype == CHIP_TYPE_Z80)) { + if (MEMORYSIZE <= MAXBANKSIZE) previousCapacity = MEMORYSIZE; + MEMORYSIZE = MAXMEMORY; + cpu_dev.awidth = MAXBANKSIZELOG2 + MAXBANKSLOG2; + cpu_clear(); + } + else if (chiptype == CHIP_TYPE_8086) { + printf("Cannot use banked memory for 8086 CPU.\n"); + return SCPE_ARG; + } + return SCPE_OK; +} + +static t_stat cpu_set_nonbanked(UNIT *uptr, int32 value, char *cptr, void *desc) { + if ((chiptype == CHIP_TYPE_8080) || (chiptype == CHIP_TYPE_Z80)) { + MEMORYSIZE = previousCapacity; + cpu_dev.awidth = MAXBANKSIZELOG2; + cpu_clear(); + } + return SCPE_OK; +} + +static int32 bankseldev(const int32 port, const int32 io, const int32 data) { + if(io) { + switch(ramtype) { + case 1: + if(data & 0x40) { + printf("HRAM: Parity %s" NLP, data & 1 ? "ON" : "OFF"); + } else { + printf("HRAM BANKSEL=%02x" NLP, data); + } + break; + case 2: +/* printf("VRAM BANKSEL=%02x" NLP, data);*/ + switch(data & 0xFF) { + case 0x01: +/* case 0x41: // OASIS uses this for some reason?*/ + setBankSelect(0); + break; + case 0x02: +/* case 0x42: // OASIS uses this for some reason?*/ + setBankSelect(1); + break; + case 0x04: + setBankSelect(2); + break; + case 0x08: + setBankSelect(3); + break; + case 0x10: + setBankSelect(4); + break; + case 0x20: + setBankSelect(5); + break; + case 0x40: + setBankSelect(6); + break; + case 0x80: + setBankSelect(7); + break; + default: +/* printf("Invalid bank select 0x%02x for VRAM" NLP, data);*/ + break; + } + break; + case 3: + printf("CRAM BANKSEL=%02x" NLP, data); + break; + case 0: + default: + break; + } + return 0; + } else { + return(0xFF); + } +} + +static t_stat cpu_set_chiptype(UNIT *uptr, int32 value, char *cptr, void *desc) { + if (chiptype == value) return SCPE_OK; /* nothing to do */ + if ((chiptype == CHIP_TYPE_8080) && (value == CHIP_TYPE_Z80) || + (chiptype == CHIP_TYPE_Z80) && (value == CHIP_TYPE_8080)) { + chiptype = value; + return SCPE_OK; + } + chiptype = value; + if (chiptype == CHIP_TYPE_8086) { + if (MEMORYSIZE <= MAXBANKSIZE) previousCapacity = MEMORYSIZE; + MEMORYSIZE = MAXMEMORY; + cpu_unit.flags &= ~(UNIT_CPU_BANKED | UNIT_CPU_ALTAIRROM); + cpu_unit.flags |= UNIT_CPU_MMU; + cpu_dev.awidth = MAXBANKSIZELOG2 + MAXBANKSLOG2; + cpu_clear(); + } + else if ((chiptype == CHIP_TYPE_8080) || (chiptype == CHIP_TYPE_Z80)) { + MEMORYSIZE = previousCapacity; + cpu_dev.awidth = MAXBANKSIZELOG2; + cpu_clear(); + } + return SCPE_OK; +} + +#ifdef CPUSWITCHER +static int32 switchcpu_io(const int32 port, const int32 io, const int32 data) { + if (cpu_unit.flags & UNIT_CPU_VERBOSE) { + MESSAGE_5("SWITCH(port=%02x, io=%i, data=%04x(%i)", port, io, data, data); + } + return 0; +} + +static t_stat cpu_show_switcher(FILE *st, UNIT *uptr, int32 val, void *desc) { + if ((cpu_unit.flags & UNIT_CPU_SWITCHER) && (switcherPort >= 0)) + fprintf(st, "SWITCHER=0x%02x", switcherPort); + else fprintf(st, "NOSWITCHER"); + return SCPE_OK; +} + +static t_stat cpu_set_switcher(UNIT *uptr, int32 value, char *cptr, void *desc) { + struct idev safe; + switcherPort &= 0xff; + safe = dev_table[switcherPort]; + if (sim_map_resource(switcherPort, 1, RESOURCE_TYPE_IO, &switchcpu_io, FALSE)) { + printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, switcherPort); + return SCPE_ARG; + } + oldSwitcherDevice = safe; + return SCPE_OK; +} + +static t_stat cpu_reset_switcher(UNIT *uptr, int32 value, char *cptr, void *desc) { + if (sim_map_resource(switcherPort, 1, RESOURCE_TYPE_IO, oldSwitcherDevice.routine, FALSE)) { + printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, switcherPort); + return SCPE_ARG; + } + return SCPE_OK; +} +#endif + +static t_stat cpu_set_ramtype(UNIT *uptr, int32 value, char *cptr, void *desc) { + + if(value == ramtype) { + printf("RAM Selection unchanged\n"); + return SCPE_OK; + } + + switch(ramtype) { + case 1: + printf("Unmapping NorthStar HRAM\n"); + sim_map_resource(0xC0, 1, RESOURCE_TYPE_IO, &bankseldev, TRUE); + break; + case 2: + printf("Unmapping Vector RAM\n"); + sim_map_resource(0x40, 1, RESOURCE_TYPE_IO, &bankseldev, TRUE); + break; + case 3: + printf("Unmapping Cromemco RAM\n"); +/* sim_map_resource(0xC0, 1, RESOURCE_TYPE_IO, &bankseldev, TRUE);*/ + break; + case 0: + default: + printf("Unmapping AltairZ80 RAM\n"); + break; + } + + switch(value) { + case 1: + printf("NorthStar HRAM Selected\n"); + sim_map_resource(0xC0, 1, RESOURCE_TYPE_IO, &bankseldev, FALSE); + break; + case 2: + printf("Vector RAM Selected\n"); + sim_map_resource(0x40, 1, RESOURCE_TYPE_IO, &bankseldev, FALSE); + break; + case 3: + printf("Cromemco RAM Selected\n"); +/* sim_map_resource(0xC0, 1, RESOURCE_TYPE_IO, &bankseldev, FALSE);*/ + break; + case 0: + default: + printf("AltairZ80 RAM Selected\n"); + break; + } + + ramtype = value; + return SCPE_OK; +} + +/* set memory to 'size' kilo byte */ +static t_stat set_size(uint32 size) { + uint32 maxsize = (((chiptype == CHIP_TYPE_8080) || (chiptype == CHIP_TYPE_Z80)) && + ((cpu_unit.flags & UNIT_CPU_BANKED) == 0)) ? MAXBANKSIZE : MAXMEMORY; + size <<= KBLOG2; + if (cpu_unit.flags & UNIT_CPU_BANKED) size &= ~ADDRMASK; + cpu_unit.flags |= UNIT_CPU_MMU; + if (size < KB) MEMORYSIZE = KB; + else if (size > maxsize) MEMORYSIZE = maxsize; + else MEMORYSIZE = size; + cpu_dev.awidth = MAXBANKSIZELOG2; + if (size > MAXBANKSIZE) cpu_dev.awidth += MAXBANKSLOG2; + cpu_clear(); + return SCPE_OK; +} + +static t_stat cpu_set_size(UNIT *uptr, int32 value, char *cptr, void *desc) { + return set_size(value); +} + +static t_stat cpu_set_memory(UNIT *uptr, int32 value, char *cptr, void *desc) { + uint32 size, result, i; + if (cptr == NULL) return SCPE_ARG; + result = sscanf(cptr, "%i%n", &size, &i); + if ((result == 1) && (cptr[i] == 'K') && ((cptr[i + 1] == 0) || + (cptr[i + 1] == 'B') && (cptr[i + 2] == 0))) + return set_size(size); + return SCPE_ARG; +} + +/* AltairZ80 Simulator initialization */ +void altairz80_init(void) { + cpu_clear(); +} + +void (*sim_vm_init) (void) = &altairz80_init; + +/* This is the binary loader. The input file is considered to be a string of + literal bytes with no special format. The load starts at the current value + of the PC if no start address is given. If the input string ends with ROM + (not case sensitive) the memory area is made read only. + ALTAIRROM/NOALTAIRROM settings are ignored. +*/ + +#define PLURAL(x) (x), (x) == 1 ? "" : "s" + +t_stat sim_load(FILE *fileref, char *cptr, char *fnam, int32 flag) { + uint32 i, addr, cnt = 0, org, pagesModified = 0, makeROM = FALSE; + t_addr j, lo, hi; + char *result; + MDEV m; + char gbuf[CBUFSIZE]; + if (flag) { + result = (chiptype == CHIP_TYPE_8086) ? + get_range(NULL, cptr, &lo, &hi, 16, ADDRMASK | (BANKMASK << MAXBANKSIZELOG2), 0) : + get_range(NULL, cptr, &lo, &hi, 16, ADDRMASK, 0); + if (result == NULL) return SCPE_ARG; + for (j = lo; j <= hi; j++) { + if (putc((chiptype == CHIP_TYPE_8086) ? GetBYTEExtended(j) : GetBYTE(j), fileref) == EOF) return SCPE_IOERR; + } + printf("%d byte%s dumped [%x - %x].\n", PLURAL(hi + 1 - lo), lo, hi); + } + else { + if (*cptr == 0) addr = PC_S; + else { + get_glyph(cptr, gbuf, 0); + if (strcmp(gbuf, "ROM") == 0) { + addr = PC_S; + makeROM = TRUE; + } + else { + addr = strtotv(cptr, &result, 16); + if (cptr == result) return SCPE_ARG; + while (isspace(*result)) result++; + get_glyph(result, gbuf, 0); + if (strcmp(gbuf, "ROM") == 0) makeROM = TRUE; + } + } + /* addr is start address to load to, makeROM == TRUE iff memory should become ROM */ + org = addr; + while ((addr < MAXMEMORY) && ((i = getc(fileref)) != EOF)) { + m = mmu_table[addr >> LOG2PAGESIZE]; + if (!m.isRAM && m.isEmpty) { + mmu_table[addr >> LOG2PAGESIZE] = RAM_PAGE; + pagesModified++; + m = RAM_PAGE; + } + if (makeROM) { + mmu_table[addr >> LOG2PAGESIZE] = ROM_PAGE; + m = ROM_PAGE; + } + if (!m.isRAM && m.routine) m.routine(addr, 1, i); + else M[addr] = i; + addr++; + cnt++; + } /* end while */ + printf("%d byte%s [%d page%s] loaded at %x%s.\n", PLURAL(cnt), + PLURAL((cnt + 0xff) >> 8), org, makeROM ? " [ROM]" : ""); + if (pagesModified) + printf("Warning: %d page%s modified.\n", PLURAL(pagesModified)); + } + return SCPE_OK; +} diff --git a/AltairZ80/altairZ80_defs.h b/AltairZ80/altairZ80_defs.h index af4cc163..5e4050d5 100644 --- a/AltairZ80/altairZ80_defs.h +++ b/AltairZ80/altairZ80_defs.h @@ -1,6 +1,6 @@ /* altairz80_defs.h: MITS Altair simulator definitions - Copyright (c) 2002-2007, Peter Schorn + Copyright (c) 2002-2008, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,55 +26,94 @@ Based on work by Charles E Owen (c) 1997 */ -#include "sim_defs.h" /* simulator definitions */ +#include "sim_defs.h" /* simulator definitions */ -#define MAXMEMSIZE 65536 /* maximum memory size */ -#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */ -#define BOOTROM_SIZE 256 /* size of boot rom */ -#define MAXBANKS 8 /* max number of memory banks */ -#define MAXBANKSLOG2 3 /* log2 of MAXBANKS */ -#define BANKMASK (MAXBANKS-1) /* bank mask */ -#define MEMSIZE (cpu_unit.capac) /* actual memory size */ -#define KB 1024 /* kilo byte */ -#define DEFAULT_ROM_LOW 0xff00 /* default for lowest address of ROM */ -#define DEFAULT_ROM_HIGH 0xffff /* default for highest address of ROM */ +#define MAXBANKSIZE 65536 /* maximum memory size, a power of 2 */ +#define MAXBANKSIZELOG2 16 /* log2 of MAXBANKSIZE */ +#define MAXBANKS 16 /* max number of memory banks, a power of 2 */ +#define MAXBANKSLOG2 4 /* log2 of MAXBANKS */ +#define MAXMEMORY (MAXBANKS * MAXBANKSIZE) /* maximum, total memory size */ +#define ADDRMASK (MAXBANKSIZE - 1) /* address mask */ +#define ADDRMASKEXTENDED (MAXMEMORY - 1) /* extended address mask */ +#define BANKMASK (MAXBANKS - 1) /* bank mask */ +#define MEMORYSIZE (cpu_unit.capac) /* actual memory size */ +#define KB 1024 /* kilo byte */ +#define KBLOG2 10 /* log2 of KB */ +#define ALTAIR_ROM_LOW 0xff00 /* start address of regular Altair ROM */ +#define RESOURCE_TYPE_MEMORY 1 +#define RESOURCE_TYPE_IO 2 -#define NUM_OF_DSK 8 /* NUM_OF_DSK must be power of two */ -#define LDA_INSTRUCTION 0x3e /* op-code for LD A,<8-bit value> instruction */ -#define UNIT_NO_OFFSET_1 0x37 /* LD A, */ -#define UNIT_NO_OFFSET_2 0xb4 /* LD a,80h | */ +#define NUM_OF_DSK 8 /* NUM_OF_DSK must be power of two */ +#define LDA_INSTRUCTION 0x3e /* op-code for LD A,<8-bit value> instruction */ +#define UNIT_NO_OFFSET_1 0x37 /* LD A, */ +#define UNIT_NO_OFFSET_2 0xb4 /* LD a,80h | */ -#define UNIT_V_OPSTOP (UNIT_V_UF+0) /* stop on invalid operation */ -#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP) -#define UNIT_V_CHIP (UNIT_V_UF+1) /* 8080 or Z80 CPU */ -#define UNIT_CHIP (1 << UNIT_V_CHIP) -#define UNIT_V_MSIZE (UNIT_V_UF+2) /* memory size */ -#define UNIT_MSIZE (1 << UNIT_V_MSIZE) -#define UNIT_V_BANKED (UNIT_V_UF+3) /* banked memory is used */ -#define UNIT_BANKED (1 << UNIT_V_BANKED) -#define UNIT_V_ROM (UNIT_V_UF+4) /* ROM exists */ -#define UNIT_ROM (1 << UNIT_V_ROM) -#define UNIT_V_ALTAIRROM (UNIT_V_UF+5) /* ALTAIR ROM exists */ -#define UNIT_ALTAIRROM (1 << UNIT_V_ALTAIRROM) -#define UNIT_V_WARNROM (UNIT_V_UF+6) /* warn if ROM is written to */ -#define UNIT_WARNROM (1 << UNIT_V_WARNROM) +#define CHIP_TYPE_8080 0 +#define CHIP_TYPE_Z80 1 +#define CHIP_TYPE_8086 2 -#define UNIX_PLATFORM (defined (__linux) || defined(__NetBSD__) || defined (__OpenBSD__) || \ - defined (__FreeBSD__) || defined (__APPLE__)) +/* simulator stop codes */ +#define STOP_HALT 0 /* HALT */ +#define STOP_IBKPT 1 /* breakpoint (program counter) */ +#define STOP_MEM 2 /* breakpoint (memory access) */ +#define STOP_OPCODE 3 /* invalid operation encountered (8080, Z80, 8086) */ -#define ADDRESS_FORMAT "[%04xh]" +#define UNIT_CPU_V_OPSTOP (UNIT_V_UF+0) /* stop on invalid operation */ +#define UNIT_CPU_OPSTOP (1 << UNIT_CPU_V_OPSTOP) +#define UNIT_CPU_V_BANKED (UNIT_V_UF+1) /* banked memory is used */ +#define UNIT_CPU_BANKED (1 << UNIT_CPU_V_BANKED) +#define UNIT_CPU_V_ALTAIRROM (UNIT_V_UF+2) /* ALTAIR ROM exists */ +#define UNIT_CPU_ALTAIRROM (1 << UNIT_CPU_V_ALTAIRROM) +#define UNIT_CPU_V_VERBOSE (UNIT_V_UF+3) /* warn if ROM is written to */ +#define UNIT_CPU_VERBOSE (1 << UNIT_CPU_V_VERBOSE) +#define UNIT_CPU_V_MMU (UNIT_V_UF+4) /* use MMU and slower CPU */ +#define UNIT_CPU_MMU (1 << UNIT_CPU_V_MMU) +#define UNIT_CPU_V_STOPONHALT (UNIT_V_UF+5) /* stop simulation on HALT */ +#define UNIT_CPU_STOPONHALT (1 << UNIT_CPU_V_STOPONHALT) + +#ifdef CPUSWITCHER +#define UNIT_CPU_V_SWITCHER (UNIT_V_UF+6) /* switcher 8086 <--> 8080/Z80 enabled */ +#define UNIT_CPU_SWITCHER (1 << UNIT_CPU_V_SWITCHER) +#endif + +#define UNIX_PLATFORM (defined (__linux) || defined(__NetBSD__) \ + || defined (__OpenBSD__) || defined (__FreeBSD__) || defined (__APPLE__)) + +#define ADDRESS_FORMAT "[0x%05x]" #define PC_FORMAT "\n" ADDRESS_FORMAT " " #define MESSAGE_1(p1) \ - sprintf(messageBuffer,PC_FORMAT p1,PCX); printMessage() + sprintf(messageBuffer,PC_FORMAT p1,PCX); printMessage() #define MESSAGE_2(p1,p2) \ - sprintf(messageBuffer,PC_FORMAT p1,PCX,p2); printMessage() + sprintf(messageBuffer,PC_FORMAT p1,PCX,p2); printMessage() #define MESSAGE_3(p1,p2,p3) \ - sprintf(messageBuffer,PC_FORMAT p1,PCX,p2,p3); printMessage() + sprintf(messageBuffer,PC_FORMAT p1,PCX,p2,p3); printMessage() #define MESSAGE_4(p1,p2,p3,p4) \ - sprintf(messageBuffer,PC_FORMAT p1,PCX,p2,p3,p4); printMessage() + sprintf(messageBuffer,PC_FORMAT p1,PCX,p2,p3,p4); printMessage() #define MESSAGE_5(p1,p2,p3,p4,p5) \ - sprintf(messageBuffer,PC_FORMAT p1,PCX,p2,p3,p4,p5); printMessage() + sprintf(messageBuffer,PC_FORMAT p1,PCX,p2,p3,p4,p5); printMessage() #define MESSAGE_6(p1,p2,p3,p4,p5,p6) \ - sprintf(messageBuffer,PC_FORMAT p1,PCX,p2,p3,p4,p5,p6); printMessage() + sprintf(messageBuffer,PC_FORMAT p1,PCX,p2,p3,p4,p5,p6); printMessage() #define MESSAGE_7(p1,p2,p3,p4,p5,p6,p7) \ sprintf(messageBuffer,PC_FORMAT p1,PCX,p2,p3,p4,p5,p6,p7); printMessage() + +/* use NLP for new line printing while the simulation is running */ +#if UNIX_PLATFORM +#define NLP "\r\n" +#else +#define NLP "\n" +#endif + +#define TRACE_PRINT(level, args) if(trace_level & level) { \ + printf args; \ + } + +#if defined (__MWERKS__) && defined (macintosh) +#define __FUNCTION__ __FILE__ +#endif + +typedef struct { + uint32 mem_base; /* Memory Base Address */ + uint32 mem_size; /* Memory Address space requirement */ + uint32 io_base; /* I/O Base Address */ + uint32 io_size; /* I/O Address Space requirement */ +} PNP_INFO; diff --git a/AltairZ80/altairZ80_dsk.c b/AltairZ80/altairZ80_dsk.c index e02ccd90..bebfe2b0 100644 --- a/AltairZ80/altairZ80_dsk.c +++ b/AltairZ80/altairZ80_dsk.c @@ -1,559 +1,548 @@ -/* altairz80_dsk.c: MITS Altair 88-DISK Simulator - - Copyright (c) 2002-2007, Peter Schorn - - 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 - PETER SCHORN 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 Peter Schorn shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Peter Schorn. - - Based on work by Charles E Owen (c) 1997 - - The 88_DISK is a 8-inch floppy controller which can control up - to 16 daisy-chained Pertec FD-400 hard-sectored floppy drives. - Each diskette has physically 77 tracks of 32 137-byte sectors - each. - - The controller is interfaced to the CPU by use of 3 I/O addresses, - standardly, these are device numbers 10, 11, and 12 (octal). - - Address Mode Function - ------- ---- -------- - - 10 Out Selects and enables Controller and Drive - 10 In Indicates status of Drive and Controller - 11 Out Controls Disk Function - 11 In Indicates current sector position of disk - 12 Out Write data - 12 In Read data - - Drive Select Out (Device 10 OUT): - - +---+---+---+---+---+---+---+---+ - | C | X | X | X | Device | - +---+---+---+---+---+---+---+---+ - - C = If this bit is 1, the disk controller selected by 'device' is - cleared. If the bit is zero, 'device' is selected as the - device being controlled by subsequent I/O operations. - X = not used - Device = value zero thru 15, selects drive to be controlled. - - Drive Status In (Device 10 IN): - - +---+---+---+---+---+---+---+---+ - | R | Z | I | X | X | H | M | W | - +---+---+---+---+---+---+---+---+ - - W - When 0, write circuit ready to write another byte. - M - When 0, head movement is allowed - H - When 0, indicates head is loaded for read/write - X - not used (will be 0) - I - When 0, indicates interrupts enabled (not used by this simulator) - Z - When 0, indicates head is on track 0 - R - When 0, indicates that read circuit has new byte to read - - Drive Control (Device 11 OUT): - - +---+---+---+---+---+---+---+---+ - | W | C | D | E | U | H | O | I | - +---+---+---+---+---+---+---+---+ - - I - When 1, steps head IN one track - O - When 1, steps head OUT one track - H - When 1, loads head to drive surface - U - When 1, unloads head - E - Enables interrupts (ignored by this simulator) - D - Disables interrupts (ignored by this simulator) - C - When 1 lowers head current (ignored by this simulator) - W - When 1, starts Write Enable sequence: W bit on device 10 - (see above) will go 1 and data will be read from port 12 - until 137 bytes have been read by the controller from - that port. The W bit will go off then, and the sector data - will be written to disk. Before you do this, you must have - stepped the track to the desired number, and waited until - the right sector number is presented on device 11 IN, then - set this bit. - - Sector Position (Device 11 IN): - - As the sectors pass by the read head, they are counted and the - number of the current one is available in this register. - - +---+---+---+---+---+---+---+---+ - | X | X | Sector Number | T | - +---+---+---+---+---+---+---+---+ - - X = Not used - Sector number = binary of the sector number currently under the - head, 0-31. - T = Sector True, is a 1 when the sector is positioned to read or - write. - -*/ - -#include "altairz80_defs.h" - -#define UNIT_V_DSK_WLK (UNIT_V_UF + 0) /* write locked */ -#define UNIT_DSK_WLK (1 << UNIT_V_DSK_WLK) -#define UNIT_V_DSK_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ -#define UNIT_DSK_VERBOSE (1 << UNIT_V_DSK_VERBOSE) -#define DSK_SECTSIZE 137 /* size of sector */ -#define DSK_SECT 32 /* sectors per track */ -#define MAX_TRACKS 254 /* number of tracks, - original Altair has 77 tracks only */ -#define DSK_TRACSIZE (DSK_SECTSIZE * DSK_SECT) -#define MAX_DSK_SIZE (DSK_TRACSIZE * MAX_TRACKS) -#define TRACE_IN_OUT 1 -#define TRACE_READ_WRITE 2 -#define TRACE_SECTOR_STUCK 4 -#define TRACE_TRACK_STUCK 8 -#define NUM_OF_DSK_MASK (NUM_OF_DSK - 1) - -int32 dsk10(const int32 port, const int32 io, const int32 data); -int32 dsk11(const int32 port, const int32 io, const int32 data); -int32 dsk12(const int32 port, const int32 io, const int32 data); -static t_stat dsk_boot(int32 unitno, DEVICE *dptr); -static t_stat dsk_reset(DEVICE *dptr); -static t_stat dsk_set_verbose(UNIT *uptr, int32 value, char *cptr, void *desc); - -extern int32 PCX; -extern int32 saved_PC; -extern char messageBuffer[]; -extern UNIT cpu_unit; - -extern void printMessage(void); -extern int32 install_bootrom(void); - -/* global data on status */ - -/* currently selected drive (values are 0 .. NUM_OF_DSK) - current_disk < NUM_OF_DSK implies that the corresponding disk is attached to a file */ -static int32 current_disk = NUM_OF_DSK; -static int32 current_track [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; -static int32 current_sector [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; -static int32 current_byte [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; -static int32 current_flag [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; -static uint8 tracks [NUM_OF_DSK] = { MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, - MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS }; -static int32 trace_flag = 0; -static int32 in9_count = 0; -static int32 in9_message = FALSE; -static int32 dirty = FALSE; /* TRUE when buffer has unwritten data in it */ -static int32 warnLevelDSK = 3; -static int32 warnLock [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; -static int32 warnAttached [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; -static int32 warnDSK10 = 0; -static int32 warnDSK11 = 0; -static int32 warnDSK12 = 0; -static int8 dskbuf[DSK_SECTSIZE]; /* data Buffer */ - -/* Altair MITS modified BOOT EPROM, fits in upper 256 byte of memory */ -int32 bootrom[BOOTROM_SIZE] = { - 0xf3, 0x06, 0x80, 0x3e, 0x0e, 0xd3, 0xfe, 0x05, /* ff00-ff07 */ - 0xc2, 0x05, 0xff, 0x3e, 0x16, 0xd3, 0xfe, 0x3e, /* ff08-ff0f */ - 0x12, 0xd3, 0xfe, 0xdb, 0xfe, 0xb7, 0xca, 0x20, /* ff10-ff17 */ - 0xff, 0x3e, 0x0c, 0xd3, 0xfe, 0xaf, 0xd3, 0xfe, /* ff18-ff1f */ - 0x21, 0x00, 0x5c, 0x11, 0x33, 0xff, 0x0e, 0x88, /* ff20-ff27 */ - 0x1a, 0x77, 0x13, 0x23, 0x0d, 0xc2, 0x28, 0xff, /* ff28-ff2f */ - 0xc3, 0x00, 0x5c, 0x31, 0x21, 0x5d, 0x3e, 0x00, /* ff30-ff37 */ - 0xd3, 0x08, 0x3e, 0x04, 0xd3, 0x09, 0xc3, 0x19, /* ff38-ff3f */ - 0x5c, 0xdb, 0x08, 0xe6, 0x02, 0xc2, 0x0e, 0x5c, /* ff40-ff47 */ - 0x3e, 0x02, 0xd3, 0x09, 0xdb, 0x08, 0xe6, 0x40, /* ff48-ff4f */ - 0xc2, 0x0e, 0x5c, 0x11, 0x00, 0x00, 0x06, 0x08, /* ff50-ff57 */ - 0xc5, 0xd5, 0x11, 0x86, 0x80, 0x21, 0x88, 0x5c, /* ff58-ff5f */ - 0xdb, 0x09, 0x1f, 0xda, 0x2d, 0x5c, 0xe6, 0x1f, /* ff60-ff67 */ - 0xb8, 0xc2, 0x2d, 0x5c, 0xdb, 0x08, 0xb7, 0xfa, /* ff68-ff6f */ - 0x39, 0x5c, 0xdb, 0x0a, 0x77, 0x23, 0x1d, 0xc2, /* ff70-ff77 */ - 0x39, 0x5c, 0xd1, 0x21, 0x8b, 0x5c, 0x06, 0x80, /* ff78-ff7f */ - 0x7e, 0x12, 0x23, 0x13, 0x05, 0xc2, 0x4d, 0x5c, /* ff80-ff87 */ - 0xc1, 0x21, 0x00, 0x5c, 0x7a, 0xbc, 0xc2, 0x60, /* ff88-ff8f */ - 0x5c, 0x7b, 0xbd, 0xd2, 0x80, 0x5c, 0x04, 0x04, /* ff90-ff97 */ - 0x78, 0xfe, 0x20, 0xda, 0x25, 0x5c, 0x06, 0x01, /* ff98-ff9f */ - 0xca, 0x25, 0x5c, 0xdb, 0x08, 0xe6, 0x02, 0xc2, /* ffa0-ffa7 */ - 0x70, 0x5c, 0x3e, 0x01, 0xd3, 0x09, 0x06, 0x00, /* ffa8-ffaf */ - 0xc3, 0x25, 0x5c, 0x3e, 0x80, 0xd3, 0x08, 0xfb, /* ffb0-ffb7 */ - 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffb8-ffbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffc0-ffc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffc8-ffcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffd0-ffd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffd8-ffdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffe0-ffe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffe8-ffef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fff0-fff7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fff8-ffff */ -}; - -/* 88DSK Standard I/O Data Structures */ - -static UNIT dsk_unit[] = { - { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, - { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, - { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, - { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, - { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, - { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, - { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, - { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) } -}; - -static REG dsk_reg[] = { - { DRDATA (DISK, current_disk, 4) }, - { BRDATA (CURTRACK, current_track, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO }, - { BRDATA (CURSECTOR, current_sector, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO }, - { BRDATA (CURBYTE, current_byte, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO }, - { BRDATA (CURFLAG, current_flag, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO }, - { BRDATA (TRACKS, tracks, 10, 8, NUM_OF_DSK), REG_CIRC }, - { ORDATA (TRACE, trace_flag, 8) }, - { DRDATA (IN9COUNT, in9_count, 4), REG_RO }, - { DRDATA (IN9MESSAGE, in9_message, 4), REG_RO }, - { DRDATA (DIRTY, dirty, 4), REG_RO }, - { DRDATA (DSKWL, warnLevelDSK, 32) }, - { BRDATA (WARNLOCK, warnLock, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO }, - { BRDATA (WARNATTACHED, warnAttached, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO }, - { DRDATA (WARNDSK10, warnDSK10, 4), REG_RO }, - { DRDATA (WARNDSK11, warnDSK11, 4), REG_RO }, - { DRDATA (WARNDSK12, warnDSK12, 4), REG_RO }, - { BRDATA (DISKBUFFER, dskbuf, 10, 8, DSK_SECTSIZE), REG_CIRC + REG_RO }, - { NULL } -}; - -static MTAB dsk_mod[] = { - { UNIT_DSK_WLK, 0, "WRTENB", "WRTENB", NULL }, - { UNIT_DSK_WLK, UNIT_DSK_WLK, "WRTLCK", "WRTLCK", NULL }, - /* quiet, no warning messages */ - { UNIT_DSK_VERBOSE, 0, "QUIET", "QUIET", NULL }, - /* verbose, show warning messages */ - { UNIT_DSK_VERBOSE, UNIT_DSK_VERBOSE, "VERBOSE", "VERBOSE", &dsk_set_verbose }, - { 0 } -}; - -DEVICE dsk_dev = { - "DSK", dsk_unit, dsk_reg, dsk_mod, - 8, 10, 31, 1, 8, 8, - NULL, NULL, &dsk_reset, - &dsk_boot, NULL, NULL, - NULL, 0, 0, - NULL, NULL, NULL -}; - -static void resetDSKWarningFlags(void) { - int32 i; - for (i = 0; i < NUM_OF_DSK; i++) { - warnLock[i] = 0; - warnAttached[i] = 0; - } - warnDSK10 = 0; - warnDSK11 = 0; - warnDSK12 = 0; -} - -static t_stat dsk_set_verbose(UNIT *uptr, int32 value, char *cptr, void *desc) { - resetDSKWarningFlags(); - return SCPE_OK; -} - -/* returns TRUE iff there exists a disk with VERBOSE */ -static int32 hasVerbose(void) { - int32 i; - for (i = 0; i < NUM_OF_DSK; i++) { - if (((dsk_dev.units + i) -> flags) & UNIT_DSK_VERBOSE) { - return TRUE; - } - } - return FALSE; -} - -static char* selectInOut(const int32 io) { - return io == 0 ? "IN" : "OUT"; -} - -/* service routines to handle simulator functions */ -/* reset routine */ - -static t_stat dsk_reset(DEVICE *dptr) { - resetDSKWarningFlags(); - current_disk = NUM_OF_DSK; - trace_flag = 0; - in9_count = 0; - in9_message = FALSE; - return SCPE_OK; -} - -/* The boot routine modifies the boot ROM in such a way that subsequently - the specified disk is used for boot purposes. -*/ -static t_stat dsk_boot(int32 unitno, DEVICE *dptr) { - if (cpu_unit.flags & (UNIT_ALTAIRROM | UNIT_BANKED)) { - /* check whether we are really modifying an LD A,<> instruction */ - if ((bootrom[UNIT_NO_OFFSET_1 - 1] == LDA_INSTRUCTION) && (bootrom[UNIT_NO_OFFSET_2 - 1] == LDA_INSTRUCTION)) { - bootrom[UNIT_NO_OFFSET_1] = unitno & 0xff; /* LD A, */ - bootrom[UNIT_NO_OFFSET_2] = 0x80 | (unitno & 0xff); /* LD a,80h | */ - } - else { /* Attempt to modify non LD A,<> instructions is refused. */ - printf("Incorrect boot ROM offsets detected.\n"); - return SCPE_IERR; - } - install_bootrom(); /* install modified ROM */ - } - saved_PC = DEFAULT_ROM_LOW; - return SCPE_OK; -} - -static int32 dskseek(const UNIT *xptr) { - return fseek(xptr -> fileref, DSK_TRACSIZE * current_track[current_disk] + - DSK_SECTSIZE * current_sector[current_disk], SEEK_SET); -} - -/* precondition: current_disk < NUM_OF_DSK */ -static void writebuf(void) { - int32 i, rtn; - UNIT *uptr; - i = current_byte[current_disk]; /* null-fill rest of sector if any */ - while (i < DSK_SECTSIZE) { - dskbuf[i++] = 0; - } - uptr = dsk_dev.units + current_disk; - if (((uptr -> flags) & UNIT_DSK_WLK) == 0) { /* write enabled */ - if (trace_flag & TRACE_READ_WRITE) { - MESSAGE_4("OUT 0x0a (WRITE) D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]); - } - if (dskseek(uptr)) { - MESSAGE_4("fseek failed D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]); - } - rtn = fwrite(dskbuf, DSK_SECTSIZE, 1, uptr -> fileref); - if (rtn != 1) { - MESSAGE_4("fwrite failed T%d S%d Return=%d", current_track[current_disk], current_sector[current_disk], rtn); - } - } - else if ( ((uptr -> flags) & UNIT_DSK_VERBOSE) && (warnLock[current_disk] < warnLevelDSK) ) { - /* write locked - print warning message if required */ - warnLock[current_disk]++; -/*05*/ MESSAGE_2("Attempt to write to locked DSK%d - ignored.", current_disk); - } - current_flag[current_disk] &= 0xfe; /* ENWD off */ - current_byte[current_disk] = 0xff; - dirty = FALSE; -} - -/* I/O instruction handlers, called from the CPU module when an - IN or OUT instruction is issued. - - Each function is passed an 'io' flag, where 0 means a read from - the port, and 1 means a write to the port. On input, the actual - input is passed as the return value, on output, 'data' is written - to the device. -*/ - -/* Disk Controller Status/Select */ - -/* IMPORTANT: The status flags read by port 8 IN instruction are - INVERTED, that is, 0 is true and 1 is false. To handle this, the - simulator keeps it's own status flags as 0=false, 1=true; and - returns the COMPLEMENT of the status flags when read. This makes - setting/testing of the flag bits more logical, yet meets the - simulation requirement that they are reversed in hardware. -*/ - -int32 dsk10(const int32 port, const int32 io, const int32 data) { - int32 current_disk_flags; - in9_count = 0; - if (io == 0) { /* IN: return flags */ - if (current_disk >= NUM_OF_DSK) { - if (hasVerbose() && (warnDSK10 < warnLevelDSK)) { - warnDSK10++; -/*01*/ MESSAGE_1("Attempt of IN 0x08 on unattached disk - ignored."); - } - return 0xff; /* no drive selected - can do nothing */ - } - return (~current_flag[current_disk]) & 0xff; /* return the COMPLEMENT! */ - } - - /* OUT: Controller set/reset/enable/disable */ - if (dirty) { /* implies that current_disk < NUM_OF_DSK */ - writebuf(); - } - if (trace_flag & TRACE_IN_OUT) { - MESSAGE_2("OUT 0x08: %x", data); - } - current_disk = data & NUM_OF_DSK_MASK; /* 0 <= current_disk < NUM_OF_DSK */ - current_disk_flags = (dsk_dev.units + current_disk) -> flags; - if ((current_disk_flags & UNIT_ATT) == 0) { /* nothing attached? */ - if ( (current_disk_flags & UNIT_DSK_VERBOSE) && (warnAttached[current_disk] < warnLevelDSK) ) { - warnAttached[current_disk]++; -/*02*/MESSAGE_2("Attempt to select unattached DSK%d - ignored.", current_disk); - } - current_disk = NUM_OF_DSK; - } - else { - current_sector[current_disk] = 0xff; /* reset internal counters */ - current_byte[current_disk] = 0xff; - current_flag[current_disk] = data & 0x80 ? 0 /* disable drive */ : - (current_track[current_disk] == 0 ? 0x5a /* enable: head move true, track 0 if there */ : - 0x1a); /* enable: head move true */ - } - return 0; /* ignored since OUT */ -} - -/* Disk Drive Status/Functions */ - -int32 dsk11(const int32 port, const int32 io, const int32 data) { - if (current_disk >= NUM_OF_DSK) { - if (hasVerbose() && (warnDSK11 < warnLevelDSK)) { - warnDSK11++; -/*03*/ MESSAGE_2("Attempt of %s 0x09 on unattached disk - ignored.", selectInOut(io)); - } - return 0; /* no drive selected - can do nothing */ - } - - /* now current_disk < NUM_OF_DSK */ - if (io == 0) { /* read sector position */ - in9_count++; - if ((trace_flag & TRACE_SECTOR_STUCK) && (in9_count > 2 * DSK_SECT) && (!in9_message)) { - in9_message = TRUE; - MESSAGE_2("Looping on sector find %d.", current_disk); - } - if (trace_flag & TRACE_IN_OUT) { - MESSAGE_1("IN 0x09"); - } - if (dirty) {/* implies that current_disk < NUM_OF_DSK */ - writebuf(); - } - if (current_flag[current_disk] & 0x04) { /* head loaded? */ - current_sector[current_disk]++; - if (current_sector[current_disk] >= DSK_SECT) { - current_sector[current_disk] = 0; - } - current_byte[current_disk] = 0xff; - return (((current_sector[current_disk] << 1) & 0x3e) /* return 'sector true' bit = 0 (true) */ - | 0xc0); /* set on 'unused' bits */ - } else { - return 0; /* head not loaded - return 0 */ - } - } - - in9_count = 0; - /* drive functions */ - - if (trace_flag & TRACE_IN_OUT) { - MESSAGE_2("OUT 0x09: %x", data); - } - if (data & 0x01) { /* step head in */ - if (trace_flag & TRACE_TRACK_STUCK) { - if (current_track[current_disk] == (tracks[current_disk] - 1)) { - MESSAGE_2("Unnecessary step in for disk %d", current_disk); - } - } - current_track[current_disk]++; - if (current_track[current_disk] > (tracks[current_disk] - 1)) { - current_track[current_disk] = (tracks[current_disk] - 1); - } - if (dirty) { /* implies that current_disk < NUM_OF_DSK */ - writebuf(); - } - current_sector[current_disk] = 0xff; - current_byte[current_disk] = 0xff; - } - - if (data & 0x02) { /* step head out */ - if (trace_flag & TRACE_TRACK_STUCK) { - if (current_track[current_disk] == 0) { - MESSAGE_2("Unnecessary step out for disk %d", current_disk); - } - } - current_track[current_disk]--; - if (current_track[current_disk] < 0) { - current_track[current_disk] = 0; - current_flag[current_disk] |= 0x40; /* track 0 if there */ - } - if (dirty) { /* implies that current_disk < NUM_OF_DSK */ - writebuf(); - } - current_sector[current_disk] = 0xff; - current_byte[current_disk] = 0xff; - } - - if (dirty) { /* implies that current_disk < NUM_OF_DSK */ - writebuf(); - } - - if (data & 0x04) { /* head load */ - current_flag[current_disk] |= 0x04; /* turn on head loaded bit */ - current_flag[current_disk] |= 0x80; /* turn on 'read data available' */ - } - - if (data & 0x08) { /* head unload */ - current_flag[current_disk] &= 0xfb; /* turn off 'head loaded' bit */ - current_flag[current_disk] &= 0x7f; /* turn off 'read data available' */ - current_sector[current_disk] = 0xff; - current_byte[current_disk] = 0xff; - } - - /* interrupts & head current are ignored */ - - if (data & 0x80) { /* write sequence start */ - current_byte[current_disk] = 0; - current_flag[current_disk] |= 0x01; /* enter new write data on */ - } - return 0; /* ignored since OUT */ -} - -/* Disk Data In/Out */ - -int32 dsk12(const int32 port, const int32 io, const int32 data) { - int32 i; - UNIT *uptr; - - if (current_disk >= NUM_OF_DSK) { - if (hasVerbose() && (warnDSK12 < warnLevelDSK)) { - warnDSK12++; -/*04*/ MESSAGE_2("Attempt of %s 0x0a on unattached disk - ignored.", selectInOut(io)); - } - return 0; - } - - /* now current_disk < NUM_OF_DSK */ - in9_count = 0; - uptr = dsk_dev.units + current_disk; - if (io == 0) { - if (current_byte[current_disk] >= DSK_SECTSIZE) { - /* physically read the sector */ - if (trace_flag & TRACE_READ_WRITE) { - MESSAGE_4("IN 0x0a (READ) D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]); - } - for (i = 0; i < DSK_SECTSIZE; i++) { - dskbuf[i] = 0; - } - dskseek(uptr); - fread(dskbuf, DSK_SECTSIZE, 1, uptr -> fileref); - current_byte[current_disk] = 0; - } - return dskbuf[current_byte[current_disk]++] & 0xff; - } - else { - if (current_byte[current_disk] >= DSK_SECTSIZE) { - writebuf(); /* from above we have that current_disk < NUM_OF_DSK */ - } - else { - dirty = TRUE; /* this guarantees for the next call to writebuf that current_disk < NUM_OF_DSK */ - dskbuf[current_byte[current_disk]++] = data & 0xff; - } - return 0; /* ignored since OUT */ - } -} +/* altairz80_dsk.c: MITS Altair 88-DISK Simulator + + Copyright (c) 2002-2008, Peter Schorn + + 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 + PETER SCHORN 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 Peter Schorn shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Peter Schorn. + + Based on work by Charles E Owen (c) 1997 + + The 88_DISK is a 8-inch floppy controller which can control up + to 16 daisy-chained Pertec FD-400 hard-sectored floppy drives. + Each diskette has physically 77 tracks of 32 137-byte sectors + each. + + The controller is interfaced to the CPU by use of 3 I/O addresses, + standardly, these are device numbers 10, 11, and 12 (octal). + + Address Mode Function + ------- ---- -------- + + 10 Out Selects and enables Controller and Drive + 10 In Indicates status of Drive and Controller + 11 Out Controls Disk Function + 11 In Indicates current sector position of disk + 12 Out Write data + 12 In Read data + + Drive Select Out (Device 10 OUT): + + +---+---+---+---+---+---+---+---+ + | C | X | X | X | Device | + +---+---+---+---+---+---+---+---+ + + C = If this bit is 1, the disk controller selected by 'device' is + cleared. If the bit is zero, 'device' is selected as the + device being controlled by subsequent I/O operations. + X = not used + Device = value zero thru 15, selects drive to be controlled. + + Drive Status In (Device 10 IN): + + +---+---+---+---+---+---+---+---+ + | R | Z | I | X | X | H | M | W | + +---+---+---+---+---+---+---+---+ + + W - When 0, write circuit ready to write another byte. + M - When 0, head movement is allowed + H - When 0, indicates head is loaded for read/write + X - not used (will be 0) + I - When 0, indicates interrupts enabled (not used by this simulator) + Z - When 0, indicates head is on track 0 + R - When 0, indicates that read circuit has new byte to read + + Drive Control (Device 11 OUT): + + +---+---+---+---+---+---+---+---+ + | W | C | D | E | U | H | O | I | + +---+---+---+---+---+---+---+---+ + + I - When 1, steps head IN one track + O - When 1, steps head OUT one track + H - When 1, loads head to drive surface + U - When 1, unloads head + E - Enables interrupts (ignored by this simulator) + D - Disables interrupts (ignored by this simulator) + C - When 1 lowers head current (ignored by this simulator) + W - When 1, starts Write Enable sequence: W bit on device 10 + (see above) will go 1 and data will be read from port 12 + until 137 bytes have been read by the controller from + that port. The W bit will go off then, and the sector data + will be written to disk. Before you do this, you must have + stepped the track to the desired number, and waited until + the right sector number is presented on device 11 IN, then + set this bit. + + Sector Position (Device 11 IN): + + As the sectors pass by the read head, they are counted and the + number of the current one is available in this register. + + +---+---+---+---+---+---+---+---+ + | X | X | Sector Number | T | + +---+---+---+---+---+---+---+---+ + + X = Not used + Sector number = binary of the sector number currently under the + head, 0-31. + T = Sector True, is a 1 when the sector is positioned to read or + write. + +*/ + +#include "altairz80_defs.h" +#include + +#define UNIT_V_DSK_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_DSK_WLK (1 << UNIT_V_DSK_WLK) +#define UNIT_V_DSK_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ +#define UNIT_DSK_VERBOSE (1 << UNIT_V_DSK_VERBOSE) +#define DSK_SECTSIZE 137 /* size of sector */ +#define DSK_SECT 32 /* sectors per track */ +#define MAX_TRACKS 254 /* number of tracks, + original Altair has 77 tracks only */ +#define DSK_TRACSIZE (DSK_SECTSIZE * DSK_SECT) +#define MAX_DSK_SIZE (DSK_TRACSIZE * MAX_TRACKS) +#define TRACE_IN_OUT 1 +#define TRACE_READ_WRITE 2 +#define TRACE_SECTOR_STUCK 4 +#define TRACE_TRACK_STUCK 8 +#define NUM_OF_DSK_MASK (NUM_OF_DSK - 1) +#define BOOTROM_SIZE_DSK 256 /* size of boot rom */ + + +int32 dsk10(const int32 port, const int32 io, const int32 data); +int32 dsk11(const int32 port, const int32 io, const int32 data); +int32 dsk12(const int32 port, const int32 io, const int32 data); +static t_stat dsk_boot(int32 unitno, DEVICE *dptr); +static t_stat dsk_reset(DEVICE *dptr); +static t_stat dsk_set_verbose(UNIT *uptr, int32 value, char *cptr, void *desc); + +extern REG *sim_PC; +extern UNIT cpu_unit; +extern char messageBuffer[]; +extern uint32 PCX; + +extern void printMessage(void); +extern t_stat install_bootrom(int32 bootrom[], int32 size, int32 addr, int32 makeROM); +void install_ALTAIRbootROM(void); + +/* global data on status */ + +/* currently selected drive (values are 0 .. NUM_OF_DSK) + current_disk < NUM_OF_DSK implies that the corresponding disk is attached to a file */ +static int32 current_disk = NUM_OF_DSK; +static int32 current_track [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; +static int32 current_sector [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; +static int32 current_byte [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; +static int32 current_flag [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; +static uint8 tracks [NUM_OF_DSK] = { MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, + MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS }; +static int32 trace_level = 0; +static int32 in9_count = 0; +static int32 in9_message = FALSE; +static int32 dirty = FALSE; /* TRUE when buffer has unwritten data in it */ +static int32 warnLevelDSK = 3; +static int32 warnLock [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; +static int32 warnAttached [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; +static int32 warnDSK10 = 0; +static int32 warnDSK11 = 0; +static int32 warnDSK12 = 0; +static int8 dskbuf[DSK_SECTSIZE]; /* data Buffer */ + +/* Altair MITS modified BOOT EPROM, fits in upper 256 byte of memory */ +int32 bootrom_dsk[BOOTROM_SIZE_DSK] = { + 0xf3, 0x06, 0x80, 0x3e, 0x0e, 0xd3, 0xfe, 0x05, /* ff00-ff07 */ + 0xc2, 0x05, 0xff, 0x3e, 0x16, 0xd3, 0xfe, 0x3e, /* ff08-ff0f */ + 0x12, 0xd3, 0xfe, 0xdb, 0xfe, 0xb7, 0xca, 0x20, /* ff10-ff17 */ + 0xff, 0x3e, 0x0c, 0xd3, 0xfe, 0xaf, 0xd3, 0xfe, /* ff18-ff1f */ + 0x21, 0x00, 0x5c, 0x11, 0x33, 0xff, 0x0e, 0x88, /* ff20-ff27 */ + 0x1a, 0x77, 0x13, 0x23, 0x0d, 0xc2, 0x28, 0xff, /* ff28-ff2f */ + 0xc3, 0x00, 0x5c, 0x31, 0x21, 0x5d, 0x3e, 0x00, /* ff30-ff37 */ + 0xd3, 0x08, 0x3e, 0x04, 0xd3, 0x09, 0xc3, 0x19, /* ff38-ff3f */ + 0x5c, 0xdb, 0x08, 0xe6, 0x02, 0xc2, 0x0e, 0x5c, /* ff40-ff47 */ + 0x3e, 0x02, 0xd3, 0x09, 0xdb, 0x08, 0xe6, 0x40, /* ff48-ff4f */ + 0xc2, 0x0e, 0x5c, 0x11, 0x00, 0x00, 0x06, 0x08, /* ff50-ff57 */ + 0xc5, 0xd5, 0x11, 0x86, 0x80, 0x21, 0x88, 0x5c, /* ff58-ff5f */ + 0xdb, 0x09, 0x1f, 0xda, 0x2d, 0x5c, 0xe6, 0x1f, /* ff60-ff67 */ + 0xb8, 0xc2, 0x2d, 0x5c, 0xdb, 0x08, 0xb7, 0xfa, /* ff68-ff6f */ + 0x39, 0x5c, 0xdb, 0x0a, 0x77, 0x23, 0x1d, 0xc2, /* ff70-ff77 */ + 0x39, 0x5c, 0xd1, 0x21, 0x8b, 0x5c, 0x06, 0x80, /* ff78-ff7f */ + 0x7e, 0x12, 0x23, 0x13, 0x05, 0xc2, 0x4d, 0x5c, /* ff80-ff87 */ + 0xc1, 0x21, 0x00, 0x5c, 0x7a, 0xbc, 0xc2, 0x60, /* ff88-ff8f */ + 0x5c, 0x7b, 0xbd, 0xd2, 0x80, 0x5c, 0x04, 0x04, /* ff90-ff97 */ + 0x78, 0xfe, 0x20, 0xda, 0x25, 0x5c, 0x06, 0x01, /* ff98-ff9f */ + 0xca, 0x25, 0x5c, 0xdb, 0x08, 0xe6, 0x02, 0xc2, /* ffa0-ffa7 */ + 0x70, 0x5c, 0x3e, 0x01, 0xd3, 0x09, 0x06, 0x00, /* ffa8-ffaf */ + 0xc3, 0x25, 0x5c, 0x3e, 0x80, 0xd3, 0x08, 0xfb, /* ffb0-ffb7 */ + 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffb8-ffbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffc0-ffc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffc8-ffcf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffd0-ffd7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffd8-ffdf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffe0-ffe7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffe8-ffef */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fff0-fff7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fff8-ffff */ +}; + +/* 88DSK Standard I/O Data Structures */ + +static UNIT dsk_unit[] = { + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) } +}; + +static REG dsk_reg[] = { + { DRDATA (DISK, current_disk, 4) }, + { BRDATA (CURTRACK, current_track, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO }, + { BRDATA (CURSECTOR, current_sector, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO }, + { BRDATA (CURBYTE, current_byte, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO }, + { BRDATA (CURFLAG, current_flag, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO }, + { BRDATA (TRACKS, tracks, 10, 8, NUM_OF_DSK), REG_CIRC }, + { HRDATA (TRACELEVEL, trace_level, 16) }, + { DRDATA (IN9COUNT, in9_count, 4), REG_RO }, + { DRDATA (IN9MESSAGE, in9_message, 4), REG_RO }, + { DRDATA (DIRTY, dirty, 4), REG_RO }, + { DRDATA (DSKWL, warnLevelDSK, 32) }, + { BRDATA (WARNLOCK, warnLock, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO }, + { BRDATA (WARNATTACHED, warnAttached, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO }, + { DRDATA (WARNDSK10, warnDSK10, 4), REG_RO }, + { DRDATA (WARNDSK11, warnDSK11, 4), REG_RO }, + { DRDATA (WARNDSK12, warnDSK12, 4), REG_RO }, + { BRDATA (DISKBUFFER, dskbuf, 10, 8, DSK_SECTSIZE), REG_CIRC + REG_RO }, + { NULL } +}; + +static MTAB dsk_mod[] = { + { UNIT_DSK_WLK, 0, "WRTENB", "WRTENB", NULL }, + { UNIT_DSK_WLK, UNIT_DSK_WLK, "WRTLCK", "WRTLCK", NULL }, + /* quiet, no warning messages */ + { UNIT_DSK_VERBOSE, 0, "QUIET", "QUIET", NULL }, + /* verbose, show warning messages */ + { UNIT_DSK_VERBOSE, UNIT_DSK_VERBOSE, "VERBOSE", "VERBOSE", &dsk_set_verbose }, + { 0 } +}; + +DEVICE dsk_dev = { + "DSK", dsk_unit, dsk_reg, dsk_mod, + 8, 10, 31, 1, 8, 8, + NULL, NULL, &dsk_reset, + &dsk_boot, NULL, NULL, + NULL, (DEV_DISABLE), 0, + NULL, NULL, NULL +}; + +static void resetDSKWarningFlags(void) { + int32 i; + for (i = 0; i < NUM_OF_DSK; i++) { + warnLock[i] = 0; + warnAttached[i] = 0; + } + warnDSK10 = 0; + warnDSK11 = 0; + warnDSK12 = 0; +} + +static t_stat dsk_set_verbose(UNIT *uptr, int32 value, char *cptr, void *desc) { + resetDSKWarningFlags(); + return SCPE_OK; +} + +/* returns TRUE iff there exists a disk with VERBOSE */ +static int32 hasVerbose(void) { + int32 i; + for (i = 0; i < NUM_OF_DSK; i++) + if (((dsk_dev.units + i) -> flags) & UNIT_DSK_VERBOSE) return TRUE; + return FALSE; +} + +static char* selectInOut(const int32 io) { + return io == 0 ? "IN" : "OUT"; +} + +/* service routines to handle simulator functions */ +/* reset routine */ + +static t_stat dsk_reset(DEVICE *dptr) { + resetDSKWarningFlags(); + current_disk = NUM_OF_DSK; + trace_level = 0; + in9_count = 0; + in9_message = FALSE; + return SCPE_OK; +} + +void install_ALTAIRbootROM(void) { + assert(install_bootrom(bootrom_dsk, BOOTROM_SIZE_DSK, ALTAIR_ROM_LOW, TRUE) == SCPE_OK); +} + +/* The boot routine modifies the boot ROM in such a way that subsequently + the specified disk is used for boot purposes. +*/ +static t_stat dsk_boot(int32 unitno, DEVICE *dptr) { + if (cpu_unit.flags & (UNIT_CPU_ALTAIRROM | UNIT_CPU_BANKED)) { + /* check whether we are really modifying an LD A,<> instruction */ + if ((bootrom_dsk[UNIT_NO_OFFSET_1 - 1] == LDA_INSTRUCTION) && (bootrom_dsk[UNIT_NO_OFFSET_2 - 1] == LDA_INSTRUCTION)) { + bootrom_dsk[UNIT_NO_OFFSET_1] = unitno & 0xff; /* LD A, */ + bootrom_dsk[UNIT_NO_OFFSET_2] = 0x80 | (unitno & 0xff); /* LD a,80h | */ + } + else { /* Attempt to modify non LD A,<> instructions is refused. */ + printf("Incorrect boot ROM offsets detected.\n"); + return SCPE_IERR; + } + install_ALTAIRbootROM(); /* install modified ROM */ + } + *((int32 *) sim_PC->loc) = ALTAIR_ROM_LOW; + return SCPE_OK; +} + +static int32 dskseek(const UNIT *xptr) { + return fseek(xptr -> fileref, DSK_TRACSIZE * current_track[current_disk] + + DSK_SECTSIZE * current_sector[current_disk], SEEK_SET); +} + +/* precondition: current_disk < NUM_OF_DSK */ +static void writebuf(void) { + int32 i, rtn; + UNIT *uptr; + i = current_byte[current_disk]; /* null-fill rest of sector if any */ + while (i < DSK_SECTSIZE) + dskbuf[i++] = 0; + uptr = dsk_dev.units + current_disk; + if (((uptr -> flags) & UNIT_DSK_WLK) == 0) { /* write enabled */ + if (trace_level & TRACE_READ_WRITE) { + MESSAGE_4("OUT 0x0a (WRITE) D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]); + } + if (dskseek(uptr)) { + MESSAGE_4("fseek failed D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]); + } + rtn = fwrite(dskbuf, DSK_SECTSIZE, 1, uptr -> fileref); + if (rtn != 1) { + MESSAGE_4("fwrite failed T%d S%d Return=%d", current_track[current_disk], current_sector[current_disk], rtn); + } + } + else if ( ((uptr -> flags) & UNIT_DSK_VERBOSE) && (warnLock[current_disk] < warnLevelDSK) ) { + /* write locked - print warning message if required */ + warnLock[current_disk]++; +/*05*/ MESSAGE_2("Attempt to write to locked DSK%d - ignored.", current_disk); + } + current_flag[current_disk] &= 0xfe; /* ENWD off */ + current_byte[current_disk] = 0xff; + dirty = FALSE; +} + +/* I/O instruction handlers, called from the CPU module when an + IN or OUT instruction is issued. + + Each function is passed an 'io' flag, where 0 means a read from + the port, and 1 means a write to the port. On input, the actual + input is passed as the return value, on output, 'data' is written + to the device. +*/ + +/* Disk Controller Status/Select */ + +/* IMPORTANT: The status flags read by port 8 IN instruction are + INVERTED, that is, 0 is true and 1 is false. To handle this, the + simulator keeps it's own status flags as 0=false, 1=true; and + returns the COMPLEMENT of the status flags when read. This makes + setting/testing of the flag bits more logical, yet meets the + simulation requirement that they are reversed in hardware. +*/ + +int32 dsk10(const int32 port, const int32 io, const int32 data) { + int32 current_disk_flags; + in9_count = 0; + if (io == 0) { /* IN: return flags */ + if (current_disk >= NUM_OF_DSK) { + if (hasVerbose() && (warnDSK10 < warnLevelDSK)) { + warnDSK10++; +/*01*/ MESSAGE_1("Attempt of IN 0x08 on unattached disk - ignored."); + } + return 0xff; /* no drive selected - can do nothing */ + } + return (~current_flag[current_disk]) & 0xff; /* return the COMPLEMENT! */ + } + + /* OUT: Controller set/reset/enable/disable */ + if (dirty) /* implies that current_disk < NUM_OF_DSK */ + writebuf(); + if (trace_level & TRACE_IN_OUT) { + MESSAGE_2("OUT 0x08: %x", data); + } + current_disk = data & NUM_OF_DSK_MASK; /* 0 <= current_disk < NUM_OF_DSK */ + current_disk_flags = (dsk_dev.units + current_disk) -> flags; + if ((current_disk_flags & UNIT_ATT) == 0) { /* nothing attached? */ + if ( (current_disk_flags & UNIT_DSK_VERBOSE) && (warnAttached[current_disk] < warnLevelDSK) ) { + warnAttached[current_disk]++; +/*02*/ MESSAGE_2("Attempt to select unattached DSK%d - ignored.", current_disk); + } + current_disk = NUM_OF_DSK; + } + else { + current_sector[current_disk] = 0xff; /* reset internal counters */ + current_byte[current_disk] = 0xff; + current_flag[current_disk] = data & 0x80 ? 0 /* disable drive */ : + (current_track[current_disk] == 0 ? 0x5a /* enable: head move true, track 0 if there */ : + 0x1a); /* enable: head move true */ + } + return 0; /* ignored since OUT */ +} + +/* Disk Drive Status/Functions */ + +int32 dsk11(const int32 port, const int32 io, const int32 data) { + if (current_disk >= NUM_OF_DSK) { + if (hasVerbose() && (warnDSK11 < warnLevelDSK)) { + warnDSK11++; +/*03*/ MESSAGE_2("Attempt of %s 0x09 on unattached disk - ignored.", selectInOut(io)); + } + return 0; /* no drive selected - can do nothing */ + } + + /* now current_disk < NUM_OF_DSK */ + if (io == 0) { /* read sector position */ + in9_count++; + if ((trace_level & TRACE_SECTOR_STUCK) && (in9_count > 2 * DSK_SECT) && (!in9_message)) { + in9_message = TRUE; + MESSAGE_2("Looping on sector find %d.", current_disk); + } + if (trace_level & TRACE_IN_OUT) { + MESSAGE_1("IN 0x09"); + } + if (dirty) /* implies that current_disk < NUM_OF_DSK */ + writebuf(); + if (current_flag[current_disk] & 0x04) { /* head loaded? */ + current_sector[current_disk]++; + if (current_sector[current_disk] >= DSK_SECT) + current_sector[current_disk] = 0; + current_byte[current_disk] = 0xff; + return (((current_sector[current_disk] << 1) & 0x3e) /* return 'sector true' bit = 0 (true) */ + | 0xc0); /* set on 'unused' bits */ + } else return 0; /* head not loaded - return 0 */ + } + + in9_count = 0; + /* drive functions */ + + if (trace_level & TRACE_IN_OUT) { + MESSAGE_2("OUT 0x09: %x", data); + } + if (data & 0x01) { /* step head in */ + if ((trace_level & TRACE_TRACK_STUCK) && (current_track[current_disk] == (tracks[current_disk] - 1))) { + MESSAGE_2("Unnecessary step in for disk %d", current_disk); + } + current_track[current_disk]++; + if (current_track[current_disk] > (tracks[current_disk] - 1)) + current_track[current_disk] = (tracks[current_disk] - 1); + if (dirty) /* implies that current_disk < NUM_OF_DSK */ + writebuf(); + current_sector[current_disk] = 0xff; + current_byte[current_disk] = 0xff; + } + + if (data & 0x02) { /* step head out */ + if ((trace_level & TRACE_TRACK_STUCK) && (current_track[current_disk] == 0)) { + MESSAGE_2("Unnecessary step out for disk %d", current_disk); + } + current_track[current_disk]--; + if (current_track[current_disk] < 0) { + current_track[current_disk] = 0; + current_flag[current_disk] |= 0x40; /* track 0 if there */ + } + if (dirty) /* implies that current_disk < NUM_OF_DSK */ + writebuf(); + current_sector[current_disk] = 0xff; + current_byte[current_disk] = 0xff; + } + + if (dirty) /* implies that current_disk < NUM_OF_DSK */ + writebuf(); + + if (data & 0x04) { /* head load */ + current_flag[current_disk] |= 0x04; /* turn on head loaded bit */ + current_flag[current_disk] |= 0x80; /* turn on 'read data available' */ + } + + if (data & 0x08) { /* head unload */ + current_flag[current_disk] &= 0xfb; /* turn off 'head loaded' bit */ + current_flag[current_disk] &= 0x7f; /* turn off 'read data available' */ + current_sector[current_disk] = 0xff; + current_byte[current_disk] = 0xff; + } + + /* interrupts & head current are ignored */ + + if (data & 0x80) { /* write sequence start */ + current_byte[current_disk] = 0; + current_flag[current_disk] |= 0x01; /* enter new write data on */ + } + return 0; /* ignored since OUT */ +} + +/* Disk Data In/Out */ + +int32 dsk12(const int32 port, const int32 io, const int32 data) { + int32 i; + UNIT *uptr; + + if (current_disk >= NUM_OF_DSK) { + if (hasVerbose() && (warnDSK12 < warnLevelDSK)) { + warnDSK12++; +/*04*/ MESSAGE_2("Attempt of %s 0x0a on unattached disk - ignored.", selectInOut(io)); + } + return 0; + } + + /* now current_disk < NUM_OF_DSK */ + in9_count = 0; + uptr = dsk_dev.units + current_disk; + if (io == 0) { + if (current_byte[current_disk] >= DSK_SECTSIZE) { + /* physically read the sector */ + if (trace_level & TRACE_READ_WRITE) { + MESSAGE_4("IN 0x0a (READ) D%d T%d S%d", current_disk, current_track[current_disk], current_sector[current_disk]); + } + for (i = 0; i < DSK_SECTSIZE; i++) + dskbuf[i] = 0; + dskseek(uptr); + fread(dskbuf, DSK_SECTSIZE, 1, uptr -> fileref); + current_byte[current_disk] = 0; + } + return dskbuf[current_byte[current_disk]++] & 0xff; + } + else { + if (current_byte[current_disk] >= DSK_SECTSIZE) + writebuf(); /* from above we have that current_disk < NUM_OF_DSK */ + else { + dirty = TRUE; /* this guarantees for the next call to writebuf that current_disk < NUM_OF_DSK */ + dskbuf[current_byte[current_disk]++] = data & 0xff; + } + return 0; /* ignored since OUT */ + } +} diff --git a/AltairZ80/altairZ80_sio.c b/AltairZ80/altairZ80_sio.c index 4dbb07ad..201dddd0 100644 --- a/AltairZ80/altairZ80_sio.c +++ b/AltairZ80/altairZ80_sio.c @@ -1,6 +1,6 @@ /* altairz80_sio.c: MITS Altair serial I/O card - Copyright (c) 2002-2007, Peter Schorn + Copyright (c) 2002-2008, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -62,28 +62,36 @@ #include #endif -#define UNIT_V_ANSI (UNIT_V_UF + 0) /* ANSI mode, strip bit 8 on output */ -#define UNIT_ANSI (1 << UNIT_V_ANSI) -#define UNIT_V_UPPER (UNIT_V_UF + 1) /* upper case mode */ -#define UNIT_UPPER (1 << UNIT_V_UPPER) -#define UNIT_V_BS (UNIT_V_UF + 2) /* map delete to backspace */ -#define UNIT_BS (1 << UNIT_V_BS) +#define UNIT_V_SIO_ANSI (UNIT_V_UF + 0) /* ANSI mode, strip bit 8 on output */ +#define UNIT_SIO_ANSI (1 << UNIT_V_SIO_ANSI) +#define UNIT_V_SIO_UPPER (UNIT_V_UF + 1) /* upper case mode */ +#define UNIT_SIO_UPPER (1 << UNIT_V_SIO_UPPER) +#define UNIT_V_SIO_BS (UNIT_V_UF + 2) /* map delete to backspace */ +#define UNIT_SIO_BS (1 << UNIT_V_SIO_BS) #define UNIT_V_SIO_VERBOSE (UNIT_V_UF + 3) /* verbose mode, i.e. show error messages */ #define UNIT_SIO_VERBOSE (1 << UNIT_V_SIO_VERBOSE) -#define UNIT_V_MAP (UNIT_V_UF + 4) /* mapping mode on */ -#define UNIT_MAP (1 << UNIT_V_MAP) -#define UNIT_V_BELL (UNIT_V_UF + 5) /* ^G (bell character) rings bell */ -#define UNIT_BELL (1 << UNIT_V_BELL) +#define UNIT_V_SIO_MAP (UNIT_V_UF + 4) /* mapping mode on */ +#define UNIT_SIO_MAP (1 << UNIT_V_SIO_MAP) +#define UNIT_V_SIO_BELL (UNIT_V_UF + 5) /* ^G (bell character) rings bell */ +#define UNIT_SIO_BELL (1 << UNIT_V_SIO_BELL) +#define UNIT_V_SIO_INTERRUPT (UNIT_V_UF + 6) /* create keyboard interrupts */ +#define UNIT_SIO_INTERRUPT (1 << UNIT_V_SIO_INTERRUPT) +#define UNIT_V_SIO_SLEEP (UNIT_V_UF + 7) /* sleep after keyboard status check */ +#define UNIT_SIO_SLEEP (1 << UNIT_V_SIO_SLEEP) #define UNIT_V_SIMH_VERBOSE (UNIT_V_UF + 0) /* verbose mode for SIMH pseudo device */ #define UNIT_SIMH_VERBOSE (1 << UNIT_V_SIMH_VERBOSE) #define UNIT_V_SIMH_TIMERON (UNIT_V_UF + 1) /* SIMH pseudo device timer generate interrupts */ -#define UNIT_SIMH_TIMERON (1 << UNIT_V_SIMH_VERBOSE) +#define UNIT_SIMH_TIMERON (1 << UNIT_V_SIMH_TIMERON) #define TERMINALS 4 /* lines per mux */ #define SIO_CAN_READ 0x01 /* bit 0 is set iff character available */ #define SIO_CAN_WRITE 0x02 /* bit 1 is set iff character can be sent */ #define SIO_RESET 0x03 /* Command to reset SIO */ +#define VGSIO_CAN_READ 0x02 /* bit 1 is set iff character available */ +#define VGSIO_CAN_WRITE 0x01 /* bit 0 is set iff character can be sent */ +#define KBD_HAS_CHAR 0x40 /* bit 6 is set iff character available */ +#define KBD_HAS_NO_CHAR 0x01 /* bit 0 is set iff no character is available */ #define BACKSPACE_CHAR 0x08 /* backspace character */ #define DELETE_CHAR 0x7f /* delete character */ @@ -91,6 +99,9 @@ #define CONTROLG_CHAR 0x07 /* control G char., rings bell when displayed */ #define CONTROLZ_CHAR 0x1a /* control Z character */ +#define PORT_TABLE_SIZE 256 /* size of port mapping table */ +#define SLEEP_ALLOWED_START_DEFAULT 100 /* default initial value for sleepAllowedCounter*/ + static t_stat sio_set_verbose (UNIT *uptr, int32 value, char *cptr, void *desc); static t_stat simh_dev_set_timeron (UNIT *uptr, int32 value, char *cptr, void *desc); static t_stat simh_dev_set_timeroff (UNIT *uptr, int32 value, char *cptr, void *desc); @@ -99,6 +110,12 @@ static t_stat sio_attach(UNIT *uptr, char *cptr); static t_stat sio_detach(UNIT *uptr); static t_stat ptr_reset(DEVICE *dptr); static t_stat ptp_reset(DEVICE *dptr); +static t_stat toBool(char tf, int *result); +static t_stat sio_dev_set_port(UNIT *uptr, int32 value, char *cptr, void *desc); +static t_stat sio_dev_show_port(FILE *st, UNIT *uptr, int32 val, void *desc); +static t_stat sio_dev_set_interrupton(UNIT *uptr, int32 value, char *cptr, void *desc); +static t_stat sio_dev_set_interruptoff(UNIT *uptr, int32 value, char *cptr, void *desc); +static t_stat sio_svc(UNIT *uptr); static t_stat simh_dev_reset(DEVICE *dptr); static t_stat simh_svc(UNIT *uptr); int32 nulldev (const int32 port, const int32 io, const int32 data); @@ -109,15 +126,23 @@ int32 sio0s (const int32 port, const int32 io, const int32 data); int32 sio1d (const int32 port, const int32 io, const int32 data); int32 sio1s (const int32 port, const int32 io, const int32 data); void printMessage(void); +void do_SIMH_sleep(void); +static void pollConnection(void); +static int32 mapCharacter(int32 ch); +static void checkSleep(void); +static void voidSleep(void); extern int32 getBankSelect(void); extern void setBankSelect(const int32 b); extern uint32 getCommon(void); extern uint8 GetBYTEWrapper(const uint32 Addr); +extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, + int32 (*routine)(const int32, const int32, const int32), uint8 unmap); -extern t_bool rtc_avail; +extern int32 chiptype; +extern const t_bool rtc_avail; extern FILE *sim_log; -extern int32 PCX; +extern uint32 PCX; extern int32 sim_switches; extern const char *scp_error_messages[]; extern int32 SR; @@ -157,10 +182,12 @@ static int32 markTimeSP = 0; /* stack pointer for timer stack #if defined (_WIN32) static uint32 SIMHSleep = 1000; /* Sleep uses milliseconds */ #elif defined (__MWERKS__) && defined (macintosh) -static uint32 SIMHSleep = 0; /* No sleep on Macintosh OS9 */ +static uint32 SIMHSleep = 0; /* no sleep on Macintosh OS9 */ #else static uint32 SIMHSleep = 100; /* on other platforms 100 micro seconds is good enough */ #endif +static uint32 sleepAllowedCounter = 0; /* only sleep on no character available when == 0 */ +static uint32 sleepAllowedStart = SLEEP_ALLOWED_START_DEFAULT; /* default start for above counter */ /* miscellaneous */ static int32 versionPos = 0; /* determines state for sending device identifier */ @@ -168,7 +195,7 @@ static int32 lastCPMStatus = 0; /* result of last attachCPM comm static int32 lastCommand = 0; /* most recent command processed on port 0xfeh */ static int32 getCommonPos = 0; /* determines state for sending the 'common' register */ -/* Support for wild card expansion */ +/* support for wild card expansion */ #if UNIX_PLATFORM static glob_t globS; static uint32 globPosNameList = 0; @@ -194,6 +221,9 @@ static int32 warnPTREOF = 0; /* display a warning message if static int32 warnUnassignedPort = 0; /* display a warning message if < warnLevel and SIO set to VERBOSE and attempt to perform IN or OUT on an unassigned PORT */ + int32 keyboardInterrupt = FALSE; /* keyboard interrupt pending */ + uint32 keyboardInterruptHandler = 0x0038;/* address of keyboard interrupt handler */ + static TMLN TerminalLines[TERMINALS] = { /* four terminals */ { 0 } }; @@ -203,8 +233,8 @@ static TMXR altairTMXR = { /* mux descriptor */ }; static UNIT sio_unit = { - UDATA (NULL, UNIT_ATTABLE + UNIT_MAP, 0), - 0, /* wait = 0 */ + UDATA (&sio_svc, UNIT_ATTABLE | UNIT_SIO_MAP | UNIT_SIO_SLEEP, 0), + 100000, /* wait */ FALSE, /* u3 = FALSE, no character available in buffer */ FALSE, /* u4 = FALSE, terminal input is not attached to a file */ FALSE, /* u5 = FALSE, terminal input has not yet reached EOF */ @@ -221,23 +251,32 @@ static REG sio_reg[] = { { HRDATA (FILEEOF, sio_unit.u5, 8), REG_RO }, /* TRUE iff terminal input file has reached EOF */ { HRDATA (TSTATUS, sio_unit.u3, 8) }, /* TRUE iff a character available in sio_unit.buf */ { DRDATA (TBUFFER, sio_unit.buf, 8) }, /* input buffer for one character */ + { DRDATA (KEYBDI, keyboardInterrupt, 3), REG_RO }, + { HRDATA (KEYBDH, keyboardInterruptHandler, 16) }, { NULL } }; static MTAB sio_mod[] = { - { UNIT_ANSI, 0, "TTY", "TTY", NULL }, /* keep bit 8 as is for output */ - { UNIT_ANSI, UNIT_ANSI, "ANSI", "ANSI", NULL }, /* set bit 8 to 0 before output */ - { UNIT_UPPER, 0, "ALL", "ALL", NULL }, /* do not change case of input characters */ - { UNIT_UPPER, UNIT_UPPER, "UPPER", "UPPER", NULL }, /* change input characters to upper case */ - { UNIT_BS, 0, "BS", "BS", NULL }, /* map delete to backspace */ - { UNIT_BS, UNIT_BS, "DEL", "DEL", NULL }, /* map backspace to delete */ - { UNIT_SIO_VERBOSE, 0, "QUIET", "QUIET", NULL }, /* quiet, no error messages */ - { UNIT_SIO_VERBOSE, UNIT_SIO_VERBOSE, "VERBOSE", "VERBOSE", &sio_set_verbose }, - /* verbose, display warning messages */ - { UNIT_MAP, 0, "NOMAP", "NOMAP", NULL }, /* disable character mapping */ - { UNIT_MAP, UNIT_MAP, "MAP", "MAP", NULL }, /* enable all character mapping */ - { UNIT_BELL, 0, "BELL", "BELL", NULL }, /* enable bell character */ - { UNIT_BELL, UNIT_BELL, "NOBELL", "NOBELL", NULL }, /* suppress ringing the bell */ + { UNIT_SIO_ANSI, 0, "TTY", "TTY", NULL }, /* keep bit 8 as is for output */ + { UNIT_SIO_ANSI, UNIT_SIO_ANSI, "ANSI", "ANSI", NULL }, /* set bit 8 to 0 before output */ + { UNIT_SIO_UPPER, 0, "ALL", "ALL", NULL }, /* do not change case of input characters */ + { UNIT_SIO_UPPER, UNIT_SIO_UPPER, "UPPER", "UPPER", NULL }, /* change input characters to upper case */ + { UNIT_SIO_BS, 0, "BS", "BS", NULL }, /* map delete to backspace */ + { UNIT_SIO_BS, UNIT_SIO_BS, "DEL", "DEL", NULL }, /* map backspace to delete */ + { UNIT_SIO_VERBOSE, 0, "QUIET", "QUIET", NULL }, /* quiet, no error messages */ + { UNIT_SIO_VERBOSE, UNIT_SIO_VERBOSE, "VERBOSE", "VERBOSE", &sio_set_verbose }, + /* verbose, display warning messages */ + { UNIT_SIO_MAP, 0, "NOMAP", "NOMAP", NULL }, /* disable character mapping */ + { UNIT_SIO_MAP, UNIT_SIO_MAP, "MAP", "MAP", NULL }, /* enable all character mapping */ + { UNIT_SIO_BELL, 0, "BELL", "BELL", NULL }, /* enable bell character */ + { UNIT_SIO_BELL, UNIT_SIO_BELL, "NOBELL", "NOBELL", NULL }, /* suppress ringing the bell */ + { UNIT_SIO_SLEEP, 0, "NOSLEEP", "NOSLEEP", NULL }, /* no sleep after keyboard status check */ + { UNIT_SIO_SLEEP, UNIT_SIO_SLEEP, "SLEEP", "SLEEP", NULL }, /* sleep after keyboard status check */ + /* no keyboard interrupts */ + { UNIT_SIO_INTERRUPT, 0, "NOINTERRUPT","NOINTERRUPT",&sio_dev_set_interruptoff }, + /* create keyboard interrupts */ + { UNIT_SIO_INTERRUPT, UNIT_SIO_INTERRUPT, "INTERRUPT","INTERRUPT",&sio_dev_set_interrupton }, + { MTAB_XTD|MTAB_VDV|MTAB_VAL, 0, "PORT", "PORT", &sio_dev_set_port, &sio_dev_show_port }, { 0 } }; @@ -250,7 +289,7 @@ DEVICE sio_dev = { NULL, NULL, NULL }; static UNIT ptr_unit = { - UDATA (NULL, UNIT_SEQ + UNIT_ATTABLE + UNIT_ROABLE, 0) + UDATA (NULL, UNIT_SEQ | UNIT_ATTABLE | UNIT_ROABLE, 0) }; static REG ptr_reg[] = { @@ -305,6 +344,7 @@ static REG simh_reg[] = { { DRDATA (TIMD, timerDelta, 32) }, { DRDATA (STDP, setTimerDeltaPos, 8), REG_RO }, { DRDATA (SLEEP, SIMHSleep, 32) }, + { DRDATA (VOSLP, sleepAllowedStart, 32) }, { DRDATA (STPDT, stopWatchDelta, 32), REG_RO }, { DRDATA (STPOS, getStopWatchDeltaPos, 8), REG_RO }, @@ -343,13 +383,7 @@ char messageBuffer[256] = { 0 }; void printMessage(void) { printf(messageBuffer); -#if UNIX_PLATFORM -/* need to make sure that carriage return is executed - ttrunstate() of scp_tty.c - has disabled \n translation */ - printf("\r\n"); -#else - printf("\n"); -#endif + printf(NLP); if (sim_log) { fprintf(sim_log, messageBuffer); fprintf(sim_log,"\n"); @@ -426,6 +460,20 @@ static t_stat ptp_reset(DEVICE *dptr) { return SCPE_OK; } +static int32 mapCharacter(int32 ch) { + ch &= 0xff; + if (sio_unit.flags & UNIT_SIO_MAP) { + if (sio_unit.flags & UNIT_SIO_BS) { + if (ch == BACKSPACE_CHAR) + return DELETE_CHAR; + } + else if (ch == DELETE_CHAR) + return BACKSPACE_CHAR; + if (sio_unit.flags & UNIT_SIO_UPPER) + return toupper(ch); + } + return ch; +} /* I/O instruction handlers, called from the CPU module when an IN or OUT instruction is issued. @@ -441,72 +489,105 @@ static t_stat ptp_reset(DEVICE *dptr) { 3) SIO not attached to a port (i.e. "regular" console I/O ) */ -int32 sio0s(const int32 port, const int32 io, const int32 data) { - int32 ti = 0, ch; - pollConnection(); - if (port != 0x10) { /* 0x10 is default port with ti == 0 */ - if (port == 0x14) ti = 1; - else if (port == 0x16) ti = 2; - else if (port == 0x18) ti = 3; - else assert(FALSE); +typedef struct { + int32 port; /* this information belongs to port number 'port' */ + int32 terminalLine; /* map to this 'terminalLine' */ + int32 sio_can_read; /* bit mask to indicate that one can read from this port */ + int32 sio_cannot_read; /* bit mask to indicate that one cannot read from this port */ + int32 sio_can_write; /* bit mask to indicate that one can write to this port */ + int32 hasReset; /* TRUE iff SIO has reset command */ + int32 sio_reset; /* reset command */ + int32 hasOUT; /* TRUE iff port supports OUT command */ + int32 isBuiltin; /* TRUE iff mapping is built in */ +} SIO_PORT_INFO; + +static SIO_PORT_INFO port_table[PORT_TABLE_SIZE] = { + {0x00, 0, KBD_HAS_CHAR, KBD_HAS_NO_CHAR, SIO_CAN_WRITE, FALSE, 0, FALSE, TRUE }, + {0x01, 0, 0, 0, 0, FALSE, 0, FALSE, TRUE }, + {0x02, 0, VGSIO_CAN_READ, 0, VGSIO_CAN_WRITE, FALSE, 0, TRUE, TRUE }, + {0x03, 0, VGSIO_CAN_READ, 0, VGSIO_CAN_WRITE, FALSE, 0, FALSE, TRUE }, + {0x10, 0, SIO_CAN_READ, 0, SIO_CAN_WRITE, TRUE, SIO_RESET, FALSE, TRUE }, + {0x14, 1, SIO_CAN_READ, 0, SIO_CAN_WRITE, TRUE, SIO_RESET, FALSE, TRUE }, + {0x16, 2, SIO_CAN_READ, 0, SIO_CAN_WRITE, TRUE, SIO_RESET, FALSE, TRUE }, + {0x18, 3, SIO_CAN_READ, 0, SIO_CAN_WRITE, TRUE, SIO_RESET, FALSE, TRUE }, + {0x11, 0, SIO_CAN_READ, 0, SIO_CAN_WRITE, TRUE, SIO_RESET, TRUE, TRUE }, + {0x15, 1, SIO_CAN_READ, 0, SIO_CAN_WRITE, TRUE, SIO_RESET, TRUE, TRUE }, + {0x17, 2, SIO_CAN_READ, 0, SIO_CAN_WRITE, TRUE, SIO_RESET, TRUE, TRUE }, + {0x19, 3, SIO_CAN_READ, 0, SIO_CAN_WRITE, TRUE, SIO_RESET, TRUE, TRUE }, + {-1, 0, 0, 0, 0, 0, 0, 0, 0} /* must be last */ +}; + +static SIO_PORT_INFO lookupPortInfo(const int32 port, int32 *position) { + int32 i = 0; + while ((port_table[i].port != -1) && (port_table[i].port != port)) i++; + *position = i; + return port_table[i]; +} + +/* keyboard idle detection: sleep when feature enabled, no character available + (duty of caller) and operation not voided (e.g. when output is available) */ +static void checkSleep(void) { + if (sio_unit.flags & UNIT_SIO_SLEEP) { + if (sleepAllowedCounter) sleepAllowedCounter--; + else do_SIMH_sleep(); } +} + +/* void sleep for next 'sleepAllowedStart' tests */ +static void voidSleep(void) { + sleepAllowedCounter = sleepAllowedStart; +} + +/* generic status port for keyboard input / terminal output */ +int32 sio0s(const int32 port, const int32 io, const int32 data) { + int32 ch, result; + SIO_PORT_INFO spi = lookupPortInfo(port, &ch); + assert(spi.port == port); + pollConnection(); if (io == 0) { /* IN */ - if (sio_unit.u4) { /* attached to a file? */ + if (sio_unit.u4) /* attached to a file? */ if (sio_unit.u5) /* EOF reached? */ sio_detach(&sio_unit); /* detach file and switch to keyboard input */ - else return SIO_CAN_READ | SIO_CAN_WRITE; - } + else return spi.sio_can_read | spi.sio_can_write; if (sio_unit.flags & UNIT_ATT) { /* attached to a port? */ - return (tmxr_rqln(&TerminalLines[ti]) ? SIO_CAN_READ : 0x00) | - /* read possible if character available */ - (TerminalLines[ti].conn && TerminalLines[ti].xmte ? SIO_CAN_WRITE : 0x00); + if (tmxr_rqln(&TerminalLines[spi.terminalLine])) + result = spi.sio_can_read; + else { + result = spi.sio_cannot_read; + checkSleep(); + } + return result | /* read possible if character available */ + (TerminalLines[spi.terminalLine].conn && TerminalLines[spi.terminalLine].xmte ? spi.sio_can_write : 0x00); /* write possible if connected and transmit enabled */ } if (sio_unit.u3) /* character available? */ - return SIO_CAN_READ | SIO_CAN_WRITE; + return spi.sio_can_read | spi.sio_can_write; ch = sim_poll_kbd(); /* no, try to get a character */ if (ch) { /* character available? */ if (ch == SCPE_STOP) { /* stop CPU in case ^E (default) was typed */ stop_cpu = TRUE; sim_interval = 0; /* detect stop condition as soon as possible*/ - return SIO_CAN_WRITE; /* do not consume stop character */ + return spi.sio_can_write | spi.sio_cannot_read; /* do not consume stop character */ } sio_unit.u3 = TRUE; /* indicate character available */ sio_unit.buf = ch; /* store character in buffer */ - return SIO_CAN_READ | SIO_CAN_WRITE; + return spi.sio_can_read | spi.sio_can_write; } - return SIO_CAN_WRITE; - } /* OUT follows */ - if (data == SIO_RESET) /* reset command */ + checkSleep(); + return spi.sio_can_write | spi.sio_cannot_read; + } /* OUT follows, no fall-through from IN */ + if (spi.hasReset && (data == spi.sio_reset)) /* reset command */ sio_unit.u3 = FALSE; /* indicate that no character is available */ return 0x00; /* ignored since OUT */ } -static int32 mapCharacter(int32 ch) { - ch &= 0xff; - if (sio_unit.flags & UNIT_MAP) { - if (sio_unit.flags & UNIT_BS) { - if (ch == BACKSPACE_CHAR) - return DELETE_CHAR; - } - else if (ch == DELETE_CHAR) - return BACKSPACE_CHAR; - if (sio_unit.flags & UNIT_UPPER) - return toupper(ch); - } - return ch; -} - +/* generic data port for keyboard input / terminal output */ int32 sio0d(const int32 port, const int32 io, const int32 data) { - int32 ti = 0, ch; + int32 ch; + SIO_PORT_INFO spi = lookupPortInfo(port, &ch); + assert(spi.port == port); pollConnection(); - if (port != 0x11) { /* 0x11 is default port with ti == 0 */ - if (port == 0x15) ti = 1; - else if (port == 0x17) ti = 2; - else if (port == 0x19) ti = 3; - else assert(FALSE); - } if (io == 0) { /* IN */ if (sio_unit.u4) { /* attached to a file? */ if (sio_unit.u5) { /* EOF reached? */ @@ -520,16 +601,19 @@ int32 sio0d(const int32 port, const int32 io, const int32 data) { return mapCharacter(ch); /* return mapped character */ } if (sio_unit.flags & UNIT_ATT) - return mapCharacter(tmxr_getc_ln(&TerminalLines[ti])); + return mapCharacter(tmxr_getc_ln(&TerminalLines[spi.terminalLine])); sio_unit.u3 = FALSE; /* no character is available any more */ return mapCharacter(sio_unit.buf); /* return previous character */ - } /* OUT follows */ - ch = sio_unit.flags & UNIT_ANSI ? data & 0x7f : data; /* clear highest bit in ANSI mode */ - if ((ch != CONTROLG_CHAR) || !(sio_unit.flags & UNIT_BELL)) { - if ((sio_unit.flags & UNIT_ATT) && (!sio_unit.u4)) /* attached to a port and not to a file */ - tmxr_putc_ln(&TerminalLines[ti], ch); /* status ignored */ - else - sim_putchar(ch); + } /* OUT follows, no fall-through from IN */ + if (spi.hasOUT) { + ch = sio_unit.flags & UNIT_SIO_ANSI ? data & 0x7f : data; /* clear highest bit in ANSI mode */ + if ((ch != CONTROLG_CHAR) || !(sio_unit.flags & UNIT_SIO_BELL)) { + voidSleep(); + if ((sio_unit.flags & UNIT_ATT) && (!sio_unit.u4)) /* attached to a port and not to a file */ + tmxr_putc_ln(&TerminalLines[spi.terminalLine], ch); /* status ignored */ + else + sim_putchar(ch); + } } return 0x00; /* ignored since OUT */ } @@ -543,7 +627,7 @@ int32 sio1s(const int32 port, const int32 io, const int32 data) { if ((ptr_unit.flags & UNIT_ATT) == 0) { /* PTR is not attached */ if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnattachedPTR < warnLevelSIO)) { warnUnattachedPTR++; -/*06*/ MESSAGE_1("Attempt to test status of unattached PTR. 0x02 returned."); +/*06*/ MESSAGE_2("Attempt to test status of unattached PTR[0x%02x]. 0x02 returned.", port); } return SIO_CAN_WRITE; } @@ -563,14 +647,14 @@ int32 sio1d(const int32 port, const int32 io, const int32 data) { if (ptr_unit.u3) { /* EOF reached, no more data available */ if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnPTREOF < warnLevelSIO)) { warnPTREOF++; -/*07*/ MESSAGE_1("PTR attempted to read past EOF. 0x00 returned."); +/*07*/ MESSAGE_2("PTR[0x%02x] attempted to read past EOF. 0x00 returned.", port); } return 0x00; } if ((ptr_unit.flags & UNIT_ATT) == 0) { /* not attached */ if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnattachedPTR < warnLevelSIO)) { warnUnattachedPTR++; -/*08*/ MESSAGE_1("Attempt to read from unattached PTR. 0x00 returned."); +/*08*/ MESSAGE_2("Attempt to read from unattached PTR[0x%02x]. 0x00 returned.", port); } return 0x00; } @@ -585,19 +669,146 @@ int32 sio1d(const int32 port, const int32 io, const int32 data) { /* else ignore data */ else if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnattachedPTP < warnLevelSIO)) { warnUnattachedPTP++; -/*09*/ MESSAGE_2("Attempt to output '0x%02x' to unattached PTP - ignored.", data); +/*09*/ MESSAGE_3("Attempt to output '0x%02x' to unattached PTP[0x%02x] - ignored.", data, port); } return 0x00; /* ignored since OUT */ } +static t_stat toBool(char tf, int *result) { + if (tf == 'T') { + *result = TRUE; + return SCPE_OK; + } + if (tf == 'F') { + *result = FALSE; + return SCPE_OK; + } + return SCPE_ARG; +} + +static void show_sio_port_info(FILE *st, SIO_PORT_INFO sip) { + if (sio_unit.flags & UNIT_SIO_VERBOSE) + fprintf(st, "(Port=%02x/Terminal=%1i/Read=0x%02x/NotRead=0x%02x/" + "Write=0x%02x/Reset?=%s/Reset=0x%02x/Data?=%s)", + sip.port, sip.terminalLine, sip.sio_can_read, sip.sio_cannot_read, + sip.sio_can_write, sip.hasReset ? "True" : "False", sip.sio_reset, + sip.hasOUT ? "True" : "False"); + else + fprintf(st, "(%02x/%1i/%02x/%02x/%02x/%s/%02x/%s)", + sip.port, sip.terminalLine, sip.sio_can_read, sip.sio_cannot_read, + sip.sio_can_write, sip.hasReset ? "T" : "F", sip.sio_reset, + sip.hasOUT ? "T" : "F"); +} + +static uint32 equalSIP(SIO_PORT_INFO x, SIO_PORT_INFO y) { + /* isBuiltin is not relevant for equality, only for display */ + return (x.port == y.port) && (x.terminalLine == y.terminalLine) && + (x.sio_can_read == y.sio_can_read) && (x.sio_cannot_read == y.sio_cannot_read) && + (x.sio_can_write == y.sio_can_write) && (x.hasReset == y.hasReset) && + (x.sio_reset == y.sio_reset) && (x.hasOUT == y.hasOUT); +} + +static t_stat sio_dev_set_port(UNIT *uptr, int32 value, char *cptr, void *desc) { + int32 result, n, position; + SIO_PORT_INFO sip = { 0 }, old; + char hasReset, hasOUT; + if (cptr == NULL) return SCPE_ARG; + result = sscanf(cptr, "%x%n", &sip.port, &n); + if ((result == 1) && (cptr[n] == 0)) { + old = lookupPortInfo(sip.port, &position); + if (old.port == -1) { + printf("No mapping for port 0x%02x exists - cannot remove.\n", sip.port); + return SCPE_ARG; + } + do { + port_table[position] = port_table[position + 1]; + position++; + } + while (port_table[position].port != -1); + sim_map_resource(sip.port, 1, RESOURCE_TYPE_IO, &nulldev, FALSE); + if (sio_unit.flags & UNIT_SIO_VERBOSE) { + printf("Removing mapping for port 0x%02x.\n\t", sip.port); + show_sio_port_info(stdout, old); + } + return SCPE_OK; + } + result = sscanf(cptr, "%x/%d/%x/%x/%x/%1c/%x/%1c%n", &sip.port, + &sip.terminalLine, &sip.sio_can_read, &sip.sio_cannot_read, + &sip.sio_can_write, &hasReset, &sip.sio_reset, &hasOUT, &n); + if ((result != 8) || (result == EOF) || (cptr[n] != 0)) return SCPE_ARG; + result = toBool(hasReset, &sip.hasReset); + if (result != SCPE_OK) return result; + result = toBool(hasOUT, &sip.hasOUT); + if (result != SCPE_OK) return result; + if (sip.port != (sip.port & 0xff)) { + printf("Truncating port 0x%x to 0x%02x.\n", sip.port, sip.port & 0xff); + sip.port &= 0xff; + } + old = lookupPortInfo(sip.port, &position); + if (old.port == sip.port) { + if (sio_unit.flags & UNIT_SIO_VERBOSE) { + printf("Replacing mapping for port 0x%02x.\n\t", sip.port); + show_sio_port_info(stdout, old); + printf("-> "); + show_sio_port_info(stdout, sip); + if (equalSIP(sip, old)) printf("[identical]"); + } + } + else { + port_table[position + 1] = old; + if (sio_unit.flags & UNIT_SIO_VERBOSE) { + printf("Adding mapping for port 0x%02x.\n\t", sip.port); + show_sio_port_info(stdout, sip); + } + } + if (sio_unit.flags & UNIT_SIO_VERBOSE) printf("\n"); + port_table[position] = sip; + sim_map_resource(sip.port, 1, RESOURCE_TYPE_IO, (sip.hasOUT || + (sip.sio_can_read == 0) && (sip.sio_cannot_read == 0) && + (sip.sio_can_write == 0)) ? &sio0d : &sio0s, FALSE); + return SCPE_OK; +} + +static t_stat sio_dev_show_port(FILE *st, UNIT *uptr, int32 val, void *desc) { + int32 i, first = TRUE; + for (i = 0; port_table[i].port != -1; i++) + if (!port_table[i].isBuiltin) { + if (first) first = FALSE; + else fprintf(st, " "); + show_sio_port_info(st, port_table[i]); + } + if (first) fprintf(st, "no extra port"); + return SCPE_OK; +} + +static t_stat sio_dev_set_interrupton(UNIT *uptr, int32 value, char *cptr, void *desc) { + keyboardInterrupt = FALSE; + return sim_activate(&sio_unit, sio_unit.wait); /* activate unit */ +} + +static t_stat sio_dev_set_interruptoff(UNIT *uptr, int32 value, char *cptr, void *desc) { + keyboardInterrupt = FALSE; + sim_cancel(&sio_unit); + return SCPE_OK; +} + +static t_stat sio_svc(UNIT *uptr) { + if (sio0s(0, 0, 0) & KBD_HAS_CHAR) { + keyboardInterrupt = TRUE; + } + if (sio_unit.flags & UNIT_SIO_INTERRUPT) + sim_activate(&sio_unit, sio_unit.wait); /* activate unit */ + return SCPE_OK; +} + int32 nulldev(const int32 port, const int32 io, const int32 data) { if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnassignedPort < warnLevelSIO)) { warnUnassignedPort++; if (io == 0) { - MESSAGE_2("Unassigned IN(%2xh) - ignored.", port); + MESSAGE_2("Attempt to input from unassigned port 0x%04x - ignored.", port); } else { - MESSAGE_3("Unassigned OUT(%2xh) -> %2xh - ignored.", port, data); + MESSAGE_3("Attempt to output 0x%02x to unassigned port 0x%04x - ignored.", data, port); } } return io == 0 ? 0xff : 0; @@ -711,8 +922,9 @@ static t_stat simh_dev_reset(DEVICE *dptr) { } static void warnNoRealTimeClock(void) { - if (simh_unit.flags & UNIT_SIMH_VERBOSE) - printf("Sorry - no real time clock available.\n"); + if (simh_unit.flags & UNIT_SIMH_VERBOSE) { + MESSAGE_1("Sorry - no real time clock available."); + } } static t_stat simh_dev_set_timeron(UNIT *uptr, int32 value, char *cptr, void *desc) { @@ -762,7 +974,7 @@ static void attachCPM(UNIT *uptr) { lastCPMStatus = attach_unit(uptr, cpmCommandLine); if ((lastCPMStatus != SCPE_OK) && (simh_unit.flags & UNIT_SIMH_VERBOSE)) { MESSAGE_3("Cannot open '%s' (%s).", cpmCommandLine, scp_error_messages[lastCPMStatus - SCPE_BASE]); - /* must keep curly braces as messageX is a macro with two statements */ + /* must keep curly braces as MESSAGE_N is a macro with two statements */ } } @@ -812,7 +1024,7 @@ static int32 simh_in(const int32 port) { case getHostFilenames: #if UNIX_PLATFORM - if (globValid) { + if (globValid) if (globPosNameList < globS.gl_pathc) { if (!(result = globS.gl_pathv[globPosNameList][globPosName++])) { globPosNameList++; @@ -824,12 +1036,10 @@ static int32 simh_in(const int32 port) { lastCommand = 0; globfree(&globS); } - } #elif defined (_WIN32) - if (globValid) { - if (globFinished) { + if (globValid) + if (globFinished) globValid = FALSE; - } else if (!(result = FindFileData.cFileName[globPosName++])) { globPosName = 0; if (!FindNextFile(hFind, &FindFileData)) { @@ -838,7 +1048,6 @@ static int32 simh_in(const int32 port) { hFind = INVALID_HANDLE_VALUE; } } - } #else lastCommand = 0; #endif @@ -852,7 +1061,7 @@ static int32 simh_in(const int32 port) { break; case getClockZSDOSCmd: - if (currentTimeValid) { + if (currentTimeValid) switch(getClockZSDOSPos) { case 0: @@ -886,14 +1095,12 @@ static int32 simh_in(const int32 port) { getClockZSDOSPos = lastCommand = 0; break; } - } - else { + else result = getClockZSDOSPos = lastCommand = 0; - } break; case getClockCPM3Cmd: - if (currentTimeValid) { + if (currentTimeValid) switch(getClockCPM3Pos) { case 0: result = daysCPM3SinceOrg & 0xff; @@ -920,23 +1127,19 @@ static int32 simh_in(const int32 port) { getClockCPM3Pos = lastCommand = 0; break; } - } - else { + else result = getClockCPM3Pos = lastCommand = 0; - } break; case getSIMHVersionCmd: result = version[versionPos++]; - if (result == 0) { + if (result == 0) versionPos = lastCommand = 0; - } break; case getBankSelectCmd: - if (cpu_unit.flags & UNIT_BANKED) { + if (cpu_unit.flags & UNIT_CPU_BANKED) result = getBankSelect(); - } else { result = 0; if (simh_unit.flags & UNIT_SIMH_VERBOSE) { @@ -958,7 +1161,7 @@ static int32 simh_in(const int32 port) { break; case hasBankedMemoryCmd: - result = cpu_unit.flags & UNIT_BANKED ? MAXBANKS : 0; + result = cpu_unit.flags & UNIT_CPU_BANKED ? MAXBANKS : 0; lastCommand = 0; break; @@ -993,6 +1196,16 @@ static int32 simh_in(const int32 port) { return result; } +void do_SIMH_sleep(void) { +#if defined (_WIN32) + if ((SIMHSleep / 1000) && !sio_unit.u4) /* time to sleep and SIO not attached to a file */ + Sleep(SIMHSleep / 1000); +#else + if (SIMHSleep && !sio_unit.u4) /* time to sleep and SIO not attached to a file */ + usleep(SIMHSleep); +#endif +} + static int32 simh_out(const int32 port, const int32 data) { time_t now; switch(lastCommand) { @@ -1022,9 +1235,8 @@ static int32 simh_out(const int32 port, const int32 data) { break; case setBankSelectCmd: - if (cpu_unit.flags & UNIT_BANKED) { + if (cpu_unit.flags & UNIT_CPU_BANKED) setBankSelect(data & BANKMASK); - } else if (simh_unit.flags & UNIT_SIMH_VERBOSE) { MESSAGE_2("Set selected bank to %i ignored for non-banked memory.", data & 3); } @@ -1090,13 +1302,7 @@ static int32 simh_out(const int32 port, const int32 data) { break; case SIMHSleepCmd: -#if defined (_WIN32) - if ((SIMHSleep / 1000) && !sio_unit.u4) /* time to sleep and SIO not attached to a file */ - Sleep(SIMHSleep / 1000); -#else - if (SIMHSleep && !sio_unit.u4) /* time to sleep and SIO not attached to a file */ - usleep(SIMHSleep); -#endif + do_SIMH_sleep(); break; case printTimeCmd: /* print time */ @@ -1109,21 +1315,17 @@ static int32 simh_out(const int32 port, const int32 data) { break; case startTimerCmd: /* create a new timer on top of stack */ - if (rtc_avail) { - if (markTimeSP < TIMER_STACK_LIMIT) { + if (rtc_avail) + if (markTimeSP < TIMER_STACK_LIMIT) markTime[markTimeSP++] = sim_os_msec(); - } else { MESSAGE_1("Timer stack overflow."); } - } - else { - warnNoRealTimeClock(); - } + else warnNoRealTimeClock(); break; case stopTimerCmd: /* stop timer on top of stack and show time difference */ - if (rtc_avail) { + if (rtc_avail) if (markTimeSP > 0) { uint32 delta = sim_os_msec() - markTime[--markTimeSP]; MESSAGE_2("Timer stopped. Elapsed time in milliseconds = %d.", delta); @@ -1131,10 +1333,7 @@ static int32 simh_out(const int32 port, const int32 data) { else { MESSAGE_1("No timer active."); } - } - else { - warnNoRealTimeClock(); - } + else warnNoRealTimeClock(); break; case resetPTRCmd: /* reset ptr device */ @@ -1204,7 +1403,7 @@ static int32 simh_out(const int32 port, const int32 data) { break; case showTimerCmd: /* show time difference to timer on top of stack */ - if (rtc_avail) { + if (rtc_avail) if (markTimeSP > 0) { uint32 delta = sim_os_msec() - markTime[markTimeSP - 1]; MESSAGE_2("Timer running. Elapsed in milliseconds = %d.", delta); @@ -1212,10 +1411,7 @@ static int32 simh_out(const int32 port, const int32 data) { else { MESSAGE_1("No timer active."); } - } - else { - warnNoRealTimeClock(); - } + else warnNoRealTimeClock(); break; case attachPTPCmd: /* attach ptp to the file with name at beginning of CP/M command line */ @@ -1227,11 +1423,11 @@ static int32 simh_out(const int32 port, const int32 data) { break; case setZ80CPUCmd: - cpu_unit.flags |= UNIT_CHIP; + chiptype = CHIP_TYPE_Z80; break; case set8080CPUCmd: - cpu_unit.flags &= ~UNIT_CHIP; + chiptype = CHIP_TYPE_8080; break; case startTimerInterruptsCmd: diff --git a/AltairZ80/altairZ80_sys.c b/AltairZ80/altairZ80_sys.c index 45496edb..5b2066cd 100644 --- a/AltairZ80/altairZ80_sys.c +++ b/AltairZ80/altairZ80_sys.c @@ -1,6 +1,6 @@ /* altairz80_sys.c: MITS Altair system interface - Copyright (c) 2002-2007, Peter Schorn + Copyright (c) 2002-2008, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -30,6 +30,8 @@ #include #include "altairz80_defs.h" +#define SIM_EMAX 6 + extern UNIT cpu_unit; extern REG cpu_reg[]; extern DEVICE cpu_dev; @@ -41,8 +43,38 @@ extern DEVICE dsk_dev; extern DEVICE hdsk_dev; extern DEVICE net_dev; -int32 fprint_sym(FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw); -int32 parse_sym(char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw); +extern DEVICE mfdc_dev; +extern DEVICE fw2_dev; +extern DEVICE fif_dev; +extern DEVICE vfdhd_dev; +extern DEVICE mdsad_dev; +extern DEVICE nsfpb_dev; +extern DEVICE disk1a_dev; +extern DEVICE disk2_dev; +extern DEVICE selchan_dev; +extern DEVICE ss1_dev; +extern DEVICE i8272_dev; +extern DEVICE mdriveh_dev; + +extern DEVICE cromfdc_dev; +extern DEVICE wd179x_dev; +extern DEVICE n8vem_dev; +extern DEVICE scp300f_dev; + +#ifdef USE_FPC +extern DEVICE fpc_dev; +#endif /* USE_FPC */ + +extern int32 chiptype; +extern long disasm (unsigned char *data, char *output, int segsize, long offset); + +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw); /* psco */ +t_stat parse_sym(char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw); /* psco */ + +t_stat set_membase(UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat show_membase(FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc); /* SCP data structures sim_name simulator name string @@ -53,10 +85,17 @@ int32 parse_sym(char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw); */ char sim_name[] = "Altair 8800 (Z80)"; -REG *sim_PC = &cpu_reg[0]; -int32 sim_emax = 4; +REG *sim_PC = &cpu_reg[6]; +int32 sim_emax = SIM_EMAX; DEVICE *sim_devices[] = { - &cpu_dev, &sio_dev, &simh_device, &ptr_dev, &ptp_dev, &dsk_dev, &hdsk_dev, &net_dev, NULL + &cpu_dev, &sio_dev, &simh_device, &ptr_dev, &ptp_dev, &dsk_dev, + &hdsk_dev, &net_dev, &mfdc_dev, &fw2_dev, &fif_dev, &vfdhd_dev, &mdsad_dev, + &disk1a_dev, &disk2_dev, &selchan_dev, &ss1_dev, &i8272_dev, &mdriveh_dev, + &cromfdc_dev, &wd179x_dev, &n8vem_dev, &scp300f_dev, +#ifdef USE_FPC + &fpc_dev, +#endif /* USE_FPC */ + NULL }; char memoryAccessMessage[80]; @@ -101,7 +140,7 @@ static char *const Mnemonics8080[] = { "RPE", "PCHL", "JPE #h", "XCHG", "CPE #h", "DB EDh", "XRI *h", "RST 5", /* e8-ef */ "RP", "POP PSW", "JP #h", "DI", "CP #h", "PUSH PSW", "ORI *h", "RST 6", /* f0-f7 */ "RM", "SPHL", "JM #h", "EI", "CM #h", "DB FDh", "CPI *h", "RST 7" /* f8-ff */ - }; +}; static char *const MnemonicsZ80[256] = { /* 0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ @@ -303,7 +342,7 @@ static int32 DAsm(char *S, const uint32 *val, const int32 useZ80Mnemonics, const uint8 J = 0, Offset = 0; uint16 B = 0; - if (useZ80Mnemonics) { + if (useZ80Mnemonics) switch(val[B]) { case 0xcb: @@ -326,18 +365,13 @@ static int32 DAsm(char *S, const uint32 *val, const int32 useZ80Mnemonics, const J = 1; T = MnemonicsXCB[val[B++]]; } - else { - T = MnemonicsXX[val[B++]]; - } + else T = MnemonicsXX[val[B++]]; break; default: T = MnemonicsZ80[val[B++]]; } - } - else { - T = Mnemonics8080[val[B++]]; - } + else T = Mnemonics8080[val[B++]]; if ( (P = strchr(T, '^')) ) { strncpy(R, T, P - T); @@ -346,14 +380,10 @@ static int32 DAsm(char *S, const uint32 *val, const int32 useZ80Mnemonics, const strcat(R, H); strcat(R, P + 1); } - else { - strcpy(R, T); - } + else strcpy(R, T); if ( (P = strchr(R, '%')) ) { *P = C; - if ( (P = strchr(P + 1, '%')) ) { - *P = C; - } + if ( (P = strchr(P + 1, '%')) ) *P = C; } if ( (P = strchr(R, '*')) ) { @@ -366,9 +396,7 @@ static int32 DAsm(char *S, const uint32 *val, const int32 useZ80Mnemonics, const else if ( (P = strchr(R, '@')) ) { strncpy(S, R, P - R); S[P - R] = '\0'; - if (!J) { - Offset = val[B++]; - } + if (!J) Offset = val[B++]; strcat(S, Offset & 0x80 ? "-" : "+"); J = Offset & 0x80 ? 256 - Offset : Offset; sprintf(H, "%02X", J); @@ -379,7 +407,7 @@ static int32 DAsm(char *S, const uint32 *val, const int32 useZ80Mnemonics, const strncpy(S, R, P - R); S[P - R] = '\0'; Offset = val[B++]; - sprintf(H, "%04X", addr + 2 + (Offset & 0x80 ? (Offset - 256) : Offset)); + sprintf(H, "%04X", (addr + 2 + (Offset & 0x80 ? (Offset - 256) : Offset)) & 0xFFFF); strcat(S, H); strcat(S, P + 1); } @@ -391,9 +419,7 @@ static int32 DAsm(char *S, const uint32 *val, const int32 useZ80Mnemonics, const strcat(S, P + 1); B += 2; } - else { - strcpy(S, R); - } + else strcpy(S, R); return(B); } @@ -409,61 +435,52 @@ static int32 DAsm(char *S, const uint32 *val, const int32 useZ80Mnemonics, const status = error code */ -int32 fprint_sym(FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw) { - char disasm[128]; +t_stat fprint_sym(FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) { + char disasm_result[128]; int32 ch = val[0] & 0x7f; + long r; + unsigned char vals[SIM_EMAX]; + int32 i; if (sw & (SWMASK('A') | SWMASK('C'))) { fprintf(of, ((0x20 <= ch) && (ch < 0x7f)) ? "'%c'" : "%02x", ch); return SCPE_OK; } - if (!(sw & SWMASK('M'))) { - return SCPE_ARG; + if (!(sw & SWMASK('M'))) return SCPE_ARG; + if (chiptype == CHIP_TYPE_8086) { + for (i = 0; i < SIM_EMAX; i++) vals[i] = val[i] & 0xff; + r = disasm(vals, disasm_result, 16, addr); } - ch = DAsm(disasm, val, cpu_unit.flags & UNIT_CHIP, addr); - fprintf(of, "%s", disasm); - return 1 - ch; /* need to return additional bytes */ + else + r = DAsm(disasm_result, val, chiptype == CHIP_TYPE_Z80, addr); + fprintf(of, "%s", disasm_result); + return 1 - r; } /* checkbase determines the base of the number (ch, *numString) and returns FALSE if the number is bad */ static int32 checkbase(char ch, const char *numString) { int32 decimal = (ch <= '9'); - if (toupper(ch) == 'H') { - return FALSE; - } - while (isxdigit(ch = *numString++)) { - if (ch > '9') { - decimal = FALSE; - } - } + if (toupper(ch) == 'H') return FALSE; + while (isxdigit(ch = *numString++)) if (ch > '9') decimal = FALSE; return toupper(ch) == 'H' ? 16 : (decimal ? 10 : FALSE); } static int32 numok(char ch, const char **numString, const int32 minvalue, const int32 maxvalue, const int32 requireSign, int32 *result) { int32 sign = 1, value = 0, base; - if (requireSign) { - if (ch == '+') { - ch = *(*numString)++; - } + if (requireSign) + if (ch == '+') ch = *(*numString)++; else if (ch == '-') { sign = -1; ch = *(*numString)++; } - else { - return FALSE; - } - } - if (!(base = checkbase(ch, *numString))) { - return FALSE; - } + else return FALSE; + if (!(base = checkbase(ch, *numString))) return FALSE; while (isxdigit(ch)) { value = base * value + ((ch <= '9') ? (ch - '0') : (toupper(ch) - 'A' + 10)); ch = *(*numString)++; } - if (toupper(ch) != 'H') { - (*numString)--; - } + if (toupper(ch) != 'H') (*numString)--; *result = value * sign; return (minvalue <= value) && (value <= maxvalue); } @@ -485,93 +502,57 @@ static int32 match(const char *pattern, const char *input, char *xyFirst, char * } /* otherwise fall through */ case ' ': - if (inp != pat) { - return FALSE; - } + if (inp != pat) return FALSE; pat = *pattern++; inp = *input++; - while (inp == ' ') { - inp = *input++; - } + while (inp == ' ') inp = *input++; continue; case '%': inp = toupper(inp); - if ((inp == 'X') || (inp == 'Y')) { - if (*xyFirst) { /* make sure that second '%' corresponds to first */ - if (*xyFirst == inp) { - *xy = inp; - } - else { - return FALSE; - } - } + if ((inp == 'X') || (inp == 'Y')) + if (*xyFirst) /* make sure that second '%' corresponds to first */ + if (*xyFirst == inp) *xy = inp; + else return FALSE; else { /* take note of first '%' for later */ *xyFirst = inp; *xy = inp; } - } - else { - return FALSE; - } + else return FALSE; break; case '#': - if (numok(inp, &input, 0, 65535, FALSE, number)) { - pattern++; /* skip h */ - } - else { - return FALSE; - } + if (numok(inp, &input, 0, 65535, FALSE, number)) pattern++; /* skip h */ + else return FALSE; break; case '*': - if (numok(inp, &input, 0, 255, FALSE, star)) { - pattern++; /* skip h */ - } - else { - return FALSE; - } + if (numok(inp, &input, 0, 255, FALSE, star)) pattern++; /* skip h */ + else return FALSE; break; case '@': - if (numok(inp, &input, -128, 65535, TRUE, at)) { - pattern++; /* skip h */ - } - else { - return FALSE; - } + if (numok(inp, &input, -128, 65535, TRUE, at)) pattern++; /* skip h */ + else return FALSE; break; case '$': - if (numok(inp, &input, 0, 65535, FALSE, dollar)) { - pattern++; /* skip h */ - } - else { - return FALSE; - } + if (numok(inp, &input, 0, 65535, FALSE, dollar)) pattern++; /* skip h */ + else return FALSE; break; case '^': - if (numok(inp, &input, 0, 255, FALSE, hat)) { - pattern++; /* skip h */ - } - else { - return FALSE; - } + if (numok(inp, &input, 0, 255, FALSE, hat)) pattern++; /* skip h */ + else return FALSE; break; default: - if (toupper(pat) != toupper(inp)) { - return FALSE; - } + if (toupper(pat) != toupper(inp)) return FALSE; } pat = *pattern++; inp = *input++; } - while (inp == ' ') { - inp = *input++; - } + while (inp == ' ') inp = *input++; return (pat == 0) && (inp == 0); } @@ -595,41 +576,31 @@ static int32 parse_X80(const char *cptr, const int32 addr, uint32 *val, char *co val[1] = (0xff) & star; return -1; /* one additional byte returned */ } - else if (at > -129) { + else if (at > -129) if ((-128 <= at) && (at <= 127)) { val[1] = (int8)(at); return -1; /* one additional byte returned */ } - else { - return SCPE_ARG; - } - } + else return SCPE_ARG; else if (dollar >= 0) { dollar -= addr + 2; /* relative translation */ if ((-128 <= dollar) && (dollar <= 127)) { val[1] = (int8)(dollar); return -1; /* one additional byte returned */ } - else { - return SCPE_ARG; - } - } - else { - return SCPE_OK; + else return SCPE_ARG; } + else return SCPE_OK; } } - if (Mnemonics == Mnemonics8080) { - return SCPE_ARG; - } + if (Mnemonics == Mnemonics8080) return SCPE_ARG; - for (op = 0; op < 256; op++) { + for (op = 0; op < 256; op++) if (match(MnemonicsCB[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { val[0] = 0xcb; val[1] = op; return -1; /* one additional byte returned */ } - } for (op = 0; op < 256; op++) { number = -1; @@ -641,9 +612,7 @@ static int32 parse_X80(const char *cptr, const int32 addr, uint32 *val, char *co val[3] = (0xff) & (number >> 8); return -3; /* three additional bytes returned */ } - else { - return -1; /* one additional byte returned */ - } + else return -1; /* one additional byte returned */ } } @@ -652,9 +621,7 @@ static int32 parse_X80(const char *cptr, const int32 addr, uint32 *val, char *co xy = 0; if (match(MnemonicsXX[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { /* all matches must have contained a '%' character */ - if (!(val[0] = checkXY(xy))) { - return SCPE_ARG; - } + if (!(val[0] = checkXY(xy))) return SCPE_ARG; val[1] = op; if (number >= 0) { val[2] = (0xff) & number; @@ -674,9 +641,7 @@ static int32 parse_X80(const char *cptr, const int32 addr, uint32 *val, char *co val[2] = (0xff) & hat; return -2; /* two additional bytes returned */ } - else { - return -1; /* one additional byte returned */ - } + else return -1; /* one additional byte returned */ } } @@ -685,13 +650,9 @@ static int32 parse_X80(const char *cptr, const int32 addr, uint32 *val, char *co xy = 0; if (match(MnemonicsXCB[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { /* all matches must have contained a '%' character */ - if (!(val[0] = checkXY(xy))) { - return SCPE_ARG; - } + if (!(val[0] = checkXY(xy))) return SCPE_ARG; val[1] = 0xcb; - if (at > -129) { - val[2] = (int8) (at); - } + if (at > -129) val[2] = (int8) (at); else { printf("Offset expected.\n"); return SCPE_ARG; @@ -715,14 +676,115 @@ static int32 parse_X80(const char *cptr, const int32 addr, uint32 *val, char *co Outputs: status = error status */ -int32 parse_sym(char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw) { - while (isspace(*cptr)) cptr++; /* absorb spaces */ +t_stat parse_sym(char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) { + while (isspace(*cptr)) cptr++; /* absorb spaces */ if ((sw & (SWMASK('A') | SWMASK('C'))) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ - if (cptr[0] == 0) { - return SCPE_ARG; /* must have one char */ - } + if (cptr[0] == 0) return SCPE_ARG; /* must have one char */ val[0] = (uint32) cptr[0]; return SCPE_OK; } - return parse_X80(cptr, addr, val, cpu_unit.flags & UNIT_CHIP ? MnemonicsZ80 : Mnemonics8080); + return parse_X80(cptr, addr, val, chiptype == CHIP_TYPE_Z80 ? MnemonicsZ80 : Mnemonics8080); } + +/* Set Memory Base Address routine */ +t_stat set_membase(UNIT *uptr, int32 val, char *cptr, void *desc) +{ + DEVICE *dptr; + PNP_INFO *pnp; + uint32 newba; + t_stat r; + + if (cptr == NULL) return SCPE_ARG; + if (uptr == NULL) return SCPE_IERR; + dptr = find_dev_from_unit (uptr); + if (dptr == NULL) return SCPE_IERR; + pnp = (PNP_INFO *) dptr->ctxt; + if (pnp == NULL) return SCPE_IERR; + + newba = get_uint (cptr, 16, 0xFFFF, &r); + if (r != SCPE_OK) return r; + + if ((newba > 0xFFFF) || + (newba % pnp->mem_size)) return SCPE_ARG; + + if(dptr->flags & DEV_DIS) { + printf("device not enabled yet.\n"); + pnp->mem_base = newba & ~(pnp->mem_size-1); + } else { + dptr->flags |= DEV_DIS; + dptr->reset(dptr); + pnp->mem_base = newba & ~(pnp->mem_size-1); + dptr->flags &= ~DEV_DIS; + dptr->reset(dptr); + } + + return SCPE_OK; +} + +/* Show Base Address routine */ +t_stat show_membase(FILE *st, UNIT *uptr, int32 val, void *desc) +{ + DEVICE *dptr; + PNP_INFO *pnp; + + if (uptr == NULL) return SCPE_IERR; + dptr = find_dev_from_unit (uptr); + if (dptr == NULL) return SCPE_IERR; + pnp = (PNP_INFO *) dptr->ctxt; + if (pnp == NULL) return SCPE_IERR; + + fprintf(st, "MEM=0x%04X-0x%04X", pnp->mem_base, pnp->mem_base+pnp->mem_size-1); + return SCPE_OK; +} + +/* Set Memory Base Address routine */ +t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc) +{ + DEVICE *dptr; + PNP_INFO *pnp; + uint32 newba; + t_stat r; + + if (cptr == NULL) return SCPE_ARG; + if (uptr == NULL) return SCPE_IERR; + dptr = find_dev_from_unit (uptr); + if (dptr == NULL) return SCPE_IERR; + pnp = (PNP_INFO *) dptr->ctxt; + if (pnp == NULL) return SCPE_IERR; + + newba = get_uint (cptr, 16, 0xFF, &r); + if (r != SCPE_OK) return r; + + if ((newba > 0xFF) || + (newba % pnp->io_size)) return SCPE_ARG; + + if(dptr->flags & DEV_DIS) { + printf("device not enabled yet.\n"); + pnp->io_base = newba & ~(pnp->io_size-1); + } else { + dptr->flags |= DEV_DIS; + dptr->reset(dptr); + pnp->io_base = newba & ~(pnp->io_size-1); + dptr->flags &= ~DEV_DIS; + dptr->reset(dptr); + } + + return SCPE_OK; +} + +/* Show I/O Base Address routine */ +t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc) +{ + DEVICE *dptr; + PNP_INFO *pnp; + + if (uptr == NULL) return SCPE_IERR; + dptr = find_dev_from_unit (uptr); + if (dptr == NULL) return SCPE_IERR; + pnp = (PNP_INFO *) dptr->ctxt; + if (pnp == NULL) return SCPE_IERR; + + fprintf(st, "I/O=0x%02X-0x%02X", pnp->io_base, pnp->io_base+pnp->io_size-1); + return SCPE_OK; +} + diff --git a/AltairZ80/altairz80_cpu_nommu.c b/AltairZ80/altairz80_cpu_nommu.c new file mode 100644 index 00000000..67d92bec --- /dev/null +++ b/AltairZ80/altairz80_cpu_nommu.c @@ -0,0 +1,4175 @@ +/* altairz80_cpu_opt.c: MITS Altair CPU (8080 and Z80) + + Copyright (c) 2002-2008, Peter Schorn + + 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 + PETER SCHORN 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 Peter Schorn shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Peter Schorn. + + Based on work by Charles E Owen (c) 1997 + Code for Z80 CPU from Frank D. Cringle ((c) 1995 under GNU license) +*/ + +#include "altairz80_defs.h" + +#define FLAG_C 1 +#define FLAG_N 2 +#define FLAG_P 4 +#define FLAG_H 16 +#define FLAG_Z 64 +#define FLAG_S 128 + +#define SETFLAG(f,c) AF = (c) ? AF | FLAG_ ## f : AF & ~FLAG_ ## f +#define TSTFLAG(f) ((AF & FLAG_ ## f) != 0) + +#define LOW_DIGIT(x) ((x) & 0xf) +#define HIGH_DIGIT(x) (((x) >> 4) & 0xf) +#define LOW_REGISTER(x) ((x) & 0xff) +#define HIGH_REGISTER(x) (((x) >> 8) & 0xff) + +#define SET_LOW_REGISTER(x, v) x = (((x) & 0xff00) | ((v) & 0xff)) +#define SET_HIGH_REGISTER(x, v) x = (((x) & 0xff) | (((v) & 0xff) << 8)) + +#define PARITY(x) parityTable[(x) & 0xff] +/* SET_PV and SET_PV2 are used to provide correct PARITY flag semantics for the 8080 in cases + where the Z80 uses the overflow flag +*/ +#define SET_PVS(s) ((chiptype == CHIP_TYPE_Z80) ? (((cbits >> 6) ^ (cbits >> 5)) & 4) : (PARITY(s))) +#define SET_PV (SET_PVS(sum)) +#define SET_PV2(x) ((chiptype == CHIP_TYPE_Z80) ? (((temp == (x)) << 2)) : (PARITY(temp))) + +/* CHECK_CPU_8080 must be invoked whenever a Z80 only instruction is executed + In case a Z80 instruction is executed on an 8080 the following two cases exist: + 1) Trapping is enabled: execution stops + 2) Trapping is not enabled: decoding continues with the next byte +*/ +#define CHECK_CPU_8080 \ + if (chiptype == CHIP_TYPE_8080) { \ + if (cpu_unit.flags & UNIT_CPU_OPSTOP) { \ + reason = STOP_OPCODE; \ + goto end_decode; \ + } \ + else continue; \ + } + +/* CHECK_CPU_Z80 must be invoked whenever a non Z80 instruction is executed */ +#define CHECK_CPU_Z80 \ + if (cpu_unit.flags & UNIT_CPU_OPSTOP) { \ + reason = STOP_OPCODE; \ + goto end_decode; \ + } + +#define POP(x) { \ + register uint32 y = RAM_PP(SP); \ + x = y + (RAM_PP(SP) << 8); \ +} + +#define JPC(cond) { \ + if (cond) { \ + PC = GET_WORD(PC); \ + } \ + else { \ + PC += 2; \ + } \ +} + +#define CALLC(cond) { \ + if (cond) { \ + register uint32 adrr = GET_WORD(PC); \ + PUSH(PC + 2); \ + PC = adrr; \ + } \ + else { \ + PC += 2; \ + } \ +} + +/* function prototypes */ +t_stat sim_instr_nommu(void); + +extern void out(const uint32 Port, const uint32 Value); +extern uint32 in(const uint32 Port); +extern UNIT cpu_unit; +extern uint32 PCX; /* external view of PC */ +extern int32 AF_S; /* AF register */ +extern int32 BC_S; /* BC register */ +extern int32 DE_S; /* DE register */ +extern int32 HL_S; /* HL register */ +extern int32 IX_S; /* IX register */ +extern int32 IY_S; /* IY register */ +extern int32 PC_S; /* program counter */ +extern int32 SP_S; /* SP register */ +extern int32 AF1_S; /* alternate AF register */ +extern int32 BC1_S; /* alternate BC register */ +extern int32 DE1_S; /* alternate DE register */ +extern int32 HL1_S; /* alternate HL register */ +extern int32 IFF_S; /* Interrupt Flip Flop */ +extern int32 IR_S; /* Interrupt (upper) / Refresh (lower) register */ +extern int32 chiptype; + +/* the following tables precompute some common subexpressions + parityTable[i] 0..255 (number of 1's in i is odd) ? 0 : 4 + incTable[i] 0..256! (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0) << 4) + decTable[i] 0..255 (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0xf) << 4) | 2 + cbitsTable[i] 0..511 (i & 0x10) | ((i >> 8) & 1) + cbitsDup8Table[i] 0..511 (i & 0x10) | ((i >> 8) & 1) | ((i & 0xff) << 8) | (i & 0xa8) | + (((i & 0xff) == 0) << 6) + cbitsDup16Table[i] 0..511 (i & 0x10) | ((i >> 8) & 1) | (i & 0x28) + cbits2Table[i] 0..511 (i & 0x10) | ((i >> 8) & 1) | 2 + rrcaTable[i] 0..255 ((i & 1) << 15) | ((i >> 1) << 8) | ((i >> 1) & 0x28) | (i & 1) + rraTable[i] 0..255 ((i >> 1) << 8) | ((i >> 1) & 0x28) | (i & 1) + addTable[i] 0..511 ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) + subTable[i] 0..255 ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) | 2 + andTable[i] 0..255 (i << 8) | (i & 0xa8) | ((i == 0) << 6) | 0x10 | parityTable[i] + xororTable[i] 0..255 (i << 8) | (i & 0xa8) | ((i == 0) << 6) | parityTable[i] + rotateShiftTable[i] 0..255 (i & 0xa8) | (((i & 0xff) == 0) << 6) | parityTable[i & 0xff] + incZ80Table[i] 0..256! (i & 0xa8) | (((i & 0xff) == 0) << 6) | + (((i & 0xf) == 0) << 4) | ((i == 0x80) << 2) + decZ80Table[i] 0..255 (i & 0xa8) | (((i & 0xff) == 0) << 6) | + (((i & 0xf) == 0xf) << 4) | ((i == 0x7f) << 2) | 2 + cbitsZ80Table[i] 0..511 (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) + cbitsZ80DupTable[i] 0..511 (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | + ((i >> 8) & 1) | (i & 0xa8) + cbits2Z80Table[i] 0..511 (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | 2 + cbits2Z80DupTable[i] 0..511 (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | 2 | + (i & 0xa8) + negTable[i] 0..255 (((i & 0x0f) != 0) << 4) | ((i == 0x80) << 2) | 2 | (i != 0) + rrdrldTable[i] 0..255 (i << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) | parityTable[i] + cpTable[i] 0..255 (i & 0x80) | (((i & 0xff) == 0) << 6) +*/ + +/* parityTable[i] = (number of 1's in i is odd) ? 0 : 4, i = 0..255 */ +static const uint8 parityTable[256] = { + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, +}; + +/* incTable[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0) << 4), i = 0..256 */ +static const uint8 incTable[257] = { + 80, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, 80 +}; + +/* decTable[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | (((i & 0xf) == 0xf) << 4) | 2, i = 0..255 */ +static const uint8 decTable[256] = { + 66, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, +}; + +/* cbitsTable[i] = (i & 0x10) | ((i >> 8) & 1), i = 0..511 */ +static const uint8 cbitsTable[512] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +}; + +/* cbitsDup8Table[i] = (i & 0x10) | ((i >> 8) & 1) | ((i & 0xff) << 8) | (i & 0xa8) | + (((i & 0xff) == 0) << 6), i = 0..511 */ +static const uint16 cbitsDup8Table[512] = { + 0x0040,0x0100,0x0200,0x0300,0x0400,0x0500,0x0600,0x0700, + 0x0808,0x0908,0x0a08,0x0b08,0x0c08,0x0d08,0x0e08,0x0f08, + 0x1010,0x1110,0x1210,0x1310,0x1410,0x1510,0x1610,0x1710, + 0x1818,0x1918,0x1a18,0x1b18,0x1c18,0x1d18,0x1e18,0x1f18, + 0x2020,0x2120,0x2220,0x2320,0x2420,0x2520,0x2620,0x2720, + 0x2828,0x2928,0x2a28,0x2b28,0x2c28,0x2d28,0x2e28,0x2f28, + 0x3030,0x3130,0x3230,0x3330,0x3430,0x3530,0x3630,0x3730, + 0x3838,0x3938,0x3a38,0x3b38,0x3c38,0x3d38,0x3e38,0x3f38, + 0x4000,0x4100,0x4200,0x4300,0x4400,0x4500,0x4600,0x4700, + 0x4808,0x4908,0x4a08,0x4b08,0x4c08,0x4d08,0x4e08,0x4f08, + 0x5010,0x5110,0x5210,0x5310,0x5410,0x5510,0x5610,0x5710, + 0x5818,0x5918,0x5a18,0x5b18,0x5c18,0x5d18,0x5e18,0x5f18, + 0x6020,0x6120,0x6220,0x6320,0x6420,0x6520,0x6620,0x6720, + 0x6828,0x6928,0x6a28,0x6b28,0x6c28,0x6d28,0x6e28,0x6f28, + 0x7030,0x7130,0x7230,0x7330,0x7430,0x7530,0x7630,0x7730, + 0x7838,0x7938,0x7a38,0x7b38,0x7c38,0x7d38,0x7e38,0x7f38, + 0x8080,0x8180,0x8280,0x8380,0x8480,0x8580,0x8680,0x8780, + 0x8888,0x8988,0x8a88,0x8b88,0x8c88,0x8d88,0x8e88,0x8f88, + 0x9090,0x9190,0x9290,0x9390,0x9490,0x9590,0x9690,0x9790, + 0x9898,0x9998,0x9a98,0x9b98,0x9c98,0x9d98,0x9e98,0x9f98, + 0xa0a0,0xa1a0,0xa2a0,0xa3a0,0xa4a0,0xa5a0,0xa6a0,0xa7a0, + 0xa8a8,0xa9a8,0xaaa8,0xaba8,0xaca8,0xada8,0xaea8,0xafa8, + 0xb0b0,0xb1b0,0xb2b0,0xb3b0,0xb4b0,0xb5b0,0xb6b0,0xb7b0, + 0xb8b8,0xb9b8,0xbab8,0xbbb8,0xbcb8,0xbdb8,0xbeb8,0xbfb8, + 0xc080,0xc180,0xc280,0xc380,0xc480,0xc580,0xc680,0xc780, + 0xc888,0xc988,0xca88,0xcb88,0xcc88,0xcd88,0xce88,0xcf88, + 0xd090,0xd190,0xd290,0xd390,0xd490,0xd590,0xd690,0xd790, + 0xd898,0xd998,0xda98,0xdb98,0xdc98,0xdd98,0xde98,0xdf98, + 0xe0a0,0xe1a0,0xe2a0,0xe3a0,0xe4a0,0xe5a0,0xe6a0,0xe7a0, + 0xe8a8,0xe9a8,0xeaa8,0xeba8,0xeca8,0xeda8,0xeea8,0xefa8, + 0xf0b0,0xf1b0,0xf2b0,0xf3b0,0xf4b0,0xf5b0,0xf6b0,0xf7b0, + 0xf8b8,0xf9b8,0xfab8,0xfbb8,0xfcb8,0xfdb8,0xfeb8,0xffb8, + 0x0041,0x0101,0x0201,0x0301,0x0401,0x0501,0x0601,0x0701, + 0x0809,0x0909,0x0a09,0x0b09,0x0c09,0x0d09,0x0e09,0x0f09, + 0x1011,0x1111,0x1211,0x1311,0x1411,0x1511,0x1611,0x1711, + 0x1819,0x1919,0x1a19,0x1b19,0x1c19,0x1d19,0x1e19,0x1f19, + 0x2021,0x2121,0x2221,0x2321,0x2421,0x2521,0x2621,0x2721, + 0x2829,0x2929,0x2a29,0x2b29,0x2c29,0x2d29,0x2e29,0x2f29, + 0x3031,0x3131,0x3231,0x3331,0x3431,0x3531,0x3631,0x3731, + 0x3839,0x3939,0x3a39,0x3b39,0x3c39,0x3d39,0x3e39,0x3f39, + 0x4001,0x4101,0x4201,0x4301,0x4401,0x4501,0x4601,0x4701, + 0x4809,0x4909,0x4a09,0x4b09,0x4c09,0x4d09,0x4e09,0x4f09, + 0x5011,0x5111,0x5211,0x5311,0x5411,0x5511,0x5611,0x5711, + 0x5819,0x5919,0x5a19,0x5b19,0x5c19,0x5d19,0x5e19,0x5f19, + 0x6021,0x6121,0x6221,0x6321,0x6421,0x6521,0x6621,0x6721, + 0x6829,0x6929,0x6a29,0x6b29,0x6c29,0x6d29,0x6e29,0x6f29, + 0x7031,0x7131,0x7231,0x7331,0x7431,0x7531,0x7631,0x7731, + 0x7839,0x7939,0x7a39,0x7b39,0x7c39,0x7d39,0x7e39,0x7f39, + 0x8081,0x8181,0x8281,0x8381,0x8481,0x8581,0x8681,0x8781, + 0x8889,0x8989,0x8a89,0x8b89,0x8c89,0x8d89,0x8e89,0x8f89, + 0x9091,0x9191,0x9291,0x9391,0x9491,0x9591,0x9691,0x9791, + 0x9899,0x9999,0x9a99,0x9b99,0x9c99,0x9d99,0x9e99,0x9f99, + 0xa0a1,0xa1a1,0xa2a1,0xa3a1,0xa4a1,0xa5a1,0xa6a1,0xa7a1, + 0xa8a9,0xa9a9,0xaaa9,0xaba9,0xaca9,0xada9,0xaea9,0xafa9, + 0xb0b1,0xb1b1,0xb2b1,0xb3b1,0xb4b1,0xb5b1,0xb6b1,0xb7b1, + 0xb8b9,0xb9b9,0xbab9,0xbbb9,0xbcb9,0xbdb9,0xbeb9,0xbfb9, + 0xc081,0xc181,0xc281,0xc381,0xc481,0xc581,0xc681,0xc781, + 0xc889,0xc989,0xca89,0xcb89,0xcc89,0xcd89,0xce89,0xcf89, + 0xd091,0xd191,0xd291,0xd391,0xd491,0xd591,0xd691,0xd791, + 0xd899,0xd999,0xda99,0xdb99,0xdc99,0xdd99,0xde99,0xdf99, + 0xe0a1,0xe1a1,0xe2a1,0xe3a1,0xe4a1,0xe5a1,0xe6a1,0xe7a1, + 0xe8a9,0xe9a9,0xeaa9,0xeba9,0xeca9,0xeda9,0xeea9,0xefa9, + 0xf0b1,0xf1b1,0xf2b1,0xf3b1,0xf4b1,0xf5b1,0xf6b1,0xf7b1, + 0xf8b9,0xf9b9,0xfab9,0xfbb9,0xfcb9,0xfdb9,0xfeb9,0xffb9, +}; + +/* cbitsDup16Table[i] = (i & 0x10) | ((i >> 8) & 1) | (i & 0x28), i = 0..511 */ +static const uint8 cbitsDup16Table[512] = { + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24, + 32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40, + 48,48,48,48,48,48,48,48,56,56,56,56,56,56,56,56, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24, + 32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40, + 48,48,48,48,48,48,48,48,56,56,56,56,56,56,56,56, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24, + 32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40, + 48,48,48,48,48,48,48,48,56,56,56,56,56,56,56,56, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16,16,16,16,16,16,16,16,24,24,24,24,24,24,24,24, + 32,32,32,32,32,32,32,32,40,40,40,40,40,40,40,40, + 48,48,48,48,48,48,48,48,56,56,56,56,56,56,56,56, + 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, + 17,17,17,17,17,17,17,17,25,25,25,25,25,25,25,25, + 33,33,33,33,33,33,33,33,41,41,41,41,41,41,41,41, + 49,49,49,49,49,49,49,49,57,57,57,57,57,57,57,57, + 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, + 17,17,17,17,17,17,17,17,25,25,25,25,25,25,25,25, + 33,33,33,33,33,33,33,33,41,41,41,41,41,41,41,41, + 49,49,49,49,49,49,49,49,57,57,57,57,57,57,57,57, + 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, + 17,17,17,17,17,17,17,17,25,25,25,25,25,25,25,25, + 33,33,33,33,33,33,33,33,41,41,41,41,41,41,41,41, + 49,49,49,49,49,49,49,49,57,57,57,57,57,57,57,57, + 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, + 17,17,17,17,17,17,17,17,25,25,25,25,25,25,25,25, + 33,33,33,33,33,33,33,33,41,41,41,41,41,41,41,41, + 49,49,49,49,49,49,49,49,57,57,57,57,57,57,57,57, +}; + +/* cbits2Table[i] = (i & 0x10) | ((i >> 8) & 1) | 2, i = 0..511 */ +static const uint8 cbits2Table[512] = { + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, +}; + +/* rrcaTable[i] = ((i & 1) << 15) | ((i >> 1) << 8) | ((i >> 1) & 0x28) | (i & 1), i = 0..255 */ +static const uint16 rrcaTable[256] = { + 0x0000,0x8001,0x0100,0x8101,0x0200,0x8201,0x0300,0x8301, + 0x0400,0x8401,0x0500,0x8501,0x0600,0x8601,0x0700,0x8701, + 0x0808,0x8809,0x0908,0x8909,0x0a08,0x8a09,0x0b08,0x8b09, + 0x0c08,0x8c09,0x0d08,0x8d09,0x0e08,0x8e09,0x0f08,0x8f09, + 0x1000,0x9001,0x1100,0x9101,0x1200,0x9201,0x1300,0x9301, + 0x1400,0x9401,0x1500,0x9501,0x1600,0x9601,0x1700,0x9701, + 0x1808,0x9809,0x1908,0x9909,0x1a08,0x9a09,0x1b08,0x9b09, + 0x1c08,0x9c09,0x1d08,0x9d09,0x1e08,0x9e09,0x1f08,0x9f09, + 0x2020,0xa021,0x2120,0xa121,0x2220,0xa221,0x2320,0xa321, + 0x2420,0xa421,0x2520,0xa521,0x2620,0xa621,0x2720,0xa721, + 0x2828,0xa829,0x2928,0xa929,0x2a28,0xaa29,0x2b28,0xab29, + 0x2c28,0xac29,0x2d28,0xad29,0x2e28,0xae29,0x2f28,0xaf29, + 0x3020,0xb021,0x3120,0xb121,0x3220,0xb221,0x3320,0xb321, + 0x3420,0xb421,0x3520,0xb521,0x3620,0xb621,0x3720,0xb721, + 0x3828,0xb829,0x3928,0xb929,0x3a28,0xba29,0x3b28,0xbb29, + 0x3c28,0xbc29,0x3d28,0xbd29,0x3e28,0xbe29,0x3f28,0xbf29, + 0x4000,0xc001,0x4100,0xc101,0x4200,0xc201,0x4300,0xc301, + 0x4400,0xc401,0x4500,0xc501,0x4600,0xc601,0x4700,0xc701, + 0x4808,0xc809,0x4908,0xc909,0x4a08,0xca09,0x4b08,0xcb09, + 0x4c08,0xcc09,0x4d08,0xcd09,0x4e08,0xce09,0x4f08,0xcf09, + 0x5000,0xd001,0x5100,0xd101,0x5200,0xd201,0x5300,0xd301, + 0x5400,0xd401,0x5500,0xd501,0x5600,0xd601,0x5700,0xd701, + 0x5808,0xd809,0x5908,0xd909,0x5a08,0xda09,0x5b08,0xdb09, + 0x5c08,0xdc09,0x5d08,0xdd09,0x5e08,0xde09,0x5f08,0xdf09, + 0x6020,0xe021,0x6120,0xe121,0x6220,0xe221,0x6320,0xe321, + 0x6420,0xe421,0x6520,0xe521,0x6620,0xe621,0x6720,0xe721, + 0x6828,0xe829,0x6928,0xe929,0x6a28,0xea29,0x6b28,0xeb29, + 0x6c28,0xec29,0x6d28,0xed29,0x6e28,0xee29,0x6f28,0xef29, + 0x7020,0xf021,0x7120,0xf121,0x7220,0xf221,0x7320,0xf321, + 0x7420,0xf421,0x7520,0xf521,0x7620,0xf621,0x7720,0xf721, + 0x7828,0xf829,0x7928,0xf929,0x7a28,0xfa29,0x7b28,0xfb29, + 0x7c28,0xfc29,0x7d28,0xfd29,0x7e28,0xfe29,0x7f28,0xff29, +}; + +/* rraTable[i] = ((i >> 1) << 8) | ((i >> 1) & 0x28) | (i & 1), i = 0..255 */ +static const uint16 rraTable[256] = { + 0x0000,0x0001,0x0100,0x0101,0x0200,0x0201,0x0300,0x0301, + 0x0400,0x0401,0x0500,0x0501,0x0600,0x0601,0x0700,0x0701, + 0x0808,0x0809,0x0908,0x0909,0x0a08,0x0a09,0x0b08,0x0b09, + 0x0c08,0x0c09,0x0d08,0x0d09,0x0e08,0x0e09,0x0f08,0x0f09, + 0x1000,0x1001,0x1100,0x1101,0x1200,0x1201,0x1300,0x1301, + 0x1400,0x1401,0x1500,0x1501,0x1600,0x1601,0x1700,0x1701, + 0x1808,0x1809,0x1908,0x1909,0x1a08,0x1a09,0x1b08,0x1b09, + 0x1c08,0x1c09,0x1d08,0x1d09,0x1e08,0x1e09,0x1f08,0x1f09, + 0x2020,0x2021,0x2120,0x2121,0x2220,0x2221,0x2320,0x2321, + 0x2420,0x2421,0x2520,0x2521,0x2620,0x2621,0x2720,0x2721, + 0x2828,0x2829,0x2928,0x2929,0x2a28,0x2a29,0x2b28,0x2b29, + 0x2c28,0x2c29,0x2d28,0x2d29,0x2e28,0x2e29,0x2f28,0x2f29, + 0x3020,0x3021,0x3120,0x3121,0x3220,0x3221,0x3320,0x3321, + 0x3420,0x3421,0x3520,0x3521,0x3620,0x3621,0x3720,0x3721, + 0x3828,0x3829,0x3928,0x3929,0x3a28,0x3a29,0x3b28,0x3b29, + 0x3c28,0x3c29,0x3d28,0x3d29,0x3e28,0x3e29,0x3f28,0x3f29, + 0x4000,0x4001,0x4100,0x4101,0x4200,0x4201,0x4300,0x4301, + 0x4400,0x4401,0x4500,0x4501,0x4600,0x4601,0x4700,0x4701, + 0x4808,0x4809,0x4908,0x4909,0x4a08,0x4a09,0x4b08,0x4b09, + 0x4c08,0x4c09,0x4d08,0x4d09,0x4e08,0x4e09,0x4f08,0x4f09, + 0x5000,0x5001,0x5100,0x5101,0x5200,0x5201,0x5300,0x5301, + 0x5400,0x5401,0x5500,0x5501,0x5600,0x5601,0x5700,0x5701, + 0x5808,0x5809,0x5908,0x5909,0x5a08,0x5a09,0x5b08,0x5b09, + 0x5c08,0x5c09,0x5d08,0x5d09,0x5e08,0x5e09,0x5f08,0x5f09, + 0x6020,0x6021,0x6120,0x6121,0x6220,0x6221,0x6320,0x6321, + 0x6420,0x6421,0x6520,0x6521,0x6620,0x6621,0x6720,0x6721, + 0x6828,0x6829,0x6928,0x6929,0x6a28,0x6a29,0x6b28,0x6b29, + 0x6c28,0x6c29,0x6d28,0x6d29,0x6e28,0x6e29,0x6f28,0x6f29, + 0x7020,0x7021,0x7120,0x7121,0x7220,0x7221,0x7320,0x7321, + 0x7420,0x7421,0x7520,0x7521,0x7620,0x7621,0x7720,0x7721, + 0x7828,0x7829,0x7928,0x7929,0x7a28,0x7a29,0x7b28,0x7b29, + 0x7c28,0x7c29,0x7d28,0x7d29,0x7e28,0x7e29,0x7f28,0x7f29, +}; + +/* addTable[i] = ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6), i = 0..511 */ +static const uint16 addTable[512] = { + 0x0040,0x0100,0x0200,0x0300,0x0400,0x0500,0x0600,0x0700, + 0x0808,0x0908,0x0a08,0x0b08,0x0c08,0x0d08,0x0e08,0x0f08, + 0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700, + 0x1808,0x1908,0x1a08,0x1b08,0x1c08,0x1d08,0x1e08,0x1f08, + 0x2020,0x2120,0x2220,0x2320,0x2420,0x2520,0x2620,0x2720, + 0x2828,0x2928,0x2a28,0x2b28,0x2c28,0x2d28,0x2e28,0x2f28, + 0x3020,0x3120,0x3220,0x3320,0x3420,0x3520,0x3620,0x3720, + 0x3828,0x3928,0x3a28,0x3b28,0x3c28,0x3d28,0x3e28,0x3f28, + 0x4000,0x4100,0x4200,0x4300,0x4400,0x4500,0x4600,0x4700, + 0x4808,0x4908,0x4a08,0x4b08,0x4c08,0x4d08,0x4e08,0x4f08, + 0x5000,0x5100,0x5200,0x5300,0x5400,0x5500,0x5600,0x5700, + 0x5808,0x5908,0x5a08,0x5b08,0x5c08,0x5d08,0x5e08,0x5f08, + 0x6020,0x6120,0x6220,0x6320,0x6420,0x6520,0x6620,0x6720, + 0x6828,0x6928,0x6a28,0x6b28,0x6c28,0x6d28,0x6e28,0x6f28, + 0x7020,0x7120,0x7220,0x7320,0x7420,0x7520,0x7620,0x7720, + 0x7828,0x7928,0x7a28,0x7b28,0x7c28,0x7d28,0x7e28,0x7f28, + 0x8080,0x8180,0x8280,0x8380,0x8480,0x8580,0x8680,0x8780, + 0x8888,0x8988,0x8a88,0x8b88,0x8c88,0x8d88,0x8e88,0x8f88, + 0x9080,0x9180,0x9280,0x9380,0x9480,0x9580,0x9680,0x9780, + 0x9888,0x9988,0x9a88,0x9b88,0x9c88,0x9d88,0x9e88,0x9f88, + 0xa0a0,0xa1a0,0xa2a0,0xa3a0,0xa4a0,0xa5a0,0xa6a0,0xa7a0, + 0xa8a8,0xa9a8,0xaaa8,0xaba8,0xaca8,0xada8,0xaea8,0xafa8, + 0xb0a0,0xb1a0,0xb2a0,0xb3a0,0xb4a0,0xb5a0,0xb6a0,0xb7a0, + 0xb8a8,0xb9a8,0xbaa8,0xbba8,0xbca8,0xbda8,0xbea8,0xbfa8, + 0xc080,0xc180,0xc280,0xc380,0xc480,0xc580,0xc680,0xc780, + 0xc888,0xc988,0xca88,0xcb88,0xcc88,0xcd88,0xce88,0xcf88, + 0xd080,0xd180,0xd280,0xd380,0xd480,0xd580,0xd680,0xd780, + 0xd888,0xd988,0xda88,0xdb88,0xdc88,0xdd88,0xde88,0xdf88, + 0xe0a0,0xe1a0,0xe2a0,0xe3a0,0xe4a0,0xe5a0,0xe6a0,0xe7a0, + 0xe8a8,0xe9a8,0xeaa8,0xeba8,0xeca8,0xeda8,0xeea8,0xefa8, + 0xf0a0,0xf1a0,0xf2a0,0xf3a0,0xf4a0,0xf5a0,0xf6a0,0xf7a0, + 0xf8a8,0xf9a8,0xfaa8,0xfba8,0xfca8,0xfda8,0xfea8,0xffa8, + 0x0040,0x0100,0x0200,0x0300,0x0400,0x0500,0x0600,0x0700, + 0x0808,0x0908,0x0a08,0x0b08,0x0c08,0x0d08,0x0e08,0x0f08, + 0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700, + 0x1808,0x1908,0x1a08,0x1b08,0x1c08,0x1d08,0x1e08,0x1f08, + 0x2020,0x2120,0x2220,0x2320,0x2420,0x2520,0x2620,0x2720, + 0x2828,0x2928,0x2a28,0x2b28,0x2c28,0x2d28,0x2e28,0x2f28, + 0x3020,0x3120,0x3220,0x3320,0x3420,0x3520,0x3620,0x3720, + 0x3828,0x3928,0x3a28,0x3b28,0x3c28,0x3d28,0x3e28,0x3f28, + 0x4000,0x4100,0x4200,0x4300,0x4400,0x4500,0x4600,0x4700, + 0x4808,0x4908,0x4a08,0x4b08,0x4c08,0x4d08,0x4e08,0x4f08, + 0x5000,0x5100,0x5200,0x5300,0x5400,0x5500,0x5600,0x5700, + 0x5808,0x5908,0x5a08,0x5b08,0x5c08,0x5d08,0x5e08,0x5f08, + 0x6020,0x6120,0x6220,0x6320,0x6420,0x6520,0x6620,0x6720, + 0x6828,0x6928,0x6a28,0x6b28,0x6c28,0x6d28,0x6e28,0x6f28, + 0x7020,0x7120,0x7220,0x7320,0x7420,0x7520,0x7620,0x7720, + 0x7828,0x7928,0x7a28,0x7b28,0x7c28,0x7d28,0x7e28,0x7f28, + 0x8080,0x8180,0x8280,0x8380,0x8480,0x8580,0x8680,0x8780, + 0x8888,0x8988,0x8a88,0x8b88,0x8c88,0x8d88,0x8e88,0x8f88, + 0x9080,0x9180,0x9280,0x9380,0x9480,0x9580,0x9680,0x9780, + 0x9888,0x9988,0x9a88,0x9b88,0x9c88,0x9d88,0x9e88,0x9f88, + 0xa0a0,0xa1a0,0xa2a0,0xa3a0,0xa4a0,0xa5a0,0xa6a0,0xa7a0, + 0xa8a8,0xa9a8,0xaaa8,0xaba8,0xaca8,0xada8,0xaea8,0xafa8, + 0xb0a0,0xb1a0,0xb2a0,0xb3a0,0xb4a0,0xb5a0,0xb6a0,0xb7a0, + 0xb8a8,0xb9a8,0xbaa8,0xbba8,0xbca8,0xbda8,0xbea8,0xbfa8, + 0xc080,0xc180,0xc280,0xc380,0xc480,0xc580,0xc680,0xc780, + 0xc888,0xc988,0xca88,0xcb88,0xcc88,0xcd88,0xce88,0xcf88, + 0xd080,0xd180,0xd280,0xd380,0xd480,0xd580,0xd680,0xd780, + 0xd888,0xd988,0xda88,0xdb88,0xdc88,0xdd88,0xde88,0xdf88, + 0xe0a0,0xe1a0,0xe2a0,0xe3a0,0xe4a0,0xe5a0,0xe6a0,0xe7a0, + 0xe8a8,0xe9a8,0xeaa8,0xeba8,0xeca8,0xeda8,0xeea8,0xefa8, + 0xf0a0,0xf1a0,0xf2a0,0xf3a0,0xf4a0,0xf5a0,0xf6a0,0xf7a0, + 0xf8a8,0xf9a8,0xfaa8,0xfba8,0xfca8,0xfda8,0xfea8,0xffa8, +}; + +/* subTable[i] = ((i & 0xff) << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) | 2, i = 0..255 */ +static const uint16 subTable[256] = { + 0x0042,0x0102,0x0202,0x0302,0x0402,0x0502,0x0602,0x0702, + 0x080a,0x090a,0x0a0a,0x0b0a,0x0c0a,0x0d0a,0x0e0a,0x0f0a, + 0x1002,0x1102,0x1202,0x1302,0x1402,0x1502,0x1602,0x1702, + 0x180a,0x190a,0x1a0a,0x1b0a,0x1c0a,0x1d0a,0x1e0a,0x1f0a, + 0x2022,0x2122,0x2222,0x2322,0x2422,0x2522,0x2622,0x2722, + 0x282a,0x292a,0x2a2a,0x2b2a,0x2c2a,0x2d2a,0x2e2a,0x2f2a, + 0x3022,0x3122,0x3222,0x3322,0x3422,0x3522,0x3622,0x3722, + 0x382a,0x392a,0x3a2a,0x3b2a,0x3c2a,0x3d2a,0x3e2a,0x3f2a, + 0x4002,0x4102,0x4202,0x4302,0x4402,0x4502,0x4602,0x4702, + 0x480a,0x490a,0x4a0a,0x4b0a,0x4c0a,0x4d0a,0x4e0a,0x4f0a, + 0x5002,0x5102,0x5202,0x5302,0x5402,0x5502,0x5602,0x5702, + 0x580a,0x590a,0x5a0a,0x5b0a,0x5c0a,0x5d0a,0x5e0a,0x5f0a, + 0x6022,0x6122,0x6222,0x6322,0x6422,0x6522,0x6622,0x6722, + 0x682a,0x692a,0x6a2a,0x6b2a,0x6c2a,0x6d2a,0x6e2a,0x6f2a, + 0x7022,0x7122,0x7222,0x7322,0x7422,0x7522,0x7622,0x7722, + 0x782a,0x792a,0x7a2a,0x7b2a,0x7c2a,0x7d2a,0x7e2a,0x7f2a, + 0x8082,0x8182,0x8282,0x8382,0x8482,0x8582,0x8682,0x8782, + 0x888a,0x898a,0x8a8a,0x8b8a,0x8c8a,0x8d8a,0x8e8a,0x8f8a, + 0x9082,0x9182,0x9282,0x9382,0x9482,0x9582,0x9682,0x9782, + 0x988a,0x998a,0x9a8a,0x9b8a,0x9c8a,0x9d8a,0x9e8a,0x9f8a, + 0xa0a2,0xa1a2,0xa2a2,0xa3a2,0xa4a2,0xa5a2,0xa6a2,0xa7a2, + 0xa8aa,0xa9aa,0xaaaa,0xabaa,0xacaa,0xadaa,0xaeaa,0xafaa, + 0xb0a2,0xb1a2,0xb2a2,0xb3a2,0xb4a2,0xb5a2,0xb6a2,0xb7a2, + 0xb8aa,0xb9aa,0xbaaa,0xbbaa,0xbcaa,0xbdaa,0xbeaa,0xbfaa, + 0xc082,0xc182,0xc282,0xc382,0xc482,0xc582,0xc682,0xc782, + 0xc88a,0xc98a,0xca8a,0xcb8a,0xcc8a,0xcd8a,0xce8a,0xcf8a, + 0xd082,0xd182,0xd282,0xd382,0xd482,0xd582,0xd682,0xd782, + 0xd88a,0xd98a,0xda8a,0xdb8a,0xdc8a,0xdd8a,0xde8a,0xdf8a, + 0xe0a2,0xe1a2,0xe2a2,0xe3a2,0xe4a2,0xe5a2,0xe6a2,0xe7a2, + 0xe8aa,0xe9aa,0xeaaa,0xebaa,0xecaa,0xedaa,0xeeaa,0xefaa, + 0xf0a2,0xf1a2,0xf2a2,0xf3a2,0xf4a2,0xf5a2,0xf6a2,0xf7a2, + 0xf8aa,0xf9aa,0xfaaa,0xfbaa,0xfcaa,0xfdaa,0xfeaa,0xffaa, +}; + +/* andTable[i] = (i << 8) | (i & 0xa8) | ((i == 0) << 6) | 0x10 | parityTable[i], i = 0..255 */ +static const uint16 andTable[256] = { + 0x0054,0x0110,0x0210,0x0314,0x0410,0x0514,0x0614,0x0710, + 0x0818,0x091c,0x0a1c,0x0b18,0x0c1c,0x0d18,0x0e18,0x0f1c, + 0x1010,0x1114,0x1214,0x1310,0x1414,0x1510,0x1610,0x1714, + 0x181c,0x1918,0x1a18,0x1b1c,0x1c18,0x1d1c,0x1e1c,0x1f18, + 0x2030,0x2134,0x2234,0x2330,0x2434,0x2530,0x2630,0x2734, + 0x283c,0x2938,0x2a38,0x2b3c,0x2c38,0x2d3c,0x2e3c,0x2f38, + 0x3034,0x3130,0x3230,0x3334,0x3430,0x3534,0x3634,0x3730, + 0x3838,0x393c,0x3a3c,0x3b38,0x3c3c,0x3d38,0x3e38,0x3f3c, + 0x4010,0x4114,0x4214,0x4310,0x4414,0x4510,0x4610,0x4714, + 0x481c,0x4918,0x4a18,0x4b1c,0x4c18,0x4d1c,0x4e1c,0x4f18, + 0x5014,0x5110,0x5210,0x5314,0x5410,0x5514,0x5614,0x5710, + 0x5818,0x591c,0x5a1c,0x5b18,0x5c1c,0x5d18,0x5e18,0x5f1c, + 0x6034,0x6130,0x6230,0x6334,0x6430,0x6534,0x6634,0x6730, + 0x6838,0x693c,0x6a3c,0x6b38,0x6c3c,0x6d38,0x6e38,0x6f3c, + 0x7030,0x7134,0x7234,0x7330,0x7434,0x7530,0x7630,0x7734, + 0x783c,0x7938,0x7a38,0x7b3c,0x7c38,0x7d3c,0x7e3c,0x7f38, + 0x8090,0x8194,0x8294,0x8390,0x8494,0x8590,0x8690,0x8794, + 0x889c,0x8998,0x8a98,0x8b9c,0x8c98,0x8d9c,0x8e9c,0x8f98, + 0x9094,0x9190,0x9290,0x9394,0x9490,0x9594,0x9694,0x9790, + 0x9898,0x999c,0x9a9c,0x9b98,0x9c9c,0x9d98,0x9e98,0x9f9c, + 0xa0b4,0xa1b0,0xa2b0,0xa3b4,0xa4b0,0xa5b4,0xa6b4,0xa7b0, + 0xa8b8,0xa9bc,0xaabc,0xabb8,0xacbc,0xadb8,0xaeb8,0xafbc, + 0xb0b0,0xb1b4,0xb2b4,0xb3b0,0xb4b4,0xb5b0,0xb6b0,0xb7b4, + 0xb8bc,0xb9b8,0xbab8,0xbbbc,0xbcb8,0xbdbc,0xbebc,0xbfb8, + 0xc094,0xc190,0xc290,0xc394,0xc490,0xc594,0xc694,0xc790, + 0xc898,0xc99c,0xca9c,0xcb98,0xcc9c,0xcd98,0xce98,0xcf9c, + 0xd090,0xd194,0xd294,0xd390,0xd494,0xd590,0xd690,0xd794, + 0xd89c,0xd998,0xda98,0xdb9c,0xdc98,0xdd9c,0xde9c,0xdf98, + 0xe0b0,0xe1b4,0xe2b4,0xe3b0,0xe4b4,0xe5b0,0xe6b0,0xe7b4, + 0xe8bc,0xe9b8,0xeab8,0xebbc,0xecb8,0xedbc,0xeebc,0xefb8, + 0xf0b4,0xf1b0,0xf2b0,0xf3b4,0xf4b0,0xf5b4,0xf6b4,0xf7b0, + 0xf8b8,0xf9bc,0xfabc,0xfbb8,0xfcbc,0xfdb8,0xfeb8,0xffbc, +}; + +/* xororTable[i] = (i << 8) | (i & 0xa8) | ((i == 0) << 6) | parityTable[i], i = 0..255 */ +static const uint16 xororTable[256] = { + 0x0044,0x0100,0x0200,0x0304,0x0400,0x0504,0x0604,0x0700, + 0x0808,0x090c,0x0a0c,0x0b08,0x0c0c,0x0d08,0x0e08,0x0f0c, + 0x1000,0x1104,0x1204,0x1300,0x1404,0x1500,0x1600,0x1704, + 0x180c,0x1908,0x1a08,0x1b0c,0x1c08,0x1d0c,0x1e0c,0x1f08, + 0x2020,0x2124,0x2224,0x2320,0x2424,0x2520,0x2620,0x2724, + 0x282c,0x2928,0x2a28,0x2b2c,0x2c28,0x2d2c,0x2e2c,0x2f28, + 0x3024,0x3120,0x3220,0x3324,0x3420,0x3524,0x3624,0x3720, + 0x3828,0x392c,0x3a2c,0x3b28,0x3c2c,0x3d28,0x3e28,0x3f2c, + 0x4000,0x4104,0x4204,0x4300,0x4404,0x4500,0x4600,0x4704, + 0x480c,0x4908,0x4a08,0x4b0c,0x4c08,0x4d0c,0x4e0c,0x4f08, + 0x5004,0x5100,0x5200,0x5304,0x5400,0x5504,0x5604,0x5700, + 0x5808,0x590c,0x5a0c,0x5b08,0x5c0c,0x5d08,0x5e08,0x5f0c, + 0x6024,0x6120,0x6220,0x6324,0x6420,0x6524,0x6624,0x6720, + 0x6828,0x692c,0x6a2c,0x6b28,0x6c2c,0x6d28,0x6e28,0x6f2c, + 0x7020,0x7124,0x7224,0x7320,0x7424,0x7520,0x7620,0x7724, + 0x782c,0x7928,0x7a28,0x7b2c,0x7c28,0x7d2c,0x7e2c,0x7f28, + 0x8080,0x8184,0x8284,0x8380,0x8484,0x8580,0x8680,0x8784, + 0x888c,0x8988,0x8a88,0x8b8c,0x8c88,0x8d8c,0x8e8c,0x8f88, + 0x9084,0x9180,0x9280,0x9384,0x9480,0x9584,0x9684,0x9780, + 0x9888,0x998c,0x9a8c,0x9b88,0x9c8c,0x9d88,0x9e88,0x9f8c, + 0xa0a4,0xa1a0,0xa2a0,0xa3a4,0xa4a0,0xa5a4,0xa6a4,0xa7a0, + 0xa8a8,0xa9ac,0xaaac,0xaba8,0xacac,0xada8,0xaea8,0xafac, + 0xb0a0,0xb1a4,0xb2a4,0xb3a0,0xb4a4,0xb5a0,0xb6a0,0xb7a4, + 0xb8ac,0xb9a8,0xbaa8,0xbbac,0xbca8,0xbdac,0xbeac,0xbfa8, + 0xc084,0xc180,0xc280,0xc384,0xc480,0xc584,0xc684,0xc780, + 0xc888,0xc98c,0xca8c,0xcb88,0xcc8c,0xcd88,0xce88,0xcf8c, + 0xd080,0xd184,0xd284,0xd380,0xd484,0xd580,0xd680,0xd784, + 0xd88c,0xd988,0xda88,0xdb8c,0xdc88,0xdd8c,0xde8c,0xdf88, + 0xe0a0,0xe1a4,0xe2a4,0xe3a0,0xe4a4,0xe5a0,0xe6a0,0xe7a4, + 0xe8ac,0xe9a8,0xeaa8,0xebac,0xeca8,0xedac,0xeeac,0xefa8, + 0xf0a4,0xf1a0,0xf2a0,0xf3a4,0xf4a0,0xf5a4,0xf6a4,0xf7a0, + 0xf8a8,0xf9ac,0xfaac,0xfba8,0xfcac,0xfda8,0xfea8,0xffac, +}; + +/* rotateShiftTable[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | parityTable[i & 0xff], i = 0..255 */ +static const uint8 rotateShiftTable[256] = { + 68, 0, 0, 4, 0, 4, 4, 0, 8, 12, 12, 8, 12, 8, 8, 12, + 0, 4, 4, 0, 4, 0, 0, 4, 12, 8, 8, 12, 8, 12, 12, 8, + 32, 36, 36, 32, 36, 32, 32, 36, 44, 40, 40, 44, 40, 44, 44, 40, + 36, 32, 32, 36, 32, 36, 36, 32, 40, 44, 44, 40, 44, 40, 40, 44, + 0, 4, 4, 0, 4, 0, 0, 4, 12, 8, 8, 12, 8, 12, 12, 8, + 4, 0, 0, 4, 0, 4, 4, 0, 8, 12, 12, 8, 12, 8, 8, 12, + 36, 32, 32, 36, 32, 36, 36, 32, 40, 44, 44, 40, 44, 40, 40, 44, + 32, 36, 36, 32, 36, 32, 32, 36, 44, 40, 40, 44, 40, 44, 44, 40, + 128,132,132,128,132,128,128,132,140,136,136,140,136,140,140,136, + 132,128,128,132,128,132,132,128,136,140,140,136,140,136,136,140, + 164,160,160,164,160,164,164,160,168,172,172,168,172,168,168,172, + 160,164,164,160,164,160,160,164,172,168,168,172,168,172,172,168, + 132,128,128,132,128,132,132,128,136,140,140,136,140,136,136,140, + 128,132,132,128,132,128,128,132,140,136,136,140,136,140,140,136, + 160,164,164,160,164,160,160,164,172,168,168,172,168,172,172,168, + 164,160,160,164,160,164,164,160,168,172,172,168,172,168,168,172, +}; + +/* incZ80Table[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | + (((i & 0xf) == 0) << 4) | ((i == 0x80) << 2), i = 0..256 */ +static const uint8 incZ80Table[257] = { + 80, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 148,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 144,128,128,128,128,128,128,128,136,136,136,136,136,136,136,136, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, + 176,160,160,160,160,160,160,160,168,168,168,168,168,168,168,168, 80, +}; + +/* decZ80Table[i] = (i & 0xa8) | (((i & 0xff) == 0) << 6) | + (((i & 0xf) == 0xf) << 4) | ((i == 0x7f) << 2) | 2, i = 0..255 */ +static const uint8 decZ80Table[256] = { + 66, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 26, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 58, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 62, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 130,130,130,130,130,130,130,130,138,138,138,138,138,138,138,154, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, + 162,162,162,162,162,162,162,162,170,170,170,170,170,170,170,186, +}; + +/* cbitsZ80Table[i] = (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1), i = 0..511 */ +static const uint8 cbitsZ80Table[512] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +}; + +/* cbitsZ80DupTable[i] = (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | + ((i >> 8) & 1) | (i & 0xa8), i = 0..511 */ +static const uint8 cbitsZ80DupTable[512] = { + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 16, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, + 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 48, 48, 48, 48, 48, 48, 48, 56, 56, 56, 56, 56, 56, 56, 56, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 16, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, + 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 48, 48, 48, 48, 48, 48, 48, 56, 56, 56, 56, 56, 56, 56, 56, + 132,132,132,132,132,132,132,132,140,140,140,140,140,140,140,140, + 148,148,148,148,148,148,148,148,156,156,156,156,156,156,156,156, + 164,164,164,164,164,164,164,164,172,172,172,172,172,172,172,172, + 180,180,180,180,180,180,180,180,188,188,188,188,188,188,188,188, + 132,132,132,132,132,132,132,132,140,140,140,140,140,140,140,140, + 148,148,148,148,148,148,148,148,156,156,156,156,156,156,156,156, + 164,164,164,164,164,164,164,164,172,172,172,172,172,172,172,172, + 180,180,180,180,180,180,180,180,188,188,188,188,188,188,188,188, + 5, 5, 5, 5, 5, 5, 5, 5, 13, 13, 13, 13, 13, 13, 13, 13, + 21, 21, 21, 21, 21, 21, 21, 21, 29, 29, 29, 29, 29, 29, 29, 29, + 37, 37, 37, 37, 37, 37, 37, 37, 45, 45, 45, 45, 45, 45, 45, 45, + 53, 53, 53, 53, 53, 53, 53, 53, 61, 61, 61, 61, 61, 61, 61, 61, + 5, 5, 5, 5, 5, 5, 5, 5, 13, 13, 13, 13, 13, 13, 13, 13, + 21, 21, 21, 21, 21, 21, 21, 21, 29, 29, 29, 29, 29, 29, 29, 29, + 37, 37, 37, 37, 37, 37, 37, 37, 45, 45, 45, 45, 45, 45, 45, 45, + 53, 53, 53, 53, 53, 53, 53, 53, 61, 61, 61, 61, 61, 61, 61, 61, + 129,129,129,129,129,129,129,129,137,137,137,137,137,137,137,137, + 145,145,145,145,145,145,145,145,153,153,153,153,153,153,153,153, + 161,161,161,161,161,161,161,161,169,169,169,169,169,169,169,169, + 177,177,177,177,177,177,177,177,185,185,185,185,185,185,185,185, + 129,129,129,129,129,129,129,129,137,137,137,137,137,137,137,137, + 145,145,145,145,145,145,145,145,153,153,153,153,153,153,153,153, + 161,161,161,161,161,161,161,161,169,169,169,169,169,169,169,169, + 177,177,177,177,177,177,177,177,185,185,185,185,185,185,185,185, +}; + +/* cbits2Z80Table[i] = (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | 2, i = 0..511 */ +static const uint8 cbits2Z80Table[512] = { + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, +}; + +/* cbits2Z80DupTable[i] = (i & 0x10) | (((i >> 6) ^ (i >> 5)) & 4) | ((i >> 8) & 1) | 2 | + (i & 0xa8), i = 0..511 */ +static const uint8 cbits2Z80DupTable[512] = { + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 10, + 18, 18, 18, 18, 18, 18, 18, 18, 26, 26, 26, 26, 26, 26, 26, 26, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 42, + 50, 50, 50, 50, 50, 50, 50, 50, 58, 58, 58, 58, 58, 58, 58, 58, + 2, 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 10, + 18, 18, 18, 18, 18, 18, 18, 18, 26, 26, 26, 26, 26, 26, 26, 26, + 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, 42, 42, + 50, 50, 50, 50, 50, 50, 50, 50, 58, 58, 58, 58, 58, 58, 58, 58, + 134,134,134,134,134,134,134,134,142,142,142,142,142,142,142,142, + 150,150,150,150,150,150,150,150,158,158,158,158,158,158,158,158, + 166,166,166,166,166,166,166,166,174,174,174,174,174,174,174,174, + 182,182,182,182,182,182,182,182,190,190,190,190,190,190,190,190, + 134,134,134,134,134,134,134,134,142,142,142,142,142,142,142,142, + 150,150,150,150,150,150,150,150,158,158,158,158,158,158,158,158, + 166,166,166,166,166,166,166,166,174,174,174,174,174,174,174,174, + 182,182,182,182,182,182,182,182,190,190,190,190,190,190,190,190, + 7, 7, 7, 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 15, 15, + 23, 23, 23, 23, 23, 23, 23, 23, 31, 31, 31, 31, 31, 31, 31, 31, + 39, 39, 39, 39, 39, 39, 39, 39, 47, 47, 47, 47, 47, 47, 47, 47, + 55, 55, 55, 55, 55, 55, 55, 55, 63, 63, 63, 63, 63, 63, 63, 63, + 7, 7, 7, 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 15, 15, + 23, 23, 23, 23, 23, 23, 23, 23, 31, 31, 31, 31, 31, 31, 31, 31, + 39, 39, 39, 39, 39, 39, 39, 39, 47, 47, 47, 47, 47, 47, 47, 47, + 55, 55, 55, 55, 55, 55, 55, 55, 63, 63, 63, 63, 63, 63, 63, 63, + 131,131,131,131,131,131,131,131,139,139,139,139,139,139,139,139, + 147,147,147,147,147,147,147,147,155,155,155,155,155,155,155,155, + 163,163,163,163,163,163,163,163,171,171,171,171,171,171,171,171, + 179,179,179,179,179,179,179,179,187,187,187,187,187,187,187,187, + 131,131,131,131,131,131,131,131,139,139,139,139,139,139,139,139, + 147,147,147,147,147,147,147,147,155,155,155,155,155,155,155,155, + 163,163,163,163,163,163,163,163,171,171,171,171,171,171,171,171, + 179,179,179,179,179,179,179,179,187,187,187,187,187,187,187,187, +}; + +/* negTable[i] = (((i & 0x0f) != 0) << 4) | ((i == 0x80) << 2) | 2 | (i != 0), i = 0..255 */ +static const uint8 negTable[256] = { + 2,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 7,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 3,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, +}; + +/* rrdrldTable[i] = (i << 8) | (i & 0xa8) | (((i & 0xff) == 0) << 6) | parityTable[i], i = 0..255 */ +static const uint16 rrdrldTable[256] = { + 0x0044,0x0100,0x0200,0x0304,0x0400,0x0504,0x0604,0x0700, + 0x0808,0x090c,0x0a0c,0x0b08,0x0c0c,0x0d08,0x0e08,0x0f0c, + 0x1000,0x1104,0x1204,0x1300,0x1404,0x1500,0x1600,0x1704, + 0x180c,0x1908,0x1a08,0x1b0c,0x1c08,0x1d0c,0x1e0c,0x1f08, + 0x2020,0x2124,0x2224,0x2320,0x2424,0x2520,0x2620,0x2724, + 0x282c,0x2928,0x2a28,0x2b2c,0x2c28,0x2d2c,0x2e2c,0x2f28, + 0x3024,0x3120,0x3220,0x3324,0x3420,0x3524,0x3624,0x3720, + 0x3828,0x392c,0x3a2c,0x3b28,0x3c2c,0x3d28,0x3e28,0x3f2c, + 0x4000,0x4104,0x4204,0x4300,0x4404,0x4500,0x4600,0x4704, + 0x480c,0x4908,0x4a08,0x4b0c,0x4c08,0x4d0c,0x4e0c,0x4f08, + 0x5004,0x5100,0x5200,0x5304,0x5400,0x5504,0x5604,0x5700, + 0x5808,0x590c,0x5a0c,0x5b08,0x5c0c,0x5d08,0x5e08,0x5f0c, + 0x6024,0x6120,0x6220,0x6324,0x6420,0x6524,0x6624,0x6720, + 0x6828,0x692c,0x6a2c,0x6b28,0x6c2c,0x6d28,0x6e28,0x6f2c, + 0x7020,0x7124,0x7224,0x7320,0x7424,0x7520,0x7620,0x7724, + 0x782c,0x7928,0x7a28,0x7b2c,0x7c28,0x7d2c,0x7e2c,0x7f28, + 0x8080,0x8184,0x8284,0x8380,0x8484,0x8580,0x8680,0x8784, + 0x888c,0x8988,0x8a88,0x8b8c,0x8c88,0x8d8c,0x8e8c,0x8f88, + 0x9084,0x9180,0x9280,0x9384,0x9480,0x9584,0x9684,0x9780, + 0x9888,0x998c,0x9a8c,0x9b88,0x9c8c,0x9d88,0x9e88,0x9f8c, + 0xa0a4,0xa1a0,0xa2a0,0xa3a4,0xa4a0,0xa5a4,0xa6a4,0xa7a0, + 0xa8a8,0xa9ac,0xaaac,0xaba8,0xacac,0xada8,0xaea8,0xafac, + 0xb0a0,0xb1a4,0xb2a4,0xb3a0,0xb4a4,0xb5a0,0xb6a0,0xb7a4, + 0xb8ac,0xb9a8,0xbaa8,0xbbac,0xbca8,0xbdac,0xbeac,0xbfa8, + 0xc084,0xc180,0xc280,0xc384,0xc480,0xc584,0xc684,0xc780, + 0xc888,0xc98c,0xca8c,0xcb88,0xcc8c,0xcd88,0xce88,0xcf8c, + 0xd080,0xd184,0xd284,0xd380,0xd484,0xd580,0xd680,0xd784, + 0xd88c,0xd988,0xda88,0xdb8c,0xdc88,0xdd8c,0xde8c,0xdf88, + 0xe0a0,0xe1a4,0xe2a4,0xe3a0,0xe4a4,0xe5a0,0xe6a0,0xe7a4, + 0xe8ac,0xe9a8,0xeaa8,0xebac,0xeca8,0xedac,0xeeac,0xefa8, + 0xf0a4,0xf1a0,0xf2a0,0xf3a4,0xf4a0,0xf5a4,0xf6a4,0xf7a0, + 0xf8a8,0xf9ac,0xfaac,0xfba8,0xfcac,0xfda8,0xfea8,0xffac, +}; + +/* cpTable[i] = (i & 0x80) | (((i & 0xff) == 0) << 6), i = 0..255 */ +static const uint8 cpTable[256] = { + 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +}; + +/* Memory management */ + +uint8 MOPT[MAXBANKSIZE]; /* RAM which is present */ + +static uint8 GET_BYTE(register uint32 Addr) { + return MOPT[Addr & ADDRMASK]; +} + +static void PUT_BYTE(register uint32 Addr, register uint32 Value) { + MOPT[Addr & ADDRMASK] = Value; +} + +static void PUT_WORD(register uint32 Addr, register uint32 Value) { + MOPT[Addr & ADDRMASK] = Value; + MOPT[(Addr + 1) & ADDRMASK] = Value >> 8; +} + +static uint16 GET_WORD(register uint32 a) { + return GET_BYTE(a) | (GET_BYTE(a + 1) << 8); +} + +#define RAM_MM(a) GET_BYTE(a--) +#define RAM_PP(a) GET_BYTE(a++) + +#define PUT_BYTE_PP(a,v) PUT_BYTE(a++, v) +#define PUT_BYTE_MM(a,v) PUT_BYTE(a--, v) +#define MM_PUT_BYTE(a,v) PUT_BYTE(--a, v) + +#define PUSH(x) do { \ + MM_PUT_BYTE(SP, (x) >> 8); \ + MM_PUT_BYTE(SP, x); \ +} while (0) + +/* Macros for the IN/OUT instructions INI/INIR/IND/INDR/OUTI/OTIR/OUTD/OTDR + + Pre condition + temp == value of register B at entry of the instruction + acu == value of transferred byte (IN or OUT) + Post condition + F is set correctly + + Use INOUTFLAGS_ZERO(x) for INIR/INDR/OTIR/OTDR where + x == (C + 1) & 0xff for INIR + x == L for OTIR and OTDR + x == (C - 1) & 0xff for INDR + Use INOUTFLAGS_NONZERO(x) for INI/IND/OUTI/OUTD where + x == (C + 1) & 0xff for INI + x == L for OUTI and OUTD + x == (C - 1) & 0xff for IND +*/ +#define INOUTFLAGS(syxz, x) \ + AF = (AF & 0xff00) | (syxz) | /* SF, YF, XF, ZF */ \ + ((acu & 0x80) >> 6) | /* NF */ \ + ((acu + (x)) > 0xff ? (FLAG_C | FLAG_H) : 0) | /* CF, HF */ \ + parityTable[((acu + (x)) & 7) ^ temp] /* PF */ + +#define INOUTFLAGS_ZERO(x) INOUTFLAGS(FLAG_Z, x) +#define INOUTFLAGS_NONZERO(x) \ + INOUTFLAGS((HIGH_REGISTER(BC) & 0xa8) | ((HIGH_REGISTER(BC) == 0) << 6), x) + +t_stat sim_instr_nommu(void) { + extern int32 sim_interval; + extern uint32 sim_brk_summ; + int32 reason = 0; + register uint32 AF; + register uint32 BC; + register uint32 DE; + register uint32 HL; + register uint32 PC; + register uint32 SP; + register uint32 IX; + register uint32 IY; + register uint32 temp = 0; + register uint32 acu = 0; + register uint32 sum; + register uint32 cbits; + register uint32 op; + register uint32 adr; + register int32 l_sim_brk_summ; + + AF = AF_S; + BC = BC_S; + DE = DE_S; + HL = HL_S; + PC = PC_S & ADDRMASK; + SP = SP_S; + IX = IX_S; + IY = IY_S; + l_sim_brk_summ = sim_brk_summ; + + /* main instruction fetch/decode loop */ + while (TRUE) { /* loop until halted */ + if (sim_interval <= 0) { /* check clock queue */ +#if !UNIX_PLATFORM + if ((reason = sim_poll_kbd()) == SCPE_STOP) break; /* poll on platforms without reliable signalling */ +#endif + if ((reason = sim_process_event())) break; + } + + if (l_sim_brk_summ && sim_brk_test(PC, SWMASK('E'))) {/* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; + } + + PCX = PC; + sim_interval--; + + switch(RAM_PP(PC)) { + + case 0x00: /* NOP */ + break; + + case 0x01: /* LD BC,nnnn */ + BC = GET_WORD(PC); + PC += 2; + break; + + case 0x02: /* LD (BC),A */ + PUT_BYTE(BC, HIGH_REGISTER(AF)); + break; + + case 0x03: /* INC BC */ + ++BC; + break; + + case 0x04: /* INC B */ + BC += 0x100; + temp = HIGH_REGISTER(BC); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); /* SET_PV2 uses temp */ + break; + + case 0x05: /* DEC B */ + BC -= 0x100; + temp = HIGH_REGISTER(BC); + AF = (AF & ~0xfe) | decTable[temp] | SET_PV2(0x7f); /* SET_PV2 uses temp */ + break; + + case 0x06: /* LD B,nn */ + SET_HIGH_REGISTER(BC, RAM_PP(PC)); + break; + + case 0x07: /* RLCA */ + AF = ((AF >> 7) & 0x0128) | ((AF << 1) & ~0x1ff) | + (AF & 0xc4) | ((AF >> 15) & 1); + break; + + case 0x08: /* EX AF,AF' */ + CHECK_CPU_8080; + temp = AF; + AF = AF1_S; + AF1_S = temp; + break; + + case 0x09: /* ADD HL,BC */ + HL &= ADDRMASK; + BC &= ADDRMASK; + sum = HL + BC; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(HL ^ BC ^ sum) >> 8]; + HL = sum; + break; + + case 0x0a: /* LD A,(BC) */ + SET_HIGH_REGISTER(AF, GET_BYTE(BC)); + break; + + case 0x0b: /* DEC BC */ + --BC; + break; + + case 0x0c: /* INC C */ + temp = LOW_REGISTER(BC) + 1; + SET_LOW_REGISTER(BC, temp); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); + break; + + case 0x0d: /* DEC C */ + temp = LOW_REGISTER(BC) - 1; + SET_LOW_REGISTER(BC, temp); + AF = (AF & ~0xfe) | decTable[temp & 0xff] | SET_PV2(0x7f); + break; + + case 0x0e: /* LD C,nn */ + SET_LOW_REGISTER(BC, RAM_PP(PC)); + break; + + case 0x0f: /* RRCA */ + AF = (AF & 0xc4) | rrcaTable[HIGH_REGISTER(AF)]; + break; + + case 0x10: /* DJNZ dd */ + CHECK_CPU_8080; + if ((BC -= 0x100) & 0xff00) PC += (int8) GET_BYTE(PC) + 1; + else PC++; + break; + + case 0x11: /* LD DE,nnnn */ + DE = GET_WORD(PC); + PC += 2; + break; + + case 0x12: /* LD (DE),A */ + PUT_BYTE(DE, HIGH_REGISTER(AF)); + break; + + case 0x13: /* INC DE */ + ++DE; + break; + + case 0x14: /* INC D */ + DE += 0x100; + temp = HIGH_REGISTER(DE); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); /* SET_PV2 uses temp */ + break; + + case 0x15: /* DEC D */ + DE -= 0x100; + temp = HIGH_REGISTER(DE); + AF = (AF & ~0xfe) | decTable[temp] | SET_PV2(0x7f); /* SET_PV2 uses temp */ + break; + + case 0x16: /* LD D,nn */ + SET_HIGH_REGISTER(DE, RAM_PP(PC)); + break; + + case 0x17: /* RLA */ + AF = ((AF << 8) & 0x0100) | ((AF >> 7) & 0x28) | ((AF << 1) & ~0x01ff) | + (AF & 0xc4) | ((AF >> 15) & 1); + break; + + case 0x18: /* JR dd */ + CHECK_CPU_8080; + PC += (int8) GET_BYTE(PC) + 1; + break; + + case 0x19: /* ADD HL,DE */ + HL &= ADDRMASK; + DE &= ADDRMASK; + sum = HL + DE; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(HL ^ DE ^ sum) >> 8]; + HL = sum; + break; + + case 0x1a: /* LD A,(DE) */ + SET_HIGH_REGISTER(AF, GET_BYTE(DE)); + break; + + case 0x1b: /* DEC DE */ + --DE; + break; + + case 0x1c: /* INC E */ + temp = LOW_REGISTER(DE) + 1; + SET_LOW_REGISTER(DE, temp); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); + break; + + case 0x1d: /* DEC E */ + temp = LOW_REGISTER(DE) - 1; + SET_LOW_REGISTER(DE, temp); + AF = (AF & ~0xfe) | decTable[temp & 0xff] | SET_PV2(0x7f); + break; + + case 0x1e: /* LD E,nn */ + SET_LOW_REGISTER(DE, RAM_PP(PC)); + break; + + case 0x1f: /* RRA */ + AF = ((AF & 1) << 15) | (AF & 0xc4) | rraTable[HIGH_REGISTER(AF)]; + break; + + case 0x20: /* JR NZ,dd */ + CHECK_CPU_8080; + if (TSTFLAG(Z)) PC++; + else PC += (int8) GET_BYTE(PC) + 1; + break; + + case 0x21: /* LD HL,nnnn */ + HL = GET_WORD(PC); + PC += 2; + break; + + case 0x22: /* LD (nnnn),HL */ + temp = GET_WORD(PC); + PUT_WORD(temp, HL); + PC += 2; + break; + + case 0x23: /* INC HL */ + ++HL; + break; + + case 0x24: /* INC H */ + HL += 0x100; + temp = HIGH_REGISTER(HL); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); /* SET_PV2 uses temp */ + break; + + case 0x25: /* DEC H */ + HL -= 0x100; + temp = HIGH_REGISTER(HL); + AF = (AF & ~0xfe) | decTable[temp] | SET_PV2(0x7f); /* SET_PV2 uses temp */ + break; + + case 0x26: /* LD H,nn */ + SET_HIGH_REGISTER(HL, RAM_PP(PC)); + break; + + case 0x27: /* DAA */ + acu = HIGH_REGISTER(AF); + temp = LOW_DIGIT(acu); + cbits = TSTFLAG(C); + if (TSTFLAG(N)) { /* last operation was a subtract */ + int hd = cbits || acu > 0x99; + if (TSTFLAG(H) || (temp > 9)) { /* adjust low digit */ + if (temp > 5) SETFLAG(H, 0); + acu -= 6; + acu &= 0xff; + } + if (hd) acu -= 0x160; /* adjust high digit */ + } + else { /* last operation was an add */ + if (TSTFLAG(H) || (temp > 9)) { /* adjust low digit */ + SETFLAG(H, (temp > 9)); + acu += 6; + } + if (cbits || ((acu & 0x1f0) > 0x90)) acu += 0x60; /* adjust high digit */ + } + AF = (AF & 0x12) | rrdrldTable[acu & 0xff] | ((acu >> 8) & 1) | cbits; + break; + + case 0x28: /* JR Z,dd */ + CHECK_CPU_8080; + if (TSTFLAG(Z)) PC += (int8) GET_BYTE(PC) + 1; + else PC++; + break; + + case 0x29: /* ADD HL,HL */ + HL &= ADDRMASK; + sum = HL + HL; + AF = (AF & ~0x3b) | cbitsDup16Table[sum >> 8]; + HL = sum; + break; + + case 0x2a: /* LD HL,(nnnn) */ + temp = GET_WORD(PC); + HL = GET_WORD(temp); + PC += 2; + break; + + case 0x2b: /* DEC HL */ + --HL; + break; + + case 0x2c: /* INC L */ + temp = LOW_REGISTER(HL) + 1; + SET_LOW_REGISTER(HL, temp); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); + break; + + case 0x2d: /* DEC L */ + temp = LOW_REGISTER(HL) - 1; + SET_LOW_REGISTER(HL, temp); + AF = (AF & ~0xfe) | decTable[temp & 0xff] | SET_PV2(0x7f); + break; + + case 0x2e: /* LD L,nn */ + SET_LOW_REGISTER(HL, RAM_PP(PC)); + break; + + case 0x2f: /* CPL */ + AF = (~AF & ~0xff) | (AF & 0xc5) | ((~AF >> 8) & 0x28) | 0x12; + break; + + case 0x30: /* JR NC,dd */ + CHECK_CPU_8080; + if (TSTFLAG(C)) PC++; + else PC += (int8) GET_BYTE(PC) + 1; + break; + + case 0x31: /* LD SP,nnnn */ + SP = GET_WORD(PC); + PC += 2; + break; + + case 0x32: /* LD (nnnn),A */ + temp = GET_WORD(PC); + PUT_BYTE(temp, HIGH_REGISTER(AF)); + PC += 2; + break; + + case 0x33: /* INC SP */ + ++SP; + break; + + case 0x34: /* INC (HL) */ + temp = GET_BYTE(HL) + 1; + PUT_BYTE(HL, temp); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); + break; + + case 0x35: /* DEC (HL) */ + temp = GET_BYTE(HL) - 1; + PUT_BYTE(HL, temp); + AF = (AF & ~0xfe) | decTable[temp & 0xff] | SET_PV2(0x7f); + break; + + case 0x36: /* LD (HL),nn */ + PUT_BYTE(HL, RAM_PP(PC)); + break; + + case 0x37: /* SCF */ + AF = (AF & ~0x3b) | ((AF >> 8) & 0x28) | 1; + break; + + case 0x38: /* JR C,dd */ + CHECK_CPU_8080; + if (TSTFLAG(C)) PC += (int8) GET_BYTE(PC) + 1; + else PC++; + break; + + case 0x39: /* ADD HL,SP */ + HL &= ADDRMASK; + SP &= ADDRMASK; + sum = HL + SP; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(HL ^ SP ^ sum) >> 8]; + HL = sum; + break; + + case 0x3a: /* LD A,(nnnn) */ + temp = GET_WORD(PC); + SET_HIGH_REGISTER(AF, GET_BYTE(temp)); + PC += 2; + break; + + case 0x3b: /* DEC SP */ + --SP; + break; + + case 0x3c: /* INC A */ + AF += 0x100; + temp = HIGH_REGISTER(AF); + AF = (AF & ~0xfe) | incTable[temp] | SET_PV2(0x80); /* SET_PV2 uses temp */ + break; + + case 0x3d: /* DEC A */ + AF -= 0x100; + temp = HIGH_REGISTER(AF); + AF = (AF & ~0xfe) | decTable[temp] | SET_PV2(0x7f); /* SET_PV2 uses temp */ + break; + + case 0x3e: /* LD A,nn */ + SET_HIGH_REGISTER(AF, RAM_PP(PC)); + break; + + case 0x3f: /* CCF */ + AF = (AF & ~0x3b) | ((AF >> 8) & 0x28) | ((AF & 1) << 4) | (~AF & 1); + break; + + case 0x40: /* LD B,B */ + break; + + case 0x41: /* LD B,C */ + BC = (BC & 0xff) | ((BC & 0xff) << 8); + break; + + case 0x42: /* LD B,D */ + BC = (BC & 0xff) | (DE & ~0xff); + break; + + case 0x43: /* LD B,E */ + BC = (BC & 0xff) | ((DE & 0xff) << 8); + break; + + case 0x44: /* LD B,H */ + BC = (BC & 0xff) | (HL & ~0xff); + break; + + case 0x45: /* LD B,L */ + BC = (BC & 0xff) | ((HL & 0xff) << 8); + break; + + case 0x46: /* LD B,(HL) */ + SET_HIGH_REGISTER(BC, GET_BYTE(HL)); + break; + + case 0x47: /* LD B,A */ + BC = (BC & 0xff) | (AF & ~0xff); + break; + + case 0x48: /* LD C,B */ + BC = (BC & ~0xff) | ((BC >> 8) & 0xff); + break; + + case 0x49: /* LD C,C */ + break; + + case 0x4a: /* LD C,D */ + BC = (BC & ~0xff) | ((DE >> 8) & 0xff); + break; + + case 0x4b: /* LD C,E */ + BC = (BC & ~0xff) | (DE & 0xff); + break; + + case 0x4c: /* LD C,H */ + BC = (BC & ~0xff) | ((HL >> 8) & 0xff); + break; + + case 0x4d: /* LD C,L */ + BC = (BC & ~0xff) | (HL & 0xff); + break; + + case 0x4e: /* LD C,(HL) */ + SET_LOW_REGISTER(BC, GET_BYTE(HL)); + break; + + case 0x4f: /* LD C,A */ + BC = (BC & ~0xff) | ((AF >> 8) & 0xff); + break; + + case 0x50: /* LD D,B */ + DE = (DE & 0xff) | (BC & ~0xff); + break; + + case 0x51: /* LD D,C */ + DE = (DE & 0xff) | ((BC & 0xff) << 8); + break; + + case 0x52: /* LD D,D */ + break; + + case 0x53: /* LD D,E */ + DE = (DE & 0xff) | ((DE & 0xff) << 8); + break; + + case 0x54: /* LD D,H */ + DE = (DE & 0xff) | (HL & ~0xff); + break; + + case 0x55: /* LD D,L */ + DE = (DE & 0xff) | ((HL & 0xff) << 8); + break; + + case 0x56: /* LD D,(HL) */ + SET_HIGH_REGISTER(DE, GET_BYTE(HL)); + break; + + case 0x57: /* LD D,A */ + DE = (DE & 0xff) | (AF & ~0xff); + break; + + case 0x58: /* LD E,B */ + DE = (DE & ~0xff) | ((BC >> 8) & 0xff); + break; + + case 0x59: /* LD E,C */ + DE = (DE & ~0xff) | (BC & 0xff); + break; + + case 0x5a: /* LD E,D */ + DE = (DE & ~0xff) | ((DE >> 8) & 0xff); + break; + + case 0x5b: /* LD E,E */ + break; + + case 0x5c: /* LD E,H */ + DE = (DE & ~0xff) | ((HL >> 8) & 0xff); + break; + + case 0x5d: /* LD E,L */ + DE = (DE & ~0xff) | (HL & 0xff); + break; + + case 0x5e: /* LD E,(HL) */ + SET_LOW_REGISTER(DE, GET_BYTE(HL)); + break; + + case 0x5f: /* LD E,A */ + DE = (DE & ~0xff) | ((AF >> 8) & 0xff); + break; + + case 0x60: /* LD H,B */ + HL = (HL & 0xff) | (BC & ~0xff); + break; + + case 0x61: /* LD H,C */ + HL = (HL & 0xff) | ((BC & 0xff) << 8); + break; + + case 0x62: /* LD H,D */ + HL = (HL & 0xff) | (DE & ~0xff); + break; + + case 0x63: /* LD H,E */ + HL = (HL & 0xff) | ((DE & 0xff) << 8); + break; + + case 0x64: /* LD H,H */ + break; + + case 0x65: /* LD H,L */ + HL = (HL & 0xff) | ((HL & 0xff) << 8); + break; + + case 0x66: /* LD H,(HL) */ + SET_HIGH_REGISTER(HL, GET_BYTE(HL)); + break; + + case 0x67: /* LD H,A */ + HL = (HL & 0xff) | (AF & ~0xff); + break; + + case 0x68: /* LD L,B */ + HL = (HL & ~0xff) | ((BC >> 8) & 0xff); + break; + + case 0x69: /* LD L,C */ + HL = (HL & ~0xff) | (BC & 0xff); + break; + + case 0x6a: /* LD L,D */ + HL = (HL & ~0xff) | ((DE >> 8) & 0xff); + break; + + case 0x6b: /* LD L,E */ + HL = (HL & ~0xff) | (DE & 0xff); + break; + + case 0x6c: /* LD L,H */ + HL = (HL & ~0xff) | ((HL >> 8) & 0xff); + break; + + case 0x6d: /* LD L,L */ + break; + + case 0x6e: /* LD L,(HL) */ + SET_LOW_REGISTER(HL, GET_BYTE(HL)); + break; + + case 0x6f: /* LD L,A */ + HL = (HL & ~0xff) | ((AF >> 8) & 0xff); + break; + + case 0x70: /* LD (HL),B */ + PUT_BYTE(HL, HIGH_REGISTER(BC)); + break; + + case 0x71: /* LD (HL),C */ + PUT_BYTE(HL, LOW_REGISTER(BC)); + break; + + case 0x72: /* LD (HL),D */ + PUT_BYTE(HL, HIGH_REGISTER(DE)); + break; + + case 0x73: /* LD (HL),E */ + PUT_BYTE(HL, LOW_REGISTER(DE)); + break; + + case 0x74: /* LD (HL),H */ + PUT_BYTE(HL, HIGH_REGISTER(HL)); + break; + + case 0x75: /* LD (HL),L */ + PUT_BYTE(HL, LOW_REGISTER(HL)); + break; + + case 0x76: /* HALT */ + PC--; + if (cpu_unit.flags & UNIT_CPU_STOPONHALT) { + reason = STOP_HALT; + goto end_decode; + } + sim_interval = 0; + break; + + case 0x77: /* LD (HL),A */ + PUT_BYTE(HL, HIGH_REGISTER(AF)); + break; + + case 0x78: /* LD A,B */ + AF = (AF & 0xff) | (BC & ~0xff); + break; + + case 0x79: /* LD A,C */ + AF = (AF & 0xff) | ((BC & 0xff) << 8); + break; + + case 0x7a: /* LD A,D */ + AF = (AF & 0xff) | (DE & ~0xff); + break; + + case 0x7b: /* LD A,E */ + AF = (AF & 0xff) | ((DE & 0xff) << 8); + break; + + case 0x7c: /* LD A,H */ + AF = (AF & 0xff) | (HL & ~0xff); + break; + + case 0x7d: /* LD A,L */ + AF = (AF & 0xff) | ((HL & 0xff) << 8); + break; + + case 0x7e: /* LD A,(HL) */ + SET_HIGH_REGISTER(AF, GET_BYTE(HL)); + break; + + case 0x7f: /* LD A,A */ + break; + + case 0x80: /* ADD A,B */ + temp = HIGH_REGISTER(BC); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x81: /* ADD A,C */ + temp = LOW_REGISTER(BC); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x82: /* ADD A,D */ + temp = HIGH_REGISTER(DE); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x83: /* ADD A,E */ + temp = LOW_REGISTER(DE); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x84: /* ADD A,H */ + temp = HIGH_REGISTER(HL); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x85: /* ADD A,L */ + temp = LOW_REGISTER(HL); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x86: /* ADD A,(HL) */ + temp = GET_BYTE(HL); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x87: /* ADD A,A */ + cbits = 2 * HIGH_REGISTER(AF); + AF = cbitsDup8Table[cbits] | (SET_PVS(cbits)); + break; + + case 0x88: /* ADC A,B */ + temp = HIGH_REGISTER(BC); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x89: /* ADC A,C */ + temp = LOW_REGISTER(BC); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x8a: /* ADC A,D */ + temp = HIGH_REGISTER(DE); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x8b: /* ADC A,E */ + temp = LOW_REGISTER(DE); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x8c: /* ADC A,H */ + temp = HIGH_REGISTER(HL); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x8d: /* ADC A,L */ + temp = LOW_REGISTER(HL); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x8e: /* ADC A,(HL) */ + temp = GET_BYTE(HL); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0x8f: /* ADC A,A */ + cbits = 2 * HIGH_REGISTER(AF) + TSTFLAG(C); + AF = cbitsDup8Table[cbits] | (SET_PVS(cbits)); + break; + + case 0x90: /* SUB B */ + temp = HIGH_REGISTER(BC); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x91: /* SUB C */ + temp = LOW_REGISTER(BC); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x92: /* SUB D */ + temp = HIGH_REGISTER(DE); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x93: /* SUB E */ + temp = LOW_REGISTER(DE); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x94: /* SUB H */ + temp = HIGH_REGISTER(HL); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x95: /* SUB L */ + temp = LOW_REGISTER(HL); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x96: /* SUB (HL) */ + temp = GET_BYTE(HL); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x97: /* SUB A */ + AF = (chiptype == CHIP_TYPE_Z80) ? 0x42 : 0x46; + break; + + case 0x98: /* SBC A,B */ + temp = HIGH_REGISTER(BC); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x99: /* SBC A,C */ + temp = LOW_REGISTER(BC); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x9a: /* SBC A,D */ + temp = HIGH_REGISTER(DE); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x9b: /* SBC A,E */ + temp = LOW_REGISTER(DE); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x9c: /* SBC A,H */ + temp = HIGH_REGISTER(HL); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x9d: /* SBC A,L */ + temp = LOW_REGISTER(HL); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x9e: /* SBC A,(HL) */ + temp = GET_BYTE(HL); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0x9f: /* SBC A,A */ + cbits = -TSTFLAG(C); + AF = subTable[cbits & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PVS(cbits)); + break; + + case 0xa0: /* AND B */ + AF = andTable[((AF & BC) >> 8) & 0xff]; + break; + + case 0xa1: /* AND C */ + AF = andTable[((AF >> 8) & BC) & 0xff]; + break; + + case 0xa2: /* AND D */ + AF = andTable[((AF & DE) >> 8) & 0xff]; + break; + + case 0xa3: /* AND E */ + AF = andTable[((AF >> 8) & DE) & 0xff]; + break; + + case 0xa4: /* AND H */ + AF = andTable[((AF & HL) >> 8) & 0xff]; + break; + + case 0xa5: /* AND L */ + AF = andTable[((AF >> 8) & HL) & 0xff]; + break; + + case 0xa6: /* AND (HL) */ + AF = andTable[((AF >> 8) & GET_BYTE(HL)) & 0xff]; + break; + + case 0xa7: /* AND A */ + AF = andTable[(AF >> 8) & 0xff]; + break; + + case 0xa8: /* XOR B */ + AF = xororTable[((AF ^ BC) >> 8) & 0xff]; + break; + + case 0xa9: /* XOR C */ + AF = xororTable[((AF >> 8) ^ BC) & 0xff]; + break; + + case 0xaa: /* XOR D */ + AF = xororTable[((AF ^ DE) >> 8) & 0xff]; + break; + + case 0xab: /* XOR E */ + AF = xororTable[((AF >> 8) ^ DE) & 0xff]; + break; + + case 0xac: /* XOR H */ + AF = xororTable[((AF ^ HL) >> 8) & 0xff]; + break; + + case 0xad: /* XOR L */ + AF = xororTable[((AF >> 8) ^ HL) & 0xff]; + break; + + case 0xae: /* XOR (HL) */ + AF = xororTable[((AF >> 8) ^ GET_BYTE(HL)) & 0xff]; + break; + + case 0xaf: /* XOR A */ + AF = 0x44; + break; + + case 0xb0: /* OR B */ + AF = xororTable[((AF | BC) >> 8) & 0xff]; + break; + + case 0xb1: /* OR C */ + AF = xororTable[((AF >> 8) | BC) & 0xff]; + break; + + case 0xb2: /* OR D */ + AF = xororTable[((AF | DE) >> 8) & 0xff]; + break; + + case 0xb3: /* OR E */ + AF = xororTable[((AF >> 8) | DE) & 0xff]; + break; + + case 0xb4: /* OR H */ + AF = xororTable[((AF | HL) >> 8) & 0xff]; + break; + + case 0xb5: /* OR L */ + AF = xororTable[((AF >> 8) | HL) & 0xff]; + break; + + case 0xb6: /* OR (HL) */ + AF = xororTable[((AF >> 8) | GET_BYTE(HL)) & 0xff]; + break; + + case 0xb7: /* OR A */ + AF = xororTable[(AF >> 8) & 0xff]; + break; + + case 0xb8: /* CP B */ + temp = HIGH_REGISTER(BC); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SET_PV) | cbits2Table[cbits & 0x1ff]; + break; + + case 0xb9: /* CP C */ + temp = LOW_REGISTER(BC); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SET_PV) | cbits2Table[cbits & 0x1ff]; + break; + + case 0xba: /* CP D */ + temp = HIGH_REGISTER(DE); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SET_PV) | cbits2Table[cbits & 0x1ff]; + break; + + case 0xbb: /* CP E */ + temp = LOW_REGISTER(DE); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SET_PV) | cbits2Table[cbits & 0x1ff]; + break; + + case 0xbc: /* CP H */ + temp = HIGH_REGISTER(HL); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SET_PV) | cbits2Table[cbits & 0x1ff]; + break; + + case 0xbd: /* CP L */ + temp = LOW_REGISTER(HL); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SET_PV) | cbits2Table[cbits & 0x1ff]; + break; + + case 0xbe: /* CP (HL) */ + temp = GET_BYTE(HL); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SET_PV) | cbits2Table[cbits & 0x1ff]; + break; + + case 0xbf: /* CP A */ + SET_LOW_REGISTER(AF, (HIGH_REGISTER(AF) & 0x28) | (chiptype == CHIP_TYPE_Z80 ? 0x42 : 0x46)); + break; + + case 0xc0: /* RET NZ */ + if (!(TSTFLAG(Z))) POP(PC); + break; + + case 0xc1: /* POP BC */ + POP(BC); + break; + + case 0xc2: /* JP NZ,nnnn */ + JPC(!TSTFLAG(Z)); + break; + + case 0xc3: /* JP nnnn */ + JPC(1); + break; + + case 0xc4: /* CALL NZ,nnnn */ + CALLC(!TSTFLAG(Z)); + break; + + case 0xc5: /* PUSH BC */ + PUSH(BC); + break; + + case 0xc6: /* ADD A,nn */ + temp = RAM_PP(PC); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0xc7: /* RST 0 */ + PUSH(PC); + PC = 0; + break; + + case 0xc8: /* RET Z */ + if (TSTFLAG(Z)) POP(PC); + break; + + case 0xc9: /* RET */ + POP(PC); + break; + + case 0xca: /* JP Z,nnnn */ + JPC(TSTFLAG(Z)); + break; + + case 0xcb: /* CB prefix */ + CHECK_CPU_8080; + adr = HL; + switch ((op = GET_BYTE(PC)) & 7) { + + case 0: + ++PC; + acu = HIGH_REGISTER(BC); + break; + + case 1: + ++PC; + acu = LOW_REGISTER(BC); + break; + + case 2: + ++PC; + acu = HIGH_REGISTER(DE); + break; + + case 3: + ++PC; + acu = LOW_REGISTER(DE); + break; + + case 4: + ++PC; + acu = HIGH_REGISTER(HL); + break; + + case 5: + ++PC; + acu = LOW_REGISTER(HL); + break; + + case 6: + ++PC; + acu = GET_BYTE(adr); + break; + + case 7: + ++PC; + acu = HIGH_REGISTER(AF); + break; + } + switch (op & 0xc0) { + + case 0x00: /* shift/rotate */ + switch (op & 0x38) { + + case 0x00:/* RLC */ + temp = (acu << 1) | (acu >> 7); + cbits = temp & 1; + goto cbshflg1; + + case 0x08:/* RRC */ + temp = (acu >> 1) | (acu << 7); + cbits = temp & 0x80; + goto cbshflg1; + + case 0x10:/* RL */ + temp = (acu << 1) | TSTFLAG(C); + cbits = acu & 0x80; + goto cbshflg1; + + case 0x18:/* RR */ + temp = (acu >> 1) | (TSTFLAG(C) << 7); + cbits = acu & 1; + goto cbshflg1; + + case 0x20:/* SLA */ + temp = acu << 1; + cbits = acu & 0x80; + goto cbshflg1; + + case 0x28:/* SRA */ + temp = (acu >> 1) | (acu & 0x80); + cbits = acu & 1; + goto cbshflg1; + + case 0x30:/* SLIA */ + temp = (acu << 1) | 1; + cbits = acu & 0x80; + goto cbshflg1; + + case 0x38:/* SRL */ + temp = acu >> 1; + cbits = acu & 1; + cbshflg1: + AF = (AF & ~0xff) | rotateShiftTable[temp & 0xff] | !!cbits; + } + break; + + case 0x40: /* BIT */ + if (acu & (1 << ((op >> 3) & 7))) + AF = (AF & ~0xfe) | 0x10 | (((op & 0x38) == 0x38) << 7); + else AF = (AF & ~0xfe) | 0x54; + if ((op & 7) != 6) AF |= (acu & 0x28); + temp = acu; + break; + + case 0x80: /* RES */ + temp = acu & ~(1 << ((op >> 3) & 7)); + break; + + case 0xc0: /* SET */ + temp = acu | (1 << ((op >> 3) & 7)); + break; + } + switch (op & 7) { + + case 0: + SET_HIGH_REGISTER(BC, temp); + break; + + case 1: + SET_LOW_REGISTER(BC, temp); + break; + + case 2: + SET_HIGH_REGISTER(DE, temp); + break; + + case 3: + SET_LOW_REGISTER(DE, temp); + break; + + case 4: + SET_HIGH_REGISTER(HL, temp); + break; + + case 5: + SET_LOW_REGISTER(HL, temp); + break; + + case 6: + PUT_BYTE(adr, temp); + break; + + case 7: + SET_HIGH_REGISTER(AF, temp); + break; + } + break; + + case 0xcc: /* CALL Z,nnnn */ + CALLC(TSTFLAG(Z)); + break; + + case 0xcd: /* CALL nnnn */ + CALLC(1); + break; + + case 0xce: /* ADC A,nn */ + temp = RAM_PP(PC); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = addTable[sum] | cbitsTable[cbits] | (SET_PV); + break; + + case 0xcf: /* RST 8 */ + PUSH(PC); + PC = 8; + break; + + case 0xd0: /* RET NC */ + if (!(TSTFLAG(C))) POP(PC); + break; + + case 0xd1: /* POP DE */ + POP(DE); + break; + + case 0xd2: /* JP NC,nnnn */ + JPC(!TSTFLAG(C)); + break; + + case 0xd3: /* OUT (nn),A */ + out(RAM_PP(PC), HIGH_REGISTER(AF)); + break; + + case 0xd4: /* CALL NC,nnnn */ + CALLC(!TSTFLAG(C)); + break; + + case 0xd5: /* PUSH DE */ + PUSH(DE); + break; + + case 0xd6: /* SUB nn */ + temp = RAM_PP(PC); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0xd7: /* RST 10H */ + PUSH(PC); + PC = 0x10; + break; + + case 0xd8: /* RET C */ + if (TSTFLAG(C)) POP(PC); + break; + + case 0xd9: /* EXX */ + CHECK_CPU_8080; + temp = BC; + BC = BC1_S; + BC1_S = temp; + temp = DE; + DE = DE1_S; + DE1_S = temp; + temp = HL; + HL = HL1_S; + HL1_S = temp; + break; + + case 0xda: /* JP C,nnnn */ + JPC(TSTFLAG(C)); + break; + + case 0xdb: /* IN A,(nn) */ + SET_HIGH_REGISTER(AF, in(RAM_PP(PC))); + break; + + case 0xdc: /* CALL C,nnnn */ + CALLC(TSTFLAG(C)); + break; + + case 0xdd: /* DD prefix */ + CHECK_CPU_8080; + switch (op = RAM_PP(PC)) { + + case 0x09: /* ADD IX,BC */ + IX &= ADDRMASK; + BC &= ADDRMASK; + sum = IX + BC; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IX ^ BC ^ sum) >> 8]; + IX = sum; + break; + + case 0x19: /* ADD IX,DE */ + IX &= ADDRMASK; + DE &= ADDRMASK; + sum = IX + DE; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IX ^ DE ^ sum) >> 8]; + IX = sum; + break; + + case 0x21: /* LD IX,nnnn */ + IX = GET_WORD(PC); + PC += 2; + break; + + case 0x22: /* LD (nnnn),IX */ + temp = GET_WORD(PC); + PUT_WORD(temp, IX); + PC += 2; + break; + + case 0x23: /* INC IX */ + ++IX; + break; + + case 0x24: /* INC IXH */ + IX += 0x100; + AF = (AF & ~0xfe) | incZ80Table[HIGH_REGISTER(IX)]; + break; + + case 0x25: /* DEC IXH */ + IX -= 0x100; + AF = (AF & ~0xfe) | decZ80Table[HIGH_REGISTER(IX)]; + break; + + case 0x26: /* LD IXH,nn */ + SET_HIGH_REGISTER(IX, RAM_PP(PC)); + break; + + case 0x29: /* ADD IX,IX */ + IX &= ADDRMASK; + sum = IX + IX; + AF = (AF & ~0x3b) | cbitsDup16Table[sum >> 8]; + IX = sum; + break; + + case 0x2a: /* LD IX,(nnnn) */ + temp = GET_WORD(PC); + IX = GET_WORD(temp); + PC += 2; + break; + + case 0x2b: /* DEC IX */ + --IX; + break; + + case 0x2c: /* INC IXL */ + temp = LOW_REGISTER(IX) + 1; + SET_LOW_REGISTER(IX, temp); + AF = (AF & ~0xfe) | incZ80Table[temp]; + break; + + case 0x2d: /* DEC IXL */ + temp = LOW_REGISTER(IX) - 1; + SET_LOW_REGISTER(IX, temp); + AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; + break; + + case 0x2e: /* LD IXL,nn */ + SET_LOW_REGISTER(IX, RAM_PP(PC)); + break; + + case 0x34: /* INC (IX+dd) */ + adr = IX + (int8) RAM_PP(PC); + temp = GET_BYTE(adr) + 1; + PUT_BYTE(adr, temp); + AF = (AF & ~0xfe) | incZ80Table[temp]; + break; + + case 0x35: /* DEC (IX+dd) */ + adr = IX + (int8) RAM_PP(PC); + temp = GET_BYTE(adr) - 1; + PUT_BYTE(adr, temp); + AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; + break; + + case 0x36: /* LD (IX+dd),nn */ + adr = IX + (int8) RAM_PP(PC); + PUT_BYTE(adr, RAM_PP(PC)); + break; + + case 0x39: /* ADD IX,SP */ + IX &= ADDRMASK; + SP &= ADDRMASK; + sum = IX + SP; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IX ^ SP ^ sum) >> 8]; + IX = sum; + break; + + case 0x44: /* LD B,IXH */ + SET_HIGH_REGISTER(BC, HIGH_REGISTER(IX)); + break; + + case 0x45: /* LD B,IXL */ + SET_HIGH_REGISTER(BC, LOW_REGISTER(IX)); + break; + + case 0x46: /* LD B,(IX+dd) */ + adr = IX + (int8) RAM_PP(PC); + SET_HIGH_REGISTER(BC, GET_BYTE(adr)); + break; + + case 0x4c: /* LD C,IXH */ + SET_LOW_REGISTER(BC, HIGH_REGISTER(IX)); + break; + + case 0x4d: /* LD C,IXL */ + SET_LOW_REGISTER(BC, LOW_REGISTER(IX)); + break; + + case 0x4e: /* LD C,(IX+dd) */ + adr = IX + (int8) RAM_PP(PC); + SET_LOW_REGISTER(BC, GET_BYTE(adr)); + break; + + case 0x54: /* LD D,IXH */ + SET_HIGH_REGISTER(DE, HIGH_REGISTER(IX)); + break; + + case 0x55: /* LD D,IXL */ + SET_HIGH_REGISTER(DE, LOW_REGISTER(IX)); + break; + + case 0x56: /* LD D,(IX+dd) */ + adr = IX + (int8) RAM_PP(PC); + SET_HIGH_REGISTER(DE, GET_BYTE(adr)); + break; + + case 0x5c: /* LD E,IXH */ + SET_LOW_REGISTER(DE, HIGH_REGISTER(IX)); + break; + + case 0x5d: /* LD E,IXL */ + SET_LOW_REGISTER(DE, LOW_REGISTER(IX)); + break; + + case 0x5e: /* LD E,(IX+dd) */ + adr = IX + (int8) RAM_PP(PC); + SET_LOW_REGISTER(DE, GET_BYTE(adr)); + break; + + case 0x60: /* LD IXH,B */ + SET_HIGH_REGISTER(IX, HIGH_REGISTER(BC)); + break; + + case 0x61: /* LD IXH,C */ + SET_HIGH_REGISTER(IX, LOW_REGISTER(BC)); + break; + + case 0x62: /* LD IXH,D */ + SET_HIGH_REGISTER(IX, HIGH_REGISTER(DE)); + break; + + case 0x63: /* LD IXH,E */ + SET_HIGH_REGISTER(IX, LOW_REGISTER(DE)); + break; + + case 0x64: /* LD IXH,IXH */ + break; + + case 0x65: /* LD IXH,IXL */ + SET_HIGH_REGISTER(IX, LOW_REGISTER(IX)); + break; + + case 0x66: /* LD H,(IX+dd) */ + adr = IX + (int8) RAM_PP(PC); + SET_HIGH_REGISTER(HL, GET_BYTE(adr)); + break; + + case 0x67: /* LD IXH,A */ + SET_HIGH_REGISTER(IX, HIGH_REGISTER(AF)); + break; + + case 0x68: /* LD IXL,B */ + SET_LOW_REGISTER(IX, HIGH_REGISTER(BC)); + break; + + case 0x69: /* LD IXL,C */ + SET_LOW_REGISTER(IX, LOW_REGISTER(BC)); + break; + + case 0x6a: /* LD IXL,D */ + SET_LOW_REGISTER(IX, HIGH_REGISTER(DE)); + break; + + case 0x6b: /* LD IXL,E */ + SET_LOW_REGISTER(IX, LOW_REGISTER(DE)); + break; + + case 0x6c: /* LD IXL,IXH */ + SET_LOW_REGISTER(IX, HIGH_REGISTER(IX)); + break; + + case 0x6d: /* LD IXL,IXL */ + break; + + case 0x6e: /* LD L,(IX+dd) */ + adr = IX + (int8) RAM_PP(PC); + SET_LOW_REGISTER(HL, GET_BYTE(adr)); + break; + + case 0x6f: /* LD IXL,A */ + SET_LOW_REGISTER(IX, HIGH_REGISTER(AF)); + break; + + case 0x70: /* LD (IX+dd),B */ + adr = IX + (int8) RAM_PP(PC); + PUT_BYTE(adr, HIGH_REGISTER(BC)); + break; + + case 0x71: /* LD (IX+dd),C */ + adr = IX + (int8) RAM_PP(PC); + PUT_BYTE(adr, LOW_REGISTER(BC)); + break; + + case 0x72: /* LD (IX+dd),D */ + adr = IX + (int8) RAM_PP(PC); + PUT_BYTE(adr, HIGH_REGISTER(DE)); + break; + + case 0x73: /* LD (IX+dd),E */ + adr = IX + (int8) RAM_PP(PC); + PUT_BYTE(adr, LOW_REGISTER(DE)); + break; + + case 0x74: /* LD (IX+dd),H */ + adr = IX + (int8) RAM_PP(PC); + PUT_BYTE(adr, HIGH_REGISTER(HL)); + break; + + case 0x75: /* LD (IX+dd),L */ + adr = IX + (int8) RAM_PP(PC); + PUT_BYTE(adr, LOW_REGISTER(HL)); + break; + + case 0x77: /* LD (IX+dd),A */ + adr = IX + (int8) RAM_PP(PC); + PUT_BYTE(adr, HIGH_REGISTER(AF)); + break; + + case 0x7c: /* LD A,IXH */ + SET_HIGH_REGISTER(AF, HIGH_REGISTER(IX)); + break; + + case 0x7d: /* LD A,IXL */ + SET_HIGH_REGISTER(AF, LOW_REGISTER(IX)); + break; + + case 0x7e: /* LD A,(IX+dd) */ + adr = IX + (int8) RAM_PP(PC); + SET_HIGH_REGISTER(AF, GET_BYTE(adr)); + break; + + case 0x84: /* ADD A,IXH */ + temp = HIGH_REGISTER(IX); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x85: /* ADD A,IXL */ + temp = LOW_REGISTER(IX); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x86: /* ADD A,(IX+dd) */ + adr = IX + (int8) RAM_PP(PC); + temp = GET_BYTE(adr); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x8c: /* ADC A,IXH */ + temp = HIGH_REGISTER(IX); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x8d: /* ADC A,IXL */ + temp = LOW_REGISTER(IX); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x8e: /* ADC A,(IX+dd) */ + adr = IX + (int8) RAM_PP(PC); + temp = GET_BYTE(adr); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x96: /* SUB (IX+dd) */ + adr = IX + (int8) RAM_PP(PC); + temp = GET_BYTE(adr); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0x94: /* SUB IXH */ + SETFLAG(C, 0);/* fall through, a bit less efficient but smaller code */ + + case 0x9c: /* SBC A,IXH */ + temp = HIGH_REGISTER(IX); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0x95: /* SUB IXL */ + SETFLAG(C, 0);/* fall through, a bit less efficient but smaller code */ + + case 0x9d: /* SBC A,IXL */ + temp = LOW_REGISTER(IX); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0x9e: /* SBC A,(IX+dd) */ + adr = IX + (int8) RAM_PP(PC); + temp = GET_BYTE(adr); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0xa4: /* AND IXH */ + AF = andTable[((AF & IX) >> 8) & 0xff]; + break; + + case 0xa5: /* AND IXL */ + AF = andTable[((AF >> 8) & IX) & 0xff]; + break; + + case 0xa6: /* AND (IX+dd) */ + adr = IX + (int8) RAM_PP(PC); + AF = andTable[((AF >> 8) & GET_BYTE(adr)) & 0xff]; + break; + + case 0xac: /* XOR IXH */ + AF = xororTable[((AF ^ IX) >> 8) & 0xff]; + break; + + case 0xad: /* XOR IXL */ + AF = xororTable[((AF >> 8) ^ IX) & 0xff]; + break; + + case 0xae: /* XOR (IX+dd) */ + adr = IX + (int8) RAM_PP(PC); + AF = xororTable[((AF >> 8) ^ GET_BYTE(adr)) & 0xff]; + break; + + case 0xb4: /* OR IXH */ + AF = xororTable[((AF | IX) >> 8) & 0xff]; + break; + + case 0xb5: /* OR IXL */ + AF = xororTable[((AF >> 8) | IX) & 0xff]; + break; + + case 0xb6: /* OR (IX+dd) */ + adr = IX + (int8) RAM_PP(PC); + AF = xororTable[((AF >> 8) | GET_BYTE(adr)) & 0xff]; + break; + + case 0xbc: /* CP IXH */ + temp = HIGH_REGISTER(IX); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0xbd: /* CP IXL */ + temp = LOW_REGISTER(IX); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0xbe: /* CP (IX+dd) */ + adr = IX + (int8) RAM_PP(PC); + temp = GET_BYTE(adr); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0xcb: /* CB prefix */ + adr = IX + (int8) RAM_PP(PC); + switch ((op = GET_BYTE(PC)) & 7) { + + case 0: + ++PC; + acu = HIGH_REGISTER(BC); + break; + + case 1: + ++PC; + acu = LOW_REGISTER(BC); + break; + + case 2: + ++PC; + acu = HIGH_REGISTER(DE); + break; + + case 3: + ++PC; + acu = LOW_REGISTER(DE); + break; + + case 4: + ++PC; + acu = HIGH_REGISTER(HL); + break; + + case 5: + ++PC; + acu = LOW_REGISTER(HL); + break; + + case 6: + ++PC; + acu = GET_BYTE(adr); + break; + + case 7: + ++PC; + acu = HIGH_REGISTER(AF); + break; + } + switch (op & 0xc0) { + + case 0x00: /* shift/rotate */ + switch (op & 0x38) { + + case 0x00:/* RLC */ + temp = (acu << 1) | (acu >> 7); + cbits = temp & 1; + goto cbshflg2; + + case 0x08:/* RRC */ + temp = (acu >> 1) | (acu << 7); + cbits = temp & 0x80; + goto cbshflg2; + + case 0x10:/* RL */ + temp = (acu << 1) | TSTFLAG(C); + cbits = acu & 0x80; + goto cbshflg2; + + case 0x18:/* RR */ + temp = (acu >> 1) | (TSTFLAG(C) << 7); + cbits = acu & 1; + goto cbshflg2; + + case 0x20:/* SLA */ + temp = acu << 1; + cbits = acu & 0x80; + goto cbshflg2; + + case 0x28:/* SRA */ + temp = (acu >> 1) | (acu & 0x80); + cbits = acu & 1; + goto cbshflg2; + + case 0x30:/* SLIA */ + temp = (acu << 1) | 1; + cbits = acu & 0x80; + goto cbshflg2; + + case 0x38:/* SRL */ + temp = acu >> 1; + cbits = acu & 1; + cbshflg2: + AF = (AF & ~0xff) | rotateShiftTable[temp & 0xff] | !!cbits; + } + break; + + case 0x40: /* BIT */ + if (acu & (1 << ((op >> 3) & 7))) + AF = (AF & ~0xfe) | 0x10 | (((op & 0x38) == 0x38) << 7); + else AF = (AF & ~0xfe) | 0x54; + if ((op & 7) != 6) AF |= (acu & 0x28); + temp = acu; + break; + + case 0x80: /* RES */ + temp = acu & ~(1 << ((op >> 3) & 7)); + break; + + case 0xc0: /* SET */ + temp = acu | (1 << ((op >> 3) & 7)); + break; + } + switch (op & 7) { + + case 0: + SET_HIGH_REGISTER(BC, temp); + break; + + case 1: + SET_LOW_REGISTER(BC, temp); + break; + + case 2: + SET_HIGH_REGISTER(DE, temp); + break; + + case 3: + SET_LOW_REGISTER(DE, temp); + break; + + case 4: + SET_HIGH_REGISTER(HL, temp); + break; + + case 5: + SET_LOW_REGISTER(HL, temp); + break; + + case 6: + PUT_BYTE(adr, temp); + break; + + case 7: + SET_HIGH_REGISTER(AF, temp); + break; + } + break; + + case 0xe1: /* POP IX */ + POP(IX); + break; + + case 0xe3: /* EX (SP),IX */ + temp = IX; + POP(IX); + PUSH(temp); + break; + + case 0xe5: /* PUSH IX */ + PUSH(IX); + break; + + case 0xe9: /* JP (IX) */ + PC = IX; + break; + + case 0xf9: /* LD SP,IX */ + SP = IX; + break; + + default: /* ignore DD */ + CHECK_CPU_Z80; + PC--; + } + break; + + case 0xde: /* SBC A,nn */ + temp = RAM_PP(PC); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = subTable[sum & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PV); + break; + + case 0xdf: /* RST 18H */ + PUSH(PC); + PC = 0x18; + break; + + case 0xe0: /* RET PO */ + if (!(TSTFLAG(P))) POP(PC); + break; + + case 0xe1: /* POP HL */ + POP(HL); + break; + + case 0xe2: /* JP PO,nnnn */ + JPC(!TSTFLAG(P)); + break; + + case 0xe3: /* EX (SP),HL */ + temp = HL; + POP(HL); + PUSH(temp); + break; + + case 0xe4: /* CALL PO,nnnn */ + CALLC(!TSTFLAG(P)); + break; + + case 0xe5: /* PUSH HL */ + PUSH(HL); + break; + + case 0xe6: /* AND nn */ + AF = andTable[((AF >> 8) & RAM_PP(PC)) & 0xff]; + break; + + case 0xe7: /* RST 20H */ + PUSH(PC); + PC = 0x20; + break; + + case 0xe8: /* RET PE */ + if (TSTFLAG(P)) POP(PC); + break; + + case 0xe9: /* JP (HL) */ + PC = HL; + break; + + case 0xea: /* JP PE,nnnn */ + JPC(TSTFLAG(P)); + break; + + case 0xeb: /* EX DE,HL */ + temp = HL; + HL = DE; + DE = temp; + break; + + case 0xec: /* CALL PE,nnnn */ + CALLC(TSTFLAG(P)); + break; + + case 0xed: /* ED prefix */ + CHECK_CPU_8080; + switch (op = RAM_PP(PC)) { + + case 0x40: /* IN B,(C) */ + temp = in(LOW_REGISTER(BC)); + SET_HIGH_REGISTER(BC, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + + case 0x41: /* OUT (C),B */ + out(LOW_REGISTER(BC), HIGH_REGISTER(BC)); + break; + + case 0x42: /* SBC HL,BC */ + HL &= ADDRMASK; + BC &= ADDRMASK; + sum = HL - BC - TSTFLAG(C); + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | + cbits2Z80Table[((HL ^ BC ^ sum) >> 8) & 0x1ff]; + HL = sum; + break; + + case 0x43: /* LD (nnnn),BC */ + temp = GET_WORD(PC); + PUT_WORD(temp, BC); + PC += 2; + break; + + case 0x44: /* NEG */ + + case 0x4C: /* NEG, unofficial */ + + case 0x54: /* NEG, unofficial */ + + case 0x5C: /* NEG, unofficial */ + + case 0x64: /* NEG, unofficial */ + + case 0x6C: /* NEG, unofficial */ + + case 0x74: /* NEG, unofficial */ + + case 0x7C: /* NEG, unofficial */ + temp = HIGH_REGISTER(AF); + AF = ((~(AF & 0xff00) + 1) & 0xff00); /* AF = (-(AF & 0xff00) & 0xff00); */ + AF |= ((AF >> 8) & 0xa8) | (((AF & 0xff00) == 0) << 6) | negTable[temp]; + break; + + case 0x45: /* RETN */ + + case 0x55: /* RETN, unofficial */ + + case 0x5D: /* RETN, unofficial */ + + case 0x65: /* RETN, unofficial */ + + case 0x6D: /* RETN, unofficial */ + + case 0x75: /* RETN, unofficial */ + + case 0x7D: /* RETN, unofficial */ + IFF_S |= IFF_S >> 1; + POP(PC); + break; + + case 0x46: /* IM 0 */ + /* interrupt mode 0 */ + break; + + case 0x47: /* LD I,A */ + IR_S = (IR_S & 0xff) | (AF & ~0xff); + break; + + case 0x48: /* IN C,(C) */ + temp = in(LOW_REGISTER(BC)); + SET_LOW_REGISTER(BC, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + + case 0x49: /* OUT (C),C */ + out(LOW_REGISTER(BC), LOW_REGISTER(BC)); + break; + + case 0x4a: /* ADC HL,BC */ + HL &= ADDRMASK; + BC &= ADDRMASK; + sum = HL + BC + TSTFLAG(C); + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | + cbitsZ80Table[(HL ^ BC ^ sum) >> 8]; + HL = sum; + break; + + case 0x4b: /* LD BC,(nnnn) */ + temp = GET_WORD(PC); + BC = GET_WORD(temp); + PC += 2; + break; + + case 0x4d: /* RETI */ + IFF_S |= IFF_S >> 1; + POP(PC); + break; + + case 0x4f: /* LD R,A */ + IR_S = (IR_S & ~0xff) | ((AF >> 8) & 0xff); + break; + + case 0x50: /* IN D,(C) */ + temp = in(LOW_REGISTER(BC)); + SET_HIGH_REGISTER(DE, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + + case 0x51: /* OUT (C),D */ + out(LOW_REGISTER(BC), HIGH_REGISTER(DE)); + break; + + case 0x52: /* SBC HL,DE */ + HL &= ADDRMASK; + DE &= ADDRMASK; + sum = HL - DE - TSTFLAG(C); + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | + cbits2Z80Table[((HL ^ DE ^ sum) >> 8) & 0x1ff]; + HL = sum; + break; + + case 0x53: /* LD (nnnn),DE */ + temp = GET_WORD(PC); + PUT_WORD(temp, DE); + PC += 2; + break; + + case 0x56: /* IM 1 */ + /* interrupt mode 1 */ + break; + + case 0x57: /* LD A,I */ + AF = (AF & 0x29) | (IR_S & ~0xff) | ((IR_S >> 8) & 0x80) | (((IR_S & ~0xff) == 0) << 6) | ((IFF_S & 2) << 1); + break; + + case 0x58: /* IN E,(C) */ + temp = in(LOW_REGISTER(BC)); + SET_LOW_REGISTER(DE, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + + case 0x59: /* OUT (C),E */ + out(LOW_REGISTER(BC), LOW_REGISTER(DE)); + break; + + case 0x5a: /* ADC HL,DE */ + HL &= ADDRMASK; + DE &= ADDRMASK; + sum = HL + DE + TSTFLAG(C); + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | + cbitsZ80Table[(HL ^ DE ^ sum) >> 8]; + HL = sum; + break; + + case 0x5b: /* LD DE,(nnnn) */ + temp = GET_WORD(PC); + DE = GET_WORD(temp); + PC += 2; + break; + + case 0x5e: /* IM 2 */ + /* interrupt mode 2 */ + break; + + case 0x5f: /* LD A,R */ + AF = (AF & 0x29) | ((IR_S & 0xff) << 8) | (IR_S & 0x80) | + (((IR_S & 0xff) == 0) << 6) | ((IFF_S & 2) << 1); + break; + + case 0x60: /* IN H,(C) */ + temp = in(LOW_REGISTER(BC)); + SET_HIGH_REGISTER(HL, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + + case 0x61: /* OUT (C),H */ + out(LOW_REGISTER(BC), HIGH_REGISTER(HL)); + break; + + case 0x62: /* SBC HL,HL */ + HL &= ADDRMASK; + sum = HL - HL - TSTFLAG(C); + AF = (AF & ~0xff) | (((sum & ADDRMASK) == 0) << 6) | + cbits2Z80DupTable[(sum >> 8) & 0x1ff]; + HL = sum; + break; + + case 0x63: /* LD (nnnn),HL */ + temp = GET_WORD(PC); + PUT_WORD(temp, HL); + PC += 2; + break; + + case 0x67: /* RRD */ + temp = GET_BYTE(HL); + acu = HIGH_REGISTER(AF); + PUT_BYTE(HL, HIGH_DIGIT(temp) | (LOW_DIGIT(acu) << 4)); + AF = rrdrldTable[(acu & 0xf0) | LOW_DIGIT(temp)] | (AF & 1); + break; + + case 0x68: /* IN L,(C) */ + temp = in(LOW_REGISTER(BC)); + SET_LOW_REGISTER(HL, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + + case 0x69: /* OUT (C),L */ + out(LOW_REGISTER(BC), LOW_REGISTER(HL)); + break; + + case 0x6a: /* ADC HL,HL */ + HL &= ADDRMASK; + sum = HL + HL + TSTFLAG(C); + AF = (AF & ~0xff) | (((sum & ADDRMASK) == 0) << 6) | + cbitsZ80DupTable[sum >> 8]; + HL = sum; + break; + + case 0x6b: /* LD HL,(nnnn) */ + temp = GET_WORD(PC); + HL = GET_WORD(temp); + PC += 2; + break; + + case 0x6f: /* RLD */ + temp = GET_BYTE(HL); + acu = HIGH_REGISTER(AF); + PUT_BYTE(HL, (LOW_DIGIT(temp) << 4) | LOW_DIGIT(acu)); + AF = rrdrldTable[(acu & 0xf0) | HIGH_DIGIT(temp)] | (AF & 1); + break; + + case 0x70: /* IN (C) */ + temp = in(LOW_REGISTER(BC)); + SET_LOW_REGISTER(temp, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + + case 0x71: /* OUT (C),0 */ + out(LOW_REGISTER(BC), 0); + break; + + case 0x72: /* SBC HL,SP */ + HL &= ADDRMASK; + SP &= ADDRMASK; + sum = HL - SP - TSTFLAG(C); + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | + cbits2Z80Table[((HL ^ SP ^ sum) >> 8) & 0x1ff]; + HL = sum; + break; + + case 0x73: /* LD (nnnn),SP */ + temp = GET_WORD(PC); + PUT_WORD(temp, SP); + PC += 2; + break; + + case 0x78: /* IN A,(C) */ + temp = in(LOW_REGISTER(BC)); + SET_HIGH_REGISTER(AF, temp); + AF = (AF & ~0xfe) | rotateShiftTable[temp & 0xff]; + break; + + case 0x79: /* OUT (C),A */ + out(LOW_REGISTER(BC), HIGH_REGISTER(AF)); + break; + + case 0x7a: /* ADC HL,SP */ + HL &= ADDRMASK; + SP &= ADDRMASK; + sum = HL + SP + TSTFLAG(C); + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | (((sum & ADDRMASK) == 0) << 6) | + cbitsZ80Table[(HL ^ SP ^ sum) >> 8]; + HL = sum; + break; + + case 0x7b: /* LD SP,(nnnn) */ + temp = GET_WORD(PC); + SP = GET_WORD(temp); + PC += 2; + break; + + case 0xa0: /* LDI */ + acu = RAM_PP(HL); + PUT_BYTE_PP(DE, acu); + acu += HIGH_REGISTER(AF); + AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4) | + (((--BC & ADDRMASK) != 0) << 2); + break; + + case 0xa1: /* CPI */ + acu = HIGH_REGISTER(AF); + temp = RAM_PP(HL); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | + (((sum - ((cbits & 16) >> 4)) & 2) << 4) | (cbits & 16) | + ((sum - ((cbits >> 4) & 1)) & 8) | + ((--BC & ADDRMASK) != 0) << 2 | 2; + if ((sum & 15) == 8 && (cbits & 16) != 0) AF &= ~8; + break; + +/* SF, ZF, YF, XF flags are affected by decreasing register B, as in DEC B. + NF flag A is copy of bit 7 of the value read from or written to an I/O port. + INI/INIR/IND/INDR use the C flag in stead of the L register. There is a + catch though, because not the value of C is used, but C + 1 if it's INI/INIR or + C - 1 if it's IND/INDR. So, first of all INI/INIR: + HF and CF Both set if ((HL) + ((C + 1) & 255) > 255) + PF The parity of (((HL) + ((C + 1) & 255)) & 7) xor B) */ + case 0xa2: /* INI */ + acu = in(LOW_REGISTER(BC)); + PUT_BYTE(HL, acu); + ++HL; + temp = HIGH_REGISTER(BC); + BC -= 0x100; + INOUTFLAGS_NONZERO((LOW_REGISTER(BC) + 1) & 0xff); + break; + +/* SF, ZF, YF, XF flags are affected by decreasing register B, as in DEC B. + NF flag A is copy of bit 7 of the value read from or written to an I/O port. + And now the for OUTI/OTIR/OUTD/OTDR instructions. Take state of the L + after the increment or decrement of HL; add the value written to the I/O port + to; call that k for now. If k > 255, then the CF and HF flags are set. The PF + flags is set like the parity of k bitwise and'ed with 7, bitwise xor'ed with B. + HF and CF Both set if ((HL) + L > 255) + PF The parity of ((((HL) + L) & 7) xor B) */ + case 0xa3: /* OUTI */ + acu = GET_BYTE(HL); + out(LOW_REGISTER(BC), acu); + ++HL; + temp = HIGH_REGISTER(BC); + BC -= 0x100; + INOUTFLAGS_NONZERO(LOW_REGISTER(HL)); + break; + + case 0xa8: /* LDD */ + acu = RAM_MM(HL); + PUT_BYTE_MM(DE, acu); + acu += HIGH_REGISTER(AF); + AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4) | + (((--BC & ADDRMASK) != 0) << 2); + break; + + case 0xa9: /* CPD */ + acu = HIGH_REGISTER(AF); + temp = RAM_MM(HL); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | + (((sum - ((cbits & 16) >> 4)) & 2) << 4) | (cbits & 16) | + ((sum - ((cbits >> 4) & 1)) & 8) | + ((--BC & ADDRMASK) != 0) << 2 | 2; + if ((sum & 15) == 8 && (cbits & 16) != 0) AF &= ~8; + break; + +/* SF, ZF, YF, XF flags are affected by decreasing register B, as in DEC B. + NF flag A is copy of bit 7 of the value read from or written to an I/O port. + INI/INIR/IND/INDR use the C flag in stead of the L register. There is a + catch though, because not the value of C is used, but C + 1 if it's INI/INIR or + C - 1 if it's IND/INDR. And last IND/INDR: + HF and CF Both set if ((HL) + ((C - 1) & 255) > 255) + PF The parity of (((HL) + ((C - 1) & 255)) & 7) xor B) */ + case 0xaa: /* IND */ + acu = in(LOW_REGISTER(BC)); + PUT_BYTE(HL, acu); + --HL; + temp = HIGH_REGISTER(BC); + BC -= 0x100; + INOUTFLAGS_NONZERO((LOW_REGISTER(BC) - 1) & 0xff); + break; + + case 0xab: /* OUTD */ + acu = GET_BYTE(HL); + out(LOW_REGISTER(BC), acu); + --HL; + temp = HIGH_REGISTER(BC); + BC -= 0x100; + INOUTFLAGS_NONZERO(LOW_REGISTER(HL)); + break; + + case 0xb0: /* LDIR */ + acu = HIGH_REGISTER(AF); + BC &= ADDRMASK; + if (BC == 0) BC = 0x10000; + do { + acu = RAM_PP(HL); + PUT_BYTE_PP(DE, acu); + } while (--BC); + acu += HIGH_REGISTER(AF); + AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4); + break; + + case 0xb1: /* CPIR */ + acu = HIGH_REGISTER(AF); + BC &= ADDRMASK; + if (BC == 0) BC = 0x10000; + do { + temp = RAM_PP(HL); + op = --BC != 0; + sum = acu - temp; + } while (op && sum != 0); + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | + (((sum - ((cbits & 16) >> 4)) & 2) << 4) | + (cbits & 16) | ((sum - ((cbits >> 4) & 1)) & 8) | + op << 2 | 2; + if ((sum & 15) == 8 && (cbits & 16) != 0) AF &= ~8; + break; + + case 0xb2: /* INIR */ + temp = HIGH_REGISTER(BC); + if (temp == 0) temp = 0x100; + do { + acu = in(LOW_REGISTER(BC)); + PUT_BYTE(HL, acu); + ++HL; + } while (--temp); + temp = HIGH_REGISTER(BC); + SET_HIGH_REGISTER(BC, 0); + INOUTFLAGS_ZERO((LOW_REGISTER(BC) + 1) & 0xff); + break; + + case 0xb3: /* OTIR */ + temp = HIGH_REGISTER(BC); + if (temp == 0) temp = 0x100; + do { + acu = GET_BYTE(HL); + out(LOW_REGISTER(BC), acu); + ++HL; + } while (--temp); + temp = HIGH_REGISTER(BC); + SET_HIGH_REGISTER(BC, 0); + INOUTFLAGS_ZERO(LOW_REGISTER(HL)); + break; + + case 0xb8: /* LDDR */ + BC &= ADDRMASK; + if (BC == 0) BC = 0x10000; + do { + acu = RAM_MM(HL); + PUT_BYTE_MM(DE, acu); + } while (--BC); + acu += HIGH_REGISTER(AF); + AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4); + break; + + case 0xb9: /* CPDR */ + acu = HIGH_REGISTER(AF); + BC &= ADDRMASK; + if (BC == 0) BC = 0x10000; + do { + temp = RAM_MM(HL); + op = --BC != 0; + sum = acu - temp; + } while (op && sum != 0); + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | + (((sum - ((cbits & 16) >> 4)) & 2) << 4) | + (cbits & 16) | ((sum - ((cbits >> 4) & 1)) & 8) | + op << 2 | 2; + if ((sum & 15) == 8 && (cbits & 16) != 0) AF &= ~8; + break; + + case 0xba: /* INDR */ + temp = HIGH_REGISTER(BC); + if (temp == 0) temp = 0x100; + do { + acu = in(LOW_REGISTER(BC)); + PUT_BYTE(HL, acu); + --HL; + } while (--temp); + temp = HIGH_REGISTER(BC); + SET_HIGH_REGISTER(BC, 0); + INOUTFLAGS_ZERO((LOW_REGISTER(BC) - 1) & 0xff); + break; + + case 0xbb: /* OTDR */ + temp = HIGH_REGISTER(BC); + if (temp == 0) temp = 0x100; + do { + acu = GET_BYTE(HL); + out(LOW_REGISTER(BC), acu); + --HL; + } while (--temp); + temp = HIGH_REGISTER(BC); + SET_HIGH_REGISTER(BC, 0); + INOUTFLAGS_ZERO(LOW_REGISTER(HL)); + break; + + default: /* ignore ED and following byte */ + CHECK_CPU_Z80; + } + break; + + case 0xee: /* XOR nn */ + AF = xororTable[((AF >> 8) ^ RAM_PP(PC)) & 0xff]; + break; + + case 0xef: /* RST 28H */ + PUSH(PC); + PC = 0x28; + break; + + case 0xf0: /* RET P */ + if (!(TSTFLAG(S))) POP(PC); + break; + + case 0xf1: /* POP AF */ + POP(AF); + break; + + case 0xf2: /* JP P,nnnn */ + JPC(!TSTFLAG(S)); + break; + + case 0xf3: /* DI */ + IFF_S = 0; + break; + + case 0xf4: /* CALL P,nnnn */ + CALLC(!TSTFLAG(S)); + break; + + case 0xf5: /* PUSH AF */ + PUSH(AF); + break; + + case 0xf6: /* OR nn */ + AF = xororTable[((AF >> 8) | RAM_PP(PC)) & 0xff]; + break; + + case 0xf7: /* RST 30H */ + PUSH(PC); + PC = 0x30; + break; + + case 0xf8: /* RET M */ + if (TSTFLAG(S)) POP(PC); + break; + + case 0xf9: /* LD SP,HL */ + SP = HL; + break; + + case 0xfa: /* JP M,nnnn */ + JPC(TSTFLAG(S)); + break; + + case 0xfb: /* EI */ + IFF_S = 3; + break; + + case 0xfc: /* CALL M,nnnn */ + CALLC(TSTFLAG(S)); + break; + + case 0xfd: /* FD prefix */ + CHECK_CPU_8080; + switch (op = RAM_PP(PC)) { + + case 0x09: /* ADD IY,BC */ + IY &= ADDRMASK; + BC &= ADDRMASK; + sum = IY + BC; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IY ^ BC ^ sum) >> 8]; + IY = sum; + break; + + case 0x19: /* ADD IY,DE */ + IY &= ADDRMASK; + DE &= ADDRMASK; + sum = IY + DE; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IY ^ DE ^ sum) >> 8]; + IY = sum; + break; + + case 0x21: /* LD IY,nnnn */ + IY = GET_WORD(PC); + PC += 2; + break; + + case 0x22: /* LD (nnnn),IY */ + temp = GET_WORD(PC); + PUT_WORD(temp, IY); + PC += 2; + break; + + case 0x23: /* INC IY */ + ++IY; + break; + + case 0x24: /* INC IYH */ + IY += 0x100; + AF = (AF & ~0xfe) | incZ80Table[HIGH_REGISTER(IY)]; + break; + + case 0x25: /* DEC IYH */ + IY -= 0x100; + AF = (AF & ~0xfe) | decZ80Table[HIGH_REGISTER(IY)]; + break; + + case 0x26: /* LD IYH,nn */ + SET_HIGH_REGISTER(IY, RAM_PP(PC)); + break; + + case 0x29: /* ADD IY,IY */ + IY &= ADDRMASK; + sum = IY + IY; + AF = (AF & ~0x3b) | cbitsDup16Table[sum >> 8]; + IY = sum; + break; + + case 0x2a: /* LD IY,(nnnn) */ + temp = GET_WORD(PC); + IY = GET_WORD(temp); + PC += 2; + break; + + case 0x2b: /* DEC IY */ + --IY; + break; + + case 0x2c: /* INC IYL */ + temp = LOW_REGISTER(IY) + 1; + SET_LOW_REGISTER(IY, temp); + AF = (AF & ~0xfe) | incZ80Table[temp]; + break; + + case 0x2d: /* DEC IYL */ + temp = LOW_REGISTER(IY) - 1; + SET_LOW_REGISTER(IY, temp); + AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; + break; + + case 0x2e: /* LD IYL,nn */ + SET_LOW_REGISTER(IY, RAM_PP(PC)); + break; + + case 0x34: /* INC (IY+dd) */ + adr = IY + (int8) RAM_PP(PC); + temp = GET_BYTE(adr) + 1; + PUT_BYTE(adr, temp); + AF = (AF & ~0xfe) | incZ80Table[temp]; + break; + + case 0x35: /* DEC (IY+dd) */ + adr = IY + (int8) RAM_PP(PC); + temp = GET_BYTE(adr) - 1; + PUT_BYTE(adr, temp); + AF = (AF & ~0xfe) | decZ80Table[temp & 0xff]; + break; + + case 0x36: /* LD (IY+dd),nn */ + adr = IY + (int8) RAM_PP(PC); + PUT_BYTE(adr, RAM_PP(PC)); + break; + + case 0x39: /* ADD IY,SP */ + IY &= ADDRMASK; + SP &= ADDRMASK; + sum = IY + SP; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | cbitsTable[(IY ^ SP ^ sum) >> 8]; + IY = sum; + break; + + case 0x44: /* LD B,IYH */ + SET_HIGH_REGISTER(BC, HIGH_REGISTER(IY)); + break; + + case 0x45: /* LD B,IYL */ + SET_HIGH_REGISTER(BC, LOW_REGISTER(IY)); + break; + + case 0x46: /* LD B,(IY+dd) */ + adr = IY + (int8) RAM_PP(PC); + SET_HIGH_REGISTER(BC, GET_BYTE(adr)); + break; + + case 0x4c: /* LD C,IYH */ + SET_LOW_REGISTER(BC, HIGH_REGISTER(IY)); + break; + + case 0x4d: /* LD C,IYL */ + SET_LOW_REGISTER(BC, LOW_REGISTER(IY)); + break; + + case 0x4e: /* LD C,(IY+dd) */ + adr = IY + (int8) RAM_PP(PC); + SET_LOW_REGISTER(BC, GET_BYTE(adr)); + break; + + case 0x54: /* LD D,IYH */ + SET_HIGH_REGISTER(DE, HIGH_REGISTER(IY)); + break; + + case 0x55: /* LD D,IYL */ + SET_HIGH_REGISTER(DE, LOW_REGISTER(IY)); + break; + + case 0x56: /* LD D,(IY+dd) */ + adr = IY + (int8) RAM_PP(PC); + SET_HIGH_REGISTER(DE, GET_BYTE(adr)); + break; + + case 0x5c: /* LD E,IYH */ + SET_LOW_REGISTER(DE, HIGH_REGISTER(IY)); + break; + + case 0x5d: /* LD E,IYL */ + SET_LOW_REGISTER(DE, LOW_REGISTER(IY)); + break; + + case 0x5e: /* LD E,(IY+dd) */ + adr = IY + (int8) RAM_PP(PC); + SET_LOW_REGISTER(DE, GET_BYTE(adr)); + break; + + case 0x60: /* LD IYH,B */ + SET_HIGH_REGISTER(IY, HIGH_REGISTER(BC)); + break; + + case 0x61: /* LD IYH,C */ + SET_HIGH_REGISTER(IY, LOW_REGISTER(BC)); + break; + + case 0x62: /* LD IYH,D */ + SET_HIGH_REGISTER(IY, HIGH_REGISTER(DE)); + break; + + case 0x63: /* LD IYH,E */ + SET_HIGH_REGISTER(IY, LOW_REGISTER(DE)); + break; + + case 0x64: /* LD IYH,IYH */ + break; + + case 0x65: /* LD IYH,IYL */ + SET_HIGH_REGISTER(IY, LOW_REGISTER(IY)); + break; + + case 0x66: /* LD H,(IY+dd) */ + adr = IY + (int8) RAM_PP(PC); + SET_HIGH_REGISTER(HL, GET_BYTE(adr)); + break; + + case 0x67: /* LD IYH,A */ + SET_HIGH_REGISTER(IY, HIGH_REGISTER(AF)); + break; + + case 0x68: /* LD IYL,B */ + SET_LOW_REGISTER(IY, HIGH_REGISTER(BC)); + break; + + case 0x69: /* LD IYL,C */ + SET_LOW_REGISTER(IY, LOW_REGISTER(BC)); + break; + + case 0x6a: /* LD IYL,D */ + SET_LOW_REGISTER(IY, HIGH_REGISTER(DE)); + break; + + case 0x6b: /* LD IYL,E */ + SET_LOW_REGISTER(IY, LOW_REGISTER(DE)); + break; + + case 0x6c: /* LD IYL,IYH */ + SET_LOW_REGISTER(IY, HIGH_REGISTER(IY)); + break; + + case 0x6d: /* LD IYL,IYL */ + break; + + case 0x6e: /* LD L,(IY+dd) */ + adr = IY + (int8) RAM_PP(PC); + SET_LOW_REGISTER(HL, GET_BYTE(adr)); + break; + + case 0x6f: /* LD IYL,A */ + SET_LOW_REGISTER(IY, HIGH_REGISTER(AF)); + break; + + case 0x70: /* LD (IY+dd),B */ + adr = IY + (int8) RAM_PP(PC); + PUT_BYTE(adr, HIGH_REGISTER(BC)); + break; + + case 0x71: /* LD (IY+dd),C */ + adr = IY + (int8) RAM_PP(PC); + PUT_BYTE(adr, LOW_REGISTER(BC)); + break; + + case 0x72: /* LD (IY+dd),D */ + adr = IY + (int8) RAM_PP(PC); + PUT_BYTE(adr, HIGH_REGISTER(DE)); + break; + + case 0x73: /* LD (IY+dd),E */ + adr = IY + (int8) RAM_PP(PC); + PUT_BYTE(adr, LOW_REGISTER(DE)); + break; + + case 0x74: /* LD (IY+dd),H */ + adr = IY + (int8) RAM_PP(PC); + PUT_BYTE(adr, HIGH_REGISTER(HL)); + break; + + case 0x75: /* LD (IY+dd),L */ + adr = IY + (int8) RAM_PP(PC); + PUT_BYTE(adr, LOW_REGISTER(HL)); + break; + + case 0x77: /* LD (IY+dd),A */ + adr = IY + (int8) RAM_PP(PC); + PUT_BYTE(adr, HIGH_REGISTER(AF)); + break; + + case 0x7c: /* LD A,IYH */ + SET_HIGH_REGISTER(AF, HIGH_REGISTER(IY)); + break; + + case 0x7d: /* LD A,IYL */ + SET_HIGH_REGISTER(AF, LOW_REGISTER(IY)); + break; + + case 0x7e: /* LD A,(IY+dd) */ + adr = IY + (int8) RAM_PP(PC); + SET_HIGH_REGISTER(AF, GET_BYTE(adr)); + break; + + case 0x84: /* ADD A,IYH */ + temp = HIGH_REGISTER(IY); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x85: /* ADD A,IYL */ + temp = LOW_REGISTER(IY); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x86: /* ADD A,(IY+dd) */ + adr = IY + (int8) RAM_PP(PC); + temp = GET_BYTE(adr); + acu = HIGH_REGISTER(AF); + sum = acu + temp; + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x8c: /* ADC A,IYH */ + temp = HIGH_REGISTER(IY); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x8d: /* ADC A,IYL */ + temp = LOW_REGISTER(IY); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x8e: /* ADC A,(IY+dd) */ + adr = IY + (int8) RAM_PP(PC); + temp = GET_BYTE(adr); + acu = HIGH_REGISTER(AF); + sum = acu + temp + TSTFLAG(C); + AF = addTable[sum] | cbitsZ80Table[acu ^ temp ^ sum]; + break; + + case 0x96: /* SUB (IY+dd) */ + adr = IY + (int8) RAM_PP(PC); + temp = GET_BYTE(adr); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0x94: /* SUB IYH */ + SETFLAG(C, 0);/* fall through, a bit less efficient but smaller code */ + + case 0x9c: /* SBC A,IYH */ + temp = HIGH_REGISTER(IY); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0x95: /* SUB IYL */ + SETFLAG(C, 0);/* fall through, a bit less efficient but smaller code */ + + case 0x9d: /* SBC A,IYL */ + temp = LOW_REGISTER(IY); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0x9e: /* SBC A,(IY+dd) */ + adr = IY + (int8) RAM_PP(PC); + temp = GET_BYTE(adr); + acu = HIGH_REGISTER(AF); + sum = acu - temp - TSTFLAG(C); + AF = addTable[sum & 0xff] | cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0xa4: /* AND IYH */ + AF = andTable[((AF & IY) >> 8) & 0xff]; + break; + + case 0xa5: /* AND IYL */ + AF = andTable[((AF >> 8) & IY) & 0xff]; + break; + + case 0xa6: /* AND (IY+dd) */ + adr = IY + (int8) RAM_PP(PC); + AF = andTable[((AF >> 8) & GET_BYTE(adr)) & 0xff]; + break; + + case 0xac: /* XOR IYH */ + AF = xororTable[((AF ^ IY) >> 8) & 0xff]; + break; + + case 0xad: /* XOR IYL */ + AF = xororTable[((AF >> 8) ^ IY) & 0xff]; + break; + + case 0xae: /* XOR (IY+dd) */ + adr = IY + (int8) RAM_PP(PC); + AF = xororTable[((AF >> 8) ^ GET_BYTE(adr)) & 0xff]; + break; + + case 0xb4: /* OR IYH */ + AF = xororTable[((AF | IY) >> 8) & 0xff]; + break; + + case 0xb5: /* OR IYL */ + AF = xororTable[((AF >> 8) | IY) & 0xff]; + break; + + case 0xb6: /* OR (IY+dd) */ + adr = IY + (int8) RAM_PP(PC); + AF = xororTable[((AF >> 8) | GET_BYTE(adr)) & 0xff]; + break; + + case 0xbc: /* CP IYH */ + temp = HIGH_REGISTER(IY); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0xbd: /* CP IYL */ + temp = LOW_REGISTER(IY); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0xbe: /* CP (IY+dd) */ + adr = IY + (int8) RAM_PP(PC); + temp = GET_BYTE(adr); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + cbits2Z80Table[(acu ^ temp ^ sum) & 0x1ff]; + break; + + case 0xcb: /* CB prefix */ + adr = IY + (int8) RAM_PP(PC); + switch ((op = GET_BYTE(PC)) & 7) { + + case 0: + ++PC; + acu = HIGH_REGISTER(BC); + break; + + case 1: + ++PC; + acu = LOW_REGISTER(BC); + break; + + case 2: + ++PC; + acu = HIGH_REGISTER(DE); + break; + + case 3: + ++PC; + acu = LOW_REGISTER(DE); + break; + + case 4: + ++PC; + acu = HIGH_REGISTER(HL); + break; + + case 5: + ++PC; + acu = LOW_REGISTER(HL); + break; + + case 6: + ++PC; + acu = GET_BYTE(adr); + break; + + case 7: + ++PC; + acu = HIGH_REGISTER(AF); + break; + } + switch (op & 0xc0) { + + case 0x00: /* shift/rotate */ + switch (op & 0x38) { + + case 0x00:/* RLC */ + temp = (acu << 1) | (acu >> 7); + cbits = temp & 1; + goto cbshflg3; + + case 0x08:/* RRC */ + temp = (acu >> 1) | (acu << 7); + cbits = temp & 0x80; + goto cbshflg3; + + case 0x10:/* RL */ + temp = (acu << 1) | TSTFLAG(C); + cbits = acu & 0x80; + goto cbshflg3; + + case 0x18:/* RR */ + temp = (acu >> 1) | (TSTFLAG(C) << 7); + cbits = acu & 1; + goto cbshflg3; + + case 0x20:/* SLA */ + temp = acu << 1; + cbits = acu & 0x80; + goto cbshflg3; + + case 0x28:/* SRA */ + temp = (acu >> 1) | (acu & 0x80); + cbits = acu & 1; + goto cbshflg3; + + case 0x30:/* SLIA */ + temp = (acu << 1) | 1; + cbits = acu & 0x80; + goto cbshflg3; + + case 0x38:/* SRL */ + temp = acu >> 1; + cbits = acu & 1; + cbshflg3: + AF = (AF & ~0xff) | rotateShiftTable[temp & 0xff] | !!cbits; + } + break; + + case 0x40: /* BIT */ + if (acu & (1 << ((op >> 3) & 7))) + AF = (AF & ~0xfe) | 0x10 | (((op & 0x38) == 0x38) << 7); + else AF = (AF & ~0xfe) | 0x54; + if ((op & 7) != 6) AF |= (acu & 0x28); + temp = acu; + break; + + case 0x80: /* RES */ + temp = acu & ~(1 << ((op >> 3) & 7)); + break; + + case 0xc0: /* SET */ + temp = acu | (1 << ((op >> 3) & 7)); + break; + } + switch (op & 7) { + + case 0: + SET_HIGH_REGISTER(BC, temp); + break; + + case 1: + SET_LOW_REGISTER(BC, temp); + break; + + case 2: + SET_HIGH_REGISTER(DE, temp); + break; + + case 3: + SET_LOW_REGISTER(DE, temp); + break; + + case 4: + SET_HIGH_REGISTER(HL, temp); + break; + + case 5: + SET_LOW_REGISTER(HL, temp); + break; + + case 6: + PUT_BYTE(adr, temp); + break; + + case 7: + SET_HIGH_REGISTER(AF, temp); + break; + } + break; + + case 0xe1: /* POP IY */ + POP(IY); + break; + + case 0xe3: /* EX (SP),IY */ + temp = IY; + POP(IY); + PUSH(temp); + break; + + case 0xe5: /* PUSH IY */ + PUSH(IY); + break; + + case 0xe9: /* JP (IY) */ + PC = IY; + break; + + case 0xf9: /* LD SP,IY */ + SP = IY; + break; + + default: /* ignore FD */ + CHECK_CPU_Z80; + PC--; + } + break; + + case 0xfe: /* CP nn */ + temp = RAM_PP(PC); + AF = (AF & ~0x28) | (temp & 0x28); + acu = HIGH_REGISTER(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | cpTable[sum & 0xff] | (temp & 0x28) | + (SET_PV) | cbits2Table[cbits & 0x1ff]; + break; + + case 0xff: /* RST 38H */ + PUSH(PC); + PC = 0x38; + } + } + end_decode: + + /* simulation halted */ + PC_S = (reason == STOP_OPCODE) ? PCX : PC; + AF_S = AF; + BC_S = BC; + DE_S = DE; + HL_S = HL; + IX_S = IX; + IY_S = IY; + SP_S = SP; + return reason; +} diff --git a/AltairZ80/altairz80_hdsk.c b/AltairZ80/altairz80_hdsk.c index 7a7fa5fa..5a01f6c5 100644 --- a/AltairZ80/altairz80_hdsk.c +++ b/AltairZ80/altairz80_hdsk.c @@ -1,616 +1,643 @@ -/* altairz80_hdsk.c: simulated hard disk device to increase capacity - - Copyright (c) 2002-2007, Peter Schorn - - 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 - PETER SCHORN 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 Peter Schorn shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Peter Schorn. - - Contains code from Howard M. Harte for defining and changing disk geometry. -*/ - -#include "altairz80_defs.h" -#include - -/* The following routines are based on work from Howard M. Harte */ -t_stat set_geom(UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat show_geom(FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat set_format(UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat show_format(FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat hdsk_attach(UNIT *uptr, char *cptr); - -#define UNIT_V_HDSK_WLK (UNIT_V_UF + 0) /* write locked */ -#define UNIT_HDSK_WLK (1 << UNIT_V_HDSK_WLK) -#define UNIT_V_HDSK_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ -#define UNIT_HDSK_VERBOSE (1 << UNIT_V_HDSK_VERBOSE) -#define HDSK_MAX_SECTOR_SIZE 1024 /* maximum size of a sector */ -#define HDSK_SECTOR_SIZE u5 /* size of sector */ -#define HDSK_SECTORS_PER_TRACK u4 /* sectors per track */ -#define HDSK_NUMBER_OF_TRACKS u3 /* number of tracks */ -#define HDSK_FORMAT_TYPE u6 /* Disk Format Type */ -#define HDSK_CAPACITY (2048*32*128) /* Default Altair HDSK Capacity */ -#define HDSK_NUMBER 8 /* number of hard disks */ -#define CPM_OK 0 /* indicates to CP/M everything ok */ -#define CPM_ERROR 1 /* indicates to CP/M an error condition */ -#define CPM_EMPTY 0xe5 /* default value for non-existing bytes */ -#define HDSK_NONE 0 -#define HDSK_RESET 1 -#define HDSK_READ 2 -#define HDSK_WRITE 3 -#define HDSK_PARAM 4 -#define HDSK_BOOT_ADDRESS 0x5c00 -#define DPB_NAME_LENGTH 15 - -extern char messageBuffer[]; -extern int32 PCX; -extern UNIT cpu_unit; -extern int32 saved_PC; - -extern int32 install_bootrom(void); -extern void printMessage(void); -extern void PutBYTEBasic(const uint32 Addr, const uint32 Bank, const uint32 Value); -extern void PutBYTEWrapper(const uint32 Addr, const uint32 Value); -extern void protect(const int32 l, const int32 h); -extern uint8 GetBYTEWrapper(const uint32 Addr); -extern int32 bootrom[BOOTROM_SIZE]; - -static t_stat hdsk_boot(int32 unitno, DEVICE *dptr); -int32 hdsk_io(const int32 port, const int32 io, const int32 data); - -static int32 hdskLastCommand = HDSK_NONE; -static int32 hdskCommandPosition = 0; -static int32 paramcount = 0; -static int32 selectedDisk; -static int32 selectedSector; -static int32 selectedTrack; -static int32 selectedDMA; -static int32 hdskTrace = FALSE; - -typedef struct { - char name[DPB_NAME_LENGTH + 1]; /* name of CP/M disk parameter block */ - t_addr capac; /* capacity */ - uint16 spt; /* sectors per track */ - uint8 bsh; /* data allocation block shift factor */ - uint8 blm; /* data allocation block mask */ - uint8 exm; /* extent mask */ - uint16 dsm; /* maximum data block number */ - uint16 drm; /* total number of directory entries */ - uint8 al0; /* determine reserved directory blocks */ - uint8 al1; /* determine reserved directory blocks */ - uint16 cks; /* size of directory check vector */ - uint16 off; /* number of reserved tracks */ - uint8 psh; /* physical record shift factor, CP/M 3 */ - uint8 phm; /* physical record mask, CP/M 3 */ -} DPB; - -/* Note in the following CKS = 0 for fixed media which are not supposed to be changed while CP/M is executing */ -static DPB dpb[] = { -/* name capac spt bsh blm exm dsm drm al0 al1 cks off psh phm */ - { "HDSK", HDSK_CAPACITY, 32, 0x05, 0x1F, 0x01, 0x07f9, 0x03FF, 0xFF, 0x00, 0x0000, 0x0006, 0x00, 0x00 }, /* AZ80 HDSK */ - { "EZ80FL", 131072, 32, 0x03, 0x07, 0x00, 127, 0x003E, 0xC0, 0x00, 0x0000, 0x0000, 0x02, 0x03 }, /* 128K FLASH */ - { "P112", 1474560, 72, 0x04, 0x0F, 0x00, 710, 0x00FE, 0xF0, 0x00, 0x0000, 0x0002, 0x02, 0x03 }, /* 1.44M P112 */ - { "SU720", 737280, 36, 0x04, 0x0F, 0x00, 354, 0x007E, 0xC0, 0x00, 0x0020, 0x0002, 0x02, 0x03 }, /* 720K Super I/O */ - { "SSSD8", 256256, 26, 0x03, 0x07, 0x00, 242, 0x003F, 0xC0, 0x00, 0x0000, 0x0002, 0x00, 0x00 }, /* Standard 8" SS SD */ - { "", 0 } -}; - -static UNIT hdsk_unit[] = { - { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, - { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, - { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, - { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, - { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, - { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, - { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, - { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) } -}; - -static REG hdsk_reg[] = { - { DRDATA (HDCMD, hdskLastCommand, 32), REG_RO }, - { DRDATA (HDPOS, hdskCommandPosition, 32), REG_RO }, - { DRDATA (HDDSK, selectedDisk, 32), REG_RO }, - { DRDATA (HDSEC, selectedSector, 32), REG_RO }, - { DRDATA (HDTRK, selectedTrack, 32), REG_RO }, - { DRDATA (HDDMA, selectedDMA, 32), REG_RO }, - { DRDATA (HDTRACE, hdskTrace, 8), }, - { NULL } -}; - -static MTAB hdsk_mod[] = { - { MTAB_XTD|MTAB_VUN|MTAB_VAL, 0, "FORMAT", "FORMAT", &set_format, &show_format, NULL }, - { UNIT_HDSK_WLK, 0, "WRTENB", "WRTENB", NULL }, - { UNIT_HDSK_WLK, UNIT_HDSK_WLK, "WRTLCK", "WRTLCK", NULL }, - /* quiet, no warning messages */ - { UNIT_HDSK_VERBOSE, 0, "QUIET", "QUIET", NULL }, - /* verbose, show warning messages */ - { UNIT_HDSK_VERBOSE, UNIT_HDSK_VERBOSE, "VERBOSE", "VERBOSE", NULL }, - { MTAB_XTD|MTAB_VUN|MTAB_VAL, 0, "GEOM", "GEOM", &set_geom, &show_geom, NULL }, - { 0 } -}; - -DEVICE hdsk_dev = { - "HDSK", hdsk_unit, hdsk_reg, hdsk_mod, - 8, 10, 31, 1, 8, 8, - NULL, NULL, NULL, - &hdsk_boot, &hdsk_attach, NULL, - NULL, 0, 0, - NULL, NULL, NULL -}; - -/* Attach routine */ -t_stat hdsk_attach(UNIT *uptr, char *cptr) { - t_stat r; - uint32 i; - char unitChar; - - r = attach_unit(uptr, cptr); /* attach unit */ - if ( r != SCPE_OK) /* error? */ - return r; - - /* Step 1: Determine capacity of this disk */ - uptr -> capac = sim_fsize(uptr -> fileref); /* the file length is a good candidate */ - if (uptr -> capac == 0) { /* file does not exist or has length 0 */ - uptr -> capac = uptr -> HDSK_NUMBER_OF_TRACKS * - uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE; - if (uptr -> capac == 0) - uptr -> capac = HDSK_CAPACITY; - } /* post condition: uptr -> capac > 0 */ - assert(uptr -> capac); - - /* Step 2: Determine format based on disk capacity */ - uptr -> HDSK_FORMAT_TYPE = -1; /* default to unknown format type */ - for (i = 0; dpb[i].capac != 0; i++) { /* find disk parameter block */ - if (dpb[i].capac == uptr -> capac) { /* found if correct capacity */ - uptr -> HDSK_FORMAT_TYPE = i; - break; - } - } - - /* Step 3: Set number of sectors per track and sector size */ - if (uptr -> HDSK_FORMAT_TYPE == -1) { /* Case 1: no disk parameter block found*/ - for (i = 0; i < hdsk_dev.numunits; i++) /* find affected unit number */ - if (&hdsk_unit[i] == uptr) - break; /* found */ - unitChar = '0' + i; - uptr -> HDSK_FORMAT_TYPE = 0; - printf("HDSK%c: WARNING: Unsupported disk capacity, assuming HDSK type with capacity %iKB.\n", - unitChar, uptr -> capac / 1000); - uptr -> flags |= UNIT_HDSK_WLK; - printf("HDSK%c: WARNING: Forcing WRTLCK.\n", unitChar); - /* check whether capacity corresponds to setting of tracks, sectors per track and sector size */ - if (uptr -> capac != (uptr -> HDSK_NUMBER_OF_TRACKS * - uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE)) { - printf("HDSK%c: WARNING: Fixing geometry.\n", unitChar); - if (uptr -> HDSK_SECTORS_PER_TRACK == 0) uptr -> HDSK_SECTORS_PER_TRACK = 32; - if (uptr -> HDSK_SECTOR_SIZE == 0) uptr -> HDSK_SECTOR_SIZE = 128; - } - } - else { /* Case 2: disk parameter block found */ - uptr -> HDSK_SECTORS_PER_TRACK = dpb[uptr -> HDSK_FORMAT_TYPE].spt >> dpb[uptr -> HDSK_FORMAT_TYPE].psh; - uptr -> HDSK_SECTOR_SIZE = (128 << dpb[uptr -> HDSK_FORMAT_TYPE].psh); - } - assert(uptr -> HDSK_SECTORS_PER_TRACK && uptr -> HDSK_SECTOR_SIZE); - - /* Step 4: Number of tracks is smallest number to accomodate capacity */ - uptr -> HDSK_NUMBER_OF_TRACKS = (uptr -> capac + uptr -> HDSK_SECTORS_PER_TRACK * - uptr -> HDSK_SECTOR_SIZE - 1) / (uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE); - assert( ( (t_addr) ((uptr -> HDSK_NUMBER_OF_TRACKS - 1) * uptr -> HDSK_SECTORS_PER_TRACK * - uptr -> HDSK_SECTOR_SIZE) < uptr -> capac) && - (uptr -> capac <= (t_addr) (uptr -> HDSK_NUMBER_OF_TRACKS * - uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE) ) ); - return SCPE_OK; -} - -/* Set disk geometry routine */ -t_stat set_geom(UNIT *uptr, int32 val, char *cptr, void *desc) { - uint32 numberOfTracks, numberOfSectors, sectorSize; - int result, n; - - if (cptr == NULL) return SCPE_ARG; - if (uptr == NULL) return SCPE_IERR; - result = sscanf(cptr, "%d/%d/%d%n", &numberOfTracks, &numberOfSectors, §orSize, &n); - if ((result != 3) || (result == EOF) || (cptr[n] != 0)) { - result = sscanf(cptr, "T:%d/N:%d/S:%d%n", &numberOfTracks, &numberOfSectors, §orSize, &n); - if ((result != 3) || (result == EOF) || (cptr[n] != 0)) return SCPE_ARG; - } - uptr -> HDSK_NUMBER_OF_TRACKS = numberOfTracks; - uptr -> HDSK_SECTORS_PER_TRACK = numberOfSectors; - uptr -> HDSK_SECTOR_SIZE = sectorSize; - uptr -> capac = numberOfTracks * numberOfSectors * sectorSize; - return SCPE_OK; -} - -/* Show disk geometry routine */ -t_stat show_geom(FILE *st, UNIT *uptr, int32 val, void *desc) { - if (uptr == NULL) return SCPE_IERR; - fprintf(st, "T:%d/N:%d/S:%d", uptr -> HDSK_NUMBER_OF_TRACKS, - uptr -> HDSK_SECTORS_PER_TRACK, uptr -> HDSK_SECTOR_SIZE); - return SCPE_OK; -} - -#define QUOTE1(text) #text -#define QUOTE2(text) QUOTE1(text) -/* Set disk format routine */ -t_stat set_format(UNIT *uptr, int32 val, char *cptr, void *desc) { - char fmtname[DPB_NAME_LENGTH + 1]; - int32 i; - - if (cptr == NULL) return SCPE_ARG; - if (uptr == NULL) return SCPE_IERR; - if (sscanf(cptr, "%" QUOTE2(DPB_NAME_LENGTH) "s", fmtname) == 0) return SCPE_ARG; - for (i = 0; dpb[i].capac != 0; i++) { - if (strncmp(fmtname, dpb[i].name, strlen(fmtname)) == 0) { - uptr -> HDSK_FORMAT_TYPE = i; - uptr -> capac = dpb[i].capac; /* Set capacity */ - - /* Configure physical disk geometry */ - uptr -> HDSK_SECTOR_SIZE = (128 << dpb[uptr -> HDSK_FORMAT_TYPE].psh); - uptr -> HDSK_SECTORS_PER_TRACK = dpb[uptr -> HDSK_FORMAT_TYPE].spt >> dpb[uptr -> HDSK_FORMAT_TYPE].psh; - uptr -> HDSK_NUMBER_OF_TRACKS = (uptr -> capac + - uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE - 1) / - (uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE); - - return SCPE_OK; - } - } - return SCPE_ARG; -} - -/* Show disk format routine */ -t_stat show_format(FILE *st, UNIT *uptr, int32 val, void *desc) { - if (uptr == NULL) return SCPE_IERR; - fprintf(st, "%s", dpb[uptr -> HDSK_FORMAT_TYPE].name); - return SCPE_OK; -} - -static const int32 hdskBoot[BOOTROM_SIZE] = { - 0xf3, 0x06, 0x80, 0x3e, 0x0e, 0xd3, 0xfe, 0x05, /* 5c00-5c07 */ - 0xc2, 0x05, 0x5c, 0x3e, 0x16, 0xd3, 0xfe, 0x3e, /* 5c08-5c0f */ - 0x12, 0xd3, 0xfe, 0xdb, 0xfe, 0xb7, 0xca, 0x20, /* 5c10-5c17 */ - 0x5c, 0x3e, 0x0c, 0xd3, 0xfe, 0xaf, 0xd3, 0xfe, /* 5c18-5c1f */ - 0x06, 0x20, 0x3e, 0x01, 0xd3, 0xfd, 0x05, 0xc2, /* 5c20-5c27 */ - 0x24, 0x5c, 0x11, 0x08, 0x00, 0x21, 0x00, 0x00, /* 5c28-5c2f */ - 0x0e, 0xb8, 0x3e, 0x02, 0xd3, 0xfd, 0x3a, 0x37, /* 5c30-5c37 */ - 0xff, 0xd6, 0x08, 0xd3, 0xfd, 0x7b, 0xd3, 0xfd, /* 5c38-5c3f */ - 0x7a, 0xd3, 0xfd, 0xaf, 0xd3, 0xfd, 0x7d, 0xd3, /* 5c40-5c47 */ - 0xfd, 0x7c, 0xd3, 0xfd, 0xdb, 0xfd, 0xb7, 0xca, /* 5c48-5c4f */ - 0x53, 0x5c, 0x76, 0x79, 0x0e, 0x80, 0x09, 0x4f, /* 5c50-5c57 */ - 0x0d, 0xc2, 0x60, 0x5c, 0xfb, 0xc3, 0x00, 0x00, /* 5c58-5c5f */ - 0x1c, 0x1c, 0x7b, 0xfe, 0x20, 0xca, 0x73, 0x5c, /* 5c60-5c67 */ - 0xfe, 0x21, 0xc2, 0x32, 0x5c, 0x1e, 0x00, 0x14, /* 5c68-5c6f */ - 0xc3, 0x32, 0x5c, 0x1e, 0x01, 0xc3, 0x32, 0x5c, /* 5c70-5c77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c78-5c7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c80-5c87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c88-5c8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c90-5c97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c98-5c9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5ca0-5ca7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5ca8-5caf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cb0-5cb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cb8-5cbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cc0-5cc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cc8-5ccf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cd0-5cd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cd8-5cdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5ce0-5ce7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5ce8-5cef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cf0-5cf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cf8-5cff */ -}; - -static t_stat hdsk_boot(int32 unitno, DEVICE *dptr) { - int32 i; - if (MEMSIZE < 24*KB) { - printf("Need at least 24KB RAM to boot from hard disk.\n"); - return SCPE_ARG; - } - if (cpu_unit.flags & (UNIT_ALTAIRROM | UNIT_BANKED)) { - /* check whether we are really modifying an LD A,<> instruction */ - if (bootrom[UNIT_NO_OFFSET_1 - 1] == LDA_INSTRUCTION) { - bootrom[UNIT_NO_OFFSET_1] = (unitno + NUM_OF_DSK) & 0xff; /* LD A, */ - } - else { /* Attempt to modify non LD A,<> instructions is refused. */ - printf("Incorrect boot ROM offset detected.\n"); - return SCPE_IERR; - } - install_bootrom(); /* install modified ROM */ - } - for (i = 0; i < BOOTROM_SIZE; i++) { - PutBYTEBasic(i + HDSK_BOOT_ADDRESS, 0, hdskBoot[i] & 0xff); - } - saved_PC = HDSK_BOOT_ADDRESS; - protect(HDSK_BOOT_ADDRESS, HDSK_BOOT_ADDRESS + BOOTROM_SIZE - 1); - return SCPE_OK; -} - -/* returns TRUE iff there exists a disk with VERBOSE */ -static int32 hdsk_hasVerbose(void) { - int32 i; - for (i = 0; i < HDSK_NUMBER; i++) { - if (hdsk_dev.units[i].flags & UNIT_HDSK_VERBOSE) { - return TRUE; - } - } - return FALSE; -} - -/* The hard disk port is 0xfd. It understands the following commands. - - 1. Reset - ld b,32 - ld a,HDSK_RESET - l: out (0fdh),a - dec b - jp nz,l - - 2. Read / write - ; parameter block - cmd: db HDSK_READ or HDSK_WRITE - hd: db 0 ; 0 .. 7, defines hard disk to be used - sector: db 0 ; 0 .. 31, defines sector - track: dw 0 ; 0 .. 2047, defines track - dma: dw 0 ; defines where result is placed in memory - - ; routine to execute - ld b,7 ; size of parameter block - ld hl,cmd ; start address of parameter block - l: ld a,(hl) ; get byte of parameter block - out (0fdh),a ; send it to port - inc hl ; point to next byte - dec b ; decrement counter - jp nz,l ; again, if not done - in a,(0fdh) ; get result code - - 3. Retrieve Disk Parameters from controller (Howard M. Harte) - Reads a 19-byte parameter block from the disk controller. - This parameter block is in CP/M DPB format for the first 17 bytes, - and the last two bytes are the lsb/msb of the disk's physical - sector size. - - ; routine to execute - ld a,hdskParam ; hdskParam = 4 - out (hdskPort),a ; Send 'get parameters' command, hdskPort = 0fdh - ld a,(diskno) - out (hdskPort),a ; Send selected HDSK number - ld b,17 - 1: in a,(hdskPort) ; Read 17-bytes of DPB - ld (hl), a - inc hl - djnz 1 - in a,(hdskPort) ; Read LSB of disk's physical sector size. - ld (hsecsiz), a - in a,(hdskPort) ; Read MSB of disk's physical sector size. - ld (hsecsiz+1), a - -*/ - -/* check the parameters and return TRUE iff parameters are correct or have been repaired */ -static int32 checkParameters(void) { - UNIT *uptr = &hdsk_dev.units[selectedDisk]; - int32 currentFlag; - if ((selectedDisk < 0) || (selectedDisk >= HDSK_NUMBER)) { - if (hdsk_hasVerbose()) { - MESSAGE_2("HDSK%d does not exist, will use HDSK0 instead.", selectedDisk); - } - selectedDisk = 0; - } - currentFlag = hdsk_dev.units[selectedDisk].flags; - if ((currentFlag & UNIT_ATT) == 0) { - if (currentFlag & UNIT_HDSK_VERBOSE) { - MESSAGE_2("HDSK%d is not attached.", selectedDisk); - } - return FALSE; /* cannot read or write */ - } - if ((selectedSector < 0) || (selectedSector >= uptr -> HDSK_SECTORS_PER_TRACK)) { - if (currentFlag & UNIT_HDSK_VERBOSE) { - MESSAGE_4("HDSK%d: 0 <= Sector=%02d < %d violated, will use 0 instead.", - selectedDisk, selectedSector, uptr -> HDSK_SECTORS_PER_TRACK); - } - selectedSector = 0; - } - if ((selectedTrack < 0) || (selectedTrack >= uptr -> HDSK_NUMBER_OF_TRACKS)) { - if (currentFlag & UNIT_HDSK_VERBOSE) { - MESSAGE_4("HDSK%d: 0 <= Track=%04d < %04d violated, will use 0 instead.", - selectedDisk, selectedTrack, uptr -> HDSK_NUMBER_OF_TRACKS); - } - selectedTrack = 0; - } - selectedDMA &= ADDRMASK; - if (hdskTrace) { - MESSAGE_7("%s HDSK%d Track=%04d Sector=%02d Len=%04d DMA=%04x\n", - (hdskLastCommand == HDSK_READ) ? "Read" : "Write", - selectedDisk, selectedTrack, selectedSector, uptr -> HDSK_SECTOR_SIZE, selectedDMA); - } - return TRUE; -} - -static int32 doSeek(void) { - UNIT *uptr = &hdsk_dev.units[selectedDisk]; - if (fseek(uptr -> fileref, - (uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE) * selectedTrack + - (uptr -> HDSK_SECTOR_SIZE * selectedSector), SEEK_SET)) { - if ((uptr -> flags) & UNIT_HDSK_VERBOSE) { - MESSAGE_4("Could not access HDSK%d Sector=%02d Track=%04d.", - selectedDisk, selectedSector, selectedTrack); - } - return CPM_ERROR; - } - else { - return CPM_OK; - } -} - -uint8 hdskbuf[HDSK_MAX_SECTOR_SIZE] = { 0 }; /* data buffer */ - -static int32 doRead(void) { - int32 i; - UNIT *uptr = &hdsk_dev.units[selectedDisk]; - if (doSeek()) { - return CPM_ERROR; - } - - if (fread(hdskbuf, uptr -> HDSK_SECTOR_SIZE, 1, uptr -> fileref) != 1) { - for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++) { - hdskbuf[i] = CPM_EMPTY; - } - if ((uptr -> flags) & UNIT_HDSK_VERBOSE) { - MESSAGE_4("Could not read HDSK%d Sector=%02d Track=%04d.", - selectedDisk, selectedSector, selectedTrack); - } - return CPM_OK; /* allows the creation of empty hard disks */ - } - for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++) { - PutBYTEWrapper(selectedDMA + i, hdskbuf[i]); - } - return CPM_OK; -} - -static int32 doWrite(void) { - int32 i; - - UNIT *uptr = &hdsk_dev.units[selectedDisk]; - if (((uptr -> flags) & UNIT_HDSK_WLK) == 0) { /* write enabled */ - if (doSeek()) { - return CPM_ERROR; - } - for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++) { - hdskbuf[i] = GetBYTEWrapper(selectedDMA + i); - } - if (fwrite(hdskbuf, uptr -> HDSK_SECTOR_SIZE, 1, uptr -> fileref) != 1) { - if ((uptr -> flags) & UNIT_HDSK_VERBOSE) { - MESSAGE_4("Could not write HDSK%d Sector=%02d Track=%04d.", - selectedDisk, selectedSector, selectedTrack); - } - return CPM_ERROR; - } - } - else { - if ((uptr -> flags) & UNIT_HDSK_VERBOSE) { - MESSAGE_4("Could not write to locked HDSK%d Sector=%02d Track=%04d.", - selectedDisk, selectedSector, selectedTrack); - } - return CPM_ERROR; - } - return CPM_OK; -} - -static int32 hdsk_in(const int32 port) { - UNIT *uptr = &hdsk_dev.units[selectedDisk]; - - int32 result; - if ((hdskCommandPosition == 6) && ((hdskLastCommand == HDSK_READ) || (hdskLastCommand == HDSK_WRITE))) { - result = checkParameters() ? ((hdskLastCommand == HDSK_READ) ? doRead() : doWrite()) : CPM_ERROR; - hdskLastCommand = HDSK_NONE; - hdskCommandPosition = 0; - return result; - } else if (hdskLastCommand == HDSK_PARAM) { - DPB current = dpb[uptr -> HDSK_FORMAT_TYPE]; - uint8 params[17]; - params[ 0] = current.spt & 0xff; params[ 1] = (current.spt >> 8) & 0xff; - params[ 2] = current.bsh; - params[ 3] = current.blm; - params[ 4] = current.exm; - params[ 5] = current.dsm & 0xff; params[ 6] = (current.dsm >> 8) & 0xff; - params[ 7] = current.drm & 0xff; params[ 8] = (current.drm >> 8) & 0xff; - params[ 9] = current.al0; - params[10] = current.al1; - params[11] = current.cks & 0xff; params[12] = (current.cks >> 8) & 0xff; - params[13] = current.off & 0xff; params[14] = (current.off >> 8) & 0xff; - params[15] = current.psh; - params[16] = current.phm; - if (++paramcount >= 19) { - hdskLastCommand = HDSK_NONE; - } - if (paramcount <= 17) - return params[paramcount - 1]; - else if (paramcount == 18) - return (uptr -> HDSK_SECTOR_SIZE & 0xff); - else if (paramcount == 19) - return (uptr -> HDSK_SECTOR_SIZE >> 8); - else - MESSAGE_2("HDSK%d Get parameter error.", selectedDisk); - - } - else if (hdsk_hasVerbose()) { - MESSAGE_4("Illegal IN command detected (port=%03xh, cmd=%d, pos=%d).", - port, hdskLastCommand, hdskCommandPosition); - } - return CPM_OK; -} - -static int32 hdsk_out(const int32 data) { - switch(hdskLastCommand) { - - case HDSK_PARAM: - paramcount = 0; - selectedDisk = data; - break; - - case HDSK_READ: - - case HDSK_WRITE: - switch(hdskCommandPosition) { - - case 0: - selectedDisk = data; - hdskCommandPosition++; - break; - - case 1: - selectedSector = data; - hdskCommandPosition++; - break; - - case 2: - selectedTrack = data; - hdskCommandPosition++; - break; - - case 3: - selectedTrack += (data << 8); - hdskCommandPosition++; - break; - - case 4: - selectedDMA = data; - hdskCommandPosition++; - break; - - case 5: - selectedDMA += (data << 8); - hdskCommandPosition++; - break; - - default: - hdskLastCommand = HDSK_NONE; - hdskCommandPosition = 0; - } - break; - - default: - hdskLastCommand = data; - hdskCommandPosition = 0; - } - return 0; /* ignored, since OUT */ -} - -int32 hdsk_io(const int32 port, const int32 io, const int32 data) { - return io == 0 ? hdsk_in(port) : hdsk_out(data); -} +/* altairz80_hdsk.c: simulated hard disk device to increase capacity + + Copyright (c) 2002-2008, Peter Schorn + + 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 + PETER SCHORN 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 Peter Schorn shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Peter Schorn. + + Contains code from Howard M. Harte for defining and changing disk geometry. +*/ + +#include "altairz80_defs.h" +#include + +/* The following routines are based on work from Howard M. Harte */ +static t_stat set_geom(UNIT *uptr, int32 val, char *cptr, void *desc); +static t_stat show_geom(FILE *st, UNIT *uptr, int32 val, void *desc); +static t_stat set_format(UNIT *uptr, int32 val, char *cptr, void *desc); +static t_stat show_format(FILE *st, UNIT *uptr, int32 val, void *desc); + +static t_stat hdsk_reset(DEVICE *dptr); +static t_stat hdsk_attach(UNIT *uptr, char *cptr); + +#define UNIT_V_HDSK_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_HDSK_WLK (1 << UNIT_V_HDSK_WLK) +#define UNIT_V_HDSK_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ +#define UNIT_HDSK_VERBOSE (1 << UNIT_V_HDSK_VERBOSE) +#define HDSK_MAX_SECTOR_SIZE 1024 /* maximum size of a sector */ +#define HDSK_SECTOR_SIZE u5 /* size of sector */ +#define HDSK_SECTORS_PER_TRACK u4 /* sectors per track */ +#define HDSK_NUMBER_OF_TRACKS u3 /* number of tracks */ +#define HDSK_FORMAT_TYPE u6 /* Disk Format Type */ +#define HDSK_CAPACITY (2048*32*128) /* Default Altair HDSK Capacity */ +#define HDSK_NUMBER 8 /* number of hard disks */ +#define CPM_OK 0 /* indicates to CP/M everything ok */ +#define CPM_ERROR 1 /* indicates to CP/M an error condition */ +#define CPM_EMPTY 0xe5 /* default value for non-existing bytes */ +#define HDSK_NONE 0 +#define HDSK_RESET 1 +#define HDSK_READ 2 +#define HDSK_WRITE 3 +#define HDSK_PARAM 4 +#define HDSK_BOOT_ADDRESS 0x5c00 +#define DPB_NAME_LENGTH 15 +#define BOOTROM_SIZE_HDSK 256 + +extern char messageBuffer[]; +extern uint32 PCX; +extern REG *sim_PC; +extern UNIT cpu_unit; + +extern void install_ALTAIRbootROM(void); +extern void printMessage(void); +extern void PutBYTEWrapper(const uint32 Addr, const uint32 Value); +extern uint8 GetBYTEWrapper(const uint32 Addr); +extern t_stat install_bootrom(int32 bootrom[], int32 size, int32 addr, int32 makeROM); +extern int32 bootrom_dsk[]; +extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc); +extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, + int32 (*routine)(const int32, const int32, const int32), uint8 unmap); + +static t_stat hdsk_boot(int32 unitno, DEVICE *dptr); +int32 hdsk_io(const int32 port, const int32 io, const int32 data); + +static int32 hdskLastCommand = HDSK_NONE; +static int32 hdskCommandPosition = 0; +static int32 paramcount = 0; +static int32 selectedDisk; +static int32 selectedSector; +static int32 selectedTrack; +static int32 selectedDMA; +static int32 trace_level = 0; + +typedef struct { + char name[DPB_NAME_LENGTH + 1]; /* name of CP/M disk parameter block */ + t_addr capac; /* capacity */ + uint16 spt; /* sectors per track */ + uint8 bsh; /* data allocation block shift factor */ + uint8 blm; /* data allocation block mask */ + uint8 exm; /* extent mask */ + uint16 dsm; /* maximum data block number */ + uint16 drm; /* total number of directory entries */ + uint8 al0; /* determine reserved directory blocks */ + uint8 al1; /* determine reserved directory blocks */ + uint16 cks; /* size of directory check vector */ + uint16 off; /* number of reserved tracks */ + uint8 psh; /* physical record shift factor, CP/M 3 */ + uint8 phm; /* physical record mask, CP/M 3 */ +} DPB; + +typedef struct { + PNP_INFO pnp; /* Plug and Play */ +} HDSK_INFO; + +static HDSK_INFO hdsk_info_data = { { 0x0000, 0, 0xFD, 1 } }; +/* static HDSK_INFO *hdsk_info = &hdsk_info_data; */ + +/* Note in the following CKS = 0 for fixed media which are not supposed to be changed while CP/M is executing */ +static DPB dpb[] = { +/* name capac spt bsh blm exm dsm drm al0 al1 cks off psh phm */ + { "HDSK", HDSK_CAPACITY, 32, 0x05, 0x1F, 0x01, 0x07f9, 0x03FF, 0xFF, 0x00, 0x0000, 0x0006, 0x00, 0x00 }, /* AZ80 HDSK */ + { "EZ80FL", 131072, 32, 0x03, 0x07, 0x00, 127, 0x003E, 0xC0, 0x00, 0x0000, 0x0000, 0x02, 0x03 }, /* 128K FLASH */ + { "P112", 1474560, 72, 0x04, 0x0F, 0x00, 710, 0x00FE, 0xF0, 0x00, 0x0000, 0x0002, 0x02, 0x03 }, /* 1.44M P112 */ + { "SU720", 737280, 36, 0x04, 0x0F, 0x00, 354, 0x007E, 0xC0, 0x00, 0x0020, 0x0002, 0x02, 0x03 }, /* 720K Super I/O */ + { "OSB1", 102400, 20, 0x04, 0x0F, 0x01, 45, 0x003F, 0x80, 0x00, 0x0000, 0x0003, 0x02, 0x03 }, /* Osborne1 5.25" SS SD */ + { "OSB2", 204800, 40, 0x03, 0x07, 0x00, 184, 0x003F, 0xC0, 0x00, 0x0000, 0x0003, 0x02, 0x03 }, /* Osborne1 5.25" SS DD */ + { "NSSS1", 179200, 40, 0x03, 0x07, 0x00, 0xA4, 0x003F, 0xC0, 0x00, 0x0010, 0x0002, 0x02, 0x03 }, /* Northstar SSDD Format 1 */ + { "NSSS2", 179200, 40, 0x04, 0x0F, 0x01, 0x51, 0x003F, 0x80, 0x00, 0x0010, 0x0002, 0x02, 0x03 }, /* Northstar SSDD Format 2 */ + { "NSDS2", 358400, 40, 0x04, 0x0F, 0x01, 0xA9, 0x003F, 0x80, 0x00, 0x0010, 0x0002, 0x02, 0x03 }, /* Northstar DSDD Format 2 */ + { "VGSS", 315392, 32, 0x04, 0x0F, 0x00, 149, 0x007F, 0xC0, 0x00, 0x0020, 0x0002, 0x02, 0x03 }, /* Vector SS SD */ + { "VGDS", 632784, 32, 0x04, 0x0F, 0x00, 299, 0x007F, 0xC0, 0x00, 0x0020, 0x0004, 0x02, 0x03 }, /* Vector DS SD */ + /* Note on DISK1A Images: this is a bit of a mess. The first track on the disk is 128x26 bytes (SD) and to make this work + I had to "move" the data from 0x2d00 in the DSK image file down to 0x4000 (2-tracks in). I used WinHex to do it. */ + { "DISK1A", 630784, 64, 0x04, 0x0F, 0x00, 299, 0x007F, 0xC0, 0x00, 0x0020, 0x0002, 0x02, 0x03 }, /* CompuPro Disk1A 8" SS SD */ + { "SSSD8", 256256, 26, 0x03, 0x07, 0x00, 242, 0x003F, 0xC0, 0x00, 0x0000, 0x0002, 0x00, 0x00 }, /* Standard 8" SS SD */ + { "", 0 } +}; + +static UNIT hdsk_unit[] = { + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) } +}; + +static REG hdsk_reg[] = { + { DRDATA (HDCMD, hdskLastCommand, 32), REG_RO }, + { DRDATA (HDPOS, hdskCommandPosition, 32), REG_RO }, + { DRDATA (HDDSK, selectedDisk, 32), REG_RO }, + { DRDATA (HDSEC, selectedSector, 32), REG_RO }, + { DRDATA (HDTRK, selectedTrack, 32), REG_RO }, + { DRDATA (HDDMA, selectedDMA, 32), REG_RO }, + { HRDATA (TRACELEVEL, trace_level, 16), }, + { NULL } +}; + +static MTAB hdsk_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL }, + { MTAB_XTD|MTAB_VUN|MTAB_VAL, 0, "FORMAT", "FORMAT", &set_format, &show_format, NULL }, + { UNIT_HDSK_WLK, 0, "WRTENB", "WRTENB", NULL }, + { UNIT_HDSK_WLK, UNIT_HDSK_WLK, "WRTLCK", "WRTLCK", NULL }, + /* quiet, no warning messages */ + { UNIT_HDSK_VERBOSE, 0, "QUIET", "QUIET", NULL }, + /* verbose, show warning messages */ + { UNIT_HDSK_VERBOSE, UNIT_HDSK_VERBOSE, "VERBOSE", "VERBOSE", NULL }, + { MTAB_XTD|MTAB_VUN|MTAB_VAL, 0, "GEOM", "GEOM", &set_geom, &show_geom, NULL }, + { 0 } +}; + +DEVICE hdsk_dev = { + "HDSK", hdsk_unit, hdsk_reg, hdsk_mod, + 8, 10, 31, 1, 8, 8, + NULL, NULL, &hdsk_reset, + &hdsk_boot, &hdsk_attach, NULL, + &hdsk_info_data, (DEV_DISABLE), 0, + NULL, NULL, NULL +}; + +/* Reset routine */ +static t_stat hdsk_reset(DEVICE *dptr) { + PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; + if (dptr->flags & DEV_DIS) { + sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &hdsk_io, TRUE); + } else { + /* Connect HDSK at base address */ + if (sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &hdsk_io, FALSE) != 0) { + printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->mem_base); + dptr->flags |= DEV_DIS; + return SCPE_ARG; + } + } + return SCPE_OK; +} + +/* Attach routine */ +static t_stat hdsk_attach(UNIT *uptr, char *cptr) { + t_stat r; + uint32 i; + char unitChar; + + r = attach_unit(uptr, cptr); /* attach unit */ + if ( r != SCPE_OK) /* error? */ + return r; + + /* Step 1: Determine capacity of this disk */ + uptr -> capac = sim_fsize(uptr -> fileref); /* the file length is a good candidate */ + if (uptr -> capac == 0) { /* file does not exist or has length 0 */ + uptr -> capac = uptr -> HDSK_NUMBER_OF_TRACKS * + uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE; + if (uptr -> capac == 0) + uptr -> capac = HDSK_CAPACITY; + } /* post condition: uptr -> capac > 0 */ + assert(uptr -> capac); + + /* Step 2: Determine format based on disk capacity */ + uptr -> HDSK_FORMAT_TYPE = -1; /* default to unknown format type */ + for (i = 0; dpb[i].capac != 0; i++) { /* find disk parameter block */ + if (dpb[i].capac == uptr -> capac) { /* found if correct capacity */ + uptr -> HDSK_FORMAT_TYPE = i; + break; + } + } + + /* Step 3: Set number of sectors per track and sector size */ + if (uptr -> HDSK_FORMAT_TYPE == -1) { /* Case 1: no disk parameter block found*/ + for (i = 0; i < hdsk_dev.numunits; i++) /* find affected unit number */ + if (&hdsk_unit[i] == uptr) + break; /* found */ + unitChar = '0' + i; + uptr -> HDSK_FORMAT_TYPE = 0; + printf("HDSK%c: WARNING: Unsupported disk capacity, assuming HDSK type with capacity %iKB.\n", + unitChar, uptr -> capac / 1000); + uptr -> flags |= UNIT_HDSK_WLK; + printf("HDSK%c: WARNING: Forcing WRTLCK.\n", unitChar); + /* check whether capacity corresponds to setting of tracks, sectors per track and sector size */ + if (uptr -> capac != (uptr -> HDSK_NUMBER_OF_TRACKS * + uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE)) { + printf("HDSK%c: WARNING: Fixing geometry.\n", unitChar); + if (uptr -> HDSK_SECTORS_PER_TRACK == 0) uptr -> HDSK_SECTORS_PER_TRACK = 32; + if (uptr -> HDSK_SECTOR_SIZE == 0) uptr -> HDSK_SECTOR_SIZE = 128; + } + } + else { /* Case 2: disk parameter block found */ + uptr -> HDSK_SECTORS_PER_TRACK = dpb[uptr -> HDSK_FORMAT_TYPE].spt >> dpb[uptr -> HDSK_FORMAT_TYPE].psh; + uptr -> HDSK_SECTOR_SIZE = (128 << dpb[uptr -> HDSK_FORMAT_TYPE].psh); + } + assert(uptr -> HDSK_SECTORS_PER_TRACK && uptr -> HDSK_SECTOR_SIZE); + + /* Step 4: Number of tracks is smallest number to accomodate capacity */ + uptr -> HDSK_NUMBER_OF_TRACKS = (uptr -> capac + uptr -> HDSK_SECTORS_PER_TRACK * + uptr -> HDSK_SECTOR_SIZE - 1) / (uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE); + assert( ( (t_addr) ((uptr -> HDSK_NUMBER_OF_TRACKS - 1) * uptr -> HDSK_SECTORS_PER_TRACK * + uptr -> HDSK_SECTOR_SIZE) < uptr -> capac) && + (uptr -> capac <= (t_addr) (uptr -> HDSK_NUMBER_OF_TRACKS * + uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE) ) ); + return SCPE_OK; +} + +/* Set disk geometry routine */ +static t_stat set_geom(UNIT *uptr, int32 val, char *cptr, void *desc) { + uint32 numberOfTracks, numberOfSectors, sectorSize; + int result, n; + + if (cptr == NULL) return SCPE_ARG; + if (uptr == NULL) return SCPE_IERR; + result = sscanf(cptr, "%d/%d/%d%n", &numberOfTracks, &numberOfSectors, §orSize, &n); + if ((result != 3) || (result == EOF) || (cptr[n] != 0)) { + result = sscanf(cptr, "T:%d/N:%d/S:%d%n", &numberOfTracks, &numberOfSectors, §orSize, &n); + if ((result != 3) || (result == EOF) || (cptr[n] != 0)) return SCPE_ARG; + } + uptr -> HDSK_NUMBER_OF_TRACKS = numberOfTracks; + uptr -> HDSK_SECTORS_PER_TRACK = numberOfSectors; + uptr -> HDSK_SECTOR_SIZE = sectorSize; + uptr -> capac = numberOfTracks * numberOfSectors * sectorSize; + return SCPE_OK; +} + +/* Show disk geometry routine */ +static t_stat show_geom(FILE *st, UNIT *uptr, int32 val, void *desc) { + if (uptr == NULL) return SCPE_IERR; + fprintf(st, "T:%d/N:%d/S:%d", uptr -> HDSK_NUMBER_OF_TRACKS, + uptr -> HDSK_SECTORS_PER_TRACK, uptr -> HDSK_SECTOR_SIZE); + return SCPE_OK; +} + +#define QUOTE1(text) #text +#define QUOTE2(text) QUOTE1(text) +/* Set disk format routine */ +static t_stat set_format(UNIT *uptr, int32 val, char *cptr, void *desc) { + char fmtname[DPB_NAME_LENGTH + 1]; + int32 i; + + if (cptr == NULL) return SCPE_ARG; + if (uptr == NULL) return SCPE_IERR; + if (sscanf(cptr, "%" QUOTE2(DPB_NAME_LENGTH) "s", fmtname) == 0) return SCPE_ARG; + for (i = 0; dpb[i].capac != 0; i++) { + if (strncmp(fmtname, dpb[i].name, strlen(fmtname)) == 0) { + uptr -> HDSK_FORMAT_TYPE = i; + uptr -> capac = dpb[i].capac; /* Set capacity */ + + /* Configure physical disk geometry */ + uptr -> HDSK_SECTOR_SIZE = (128 << dpb[uptr -> HDSK_FORMAT_TYPE].psh); + uptr -> HDSK_SECTORS_PER_TRACK = dpb[uptr -> HDSK_FORMAT_TYPE].spt >> dpb[uptr -> HDSK_FORMAT_TYPE].psh; + uptr -> HDSK_NUMBER_OF_TRACKS = (uptr -> capac + + uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE - 1) / + (uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE); + + return SCPE_OK; + } + } + return SCPE_ARG; +} + +/* Show disk format routine */ +static t_stat show_format(FILE *st, UNIT *uptr, int32 val, void *desc) { + if (uptr == NULL) return SCPE_IERR; + fprintf(st, "%s", dpb[uptr -> HDSK_FORMAT_TYPE].name); + return SCPE_OK; +} + +static int32 bootrom_hdsk[BOOTROM_SIZE_HDSK] = { + 0xf3, 0x06, 0x80, 0x3e, 0x0e, 0xd3, 0xfe, 0x05, /* 5c00-5c07 */ + 0xc2, 0x05, 0x5c, 0x3e, 0x16, 0xd3, 0xfe, 0x3e, /* 5c08-5c0f */ + 0x12, 0xd3, 0xfe, 0xdb, 0xfe, 0xb7, 0xca, 0x20, /* 5c10-5c17 */ + 0x5c, 0x3e, 0x0c, 0xd3, 0xfe, 0xaf, 0xd3, 0xfe, /* 5c18-5c1f */ + 0x06, 0x20, 0x3e, 0x01, 0xd3, 0xfd, 0x05, 0xc2, /* 5c20-5c27 */ + 0x24, 0x5c, 0x11, 0x08, 0x00, 0x21, 0x00, 0x00, /* 5c28-5c2f */ + 0x0e, 0xb8, 0x3e, 0x02, 0xd3, 0xfd, 0x3a, 0x37, /* 5c30-5c37 */ + 0xff, 0xd6, 0x08, 0xd3, 0xfd, 0x7b, 0xd3, 0xfd, /* 5c38-5c3f */ + 0x7a, 0xd3, 0xfd, 0xaf, 0xd3, 0xfd, 0x7d, 0xd3, /* 5c40-5c47 */ + 0xfd, 0x7c, 0xd3, 0xfd, 0xdb, 0xfd, 0xb7, 0xca, /* 5c48-5c4f */ + 0x53, 0x5c, 0x76, 0x79, 0x0e, 0x80, 0x09, 0x4f, /* 5c50-5c57 */ + 0x0d, 0xc2, 0x60, 0x5c, 0xfb, 0xc3, 0x00, 0x00, /* 5c58-5c5f */ + 0x1c, 0x1c, 0x7b, 0xfe, 0x20, 0xca, 0x73, 0x5c, /* 5c60-5c67 */ + 0xfe, 0x21, 0xc2, 0x32, 0x5c, 0x1e, 0x00, 0x14, /* 5c68-5c6f */ + 0xc3, 0x32, 0x5c, 0x1e, 0x01, 0xc3, 0x32, 0x5c, /* 5c70-5c77 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c78-5c7f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c80-5c87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c88-5c8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c90-5c97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c98-5c9f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5ca0-5ca7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5ca8-5caf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cb0-5cb7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cb8-5cbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cc0-5cc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cc8-5ccf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cd0-5cd7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cd8-5cdf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5ce0-5ce7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5ce8-5cef */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cf0-5cf7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cf8-5cff */ +}; + +static t_stat hdsk_boot(int32 unitno, DEVICE *dptr) { + if (MEMORYSIZE < 24*KB) { + printf("Need at least 24KB RAM to boot from hard disk.\n"); + return SCPE_ARG; + } + if (cpu_unit.flags & (UNIT_CPU_ALTAIRROM | UNIT_CPU_BANKED)) { + /* check whether we are really modifying an LD A,<> instruction */ + if (bootrom_dsk[UNIT_NO_OFFSET_1 - 1] == LDA_INSTRUCTION) + bootrom_dsk[UNIT_NO_OFFSET_1] = (unitno + NUM_OF_DSK) & 0xff; /* LD A, */ + else { /* Attempt to modify non LD A,<> instructions is refused. */ + printf("Incorrect boot ROM offset detected.\n"); + return SCPE_IERR; + } + install_ALTAIRbootROM(); /* install modified ROM */ + } + assert(install_bootrom(bootrom_hdsk, BOOTROM_SIZE_HDSK, HDSK_BOOT_ADDRESS, FALSE) == SCPE_OK); + *((int32 *) sim_PC->loc) = HDSK_BOOT_ADDRESS; + return SCPE_OK; +} + +/* returns TRUE iff there exists a disk with VERBOSE */ +static int32 hdsk_hasVerbose(void) { + int32 i; + for (i = 0; i < HDSK_NUMBER; i++) + if (hdsk_dev.units[i].flags & UNIT_HDSK_VERBOSE) return TRUE; + return FALSE; +} + +/* The hard disk port is 0xfd. It understands the following commands. + + 1. Reset + ld b,32 + ld a,HDSK_RESET + l: out (0fdh),a + dec b + jp nz,l + + 2. Read / write + ; parameter block + cmd: db HDSK_READ or HDSK_WRITE + hd: db 0 ; 0 .. 7, defines hard disk to be used + sector: db 0 ; 0 .. 31, defines sector + track: dw 0 ; 0 .. 2047, defines track + dma: dw 0 ; defines where result is placed in memory + + ; routine to execute + ld b,7 ; size of parameter block + ld hl,cmd ; start address of parameter block + l: ld a,(hl) ; get byte of parameter block + out (0fdh),a ; send it to port + inc hl ; point to next byte + dec b ; decrement counter + jp nz,l ; again, if not done + in a,(0fdh) ; get result code + + 3. Retrieve Disk Parameters from controller (Howard M. Harte) + Reads a 19-byte parameter block from the disk controller. + This parameter block is in CP/M DPB format for the first 17 bytes, + and the last two bytes are the lsb/msb of the disk's physical + sector size. + + ; routine to execute + ld a,hdskParam ; hdskParam = 4 + out (hdskPort),a ; Send 'get parameters' command, hdskPort = 0fdh + ld a,(diskno) + out (hdskPort),a ; Send selected HDSK number + ld b,17 + 1: in a,(hdskPort) ; Read 17-bytes of DPB + ld (hl), a + inc hl + djnz 1 + in a,(hdskPort) ; Read LSB of disk's physical sector size. + ld (hsecsiz), a + in a,(hdskPort) ; Read MSB of disk's physical sector size. + ld (hsecsiz+1), a + +*/ + +/* check the parameters and return TRUE iff parameters are correct or have been repaired */ +static int32 checkParameters(void) { + UNIT *uptr = &hdsk_dev.units[selectedDisk]; + int32 currentFlag; + if ((selectedDisk < 0) || (selectedDisk >= HDSK_NUMBER)) { + if (hdsk_hasVerbose()) { + MESSAGE_2("HDSK%d does not exist, will use HDSK0 instead.", selectedDisk); + } + selectedDisk = 0; + } + currentFlag = hdsk_dev.units[selectedDisk].flags; + if ((currentFlag & UNIT_ATT) == 0) { + if (currentFlag & UNIT_HDSK_VERBOSE) { + MESSAGE_2("HDSK%d is not attached.", selectedDisk); + } + return FALSE; /* cannot read or write */ + } + if ((selectedSector < 0) || (selectedSector >= uptr -> HDSK_SECTORS_PER_TRACK)) { + if (currentFlag & UNIT_HDSK_VERBOSE) { + MESSAGE_4("HDSK%d: 0 <= Sector=%02d < %d violated, will use 0 instead.", + selectedDisk, selectedSector, uptr -> HDSK_SECTORS_PER_TRACK); + } + selectedSector = 0; + } + if ((selectedTrack < 0) || (selectedTrack >= uptr -> HDSK_NUMBER_OF_TRACKS)) { + if (currentFlag & UNIT_HDSK_VERBOSE) { + MESSAGE_4("HDSK%d: 0 <= Track=%04d < %04d violated, will use 0 instead.", + selectedDisk, selectedTrack, uptr -> HDSK_NUMBER_OF_TRACKS); + } + selectedTrack = 0; + } + selectedDMA &= ADDRMASK; + if (trace_level) { + MESSAGE_7("%s HDSK%d Track=%04d Sector=%02d Len=%04d DMA=%04x", + (hdskLastCommand == HDSK_READ) ? "Read" : "Write", + selectedDisk, selectedTrack, selectedSector, uptr -> HDSK_SECTOR_SIZE, selectedDMA); + } + return TRUE; +} + +static int32 doSeek(void) { + UNIT *uptr = &hdsk_dev.units[selectedDisk]; + if (fseek(uptr -> fileref, + (uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE) * selectedTrack + + (uptr -> HDSK_SECTOR_SIZE * selectedSector), SEEK_SET)) { + if ((uptr -> flags) & UNIT_HDSK_VERBOSE) { + MESSAGE_4("Could not access HDSK%d Sector=%02d Track=%04d.", + selectedDisk, selectedSector, selectedTrack); + } + return CPM_ERROR; + } + else return CPM_OK; +} + +uint8 hdskbuf[HDSK_MAX_SECTOR_SIZE] = { 0 }; /* data buffer */ + +static int32 doRead(void) { + int32 i; + UNIT *uptr = &hdsk_dev.units[selectedDisk]; + if (doSeek()) return CPM_ERROR; + + if (fread(hdskbuf, uptr -> HDSK_SECTOR_SIZE, 1, uptr -> fileref) != 1) { + for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++) hdskbuf[i] = CPM_EMPTY; + if ((uptr -> flags) & UNIT_HDSK_VERBOSE) { + MESSAGE_4("Could not read HDSK%d Sector=%02d Track=%04d.", + selectedDisk, selectedSector, selectedTrack); + } + return CPM_OK; /* allows the creation of empty hard disks */ + } + for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++) PutBYTEWrapper(selectedDMA + i, hdskbuf[i]); + return CPM_OK; +} + +static int32 doWrite(void) { + int32 i; + + UNIT *uptr = &hdsk_dev.units[selectedDisk]; + if (((uptr -> flags) & UNIT_HDSK_WLK) == 0) { /* write enabled */ + if (doSeek()) return CPM_ERROR; + for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++) hdskbuf[i] = GetBYTEWrapper(selectedDMA + i); + if (fwrite(hdskbuf, uptr -> HDSK_SECTOR_SIZE, 1, uptr -> fileref) != 1) { + if ((uptr -> flags) & UNIT_HDSK_VERBOSE) { + MESSAGE_4("Could not write HDSK%d Sector=%02d Track=%04d.", + selectedDisk, selectedSector, selectedTrack); + } + return CPM_ERROR; + } + } + else { + if ((uptr -> flags) & UNIT_HDSK_VERBOSE) { + MESSAGE_4("Could not write to locked HDSK%d Sector=%02d Track=%04d.", + selectedDisk, selectedSector, selectedTrack); + } + return CPM_ERROR; + } + return CPM_OK; +} + +static int32 hdsk_in(const int32 port) { + UNIT *uptr = &hdsk_dev.units[selectedDisk]; + + int32 result; + if ((hdskCommandPosition == 6) && ((hdskLastCommand == HDSK_READ) || (hdskLastCommand == HDSK_WRITE))) { + result = checkParameters() ? ((hdskLastCommand == HDSK_READ) ? doRead() : doWrite()) : CPM_ERROR; + hdskLastCommand = HDSK_NONE; + hdskCommandPosition = 0; + return result; + } else if (hdskLastCommand == HDSK_PARAM) { + DPB current = dpb[uptr -> HDSK_FORMAT_TYPE]; + uint8 params[17]; + params[ 0] = current.spt & 0xff; params[ 1] = (current.spt >> 8) & 0xff; + params[ 2] = current.bsh; + params[ 3] = current.blm; + params[ 4] = current.exm; + params[ 5] = current.dsm & 0xff; params[ 6] = (current.dsm >> 8) & 0xff; + params[ 7] = current.drm & 0xff; params[ 8] = (current.drm >> 8) & 0xff; + params[ 9] = current.al0; + params[10] = current.al1; + params[11] = current.cks & 0xff; params[12] = (current.cks >> 8) & 0xff; + params[13] = current.off & 0xff; params[14] = (current.off >> 8) & 0xff; + params[15] = current.psh; + params[16] = current.phm; + if (++paramcount >= 19) hdskLastCommand = HDSK_NONE; + if (paramcount <= 17) + return params[paramcount - 1]; + else if (paramcount == 18) + return (uptr -> HDSK_SECTOR_SIZE & 0xff); + else if (paramcount == 19) + return (uptr -> HDSK_SECTOR_SIZE >> 8); + else { + MESSAGE_2("HDSK%d Get parameter error.", selectedDisk); + } + + } + else if (hdsk_hasVerbose()) { + MESSAGE_4("Illegal IN command detected (port=%03xh, cmd=%d, pos=%d).", + port, hdskLastCommand, hdskCommandPosition); + } + return CPM_OK; +} + +static int32 hdsk_out(const int32 port, const int32 data) { + switch(hdskLastCommand) { + + case HDSK_PARAM: + paramcount = 0; + selectedDisk = data; + break; + + case HDSK_READ: + + case HDSK_WRITE: + switch(hdskCommandPosition) { + + case 0: + selectedDisk = data; + hdskCommandPosition++; + break; + + case 1: + selectedSector = data; + hdskCommandPosition++; + break; + + case 2: + selectedTrack = data; + hdskCommandPosition++; + break; + + case 3: + selectedTrack += (data << 8); + hdskCommandPosition++; + break; + + case 4: + selectedDMA = data; + hdskCommandPosition++; + break; + + case 5: + selectedDMA += (data << 8); + hdskCommandPosition++; + break; + + default: + hdskLastCommand = HDSK_NONE; + hdskCommandPosition = 0; + } + break; + + default: + if ((HDSK_RESET <= data) && (data <= HDSK_PARAM)) + hdskLastCommand = data; + else { + if (hdsk_hasVerbose()) { + MESSAGE_3("Illegal OUT command detected (port=%03xh, cmd=%d).", + port, data); + } + hdskLastCommand = HDSK_RESET; + } + hdskCommandPosition = 0; + } + return 0; /* ignored, since OUT */ +} + +int32 hdsk_io(const int32 port, const int32 io, const int32 data) { + return io == 0 ? hdsk_in(port) : hdsk_out(port, data); +} diff --git a/AltairZ80/altairz80_net.c b/AltairZ80/altairz80_net.c index 6928c826..3b4607b5 100644 --- a/AltairZ80/altairz80_net.c +++ b/AltairZ80/altairz80_net.c @@ -1,293 +1,301 @@ -/* altairz80_net.c: networking capability - - Copyright (c) 2002-2007, Peter Schorn - - 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 - PETER SCHORN 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 Peter Schorn shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Peter Schorn. -*/ - -#include "altairz80_defs.h" -#include "sim_sock.h" - -#define UNIT_V_SERVER (UNIT_V_UF + 0) /* define machine as a server */ -#define UNIT_SERVER (1 << UNIT_V_SERVER) -#define NET_INIT_POLL_SERVER 16000 -#define NET_INIT_POLL_CLIENT 15000 - -/*#define DEBUG_NETWORK TRUE*/ - -static t_stat net_attach (UNIT *uptr, char *cptr); -static t_stat net_detach (UNIT *uptr); -static t_stat net_reset (DEVICE *dptr); -static t_stat net_svc (UNIT *uptr); -static t_stat set_net (UNIT *uptr, int32 value, char *cptr, void *desc); -int32 netStatus (const int32 port, const int32 io, const int32 data); -int32 netData (const int32 port, const int32 io, const int32 data); - -#define MAX_CONNECTIONS 2 /* maximal number of server connections */ -#define BUFFER_LENGTH 512 /* length of input and output buffer */ - -static struct { - int32 Z80StatusPort; /* Z80 status port associated with this ioSocket, read only */ - int32 Z80DataPort; /* Z80 data port associated with this ioSocket, read only */ - SOCKET masterSocket; /* server master socket, only defined at [1] */ - SOCKET ioSocket; /* accepted server socket or connected client socket, 0 iff free */ - char inputBuffer[BUFFER_LENGTH]; /* buffer for input characters read from ioSocket */ - int32 inputPosRead; /* position of next character to read from buffer */ - int32 inputPosWrite; /* position of next character to append to input buffer from ioSocket */ - int32 inputSize; /* number of characters in circular input buffer */ - char outputBuffer[BUFFER_LENGTH];/* buffer for output characters to be written to ioSocket */ - int32 outputPosRead; /* position of next character to write to ioSocket */ - int32 outputPosWrite; /* position of next character to append to output buffer */ - int32 outputSize; /* number of characters in circular output buffer */ -} serviceDescriptor[MAX_CONNECTIONS+1] = { /* serviceDescriptor[0] holds the information for a client */ -/* stat dat ms ios in inPR inPW inS out outPR outPW outS */ - {50, 51, 0, 0, {0}, 0, 0, 0, {0}, 0, 0, 0}, /* client Z80 port 50 and 51 */ - {40, 41, 0, 0, {0}, 0, 0, 0, {0}, 0, 0, 0}, /* server Z80 port 40 and 41 */ - {42, 43, 0, 0, {0}, 0, 0, 0, {0}, 0, 0, 0} /* server Z80 port 42 and 43 */ -}; - -static UNIT net_unit = { - UDATA (&net_svc, UNIT_ATTABLE, 0), - 0, /* wait, set in attach */ - 0, /* u3 = Port */ - 0, /* u4 = IP of host */ - 0, /* u5, unused */ - 0, /* u6, unused */ -}; - -static REG net_reg[] = { - { DRDATA (POLL, net_unit.wait, 32) }, - { HRDATA (IPHOST, net_unit.u4, 32), REG_RO }, - { DRDATA (PORT, net_unit.u3, 32), REG_RO }, - { NULL } -}; - -static MTAB net_mod[] = { - { UNIT_SERVER, 0, "CLIENT", "CLIENT", &set_net}, /* machine is a client */ - { UNIT_SERVER, UNIT_SERVER, "SERVER", "SERVER", &set_net}, /* machine is a server */ - { 0 } -}; - -DEVICE net_dev = { - "NET", &net_unit, net_reg, net_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &net_reset, - NULL, &net_attach, &net_detach, - NULL, 0, 0, - NULL, NULL, NULL -}; - -static t_stat set_net(UNIT *uptr, int32 value, char *cptr, void *desc) { - char temp[CBUFSIZE]; - if ((net_unit.flags & UNIT_ATT) && ((net_unit.flags & UNIT_SERVER) != value)) { - strncpy(temp, net_unit.filename, CBUFSIZE); /* save name for later attach */ - net_detach(&net_unit); - net_unit.flags ^= UNIT_SERVER; /* now switch from client to server and vice versa */ - net_attach(uptr, temp); - return SCPE_OK; - } - return SCPE_OK; -} - -static void serviceDescriptor_reset(const uint32 i) { - serviceDescriptor[i].inputPosRead = 0; - serviceDescriptor[i].inputPosWrite = 0; - serviceDescriptor[i].inputSize = 0; - serviceDescriptor[i].outputPosRead = 0; - serviceDescriptor[i].outputPosWrite = 0; - serviceDescriptor[i].outputSize = 0; -} - -static t_stat net_reset(DEVICE *dptr) { - uint32 i; - if (net_unit.flags & UNIT_ATT) - sim_activate(&net_unit, net_unit.wait); /* start poll */ - for (i = 0; i <= MAX_CONNECTIONS; i++) - serviceDescriptor_reset(i); - return SCPE_OK; -} - -static t_stat net_attach(UNIT *uptr, char *cptr) { - uint32 i, ipa, ipp; - t_stat r = get_ipaddr(cptr, &ipa, &ipp); - if (r != SCPE_OK) return SCPE_ARG; - if (ipa == 0) ipa = 0x7F000001; /* localhost = 127.0.0.1 */ - if (ipp == 0) ipp = 3000; - net_unit.u3 = ipp; - net_unit.u4 = ipa; - net_reset(&net_dev); - for (i = 0; i <= MAX_CONNECTIONS; i++) serviceDescriptor[i].ioSocket = 0; - if (net_unit.flags & UNIT_SERVER) { - net_unit.wait = NET_INIT_POLL_SERVER; - serviceDescriptor[1].masterSocket = sim_master_sock(ipp); - if (serviceDescriptor[1].masterSocket == INVALID_SOCKET) return SCPE_IOERR; - } - else { - net_unit.wait = NET_INIT_POLL_CLIENT; - serviceDescriptor[0].ioSocket = sim_connect_sock(ipa, ipp); - if (serviceDescriptor[0].ioSocket == INVALID_SOCKET) return SCPE_IOERR; - } - net_unit.flags |= UNIT_ATT; - net_unit.filename = (char *) calloc(CBUFSIZE, sizeof (char)); /* alloc name buf */ - if (net_unit.filename == NULL) return SCPE_MEM; - strncpy(net_unit.filename, cptr, CBUFSIZE); /* save name */ - return SCPE_OK; -} - -static t_stat net_detach(UNIT *uptr) { - uint32 i; - if (!(net_unit.flags & UNIT_ATT)) return SCPE_OK; /* if not attached simply return */ - if (net_unit.flags & UNIT_SERVER) - sim_close_sock(serviceDescriptor[1].masterSocket, TRUE); - for (i = 0; i <= MAX_CONNECTIONS; i++) - if (serviceDescriptor[i].ioSocket) - sim_close_sock(serviceDescriptor[i].ioSocket, FALSE); - free(net_unit.filename); /* free port string */ - net_unit.filename = NULL; - net_unit.flags &= ~UNIT_ATT; /* not attached */ - return SCPE_OK; -} - -/* cannot use sim_check_conn to check whether read will return an error */ -static t_stat net_svc(UNIT *uptr) { - int32 i, j, k, r; - SOCKET s; - static char svcBuffer[BUFFER_LENGTH]; - if (net_unit.flags & UNIT_ATT) { - sim_activate(&net_unit, net_unit.wait); /* continue poll */ - if (net_unit.flags & UNIT_SERVER) { - for (i = 1; i <= MAX_CONNECTIONS; i++) - if (serviceDescriptor[i].ioSocket == 0) { - s = sim_accept_conn(serviceDescriptor[1].masterSocket, NULL); - if (s != INVALID_SOCKET) { - serviceDescriptor[i].ioSocket = s; -#ifdef DEBUG_NETWORK - printf("Accepted connection %i with socket %i.\n\r", i, s); -#endif - } - } - } - else if (serviceDescriptor[0].ioSocket == 0) { - serviceDescriptor[0].ioSocket = sim_connect_sock(net_unit.u4, net_unit.u3); - if (serviceDescriptor[0].ioSocket == INVALID_SOCKET) return SCPE_IOERR; - printf("\rWaiting for server ... Type g (possibly twice) when ready\n\r"); - return SCPE_STOP; - } - for (i = 0; i <= MAX_CONNECTIONS; i++) - if (serviceDescriptor[i].ioSocket) { - if (serviceDescriptor[i].inputSize < BUFFER_LENGTH) { /* there is space left in inputBuffer */ - r = sim_read_sock(serviceDescriptor[i].ioSocket, svcBuffer, - BUFFER_LENGTH - serviceDescriptor[i].inputSize); - if (r == -1) { -#ifdef DEBUG_NETWORK - printf("Drop connection %i with socket %i.\n\r", i, serviceDescriptor[i].ioSocket); -#endif - sim_close_sock(serviceDescriptor[i].ioSocket, FALSE); - serviceDescriptor[i].ioSocket = 0; - serviceDescriptor_reset(i); - continue; - } - else { - for (j = 0; j < r; j++) { - serviceDescriptor[i].inputBuffer[serviceDescriptor[i].inputPosWrite++] = svcBuffer[j]; - if (serviceDescriptor[i].inputPosWrite == BUFFER_LENGTH) - serviceDescriptor[i].inputPosWrite = 0; - } - serviceDescriptor[i].inputSize += r; - } - } - if (serviceDescriptor[i].outputSize > 0) { /* there is something to write in outputBuffer */ - k = serviceDescriptor[i].outputPosRead; - for (j = 0; j < serviceDescriptor[i].outputSize; j++) { - svcBuffer[j] = serviceDescriptor[i].outputBuffer[k++]; - if (k == BUFFER_LENGTH) k = 0; - } - r = sim_write_sock(serviceDescriptor[i].ioSocket, svcBuffer, serviceDescriptor[i].outputSize); - if (r >= 0) { - serviceDescriptor[i].outputSize -= r; - serviceDescriptor[i].outputPosRead += r; - if (serviceDescriptor[i].outputPosRead >= BUFFER_LENGTH) - serviceDescriptor[i].outputPosRead -= BUFFER_LENGTH; - } - else printf("write %i\r\n", r); - } - } - } - return SCPE_OK; -} - -int32 netStatus(const int32 port, const int32 io, const int32 data) { - uint32 i; - net_svc(&net_unit); - if (io == 0) { /* IN */ - for (i = 0; i <= MAX_CONNECTIONS; i++) - if (serviceDescriptor[i].Z80StatusPort == port) - return (serviceDescriptor[i].inputSize > 0 ? 1 : 0) | - (serviceDescriptor[i].outputSize < BUFFER_LENGTH ? 2 : 0); - } - return 0; -} - -int32 netData(const int32 port, const int32 io, const int32 data) { - uint32 i; - char result; - net_svc(&net_unit); - for (i = 0; i <= MAX_CONNECTIONS; i++) - if (serviceDescriptor[i].Z80DataPort == port) { - if (io == 0) { /* IN */ - if (serviceDescriptor[i].inputSize == 0) { - printf("re-read from %i\r\n", port); - result = serviceDescriptor[i].inputBuffer[serviceDescriptor[i].inputPosRead > 0 ? - serviceDescriptor[i].inputPosRead - 1 : BUFFER_LENGTH - 1]; - } - else { - result = serviceDescriptor[i].inputBuffer[serviceDescriptor[i].inputPosRead++]; - if (serviceDescriptor[i].inputPosRead == BUFFER_LENGTH) - serviceDescriptor[i].inputPosRead = 0; - serviceDescriptor[i].inputSize--; - } -#ifdef DEBUG_NETWORK - printf(" IN(%i)=%03xh (%c)\r\n", port, (result & 0xff), - (32 <= (result & 0xff)) && ((result & 0xff) <= 127) ? (result & 0xff) : '?'); -#endif - return result; - } - else { /* OUT */ - if (serviceDescriptor[i].outputSize == BUFFER_LENGTH) { - printf("over-write %i to %i\r\n", data, port); - serviceDescriptor[i].outputBuffer[serviceDescriptor[i].outputPosWrite > 0 ? - serviceDescriptor[i].outputPosWrite - 1 : BUFFER_LENGTH - 1] = data; - } - else { - serviceDescriptor[i].outputBuffer[serviceDescriptor[i].outputPosWrite++] = data; - if (serviceDescriptor[i].outputPosWrite== BUFFER_LENGTH) - serviceDescriptor[i].outputPosWrite = 0; - serviceDescriptor[i].outputSize++; - } -#ifdef DEBUG_NETWORK - printf("OUT(%i)=%03xh (%c)\r\n", port, data, (32 <= data) && (data <= 127) ? data : '?'); -#endif - return 0; - } - } - return 0; -} +/* altairz80_net.c: networking capability + + Copyright (c) 2002-2008, Peter Schorn + + 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 + PETER SCHORN 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 Peter Schorn shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Peter Schorn. +*/ + +#include "altairz80_defs.h" +#include "sim_sock.h" +extern uint32 PCX; +extern char messageBuffer[]; +extern void printMessage(void); + +#define UNIT_V_SERVER (UNIT_V_UF + 0) /* define machine as a server */ +#define UNIT_SERVER (1 << UNIT_V_SERVER) +#define NET_INIT_POLL_SERVER 16000 +#define NET_INIT_POLL_CLIENT 15000 + +static t_stat net_attach (UNIT *uptr, char *cptr); +static t_stat net_detach (UNIT *uptr); +static t_stat net_reset (DEVICE *dptr); +static t_stat net_svc (UNIT *uptr); +static t_stat set_net (UNIT *uptr, int32 value, char *cptr, void *desc); +int32 netStatus (const int32 port, const int32 io, const int32 data); +int32 netData (const int32 port, const int32 io, const int32 data); + +#define MAX_CONNECTIONS 2 /* maximal number of server connections */ +#define BUFFER_LENGTH 512 /* length of input and output buffer */ +#define NET_ACCEPT 1 /* bit masks for trace_level */ +#define NET_DROP 2 +#define NET_IN 4 +#define NET_OUT 8 +static int32 trace_level = 0; + +static struct { + int32 Z80StatusPort; /* Z80 status port associated with this ioSocket, read only */ + int32 Z80DataPort; /* Z80 data port associated with this ioSocket, read only */ + SOCKET masterSocket; /* server master socket, only defined at [1] */ + SOCKET ioSocket; /* accepted server socket or connected client socket, 0 iff free */ + char inputBuffer[BUFFER_LENGTH]; /* buffer for input characters read from ioSocket */ + int32 inputPosRead; /* position of next character to read from buffer */ + int32 inputPosWrite; /* position of next character to append to input buffer from ioSocket */ + int32 inputSize; /* number of characters in circular input buffer */ + char outputBuffer[BUFFER_LENGTH];/* buffer for output characters to be written to ioSocket */ + int32 outputPosRead; /* position of next character to write to ioSocket */ + int32 outputPosWrite; /* position of next character to append to output buffer */ + int32 outputSize; /* number of characters in circular output buffer */ +} serviceDescriptor[MAX_CONNECTIONS+1] = { /* serviceDescriptor[0] holds the information for a client */ +/* stat dat ms ios in inPR inPW inS out outPR outPW outS */ + {50, 51, 0, 0, {0}, 0, 0, 0, {0}, 0, 0, 0}, /* client Z80 port 50 and 51 */ + {40, 41, 0, 0, {0}, 0, 0, 0, {0}, 0, 0, 0}, /* server Z80 port 40 and 41 */ + {42, 43, 0, 0, {0}, 0, 0, 0, {0}, 0, 0, 0} /* server Z80 port 42 and 43 */ +}; + +static UNIT net_unit = { + UDATA (&net_svc, UNIT_ATTABLE, 0), + 0, /* wait, set in attach */ + 0, /* u3 = Port */ + 0, /* u4 = IP of host */ + 0, /* u5, unused */ + 0, /* u6, unused */ +}; + +static REG net_reg[] = { + { DRDATA (POLL, net_unit.wait, 32) }, + { HRDATA (IPHOST, net_unit.u4, 32), REG_RO }, + { DRDATA (PORT, net_unit.u3, 32), REG_RO }, + { HRDATA (TRACELEVEL, trace_level, 32) }, + { NULL } +}; + +static MTAB net_mod[] = { + { UNIT_SERVER, 0, "CLIENT", "CLIENT", &set_net}, /* machine is a client */ + { UNIT_SERVER, UNIT_SERVER, "SERVER", "SERVER", &set_net}, /* machine is a server */ + { 0 } +}; + +DEVICE net_dev = { + "NET", &net_unit, net_reg, net_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &net_reset, + NULL, &net_attach, &net_detach, + NULL, 0, 0, + NULL, NULL, NULL +}; + +static t_stat set_net(UNIT *uptr, int32 value, char *cptr, void *desc) { + char temp[CBUFSIZE]; + if ((net_unit.flags & UNIT_ATT) && ((net_unit.flags & UNIT_SERVER) != value)) { + strncpy(temp, net_unit.filename, CBUFSIZE); /* save name for later attach */ + net_detach(&net_unit); + net_unit.flags ^= UNIT_SERVER; /* now switch from client to server and vice versa */ + net_attach(uptr, temp); + return SCPE_OK; + } + return SCPE_OK; +} + +static void serviceDescriptor_reset(const uint32 i) { + serviceDescriptor[i].inputPosRead = 0; + serviceDescriptor[i].inputPosWrite = 0; + serviceDescriptor[i].inputSize = 0; + serviceDescriptor[i].outputPosRead = 0; + serviceDescriptor[i].outputPosWrite = 0; + serviceDescriptor[i].outputSize = 0; +} + +static t_stat net_reset(DEVICE *dptr) { + uint32 i; + if (net_unit.flags & UNIT_ATT) + sim_activate(&net_unit, net_unit.wait); /* start poll */ + for (i = 0; i <= MAX_CONNECTIONS; i++) + serviceDescriptor_reset(i); + return SCPE_OK; +} + +static t_stat net_attach(UNIT *uptr, char *cptr) { + uint32 i, ipa, ipp; + t_stat r = get_ipaddr(cptr, &ipa, &ipp); + if (r != SCPE_OK) return SCPE_ARG; + if (ipa == 0) ipa = 0x7F000001; /* localhost = 127.0.0.1 */ + if (ipp == 0) ipp = 3000; + net_unit.u3 = ipp; + net_unit.u4 = ipa; + net_reset(&net_dev); + for (i = 0; i <= MAX_CONNECTIONS; i++) serviceDescriptor[i].ioSocket = 0; + if (net_unit.flags & UNIT_SERVER) { + net_unit.wait = NET_INIT_POLL_SERVER; + serviceDescriptor[1].masterSocket = sim_master_sock(ipp); + if (serviceDescriptor[1].masterSocket == INVALID_SOCKET) return SCPE_IOERR; + } + else { + net_unit.wait = NET_INIT_POLL_CLIENT; + serviceDescriptor[0].ioSocket = sim_connect_sock(ipa, ipp); + if (serviceDescriptor[0].ioSocket == INVALID_SOCKET) return SCPE_IOERR; + } + net_unit.flags |= UNIT_ATT; + net_unit.filename = (char *) calloc(CBUFSIZE, sizeof (char)); /* alloc name buf */ + if (net_unit.filename == NULL) return SCPE_MEM; + strncpy(net_unit.filename, cptr, CBUFSIZE); /* save name */ + return SCPE_OK; +} + +static t_stat net_detach(UNIT *uptr) { + uint32 i; + if (!(net_unit.flags & UNIT_ATT)) return SCPE_OK; /* if not attached simply return */ + if (net_unit.flags & UNIT_SERVER) + sim_close_sock(serviceDescriptor[1].masterSocket, TRUE); + for (i = 0; i <= MAX_CONNECTIONS; i++) + if (serviceDescriptor[i].ioSocket) + sim_close_sock(serviceDescriptor[i].ioSocket, FALSE); + free(net_unit.filename); /* free port string */ + net_unit.filename = NULL; + net_unit.flags &= ~UNIT_ATT; /* not attached */ + return SCPE_OK; +} + +/* cannot use sim_check_conn to check whether read will return an error */ +static t_stat net_svc(UNIT *uptr) { + int32 i, j, k, r; + SOCKET s; + static char svcBuffer[BUFFER_LENGTH]; + if (net_unit.flags & UNIT_ATT) { /* cannot remove due to following else */ + sim_activate(&net_unit, net_unit.wait); /* continue poll */ + if (net_unit.flags & UNIT_SERVER) { + for (i = 1; i <= MAX_CONNECTIONS; i++) + if (serviceDescriptor[i].ioSocket == 0) { + s = sim_accept_conn(serviceDescriptor[1].masterSocket, NULL); + if (s != INVALID_SOCKET) { + serviceDescriptor[i].ioSocket = s; + if (trace_level & NET_ACCEPT) { + MESSAGE_3("Accepted connection %i with socket %i.", i, s); + } + } + } + } + else if (serviceDescriptor[0].ioSocket == 0) { + serviceDescriptor[0].ioSocket = sim_connect_sock(net_unit.u4, net_unit.u3); + if (serviceDescriptor[0].ioSocket == INVALID_SOCKET) return SCPE_IOERR; + printf("\rWaiting for server ... Type g (possibly twice) when ready" NLP); + return SCPE_STOP; + } + for (i = 0; i <= MAX_CONNECTIONS; i++) + if (serviceDescriptor[i].ioSocket) { + if (serviceDescriptor[i].inputSize < BUFFER_LENGTH) { /* there is space left in inputBuffer */ + r = sim_read_sock(serviceDescriptor[i].ioSocket, svcBuffer, + BUFFER_LENGTH - serviceDescriptor[i].inputSize); + if (r == -1) { + if (trace_level & NET_DROP) { + MESSAGE_3("Drop connection %i with socket %i.", i, serviceDescriptor[i].ioSocket); + } + sim_close_sock(serviceDescriptor[i].ioSocket, FALSE); + serviceDescriptor[i].ioSocket = 0; + serviceDescriptor_reset(i); + continue; + } + else { + for (j = 0; j < r; j++) { + serviceDescriptor[i].inputBuffer[serviceDescriptor[i].inputPosWrite++] = svcBuffer[j]; + if (serviceDescriptor[i].inputPosWrite == BUFFER_LENGTH) + serviceDescriptor[i].inputPosWrite = 0; + } + serviceDescriptor[i].inputSize += r; + } + } + if (serviceDescriptor[i].outputSize > 0) { /* there is something to write in outputBuffer */ + k = serviceDescriptor[i].outputPosRead; + for (j = 0; j < serviceDescriptor[i].outputSize; j++) { + svcBuffer[j] = serviceDescriptor[i].outputBuffer[k++]; + if (k == BUFFER_LENGTH) k = 0; + } + r = sim_write_sock(serviceDescriptor[i].ioSocket, svcBuffer, serviceDescriptor[i].outputSize); + if (r >= 0) { + serviceDescriptor[i].outputSize -= r; + serviceDescriptor[i].outputPosRead += r; + if (serviceDescriptor[i].outputPosRead >= BUFFER_LENGTH) + serviceDescriptor[i].outputPosRead -= BUFFER_LENGTH; + } + else printf("write %i" NLP, r); + } + } + } + return SCPE_OK; +} + +int32 netStatus(const int32 port, const int32 io, const int32 data) { + uint32 i; + if ((net_unit.flags & UNIT_ATT) == 0) return 0; + net_svc(&net_unit); + if (io == 0) /* IN */ + for (i = 0; i <= MAX_CONNECTIONS; i++) + if (serviceDescriptor[i].Z80StatusPort == port) + return (serviceDescriptor[i].inputSize > 0 ? 1 : 0) | + (serviceDescriptor[i].outputSize < BUFFER_LENGTH ? 2 : 0); + return 0; +} + +int32 netData(const int32 port, const int32 io, const int32 data) { + uint32 i; + char result; + if ((net_unit.flags & UNIT_ATT) == 0) return 0; + net_svc(&net_unit); + for (i = 0; i <= MAX_CONNECTIONS; i++) + if (serviceDescriptor[i].Z80DataPort == port) + if (io == 0) { /* IN */ + if (serviceDescriptor[i].inputSize == 0) { + printf("re-read from %i" NLP, port); + result = serviceDescriptor[i].inputBuffer[serviceDescriptor[i].inputPosRead > 0 ? + serviceDescriptor[i].inputPosRead - 1 : BUFFER_LENGTH - 1]; + } + else { + result = serviceDescriptor[i].inputBuffer[serviceDescriptor[i].inputPosRead++]; + if (serviceDescriptor[i].inputPosRead == BUFFER_LENGTH) + serviceDescriptor[i].inputPosRead = 0; + serviceDescriptor[i].inputSize--; + } + if (trace_level & NET_IN) { + MESSAGE_4(" IN(%i)=%03xh (%c)", port, (result & 0xff), + (32 <= (result & 0xff)) && ((result & 0xff) <= 127) ? (result & 0xff) : '?'); + } + return result; + } + else { /* OUT */ + if (serviceDescriptor[i].outputSize == BUFFER_LENGTH) { + printf("over-write %i to %i" NLP, data, port); + serviceDescriptor[i].outputBuffer[serviceDescriptor[i].outputPosWrite > 0 ? + serviceDescriptor[i].outputPosWrite - 1 : BUFFER_LENGTH - 1] = data; + } + else { + serviceDescriptor[i].outputBuffer[serviceDescriptor[i].outputPosWrite++] = data; + if (serviceDescriptor[i].outputPosWrite== BUFFER_LENGTH) + serviceDescriptor[i].outputPosWrite = 0; + serviceDescriptor[i].outputSize++; + } + if (trace_level & NET_OUT) { + MESSAGE_4("OUT(%i)=%03xh (%c)", port, data, + (32 <= data) && (data <= 127) ? data : '?'); + } + return 0; + } + return 0; +} diff --git a/AltairZ80/disasm.c b/AltairZ80/disasm.c new file mode 100644 index 00000000..8baaf151 --- /dev/null +++ b/AltairZ80/disasm.c @@ -0,0 +1,1424 @@ +/* disasm.c where all the _work_ gets done in the Netwide Disassembler + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + * + * initial version 27/iii/95 by Simon Tatham + */ + +#include +#include + +#include "nasm.h" +#include "insns.h" + +/* names.c included source file defining instruction and register + * names for the Netwide [Dis]Assembler + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +static const char *conditions[] = { /* condition code names */ + "a", "ae", "b", "be", "c", "e", "g", "ge", "l", "le", "na", "nae", + "nb", "nbe", "nc", "ne", "ng", "nge", "nl", "nle", "no", "np", + "ns", "nz", "o", "p", "pe", "po", "s", "z" +}; + +/* Register names automatically generated from regs.dat */ +/* automatically generated from ./regs.dat - do not edit */ +static const char *reg_names[] = { + "ah", + "al", + "ax", + "bh", + "bl", + "bp", + "bx", + "ch", + "cl", + "cr0", + "cr1", + "cr2", + "cr3", + "cr4", + "cr5", + "cr6", + "cr7", + "cs", + "cx", + "dh", + "di", + "dl", + "dr0", + "dr1", + "dr2", + "dr3", + "dr4", + "dr5", + "dr6", + "dr7", + "ds", + "dx", + "eax", + "ebp", + "ebx", + "ecx", + "edi", + "edx", + "es", + "esi", + "esp", + "fs", + "gs", + "mm0", + "mm1", + "mm2", + "mm3", + "mm4", + "mm5", + "mm6", + "mm7", + "segr6", + "segr7", + "si", + "sp", + "ss", + "st0", + "st1", + "st2", + "st3", + "st4", + "st5", + "st6", + "st7", + "tr0", + "tr1", + "tr2", + "tr3", + "tr4", + "tr5", + "tr6", + "tr7", + "xmm0", + "xmm1", + "xmm2", + "xmm3", + "xmm4", + "xmm5", + "xmm6", + "xmm7" +}; + +/* Instruction names automatically generated from insns.dat */ +/* This file is auto-generated from insns.dat by insns.pl - don't edit it */ +/* This file in included by names.c */ +static const char *insn_names[] = { + "aaa", + "aad", + "aam", + "aas", + "adc", + "add", + "addpd", + "addps", + "addsd", + "addss", + "addsubpd", + "addsubps", + "and", + "andnpd", + "andnps", + "andpd", + "andps", + "arpl", + "bound", + "bsf", + "bsr", + "bswap", + "bt", + "btc", + "btr", + "bts", + "call", + "cbw", + "cdq", + "clc", + "cld", + "clflush", + "cli", + "clts", + "cmc", + "cmp", + "cmpeqpd", + "cmpeqps", + "cmpeqsd", + "cmpeqss", + "cmplepd", + "cmpleps", + "cmplesd", + "cmpless", + "cmpltpd", + "cmpltps", + "cmpltsd", + "cmpltss", + "cmpneqpd", + "cmpneqps", + "cmpneqsd", + "cmpneqss", + "cmpnlepd", + "cmpnleps", + "cmpnlesd", + "cmpnless", + "cmpnltpd", + "cmpnltps", + "cmpnltsd", + "cmpnltss", + "cmpordpd", + "cmpordps", + "cmpordsd", + "cmpordss", + "cmppd", + "cmpps", + "cmpsb", + "cmpsd", + "cmpss", + "cmpsw", + "cmpunordpd", + "cmpunordps", + "cmpunordsd", + "cmpunordss", + "cmpxchg", + "cmpxchg486", + "cmpxchg8b", + "comisd", + "comiss", + "cpuid", + "cvtdq2pd", + "cvtdq2ps", + "cvtpd2dq", + "cvtpd2pi", + "cvtpd2ps", + "cvtpi2pd", + "cvtpi2ps", + "cvtps2dq", + "cvtps2pd", + "cvtps2pi", + "cvtsd2si", + "cvtsd2ss", + "cvtsi2sd", + "cvtsi2ss", + "cvtss2sd", + "cvtss2si", + "cvttpd2dq", + "cvttpd2pi", + "cvttps2dq", + "cvttps2pi", + "cvttsd2si", + "cvttss2si", + "cwd", + "cwde", + "daa", + "das", + "db", + "dd", + "dec", + "div", + "divpd", + "divps", + "divsd", + "divss", + "dq", + "dt", + "dw", + "emms", + "enter", + "equ", + "f2xm1", + "fabs", + "fadd", + "faddp", + "fbld", + "fbstp", + "fchs", + "fclex", + "fcmovb", + "fcmovbe", + "fcmove", + "fcmovnb", + "fcmovnbe", + "fcmovne", + "fcmovnu", + "fcmovu", + "fcom", + "fcomi", + "fcomip", + "fcomp", + "fcompp", + "fcos", + "fdecstp", + "fdisi", + "fdiv", + "fdivp", + "fdivr", + "fdivrp", + "femms", + "feni", + "ffree", + "ffreep", + "fiadd", + "ficom", + "ficomp", + "fidiv", + "fidivr", + "fild", + "fimul", + "fincstp", + "finit", + "fist", + "fistp", + "fisttp", + "fisub", + "fisubr", + "fld", + "fld1", + "fldcw", + "fldenv", + "fldl2e", + "fldl2t", + "fldlg2", + "fldln2", + "fldpi", + "fldz", + "fmul", + "fmulp", + "fnclex", + "fndisi", + "fneni", + "fninit", + "fnop", + "fnsave", + "fnstcw", + "fnstenv", + "fnstsw", + "fpatan", + "fprem", + "fprem1", + "fptan", + "frndint", + "frstor", + "fsave", + "fscale", + "fsetpm", + "fsin", + "fsincos", + "fsqrt", + "fst", + "fstcw", + "fstenv", + "fstp", + "fstsw", + "fsub", + "fsubp", + "fsubr", + "fsubrp", + "ftst", + "fucom", + "fucomi", + "fucomip", + "fucomp", + "fucompp", + "fwait", + "fxam", + "fxch", + "fxrstor", + "fxsave", + "fxtract", + "fyl2x", + "fyl2xp1", + "haddpd", + "haddps", + "hlt", + "hsubpd", + "hsubps", + "ibts", + "icebp", + "idiv", + "imul", + "in", + "inc", + "incbin", + "insb", + "insd", + "insw", + "int", + "int01", + "int03", + "int1", + "int3", + "into", + "invd", + "invlpg", + "iret", + "iretd", + "iretw", + "jcxz", + "jecxz", + "jmp", + "jmpe", + "lahf", + "lar", + "lddqu", + "ldmxcsr", + "lds", + "lea", + "leave", + "les", + "lfence", + "lfs", + "lgdt", + "lgs", + "lidt", + "lldt", + "lmsw", + "loadall", + "loadall286", + "lodsb", + "lodsd", + "lodsw", + "loop", + "loope", + "loopne", + "loopnz", + "loopz", + "lsl", + "lss", + "ltr", + "maskmovdqu", + "maskmovq", + "maxpd", + "maxps", + "maxsd", + "maxss", + "mfence", + "minpd", + "minps", + "minsd", + "minss", + "monitor", + "mov", + "movapd", + "movaps", + "movd", + "movddup", + "movdq2q", + "movdqa", + "movdqu", + "movhlps", + "movhpd", + "movhps", + "movlhps", + "movlpd", + "movlps", + "movmskpd", + "movmskps", + "movntdq", + "movnti", + "movntpd", + "movntps", + "movntq", + "movq", + "movq2dq", + "movsb", + "movsd", + "movshdup", + "movsldup", + "movss", + "movsw", + "movsx", + "movupd", + "movups", + "movzx", + "mul", + "mulpd", + "mulps", + "mulsd", + "mulss", + "mwait", + "neg", + "nop", + "not", + "or", + "orpd", + "orps", + "out", + "outsb", + "outsd", + "outsw", + "packssdw", + "packsswb", + "packuswb", + "paddb", + "paddd", + "paddq", + "paddsb", + "paddsiw", + "paddsw", + "paddusb", + "paddusw", + "paddw", + "pand", + "pandn", + "pause", + "paveb", + "pavgb", + "pavgusb", + "pavgw", + "pcmpeqb", + "pcmpeqd", + "pcmpeqw", + "pcmpgtb", + "pcmpgtd", + "pcmpgtw", + "pdistib", + "pextrw", + "pf2id", + "pf2iw", + "pfacc", + "pfadd", + "pfcmpeq", + "pfcmpge", + "pfcmpgt", + "pfmax", + "pfmin", + "pfmul", + "pfnacc", + "pfpnacc", + "pfrcp", + "pfrcpit1", + "pfrcpit2", + "pfrsqit1", + "pfrsqrt", + "pfsub", + "pfsubr", + "pi2fd", + "pi2fw", + "pinsrw", + "pmachriw", + "pmaddwd", + "pmagw", + "pmaxsw", + "pmaxub", + "pminsw", + "pminub", + "pmovmskb", + "pmulhriw", + "pmulhrwa", + "pmulhrwc", + "pmulhuw", + "pmulhw", + "pmullw", + "pmuludq", + "pmvgezb", + "pmvlzb", + "pmvnzb", + "pmvzb", + "pop", + "popa", + "popad", + "popaw", + "popf", + "popfd", + "popfw", + "por", + "prefetch", + "prefetchnta", + "prefetcht0", + "prefetcht1", + "prefetcht2", + "prefetchw", + "psadbw", + "pshufd", + "pshufhw", + "pshuflw", + "pshufw", + "pslld", + "pslldq", + "psllq", + "psllw", + "psrad", + "psraw", + "psrld", + "psrldq", + "psrlq", + "psrlw", + "psubb", + "psubd", + "psubq", + "psubsb", + "psubsiw", + "psubsw", + "psubusb", + "psubusw", + "psubw", + "pswapd", + "punpckhbw", + "punpckhdq", + "punpckhqdq", + "punpckhwd", + "punpcklbw", + "punpckldq", + "punpcklqdq", + "punpcklwd", + "push", + "pusha", + "pushad", + "pushaw", + "pushf", + "pushfd", + "pushfw", + "pxor", + "rcl", + "rcpps", + "rcpss", + "rcr", + "rdmsr", + "rdpmc", + "rdshr", + "rdtsc", + "resb", + "resd", + "resq", + "rest", + "resw", + "ret", + "retf", + "retn", + "rol", + "ror", + "rsdc", + "rsldt", + "rsm", + "rsqrtps", + "rsqrtss", + "rsts", + "sahf", + "sal", + "salc", + "sar", + "sbb", + "scasb", + "scasd", + "scasw", + "sfence", + "sgdt", + "shl", + "shld", + "shr", + "shrd", + "shufpd", + "shufps", + "sidt", + "sldt", + "smi", + "smint", + "smintold", + "smsw", + "sqrtpd", + "sqrtps", + "sqrtsd", + "sqrtss", + "stc", + "std", + "sti", + "stmxcsr", + "stosb", + "stosd", + "stosw", + "str", + "sub", + "subpd", + "subps", + "subsd", + "subss", + "svdc", + "svldt", + "svts", + "syscall", + "sysenter", + "sysexit", + "sysret", + "test", + "ucomisd", + "ucomiss", + "ud0", + "ud1", + "ud2", + "umov", + "unpckhpd", + "unpckhps", + "unpcklpd", + "unpcklps", + "verr", + "verw", + "wait", + "wbinvd", + "wrmsr", + "wrshr", + "xadd", + "xbts", + "xchg", + "xlat", + "xlatb", + "xor", + "xorpd", + "xorps", + "xstore" +}; + +/* Conditional instructions */ +static const char *icn[] = { + "cmov", + "j", + "set" +}; + +/* and the corresponding opcodes */ +static int ico[] = { + I_CMOVcc, + I_Jcc, + I_SETcc +}; + +#define INSN_MAX 32 /* one instruction can't be longer than this */ +long disasm (unsigned char *data, char *output, int segsize, long offset); +extern struct itemplate **itable[]; + +/* + * Flags that go into the `segment' field of `insn' structures + * during disassembly. + */ +#define SEG_RELATIVE 1 +#define SEG_32BIT 2 +#define SEG_RMREG 4 +#define SEG_DISP8 8 +#define SEG_DISP16 16 +#define SEG_DISP32 32 +#define SEG_NODISP 64 +#define SEG_SIGNED 128 + +static int whichreg(long regflags, int regval) +{ + /* automatically generated from ./regs.dat - do not edit */ + static const int creg [] = {R_CR0,R_CR1,R_CR2,R_CR3,R_CR4,R_CR5,R_CR6,R_CR7}; + static const int dreg [] = {R_DR0,R_DR1,R_DR2,R_DR3,R_DR4,R_DR5,R_DR6,R_DR7}; + static const int fpureg [] = {R_ST0,R_ST1,R_ST2,R_ST3,R_ST4,R_ST5,R_ST6,R_ST7}; + static const int mmxreg [] = {R_MM0,R_MM1,R_MM2,R_MM3,R_MM4,R_MM5,R_MM6,R_MM7}; + static const int reg16 [] = {R_AX,R_CX,R_DX,R_BX,R_SP,R_BP,R_SI,R_DI}; + static const int reg32 [] = {R_EAX,R_ECX,R_EDX,R_EBX,R_ESP,R_EBP,R_ESI,R_EDI}; + static const int reg8 [] = {R_AL,R_CL,R_DL,R_BL,R_AH,R_CH,R_DH,R_BH}; + static const int sreg [] = {R_ES,R_CS,R_SS,R_DS,R_FS,R_GS,R_SEGR6,R_SEGR7}; + static const int treg [] = {R_TR0,R_TR1,R_TR2,R_TR3,R_TR4,R_TR5,R_TR6,R_TR7}; + static const int xmmreg [] = {R_XMM0,R_XMM1,R_XMM2,R_XMM3,R_XMM4,R_XMM5,R_XMM6,R_XMM7}; + + if (!(REG_AL & ~regflags)) + return R_AL; + if (!(REG_AX & ~regflags)) + return R_AX; + if (!(REG_EAX & ~regflags)) + return R_EAX; + if (!(REG_DL & ~regflags)) + return R_DL; + if (!(REG_DX & ~regflags)) + return R_DX; + if (!(REG_EDX & ~regflags)) + return R_EDX; + if (!(REG_CL & ~regflags)) + return R_CL; + if (!(REG_CX & ~regflags)) + return R_CX; + if (!(REG_ECX & ~regflags)) + return R_ECX; + if (!(FPU0 & ~regflags)) + return R_ST0; + if (!(REG_CS & ~regflags)) + return (regval == 1) ? R_CS : 0; + if (!(REG_DESS & ~regflags)) + return (regval == 0 || regval == 2 || regval == 3 ? sreg[regval] : 0); + if (!(REG_FSGS & ~regflags)) + return (regval == 4 || regval == 5 ? sreg[regval] : 0); + if (!(REG_SEG67 & ~regflags)) + return (regval == 6 || regval == 7 ? sreg[regval] : 0); + + /* All the entries below look up regval in an 8-entry array */ + if (regval < 0 || regval > 7) + return 0; + + if (!((REGMEM|BITS8) & ~regflags)) + return reg8[regval]; + if (!((REGMEM|BITS16) & ~regflags)) + return reg16[regval]; + if (!((REGMEM|BITS32) & ~regflags)) + return reg32[regval]; + if (!(REG_SREG & ~regflags)) + return sreg[regval]; + if (!(REG_CREG & ~regflags)) + return creg[regval]; + if (!(REG_DREG & ~regflags)) + return dreg[regval]; + if (!(REG_TREG & ~regflags)) + return treg[regval]; + if (!(FPUREG & ~regflags)) + return fpureg[regval]; + if (!(MMXREG & ~regflags)) + return mmxreg[regval]; + if (!(XMMREG & ~regflags)) + return xmmreg[regval]; + + return 0; +} + +static const char *whichcond(int condval) +{ + static int conds[] = { + C_O, C_NO, C_C, C_NC, C_Z, C_NZ, C_NA, C_A, + C_S, C_NS, C_PE, C_PO, C_L, C_NL, C_NG, C_G + }; + return conditions[conds[condval]]; +} + +/* + * Process an effective address (ModRM) specification. + */ +static unsigned char *do_ea (unsigned char *data, int modrm, int asize, + int segsize, operand *op) +{ + int mod, rm, scale, index, base; + + mod = (modrm >> 6) & 03; + rm = modrm & 07; + + if (mod == 3) { /* pure register version */ + op->basereg = rm; + op->segment |= SEG_RMREG; + return data; + } + + op->addr_size = 0; + + if (asize == 16) { + /* + * specifies the displacement size (none, byte or + * word), and specifies the register combination. + * Exception: mod=0,rm=6 does not specify [BP] as one might + * expect, but instead specifies [disp16]. + */ + op->indexreg = op->basereg = -1; + op->scale = 1; /* always, in 16 bits */ + switch (rm) { + case 0: op->basereg = R_BX; op->indexreg = R_SI; break; + case 1: op->basereg = R_BX; op->indexreg = R_DI; break; + case 2: op->basereg = R_BP; op->indexreg = R_SI; break; + case 3: op->basereg = R_BP; op->indexreg = R_DI; break; + case 4: op->basereg = R_SI; break; + case 5: op->basereg = R_DI; break; + case 6: op->basereg = R_BP; break; + case 7: op->basereg = R_BX; break; + } + if (rm == 6 && mod == 0) { /* special case */ + op->basereg = -1; + if (segsize != 16) + op->addr_size = 16; + mod = 2; /* fake disp16 */ + } + switch (mod) { + case 0: + op->segment |= SEG_NODISP; + break; + case 1: + op->segment |= SEG_DISP8; + op->offset = (signed char) *data++; + break; + case 2: + op->segment |= SEG_DISP16; + op->offset = *data++; + op->offset |= ((unsigned) *data++) << 8; + break; + } + return data; + } else { + /* + * Once again, specifies displacement size (this time + * none, byte or *dword*), while specifies the base + * register. Again, [EBP] is missing, replaced by a pure + * disp32 (this time that's mod=0,rm=*5*). However, rm=4 + * indicates not a single base register, but instead the + * presence of a SIB byte... + */ + op->indexreg = -1; + switch (rm) { + case 0: op->basereg = R_EAX; break; + case 1: op->basereg = R_ECX; break; + case 2: op->basereg = R_EDX; break; + case 3: op->basereg = R_EBX; break; + case 5: op->basereg = R_EBP; break; + case 6: op->basereg = R_ESI; break; + case 7: op->basereg = R_EDI; break; + } + if (rm == 5 && mod == 0) { + op->basereg = -1; + if (segsize != 32) + op->addr_size = 32; + mod = 2; /* fake disp32 */ + } + if (rm == 4) { /* process SIB */ + scale = (*data >> 6) & 03; + index = (*data >> 3) & 07; + base = *data & 07; + data++; + + op->scale = 1 << scale; + switch (index) { + case 0: op->indexreg = R_EAX; break; + case 1: op->indexreg = R_ECX; break; + case 2: op->indexreg = R_EDX; break; + case 3: op->indexreg = R_EBX; break; + case 4: op->indexreg = -1; break; + case 5: op->indexreg = R_EBP; break; + case 6: op->indexreg = R_ESI; break; + case 7: op->indexreg = R_EDI; break; + } + + switch (base) { + case 0: op->basereg = R_EAX; break; + case 1: op->basereg = R_ECX; break; + case 2: op->basereg = R_EDX; break; + case 3: op->basereg = R_EBX; break; + case 4: op->basereg = R_ESP; break; + case 6: op->basereg = R_ESI; break; + case 7: op->basereg = R_EDI; break; + case 5: + if (mod == 0) { + mod = 2; + op->basereg = -1; + } else + op->basereg = R_EBP; + break; + } + } + switch (mod) { + case 0: + op->segment |= SEG_NODISP; + break; + case 1: + op->segment |= SEG_DISP8; + op->offset = (signed char) *data++; + break; + case 2: + op->segment |= SEG_DISP32; + op->offset = *data++; + op->offset |= ((unsigned) *data++) << 8; + op->offset |= ((long) *data++) << 16; + op->offset |= ((long) *data++) << 24; + break; + } + return data; + } +} + +/* + * Determine whether the instruction template in t corresponds to the data + * stream in data. Return the number of bytes matched if so. + */ +static int matches (struct itemplate *t, unsigned char *data, int asize, + int osize, int segsize, int rep, insn *ins) +{ + unsigned char * r = (unsigned char *)(t->code); + unsigned char * origdata = data; + int a_used = FALSE, o_used = FALSE; + int drep = 0; + + if ( rep == 0xF2 ) + drep = P_REPNE; + else if ( rep == 0xF3 ) + drep = P_REP; + + while (*r) + { + int c = *r++; + if (c >= 01 && c <= 03) { + while (c--) + if (*r++ != *data++) + return FALSE; + } + if (c == 04) { + switch (*data++) { + case 0x07: ins->oprs[0].basereg = 0; break; + case 0x17: ins->oprs[0].basereg = 2; break; + case 0x1F: ins->oprs[0].basereg = 3; break; + default: return FALSE; + } + } + if (c == 05) { + switch (*data++) { + case 0xA1: ins->oprs[0].basereg = 4; break; + case 0xA9: ins->oprs[0].basereg = 5; break; + default: return FALSE; + } + } + if (c == 06) { + switch (*data++) { + case 0x06: ins->oprs[0].basereg = 0; break; + case 0x0E: ins->oprs[0].basereg = 1; break; + case 0x16: ins->oprs[0].basereg = 2; break; + case 0x1E: ins->oprs[0].basereg = 3; break; + default: return FALSE; + } + } + if (c == 07) { + switch (*data++) { + case 0xA0: ins->oprs[0].basereg = 4; break; + case 0xA8: ins->oprs[0].basereg = 5; break; + default: return FALSE; + } + } + if (c >= 010 && c <= 012) { + int t = *r++, d = *data++; + if (d < t || d > t+7) + return FALSE; + else { + ins->oprs[c-010].basereg = d-t; + ins->oprs[c-010].segment |= SEG_RMREG; + } + } + if (c == 017) + if (*data++) + return FALSE; + if (c >= 014 && c <= 016) { + ins->oprs[c-014].offset = (signed char) *data++; + ins->oprs[c-014].segment |= SEG_SIGNED; + } + if (c >= 020 && c <= 022) + ins->oprs[c-020].offset = *data++; + if (c >= 024 && c <= 026) + ins->oprs[c-024].offset = *data++; + if (c >= 030 && c <= 032) { + ins->oprs[c-030].offset = *data++; + ins->oprs[c-030].offset |= (((unsigned) *data++) << 8); + } + if (c >= 034 && c <= 036) { + ins->oprs[c-034].offset = *data++; + ins->oprs[c-034].offset |= (((unsigned) *data++) << 8); + if (osize == 32) { + ins->oprs[c-034].offset |= (((long) *data++) << 16); + ins->oprs[c-034].offset |= (((long) *data++) << 24); + } + if (segsize != asize) + ins->oprs[c-034].addr_size = asize; + } + if (c >= 040 && c <= 042) { + ins->oprs[c-040].offset = *data++; + ins->oprs[c-040].offset |= (((unsigned) *data++) << 8); + ins->oprs[c-040].offset |= (((long) *data++) << 16); + ins->oprs[c-040].offset |= (((long) *data++) << 24); + } + if (c >= 044 && c <= 046) { + ins->oprs[c-044].offset = *data++; + ins->oprs[c-044].offset |= (((unsigned) *data++) << 8); + if (asize == 32) { + ins->oprs[c-044].offset |= (((long) *data++) << 16); + ins->oprs[c-044].offset |= (((long) *data++) << 24); + } + if (segsize != asize) + ins->oprs[c-044].addr_size = asize; + } + if (c >= 050 && c <= 052) { + ins->oprs[c-050].offset = (signed char) *data++; + ins->oprs[c-050].segment |= SEG_RELATIVE; + } + if (c >= 060 && c <= 062) { + ins->oprs[c-060].offset = *data++; + ins->oprs[c-060].offset |= (((unsigned) *data++) << 8); + ins->oprs[c-060].segment |= SEG_RELATIVE; + ins->oprs[c-060].segment &= ~SEG_32BIT; + } + if (c >= 064 && c <= 066) { + ins->oprs[c-064].offset = *data++; + ins->oprs[c-064].offset |= (((unsigned) *data++) << 8); + if (osize == 32) { + ins->oprs[c-064].offset |= (((long) *data++) << 16); + ins->oprs[c-064].offset |= (((long) *data++) << 24); + ins->oprs[c-064].segment |= SEG_32BIT; + } else + ins->oprs[c-064].segment &= ~SEG_32BIT; + ins->oprs[c-064].segment |= SEG_RELATIVE; + if (segsize != osize) { + ins->oprs[c-064].type = + (ins->oprs[c-064].type & NON_SIZE) + | ((osize == 16) ? BITS16 : BITS32); + } + } + if (c >= 070 && c <= 072) { + ins->oprs[c-070].offset = *data++; + ins->oprs[c-070].offset |= (((unsigned) *data++) << 8); + ins->oprs[c-070].offset |= (((long) *data++) << 16); + ins->oprs[c-070].offset |= (((long) *data++) << 24); + ins->oprs[c-070].segment |= SEG_32BIT | SEG_RELATIVE; + } + if (c >= 0100 && c < 0130) { + int modrm = *data++; + ins->oprs[c & 07].basereg = (modrm >> 3) & 07; + ins->oprs[c & 07].segment |= SEG_RMREG; + data = do_ea (data, modrm, asize, segsize, + &ins->oprs[(c >> 3) & 07]); + } + if (c >= 0130 && c <= 0132) { + ins->oprs[c-0130].offset = *data++; + ins->oprs[c-0130].offset |= (((unsigned) *data++) << 8); + } + if (c >= 0140 && c <= 0142) { + ins->oprs[c-0140].offset = *data++; + ins->oprs[c-0140].offset |= (((unsigned) *data++) << 8); + ins->oprs[c-0140].offset |= (((long) *data++) << 16); + ins->oprs[c-0140].offset |= (((long) *data++) << 24); + } + if (c >= 0200 && c <= 0277) { + int modrm = *data++; + if (((modrm >> 3) & 07) != (c & 07)) + return FALSE; /* spare field doesn't match up */ + data = do_ea (data, modrm, asize, segsize, + &ins->oprs[(c >> 3) & 07]); + } + if (c >= 0300 && c <= 0302) { + if (asize) + ins->oprs[c-0300].segment |= SEG_32BIT; + else + ins->oprs[c-0300].segment &= ~SEG_32BIT; + a_used = TRUE; + } + if (c == 0310) { + if (asize == 32) + return FALSE; + else + a_used = TRUE; + } + if (c == 0311) { + if (asize == 16) + return FALSE; + else + a_used = TRUE; + } + if (c == 0312) { + if (asize != segsize) + return FALSE; + else + a_used = TRUE; + } + if (c == 0320) { + if (osize == 32) + return FALSE; + else + o_used = TRUE; + } + if (c == 0321) { + if (osize == 16) + return FALSE; + else + o_used = TRUE; + } + if (c == 0322) { + if (osize != segsize) + return FALSE; + else + o_used = TRUE; + } + if (c == 0330) { + int t = *r++, d = *data++; + if (d < t || d > t+15) + return FALSE; + else + ins->condition = d - t; + } + if (c == 0331) { + if ( rep ) + return FALSE; + } + if (c == 0332) { + if (drep == P_REP) + drep = P_REPE; + } + if (c == 0333) { + if ( rep != 0xF3 ) + return FALSE; + drep = 0; + } + } + + /* + * Check for unused rep or a/o prefixes. + */ + ins->nprefix = 0; + if (drep) + ins->prefixes[ins->nprefix++] = drep; + if (!a_used && asize != segsize) + ins->prefixes[ins->nprefix++] = (asize == 16 ? P_A16 : P_A32); + if (!o_used && osize != segsize) + ins->prefixes[ins->nprefix++] = (osize == 16 ? P_O16 : P_O32); + + return data - origdata; +} + +long disasm (unsigned char *data, char *output, int segsize, long offset) +{ + struct itemplate **p, **best_p; + int length, best_length = 0; + char *segover; + int rep, lock, asize, osize, i, slen, colon; + unsigned char *origdata; + int works; + insn tmp_ins, ins; + unsigned long goodness, best; + + /* + * Scan for prefixes. + */ + asize = osize = segsize; + segover = NULL; + ins.condition = ins.nprefix = rep = lock = 0; + origdata = data; + for (;;) { + if (*data == 0xF3 || *data == 0xF2) + rep = *data++; + else if (*data == 0xF0) + lock = *data++; + else if (*data == 0x2E || *data == 0x36 || *data == 0x3E || + *data == 0x26 || *data == 0x64 || *data == 0x65) { + switch (*data++) { + case 0x2E: segover = "cs"; break; + case 0x36: segover = "ss"; break; + case 0x3E: segover = "ds"; break; + case 0x26: segover = "es"; break; + case 0x64: segover = "fs"; break; + case 0x65: segover = "gs"; break; + } + } else if (*data == 0x66) + osize = 48 - segsize, data++; + else if (*data == 0x67) + asize = 48 - segsize, data++; + else + break; + } + + tmp_ins.oprs[0].segment = tmp_ins.oprs[1].segment = + tmp_ins.oprs[2].segment = + tmp_ins.oprs[0].addr_size = tmp_ins.oprs[1].addr_size = + tmp_ins.oprs[2].addr_size = (segsize == 16 ? 0 : SEG_32BIT); + tmp_ins.condition = -1; + best = ~0UL; /* Worst possible */ + best_p = NULL; + for (p = itable[*data]; *p; p++) { + if ( (length = matches(*p, data, asize, osize, + segsize, rep, &tmp_ins)) ) { + works = TRUE; + /* + * Final check to make sure the types of r/m match up. + */ + for (i = 0; i < (*p)->operands; i++) { + if ( + /* If it's a mem-only EA but we have a register, die. */ + ((tmp_ins.oprs[i].segment & SEG_RMREG) && + !(MEMORY & ~(*p)->opd[i])) || + + /* If it's a reg-only EA but we have a memory ref, die. */ + (!(tmp_ins.oprs[i].segment & SEG_RMREG) && + !(REGNORM & ~(*p)->opd[i]) && + !((*p)->opd[i] & REG_SMASK)) || + + /* Register type mismatch (eg FS vs REG_DESS): die. */ + ((((*p)->opd[i] & (REGISTER | FPUREG)) || + (tmp_ins.oprs[i].segment & SEG_RMREG)) && + !whichreg ((*p)->opd[i], tmp_ins.oprs[i].basereg))) { + works = FALSE; + break; + } + } + + if (works) { + goodness = (*p)->flags & IF_PFMASK; + if ( goodness < best ) { + /* This is the best one found so far */ + best = goodness; + best_p = p; + best_length = length; + ins = tmp_ins; + } + } + } + } + + if (!best_p) + return 0; /* no instruction was matched */ + + /* Pick the best match */ + p = best_p; + length = best_length; + + slen = 0; + + if (lock) + slen += sprintf(output+slen, "lock "); + for (i = 0; i < ins.nprefix; i++) + switch (ins.prefixes[i]) { + case P_REP: slen += sprintf(output+slen, "rep "); break; + case P_REPE: slen += sprintf(output+slen, "repe "); break; + case P_REPNE: slen += sprintf(output+slen, "repne "); break; + case P_A16: slen += sprintf(output+slen, "a16 "); break; + case P_A32: slen += sprintf(output+slen, "a32 "); break; + case P_O16: slen += sprintf(output+slen, "o16 "); break; + case P_O32: slen += sprintf(output+slen, "o32 "); break; + } + + for (i = 0; i < elements(ico); i++) + if ((*p)->opcode == ico[i]) { + slen += sprintf(output+slen, "%s%s", icn[i], + whichcond(ins.condition)); + break; + } + if (i >= elements(ico)) + slen += sprintf(output+slen, "%s", insn_names[(*p)->opcode]); + colon = FALSE; + length += data - origdata; /* fix up for prefixes */ + for (i=0; i<(*p)->operands; i++) { + output[slen++] = (colon ? ':' : i==0 ? ' ' : ','); + + if (ins.oprs[i].segment & SEG_RELATIVE) { + ins.oprs[i].offset += offset + length; + /* + * sort out wraparound + */ + if (!(ins.oprs[i].segment & SEG_32BIT)) + ins.oprs[i].offset &= 0xFFFF; + } + + if ((*p)->opd[i] & COLON) + colon = TRUE; + else + colon = FALSE; + + if (((*p)->opd[i] & (REGISTER | FPUREG)) || + (ins.oprs[i].segment & SEG_RMREG)) + { + ins.oprs[i].basereg = whichreg ((*p)->opd[i], + ins.oprs[i].basereg); + if ( (*p)->opd[i] & TO ) + slen += sprintf(output+slen, "to "); + slen += sprintf(output+slen, "%s", + reg_names[ins.oprs[i].basereg-EXPR_REG_START]); + } else if (!(UNITY & ~(*p)->opd[i])) { + output[slen++] = '1'; + } else if ( (*p)->opd[i] & IMMEDIATE ) { + if ( (*p)->opd[i] & BITS8 ) { + slen += sprintf(output+slen, "byte "); + if (ins.oprs[i].segment & SEG_SIGNED) { + if (ins.oprs[i].offset < 0) { + ins.oprs[i].offset *= -1; + output[slen++] = '-'; + } else + output[slen++] = '+'; + } + } else if ( (*p)->opd[i] & BITS16 ) { + slen += sprintf(output+slen, "word "); + } else if ( (*p)->opd[i] & BITS32 ) { + slen += sprintf(output+slen, "dword "); + } else if ( (*p)->opd[i] & NEAR ) { + slen += sprintf(output+slen, "near "); + } else if ( (*p)->opd[i] & SHORT ) { + slen += sprintf(output+slen, "short "); + } + slen += sprintf(output+slen, "0x%lx", ins.oprs[i].offset); + } else if ( !(MEM_OFFS & ~(*p)->opd[i]) ) { + slen += sprintf(output+slen, "[%s%s%s0x%lx]", + (segover ? segover : ""), + (segover ? ":" : ""), + (ins.oprs[i].addr_size == 32 ? "dword " : + ins.oprs[i].addr_size == 16 ? "word " : ""), + ins.oprs[i].offset); + segover = NULL; + } else if ( !(REGMEM & ~(*p)->opd[i]) ) { + int started = FALSE; + if ( (*p)->opd[i] & BITS8 ) + slen += sprintf(output+slen, "byte "); + if ( (*p)->opd[i] & BITS16 ) + slen += sprintf(output+slen, "word "); + if ( (*p)->opd[i] & BITS32 ) + slen += sprintf(output+slen, "dword "); + if ( (*p)->opd[i] & BITS64 ) + slen += sprintf(output+slen, "qword "); + if ( (*p)->opd[i] & BITS80 ) + slen += sprintf(output+slen, "tword "); + if ( (*p)->opd[i] & FAR ) + slen += sprintf(output+slen, "far "); + if ( (*p)->opd[i] & NEAR ) + slen += sprintf(output+slen, "near "); + output[slen++] = '['; + if (ins.oprs[i].addr_size) + slen += sprintf(output+slen, "%s", + (ins.oprs[i].addr_size == 32 ? "dword " : + ins.oprs[i].addr_size == 16 ? "word " : "")); + if (segover) { + slen += sprintf(output+slen, "%s:", segover); + segover = NULL; + } + if (ins.oprs[i].basereg != -1) { + slen += sprintf(output+slen, "%s", + reg_names[(ins.oprs[i].basereg - + EXPR_REG_START)]); + started = TRUE; + } + if (ins.oprs[i].indexreg != -1) { + if (started) + output[slen++] = '+'; + slen += sprintf(output+slen, "%s", + reg_names[(ins.oprs[i].indexreg - + EXPR_REG_START)]); + if (ins.oprs[i].scale > 1) + slen += sprintf(output+slen, "*%d", ins.oprs[i].scale); + started = TRUE; + } + if (ins.oprs[i].segment & SEG_DISP8) { + int sign = '+'; + if (ins.oprs[i].offset & 0x80) { + ins.oprs[i].offset = - (signed char) ins.oprs[i].offset; + sign = '-'; + } + slen += sprintf(output+slen, "%c0x%lx", sign, + ins.oprs[i].offset); + } else if (ins.oprs[i].segment & SEG_DISP16) { + if (started) + output[slen++] = '+'; + slen += sprintf(output+slen, "0x%lx", ins.oprs[i].offset); + } else if (ins.oprs[i].segment & SEG_DISP32) { + if (started) + output[slen++] = '+'; + slen += sprintf(output+slen, "0x%lx", ins.oprs[i].offset); + } + output[slen++] = ']'; + } else { + slen += sprintf(output+slen, "", i); + } + } + output[slen] = '\0'; + if (segover) { /* unused segment override */ + char *p = output; + int count = slen+1; + while (count--) + p[count+3] = p[count]; + strncpy (output, segover, 2); + output[2] = ' '; + } + return length; +} diff --git a/AltairZ80/flashwriter2.c b/AltairZ80/flashwriter2.c new file mode 100644 index 00000000..7ff8d541 --- /dev/null +++ b/AltairZ80/flashwriter2.c @@ -0,0 +1,334 @@ +/************************************************************************* + * * + * $Id: flashwriter2.c 1753 2008-01-02 16:36:47Z Hharte $ * + * * + * Copyright (c) 2007-2008 Howard M. Harte. * + * http:/*www.hartetec.com * + * * + * 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 HOWARD M. HARTE 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 Howard M. Harte shall * + * not be used in advertising or otherwise to promote the sale, use or * + * other dealings in this Software without prior written authorization * + * Howard M. Harte. * + * * + * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. * + * * + * Module Description: * + * Vector Graphic, Inc. FlashWriter II module for SIMH * + * * + * Environment: * + * User mode only * + * * + *************************************************************************/ + +/*#define DBG_MSG*/ + +#include "altairz80_defs.h" + +#if defined (_WIN32) +#include +#else +#include "sim_sock.h" +#endif + +#include "sim_tmxr.h" + +#ifdef DBG_MSG +#define DBG_PRINT(args) printf args +#else +#define DBG_PRINT(args) +#endif + + +extern int32 sio0s(const int32 port, const int32 io, const int32 data); +extern int32 sio0d(const int32 port, const int32 io, const int32 data); +extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, + int32 (*routine)(const int32, const int32, const int32), uint8 unmap); + +static char ansibuf[10]; + +#define FW2_MAX_BOARDS 4 +#define UNIT_V_FW2_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ +#define UNIT_FW2_VERBOSE (1 << UNIT_V_FW2_VERBOSE) +#define FW2_CAPACITY (2048) /* FlashWriter II Memory Size */ + +typedef struct { + UNIT *uptr; /* UNIT pointer */ + uint8 cur_FL_Row; /* Current Flashwriter Row */ + uint8 cur_FL_Col; /* Current Flashwriter Column */ + uint8 FL_Row; + uint8 FL_Col; + uint8 reversevideo; /* Flag set if reverse video is currently on */ + uint8 M[FW2_CAPACITY]; /* FlashWriter 2K Video Memory */ +} FW2_INFO; + +static FW2_INFO *fw2_info[4]; +static uint8 port_map[4] = { 0x11, 0x15, 0x17, 0x19 }; + +static int32 fw2dev(const int32 Addr, const int32 rw, const int32 data); +static t_stat fw2_reset(DEVICE *dptr); +static t_stat fw2_attach(UNIT *uptr, char *cptr); +static t_stat fw2_detach(UNIT *uptr); +static uint8 FW2_Read(const uint32 Addr); +static uint8 FW2_Write(const uint32 Addr, uint8 cData); +static t_stat get_base_address(char *cptr, uint32 *baseaddr); + +static int32 FWIITrace = FALSE; + +static UNIT fw2_unit[] = { + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, FW2_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, FW2_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, FW2_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, FW2_CAPACITY) } +}; + +static REG fw2_reg[] = { + { DRDATA (FWIITRACE, FWIITrace, 8), }, + { NULL } +}; + +static MTAB fw2_mod[] = { + /* quiet, no warning messages */ + { UNIT_FW2_VERBOSE, 0, "QUIET", "QUIET", NULL }, + /* verbose, show warning messages */ + { UNIT_FW2_VERBOSE, UNIT_FW2_VERBOSE, "VERBOSE", "VERBOSE", NULL }, + { 0 } +}; + +DEVICE fw2_dev = { + "FWII", fw2_unit, fw2_reg, fw2_mod, + FW2_MAX_BOARDS, 10, 31, 1, FW2_MAX_BOARDS, FW2_MAX_BOARDS, + NULL, NULL, &fw2_reset, + NULL, &fw2_attach, &fw2_detach, + NULL, 0, 0, + NULL, NULL, NULL +}; + +/* Reset routine */ +static t_stat fw2_reset(DEVICE *dptr) +{ + return SCPE_OK; +} + +/* Attach routine */ +static t_stat fw2_attach(UNIT *uptr, char *cptr) +{ + t_stat r; + unsigned int i = 0; + uint32 baseaddr; + char *tptr; + + r = get_base_address(cptr, &baseaddr); + if(r != SCPE_OK) /* error?*/ + return r; + + DBG_PRINT(("%s\n", __FUNCTION__)); + + for(i = 0; i < FW2_MAX_BOARDS; i++) { + if(&fw2_dev.units[i] == uptr) { + if(uptr->flags & UNIT_FW2_VERBOSE) { + printf("Attaching unit %d\n at %04x", i, baseaddr); + } + break; + } + } + + fw2_info[i] = calloc(1, sizeof(FW2_INFO)); + fw2_info[i]->uptr = uptr; + fw2_info[i]->uptr->u3 = baseaddr; + + if(sim_map_resource(baseaddr, FW2_CAPACITY, RESOURCE_TYPE_MEMORY, &fw2dev, FALSE) != 0) { + printf("%s: error mapping MEM resource at 0x%04x\n", __FUNCTION__, baseaddr); + return SCPE_ARG; + } + + if(sim_map_resource(0x00, 1, RESOURCE_TYPE_IO, &sio0s, FALSE) != 0) { + printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, 0x00); + return SCPE_ARG; + } + + if(sim_map_resource(0x01, 1, RESOURCE_TYPE_IO, &sio0d, FALSE) != 0) { + printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, 0x01); + return SCPE_ARG; + } + + tptr = (char *) malloc (strlen (cptr) + 3); /* get string buf */ + if (tptr == NULL) return SCPE_MEM; /* no more mem? */ + sprintf(tptr, "0x%04x", baseaddr); /* copy base address */ + uptr->filename = tptr; /* save */ + uptr->flags = uptr->flags | UNIT_ATT; + return SCPE_OK; +} + + +/* Detach routine */ +static t_stat fw2_detach(UNIT *uptr) +{ + uint8 i; + + DBG_PRINT(("%s\n", __FUNCTION__)); + + for(i = 0; i < FW2_MAX_BOARDS; i++) { + if(&fw2_dev.units[i] == uptr) { + break; + } + } + + if (i >= FW2_MAX_BOARDS) return SCPE_ARG; + + /* Disconnect FlashWriter2: unmap memory and I/O resources */ + sim_map_resource(fw2_info[i]->uptr->u3, FW2_CAPACITY, RESOURCE_TYPE_MEMORY, &fw2dev, TRUE); + sim_map_resource(0x00, 1, RESOURCE_TYPE_IO, &sio0s, TRUE); + sim_map_resource(0x01, 1, RESOURCE_TYPE_IO, &sio0d, TRUE); + + if(fw2_info[i]) { + free(fw2_info[1]); + } + + free (uptr->filename); /* free base address string */ + uptr->filename = NULL; + uptr->flags = uptr->flags & ~UNIT_ATT; /* not attached */ + return SCPE_OK; +} + +static t_stat get_base_address(char *cptr, uint32 *baseaddr) { + uint32 b; + sscanf(cptr, "%x", &b); + if(b & (FW2_CAPACITY-1)) { + printf("FWII must be on a %d-byte boundary.\n", FW2_CAPACITY); + return SCPE_ARG; + } + *baseaddr = b & ~(FW2_CAPACITY-1); + return SCPE_OK; +} + +extern int32 getBankSelect(void); + +/* This is the main entry point into the Flashwriter2 emulation. */ +static int32 fw2dev(const int32 Addr, const int32 rw, const int32 data) +{ + int32 bank = getBankSelect(); + if(bank == 0) { + if(rw == 0) { /* Read */ + return(FW2_Read(Addr)); + } else { /* Write */ + return(FW2_Write(Addr, data)); + } + } else return 0xff; +} + + +static uint8 FW2_Write(const uint32 Addr, uint8 Value) +{ + FW2_INFO *fw2 = NULL; + uint8 FL_Row; + uint8 FL_Col; + uint32 baseaddr = 0; + uint8 i; + uint8 outchar; + uint8 port; + + for(i = 0; i < FW2_MAX_BOARDS; i++) { + if(fw2_info[i] != NULL) { + baseaddr = fw2_info[i]->uptr->u3; + if((Addr >= baseaddr) && (Addr < (baseaddr + FW2_CAPACITY))) { + break; + } + } + } + + if(i == FW2_MAX_BOARDS) { + return 0; + } + + fw2 = fw2_info[i]; + port = port_map[i]; + + fw2->M[Addr - baseaddr] = Value; + + /* Only print if it is in the visible part of the Flashwriter memory */ + if((Addr >= baseaddr) && (Addr < (baseaddr + (80 * 24)))) { + FL_Col = ((Addr-baseaddr) % 80) + 1; + FL_Row = ((Addr-baseaddr) / 80) + 1; + + if(Value & 0x80) { /* reverse video */ + if(fw2->reversevideo == 0) { + fw2->reversevideo = 1; + sprintf(ansibuf, "\x1b[07m"); + for(i=0;ireversevideo == 1) { + fw2->reversevideo = 0; + sprintf(ansibuf, "\x1b[00m"); + for(i=0;icur_FL_Row == FL_Row) && (FL_Col == fw2->cur_FL_Col + 1)) { + sio0d(port, 1, outchar); + } else { + /* ESC[#;#H */ + sprintf(ansibuf, "\x1b[%d;%dH%c", FL_Row, FL_Col, outchar); + for(i=0;icur_FL_Col = FL_Col; + fw2->cur_FL_Row = FL_Row; + } + + return(1); +} + + +static uint8 FW2_Read(const uint32 Addr) +{ + uint32 baseaddr = 0; + uint8 i; + + for(i = 0; i < FW2_MAX_BOARDS; i++) { + if(fw2_info[i] != NULL) { + baseaddr = fw2_info[i]->uptr->u3; + if((Addr >= baseaddr) && (Addr < (baseaddr + FW2_CAPACITY))) { + break; + } + } + } + + if(i == FW2_MAX_BOARDS) { + return 0xFF; + } + + return(fw2_info[i]->M[Addr - baseaddr]); +} diff --git a/AltairZ80/i8272.c b/AltairZ80/i8272.c new file mode 100644 index 00000000..da2a4e36 --- /dev/null +++ b/AltairZ80/i8272.c @@ -0,0 +1,906 @@ +/************************************************************************* + * * + * $Id: i8272.c 1773 2008-01-11 05:46:19Z hharte $ * + * * + * Copyright (c) 2007-2008 Howard M. Harte. * + * http://www.hartetec.com * + * * + * 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 HOWARD M. HARTE 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 Howard M. Harte shall * + * not be used in advertising or otherwise to promote the sale, use or * + * other dealings in this Software without prior written authorization * + * Howard M. Harte. * + * * + * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. * + * * + * Module Description: * + * Generic Intel 8272 Disk Controller module for SIMH. * + * * + * Environment: * + * User mode only * + * * + *************************************************************************/ + +/* Change log: + - 19-Apr-2008, Tony Nicholson, added other .IMD formats +*/ + +/*#define DBG_MSG */ + +#include "altairz80_defs.h" + +#if defined (_WIN32) +#include +#endif + +#include "sim_imd.h" +#include "i8272.h" + +#ifdef DBG_MSG +#define DBG_PRINT(args) printf args +#else +#define DBG_PRINT(args) +#endif + +#define SEEK_MSG 0x01 +#define CMD_MSG 0x04 +#define RD_DATA_MSG 0x08 +#define WR_DATA_MSG 0x10 +#define STATUS_MSG 0x20 +#define VERBOSE_MSG 0x80 + +#define I8272_MAX_DRIVES 4 +#define I8272_SECTOR_LEN 8192 + +#define CMD_PHASE 0 +#define EXEC_PHASE 1 +#define DATA_PHASE 2 + +typedef union { + uint8 raw[I8272_SECTOR_LEN]; +} SECTOR_FORMAT; + +typedef struct { + UNIT *uptr; + DISK_INFO *imd; + uint8 ntracks; /* number of tracks */ + uint8 nheads; /* number of heads */ + uint32 sectsize; /* sector size, not including pre/postamble */ + uint8 track; /* Current Track */ + uint8 ready; /* Is drive ready? */ +} I8272_DRIVE_INFO; + +typedef struct { + PNP_INFO pnp; /* Plug-n-Play Information */ + uint32 fdc_dma_addr;/* DMA Transfer Address */ + uint8 fdc_msr; /* 8272 Main Status Register */ + uint8 fdc_phase; /* Phase that the 8272 is currently in */ + uint8 fdc_srt; /* Step Rate in ms */ + uint8 fdc_hut; /* Head Unload Time in ms */ + uint8 fdc_hlt; /* Head Load Time in ms */ + uint8 fdc_nd; /* Non-DMA Mode 1=Non-DMA, 0=DMA */ + uint8 fdc_head; /* H Head Number */ + uint8 fdc_sector; /* R Record (Sector) */ + uint8 fdc_sec_len; /* N Sector Length */ + uint8 fdc_eot; /* EOT End of Track (Final sector number of cyl) */ + uint8 fdc_gpl; /* GPL Gap3 Length */ + uint8 fdc_dtl; /* DTL Data Length */ + uint8 fdc_mt; /* Multiple sectors */ + uint8 fdc_mfm; /* MFM mode */ + uint8 fdc_sk; /* Skip Deleted Data */ + uint8 fdc_hds; /* Head Select */ + uint8 fdc_fillbyte; /* Fill-byte used for FORMAT TRACK */ + uint8 fdc_sc; /* Sector count for FORMAT TRACK */ + uint8 fdc_status[3];/* Status Register Bytes */ + uint8 fdc_seek_end; /* Seek was executed successfully */ + uint8 cmd_index; /* Index of command byte */ + uint8 cmd[10]; /* Storage for current command */ + uint8 cmd_len; /* FDC Command Length */ + uint8 result_index; /* Index of result byte */ + uint8 result[10]; /* Result data */ + uint8 result_len; /* FDC Result Length */ + uint8 sel_drive; /* Currently selected drive */ + I8272_DRIVE_INFO drive[I8272_MAX_DRIVES]; +} I8272_INFO; + +static SECTOR_FORMAT sdata; +extern uint32 PCX; +extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc); +extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, + int32 (*routine)(const int32, const int32, const int32), uint8 unmap); + +/* These are needed for DMA. PIO Mode has not been implemented yet. */ +extern void PutBYTEWrapper(const uint32 Addr, const uint32 Value); +extern uint8 GetBYTEWrapper(const uint32 Addr); + +#define UNIT_V_I8272_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_I8272_WLK (1 << UNIT_V_I8272_WLK) +#define UNIT_V_I8272_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ +#define UNIT_I8272_VERBOSE (1 << UNIT_V_I8272_VERBOSE) +#define I8272_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */ +#define I8272_CAPACITY_SSSD (77*1*26*128) /* Single-sided Single Density IBM Diskette1 */ +#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */ +#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */ +#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */ + +/* Intel 8272 Commands */ +#define I8272_READ_TRACK 0x02 +#define I8272_SPECIFY 0x03 +#define I8272_SENSE_DRIVE_STATUS 0x04 +#define I8272_WRITE_DATA 0x05 +#define I8272_READ_DATA 0x06 +#define I8272_RECALIBRATE 0x07 +#define I8272_SENSE_INTR_STATUS 0x08 +#define I8272_WRITE_DELETED_DATA 0x09 +#define I8272_READ_ID 0x0A +#define I8272_READ_DELETED_DATA 0x0C +#define I8272_FORMAT_TRACK 0x0D +#define I8272_SEEK 0x0F +#define I8272_SCAN_EQUAL 0x11 +#define I8272_SCAN_LOW_EQUAL 0x19 +#define I8272_SCAN_HIGH_EQUAL 0x1D + +/* SENSE DRIVE STATUS bit definitions */ +#define DRIVE_STATUS_TWO_SIDED 0x08 +#define DRIVE_STATUS_TRACK0 0x10 +#define DRIVE_STATUS_READY 0x20 +#define DRIVE_STATUS_WP 0x40 +#define DRIVE_STATUS_FAULT 0x80 + +static int32 trace_level = 0; /* Disable all tracing by default. */ +static int32 bootstrap = 0; + +static int32 i8272dev(const int32 port, const int32 io, const int32 data); +static t_stat i8272_reset(DEVICE *dptr); +int32 find_unit_index (UNIT *uptr); + +I8272_INFO i8272_info_data = { { 0x0, 0, 0xC0, 2 } }; +I8272_INFO *i8272_info = &i8272_info_data; + +static UNIT i8272_unit[] = { + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, I8272_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, I8272_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, I8272_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, I8272_CAPACITY) } +}; + +static REG i8272_reg[] = { + { HRDATA (TRACELEVEL, trace_level, 16), }, + { DRDATA (BOOTSTRAP, bootstrap, 10), }, + { NULL } +}; + +static MTAB i8272_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL }, + { UNIT_I8272_WLK, 0, "WRTENB", "WRTENB", NULL }, + { UNIT_I8272_WLK, UNIT_I8272_WLK, "WRTLCK", "WRTLCK", NULL }, + /* quiet, no warning messages */ + { UNIT_I8272_VERBOSE, 0, "QUIET", "QUIET", NULL }, + /* verbose, show warning messages */ + { UNIT_I8272_VERBOSE, UNIT_I8272_VERBOSE, "VERBOSE", "VERBOSE", NULL }, + { 0 } +}; + +DEVICE i8272_dev = { + "I8272", i8272_unit, i8272_reg, i8272_mod, + I8272_MAX_DRIVES, 10, 31, 1, I8272_MAX_DRIVES, I8272_MAX_DRIVES, + NULL, NULL, &i8272_reset, + NULL, &i8272_attach, &i8272_detach, + &i8272_info_data, (DEV_DISABLE | DEV_DIS), 0, + NULL, NULL, NULL +}; + +static uint8 I8272_Setup_Cmd(uint8 fdc_cmd); + + +/* Reset routine */ +static t_stat i8272_reset(DEVICE *dptr) +{ + PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; + + if(dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */ + sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &i8272dev, TRUE); + } else { + /* Connect I/O Ports at base address */ + if(sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &i8272dev, FALSE) != 0) { + printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->io_base); + return SCPE_ARG; + } + } + return SCPE_OK; +} + + +/* find_unit_index find index of a unit + + Inputs: + uptr = pointer to unit + Outputs: + result = index of device +*/ +int32 find_unit_index (UNIT *uptr) +{ + DEVICE *dptr; + uint32 i; + + if (uptr == NULL) return (-1); + dptr = find_dev_from_unit(uptr); + for(i=0; inumunits; i++) { + if(dptr->units + i == uptr) { + break; + } + } + if(i == dptr->numunits) { + return (-1); + } + return (i); +} + +/* Attach routine */ +t_stat i8272_attach(UNIT *uptr, char *cptr) +{ + char header[4]; + t_stat r; + int32 i = 0; + + r = attach_unit(uptr, cptr); /* attach unit */ + if ( r != SCPE_OK) /* error? */ + return r; + + /* Determine length of this disk */ + uptr->capac = sim_fsize(uptr->fileref); + + i = find_unit_index(uptr); + + if (i == -1) { + return (SCPE_IERR); + } + + DBG_PRINT(("Attach I8272%d\n", i)); + i8272_info->drive[i].uptr = uptr; + + /* Default to drive not ready */ + i8272_info->drive[i].ready = 0; + + if(uptr->capac > 0) { + fgets(header, 4, uptr->fileref); + if(!strcmp(header, "IMD")) { + uptr->u3 = IMAGE_TYPE_IMD; + } else if(!strcmp(header, "CPT")) { + printf("CPT images not yet supported\n"); + uptr->u3 = IMAGE_TYPE_CPT; + i8272_detach(uptr); + return SCPE_OPENERR; + } else { + printf("DSK images not yet supported\n"); + uptr->u3 = IMAGE_TYPE_DSK; + i8272_detach(uptr); + return SCPE_OPENERR; + } + } else { + /* creating file, must be DSK format. */ + printf("Cannot create images, must start with a I8272 IMD image.\n"); + uptr->u3 = IMAGE_TYPE_DSK; + i8272_detach(uptr); + return SCPE_OPENERR; + } + + if (uptr->flags & UNIT_I8272_VERBOSE) + printf("I8272%d: attached to '%s', type=%s, len=%d\n", i, cptr, + uptr->u3 == IMAGE_TYPE_IMD ? "IMD" : uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK", + uptr->capac); + + if(uptr->u3 == IMAGE_TYPE_IMD) { + if(uptr->capac < I8272_CAPACITY_SSSD) { /*was 318000 but changed to allow 8inch SSSD disks*/ + printf("IMD file too small for use with SIMH.\nCopy an existing file and format it with CP/M.\n"); + i8272_detach(uptr); + return SCPE_OPENERR; + } + + if (uptr->flags & UNIT_I8272_VERBOSE) + printf("--------------------------------------------------------\n"); + i8272_info->drive[i].imd = diskOpen((uptr->fileref), (uptr->flags & UNIT_I8272_VERBOSE)); + i8272_info->drive[i].ready = 1; + if (uptr->flags & UNIT_I8272_VERBOSE) + printf("\n"); + } else { + i8272_info->drive[i].imd = NULL; + } + + return SCPE_OK; +} + + +/* Detach routine */ +t_stat i8272_detach(UNIT *uptr) +{ + t_stat r; + int8 i; + + i = find_unit_index(uptr); + + if (i == -1) { + return (SCPE_IERR); + } + + DBG_PRINT(("Detach I8272%d\n", i)); + diskClose(i8272_info->drive[i].imd); + i8272_info->drive[i].ready = 0; + + r = detach_unit(uptr); /* detach unit */ + if ( r != SCPE_OK) + return r; + + return SCPE_OK; +} + + +static int32 i8272dev(const int32 port, const int32 io, const int32 data) +{ + DBG_PRINT(("I8272: " ADDRESS_FORMAT " %s, Port 0x%02x Data 0x%02x" NLP, + PCX, io ? "OUT" : " IN", port, data)); + if(io) { + I8272_Write(port, data); + return 0; + } else { + return(I8272_Read(port)); + } +} + +uint8 I8272_Set_DMA(const uint32 dma_addr) +{ + i8272_info->fdc_dma_addr = dma_addr & 0xFFFFFF; + + return 0; +} + +static uint8 floorlog2(unsigned int n) +{ + /* Compute log2(n) */ + uint8 r = 0; + if(n >= 1<<16) { n >>=16; r += 16; } + if(n >= 1<< 8) { n >>= 8; r += 8; } + if(n >= 1<< 4) { n >>= 4; r += 4; } + if(n >= 1<< 2) { n >>= 2; r += 2; } + if(n >= 1<< 1) { r += 1; } + return ((n == 0) ? (0xFF) : r); /* 0xFF is error return value */ +} + +uint8 I8272_Read(const uint32 Addr) +{ + uint8 cData; + I8272_DRIVE_INFO *pDrive; + + pDrive = &i8272_info->drive[i8272_info->sel_drive]; + + if(pDrive->uptr == NULL) { + return 0xFF; + } + + cData = 0x00; + + switch(Addr & 0x3) { + case I8272_FDC_MSR: + cData = i8272_info->fdc_msr | 0x80; + if(i8272_info->fdc_phase == 0) { + cData &= ~0x40; + } else { + cData |= 0x40; + } + + TRACE_PRINT(STATUS_MSG, ("I8272: " ADDRESS_FORMAT " RD FDC MSR = 0x%02x" NLP, PCX, cData)); + break; + case I8272_FDC_DATA: + if(i8272_info->fdc_phase == DATA_PHASE) { + cData = i8272_info->result[i8272_info->result_index]; + i8272_info->result_index ++; + if(i8272_info->result_index == i8272_info->result_len) { + TRACE_PRINT(VERBOSE_MSG, ("I8272: " ADDRESS_FORMAT " result phase complete." NLP, PCX)); + i8272_info->fdc_phase = 0; + } + } + + TRACE_PRINT(VERBOSE_MSG, ("I8272: " ADDRESS_FORMAT " RD Data, phase=%d, [%d]=0x%02x" NLP, PCX, i8272_info->fdc_phase, i8272_info->result_index-1, cData)); + + break; + default: + TRACE_PRINT(VERBOSE_MSG, ("I8272: " ADDRESS_FORMAT " Cannot read register %x" NLP, PCX, Addr)); + cData = 0xFF; + } + + return (cData); +} + +static char *messages[0x20] = { +/* 0 1 2 3 */ + "Undefined Command 0x0","Undefined Command 0x1","Read Track", "Specify", +/* 4 5 6 7 */ + "Sense Drive Status", "Write Data", "Read Data", "Recalibrate", +/* 8 9 A B */ + "Sense Interrupt Status", "Write Deleted Data", "Read ID", "Undefined Command 0xB", +/* C D E F */ + "Read Deleted Data", "Format Track", "Undefined Command 0xE","Seek", +/* 10 11 12 13 */ + "Undefined Command 0x10","Scan Equal", "Undefined Command 0x12","Undefined Command 0x13", +/* 14 15 16 17 */ + "Undefined Command 0x14","Undefined Command 0x15","Undefined Command 0x16","Undefined Command 0x17", +/* 18 19 1A 1B */ + "Undefined Command 0x18","Scan Low Equal", "Undefined Command 0x1A","Undefined Command 0x1B", +/* 1C 1D 1E 1F */ + "Undefined Command 0x1C","Scan High Equal", "Undefined Command 0x1E","Undefined Command 0x1F" +}; + +uint8 I8272_Write(const uint32 Addr, uint8 cData) +{ + I8272_DRIVE_INFO *pDrive; + unsigned int flags; + unsigned int readlen; + uint8 disk_read = 0; + int32 i; + + pDrive = &i8272_info->drive[i8272_info->sel_drive]; + + if(pDrive->uptr == NULL) { + return 0xFF; + } + + switch(Addr & 0x3) { + case I8272_FDC_MSR: + TRACE_PRINT(WR_DATA_MSG, ("I8272: " ADDRESS_FORMAT " WR Drive Select Reg=%02x" NLP, + PCX, cData)); + break; + case I8272_FDC_DATA: + TRACE_PRINT(VERBOSE_MSG, ("I8272: " ADDRESS_FORMAT " WR Data, phase=%d, index=%d" NLP, + PCX, i8272_info->fdc_phase, i8272_info->cmd_index)); + if(i8272_info->fdc_phase == CMD_PHASE) { + i8272_info->cmd[i8272_info->cmd_index] = cData; + + if(i8272_info->cmd_index == 0) { + TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " CMD=0x%02x[%s]" NLP, + PCX, cData & 0x1F, messages[cData & 0x1F])); + I8272_Setup_Cmd(cData & 0x1F); + } + i8272_info->cmd_index ++; + + if(i8272_info->cmd_len == i8272_info->cmd_index) { + i8272_info->cmd_index = 0; + i8272_info->fdc_phase = EXEC_PHASE; + } + } + + if(i8272_info->fdc_phase == EXEC_PHASE) { + switch(i8272_info->cmd[0] & 0x1F) { + case I8272_READ_DATA: + case I8272_WRITE_DATA: + case I8272_READ_DELETED_DATA: + case I8272_WRITE_DELETED_DATA: + case I8272_READ_TRACK: + case I8272_SCAN_LOW_EQUAL: + case I8272_SCAN_HIGH_EQUAL: + case I8272_SCAN_EQUAL: + i8272_info->fdc_mt = (i8272_info->cmd[0] & 0x80) >> 7; + i8272_info->fdc_mfm = (i8272_info->cmd[0] & 0x40) >> 6; + i8272_info->fdc_sk = (i8272_info->cmd[0] & 0x20) >> 5; + i8272_info->fdc_hds = (i8272_info->cmd[1] & 0x04) >> 2; + i8272_info->sel_drive = (i8272_info->cmd[1] & 0x03); + pDrive = &i8272_info->drive[i8272_info->sel_drive]; + if(pDrive->uptr == NULL) { + return 0xFF; + } + + if(pDrive->track != i8272_info->cmd[2]) { + i8272_info->fdc_seek_end = 1; + } else { + i8272_info->fdc_seek_end = 0; + } + pDrive->track = i8272_info->cmd[2]; + i8272_info->fdc_head = i8272_info->cmd[3]; + i8272_info->fdc_sector = i8272_info->cmd[4]; + i8272_info->fdc_sec_len = i8272_info->cmd[5]; + i8272_info->fdc_eot = i8272_info->cmd[6]; + i8272_info->fdc_gpl = i8272_info->cmd[7]; + i8272_info->fdc_dtl = i8272_info->cmd[8]; + + TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT + " CMD=0x%02x[%s]: Drive: %d, %s %s, C=%d. H=%d. S=%d, N=%d, EOT=%02x, GPL=%02x, DTL=%02x" NLP, + PCX, + i8272_info->cmd[0] & 0x1F, + messages[i8272_info->cmd[0] & 0x1F], + i8272_info->sel_drive, + i8272_info->fdc_mt ? "Multi" : "Single", + i8272_info->fdc_mfm ? "MFM" : "FM", + pDrive->track, + i8272_info->fdc_head, + i8272_info->fdc_sector, + i8272_info->fdc_sec_len, + i8272_info->fdc_eot, + i8272_info->fdc_gpl, + i8272_info->fdc_dtl)); + + i8272_info->fdc_status[0] = (i8272_info->fdc_hds & 1) << 2; + i8272_info->fdc_status[0] |= (i8272_info->sel_drive & 3); + i8272_info->fdc_status[0] |= 0x40; + + i8272_info->fdc_status[1] = 0; + i8272_info->fdc_status[2] = 0; + + i8272_info->result[0] = i8272_info->fdc_status[0]; + i8272_info->result[1] = i8272_info->fdc_status[1]; + i8272_info->result[2] = i8272_info->fdc_status[2]; + i8272_info->result[3] = pDrive->track; + i8272_info->result[4] = i8272_info->fdc_head; + i8272_info->result[5] = i8272_info->fdc_sector; + i8272_info->result[6] = i8272_info->fdc_sec_len; + break; + case I8272_READ_ID: /* READ ID */ + i8272_info->fdc_mfm = (i8272_info->cmd[0] & 0x40) >> 6; + i8272_info->fdc_hds = (i8272_info->cmd[1] & 0x04) >> 2; + i8272_info->sel_drive = (i8272_info->cmd[1] & 0x03); + pDrive = &i8272_info->drive[i8272_info->sel_drive]; + if(pDrive->uptr == NULL) { + return 0xFF; + } + /* Compute the i8272 "N" value from the sectorsize of this */ + /* disk's current track - i.e. N = log2(sectsize) - log2(128) */ + /* The calculation also works for non-standard format disk images with */ + /* sectorsizes of 2048, 4096 and 8192 bytes */ + i8272_info->fdc_sec_len = floorlog2( + pDrive->imd->track[pDrive->track][i8272_info->fdc_head].sectsize) - 7; + if(i8272_info->fdc_sec_len == 0xF8) { /*Error calculating N*/ + return 0xFF; + } + i8272_info->fdc_status[0] = (i8272_info->fdc_hds & 1) << 2; + i8272_info->fdc_status[0] |= (i8272_info->sel_drive & 3); + + i8272_info->fdc_status[1] = 0; + i8272_info->fdc_status[2] = 0; + + i8272_info->result[0] = i8272_info->fdc_status[0]; + i8272_info->result[1] = i8272_info->fdc_status[1]; + i8272_info->result[2] = i8272_info->fdc_status[2]; + i8272_info->result[3] = pDrive->track; + i8272_info->result[4] = i8272_info->fdc_head; + i8272_info->result[5] = i8272_info->fdc_sector; + i8272_info->result[6] = i8272_info->fdc_sec_len; /*was hardcoded to 0x3*/ + break; + case I8272_RECALIBRATE: /* RECALIBRATE */ + i8272_info->sel_drive = i8272_info->cmd[1] & 3; + pDrive = &i8272_info->drive[i8272_info->sel_drive]; + if(pDrive->uptr == NULL) { + return 0xFF; + } + + pDrive->track = 0; + i8272_info->fdc_phase = 0; /* No result phase */ + pDrive->track = 0; + i8272_info->fdc_seek_end = 1; + TRACE_PRINT(SEEK_MSG, ("I8272: " ADDRESS_FORMAT " Recalibrate: Drive 0x%02x" NLP, + PCX, i8272_info->sel_drive)); + break; + case I8272_FORMAT_TRACK: /* FORMAT A TRACK */ + i8272_info->fdc_mfm = (i8272_info->cmd[0] & 0x40) >> 6; + i8272_info->fdc_hds = (i8272_info->cmd[1] & 0x04) >> 2; + i8272_info->fdc_head = i8272_info->fdc_hds; /* psco added */ + i8272_info->sel_drive = (i8272_info->cmd[1] & 0x03); + pDrive = &i8272_info->drive[i8272_info->sel_drive]; + if(pDrive->uptr == NULL) { + return 0xFF; + } + + if(pDrive->track != i8272_info->cmd[2]) { + i8272_info->fdc_seek_end = 1; + } else { + i8272_info->fdc_seek_end = 0; + } + i8272_info->fdc_sec_len = i8272_info->cmd[2]; + i8272_info->fdc_sc = i8272_info->cmd[3]; + i8272_info->fdc_gpl = i8272_info->cmd[4]; + i8272_info->fdc_fillbyte = i8272_info->cmd[5]; + + TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Format Drive: %d, %s, C=%d. H=%d. N=%d, SC=%d, GPL=%02x, FILL=%02x" NLP, + PCX, + i8272_info->sel_drive, + i8272_info->fdc_mfm ? "MFM" : "FM", + pDrive->track, + i8272_info->fdc_head, + i8272_info->fdc_sec_len, + i8272_info->fdc_sc, + i8272_info->fdc_gpl, + i8272_info->fdc_fillbyte)); + + i8272_info->fdc_status[0] = (i8272_info->fdc_hds & 1) << 2; + i8272_info->fdc_status[0] |= (i8272_info->sel_drive & 3); + /*i8272_info->fdc_status[0] |= 0x40; psco removed */ + + i8272_info->fdc_status[1] = 0; + i8272_info->fdc_status[2] = 0; + + i8272_info->result[0] = i8272_info->fdc_status[0]; + i8272_info->result[1] = i8272_info->fdc_status[1]; + i8272_info->result[2] = i8272_info->fdc_status[2]; + i8272_info->result[3] = pDrive->track; + i8272_info->result[4] = i8272_info->fdc_head; + i8272_info->result[5] = i8272_info->fdc_sector; + i8272_info->result[6] = i8272_info->fdc_sec_len; + break; + case I8272_SENSE_INTR_STATUS: /* SENSE INTERRUPT STATUS */ + TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Sense Interrupt Status" NLP, PCX)); + i8272_info->result[0] = i8272_info->fdc_seek_end ? 0x20 : 0x00; /* SEEK_END */ + i8272_info->result[0] |= i8272_info->sel_drive; + i8272_info->result[1] = pDrive->track; + break; + case I8272_SPECIFY: /* SPECIFY */ + i8272_info->fdc_srt = 16 - ((i8272_info->cmd[1] & 0xF0) >> 4); + i8272_info->fdc_hut = (i8272_info->cmd[1] & 0x0F) * 16; + i8272_info->fdc_hlt = ((i8272_info->cmd[2] & 0xFE) >> 1) * 2; + i8272_info->fdc_nd = (i8272_info->cmd[2] & 0x01); + i8272_info->fdc_phase = 0; /* No result phase */ + TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Specify: SRT=%d, HUT=%d, HLT=%d, ND=%s" NLP, + PCX, + i8272_info->fdc_srt, + i8272_info->fdc_hut, + i8272_info->fdc_hlt, + i8272_info->fdc_nd ? "NON-DMA" : "DMA")); + break; + case I8272_SENSE_DRIVE_STATUS: /* Setup Status3 Byte */ + i8272_info->fdc_hds = (i8272_info->cmd[1] & 0x04) >> 2; + i8272_info->sel_drive = (i8272_info->cmd[1] & 0x03); + pDrive = &i8272_info->drive[i8272_info->sel_drive]; + if(pDrive->uptr == NULL) { + return 0xFF; + } + + i8272_info->result[0] = (pDrive->ready) ? DRIVE_STATUS_READY : 0; /* Drive Ready */ + if(imdGetSides(pDrive->imd) == 2) { + i8272_info->result[0] |= DRIVE_STATUS_TWO_SIDED; /* Two-sided? */ + } + if(imdIsWriteLocked(pDrive->imd)) { + i8272_info->result[0] |= DRIVE_STATUS_WP; /* Write Protected? */ + } + i8272_info->result[0] |= (i8272_info->fdc_hds & 1) << 2; + i8272_info->result[0] |= (i8272_info->sel_drive & 3); + i8272_info->result[0] |= (pDrive->track == 0) ? DRIVE_STATUS_TRACK0 : 0x00; /* Track 0 */ + TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Sense Drive Status = %02x" NLP, + PCX, i8272_info->result[0])); + break; + case I8272_SEEK: /* SEEK */ + i8272_info->fdc_mt = (i8272_info->cmd[0] & 0x80) >> 7; + i8272_info->fdc_mfm = (i8272_info->cmd[0] & 0x40) >> 6; + i8272_info->fdc_sk = (i8272_info->cmd[0] & 0x20) >> 5; + i8272_info->fdc_hds = (i8272_info->cmd[1] & 0x04) >> 2; + i8272_info->sel_drive = (i8272_info->cmd[1] & 0x03); + pDrive = &i8272_info->drive[i8272_info->sel_drive]; + if(pDrive->uptr == NULL) { + return 0xFF; + } + + pDrive->track = i8272_info->cmd[2]; + i8272_info->fdc_seek_end = 1; + TRACE_PRINT(SEEK_MSG, ("I8272: " ADDRESS_FORMAT " Seek %d" NLP, + PCX, pDrive->track)); + break; + default: /* INVALID */ + break; + } + + if(i8272_info->fdc_phase == EXEC_PHASE) { + switch(i8272_info->cmd[0] & 0x1F) { + case I8272_READ_TRACK: + printf("I8272: " ADDRESS_FORMAT " Read a track (untested.)" NLP, PCX); + i8272_info->fdc_sector = 1; /* Read entire track from sector 1...eot */ + case I8272_READ_DATA: + case I8272_READ_DELETED_DATA: + disk_read = 1; + case I8272_WRITE_DATA: + case I8272_WRITE_DELETED_DATA: + for(;i8272_info->fdc_sector<=i8272_info->fdc_eot;i8272_info->fdc_sector++) { + TRACE_PRINT(RD_DATA_MSG, ("I8272: " ADDRESS_FORMAT " %s Data, sector: %d sector len=%d" NLP, + PCX, disk_read ? "RD" : "WR", + i8272_info->fdc_sector, + 128 << i8272_info->fdc_sec_len)); + switch((pDrive->uptr)->u3) + { + case IMAGE_TYPE_IMD: + if(pDrive->imd == NULL) { + printf(".imd is NULL!" NLP); + } + if(disk_read) { /* Read sector */ + sectRead(pDrive->imd, + pDrive->track, + i8272_info->fdc_head, + i8272_info->fdc_sector, + sdata.raw, + 128 << i8272_info->fdc_sec_len, + &flags, + &readlen); + + for(i=0;i<(128 << i8272_info->fdc_sec_len);i++) { + PutBYTEWrapper(i8272_info->fdc_dma_addr, sdata.raw[i]); + i8272_info->fdc_dma_addr++; + } + TRACE_PRINT(RD_DATA_MSG, ("I8272: " ADDRESS_FORMAT " Data transferred to RAM at 0x%06x" NLP, + PCX, i8272_info->fdc_dma_addr)); + } else { /* Write */ + for(i=0;i<(128 << i8272_info->fdc_sec_len);i++) { + sdata.raw[i] = GetBYTEWrapper(i8272_info->fdc_dma_addr); + i8272_info->fdc_dma_addr++; + } + TRACE_PRINT(WR_DATA_MSG, ("I8272: " ADDRESS_FORMAT " Data transferred from RAM at 0x%06x" NLP, + PCX, i8272_info->fdc_dma_addr)); + sectWrite(pDrive->imd, + pDrive->track, + i8272_info->fdc_head, + i8272_info->fdc_sector, + sdata.raw, + 128 << i8272_info->fdc_sec_len, + &flags, + &readlen); + } + + i8272_info->result[5] = i8272_info->fdc_sector; + i8272_info->result[1] = 0x80; + break; + case IMAGE_TYPE_DSK: + printf("%s: DSK Format not supported" NLP, __FUNCTION__); + break; + case IMAGE_TYPE_CPT: + printf("%s: CPT Format not supported" NLP, __FUNCTION__); + break; + default: + printf("%s: Unknown image Format" NLP, __FUNCTION__); + break; + } + } + break; + case I8272_FORMAT_TRACK: /* FORMAT A TRACK */ + for(i8272_info->fdc_sector = 1;i8272_info->fdc_sector<=i8272_info->fdc_sc;i8272_info->fdc_sector++) { + TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Format Track %d, Sector=%d, len=%d" NLP, + PCX, + pDrive->track, + i8272_info->fdc_sector, + 128 << i8272_info->fdc_sec_len)); + switch((pDrive->uptr)->u3) + { + case IMAGE_TYPE_IMD: + if(pDrive->imd == NULL) { + printf(".imd is NULL!" NLP); + } + TRACE_PRINT(WR_DATA_MSG, ("%s: Write: imd=%p t=%i h=%i s=%i l=%i" NLP, + __FUNCTION__, pDrive->imd, pDrive->track, i8272_info->fdc_head, + i8272_info->fdc_sector, 128 << i8272_info->fdc_sec_len)); + memset(sdata.raw, i8272_info->fdc_fillbyte, 128 << i8272_info->fdc_sec_len); + sectWrite(pDrive->imd, + pDrive->track, + i8272_info->fdc_head, + i8272_info->fdc_sector, + sdata.raw, + 128 << i8272_info->fdc_sec_len, + &flags, + &readlen); + i8272_info->result[1] = 0x80; + i8272_info->result[5] = i8272_info->fdc_sector; + break; + case IMAGE_TYPE_DSK: + printf("%s: DSK Format not supported" NLP, __FUNCTION__); + break; + case IMAGE_TYPE_CPT: + printf("%s: CPT Format not supported" NLP, __FUNCTION__); + break; + default: + printf("%s: Unknown image Format" NLP, __FUNCTION__); + break; + } + } + break; + + case I8272_SCAN_LOW_EQUAL: /* SCAN LOW OR EQUAL */ + case I8272_SCAN_HIGH_EQUAL: /* SCAN HIGH OR EQUAL */ + case I8272_SCAN_EQUAL: /* SCAN EQUAL */ + TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT " Scan Data" NLP, + PCX)); + printf("I8272: " ADDRESS_FORMAT " Scan not implemented." NLP, PCX); + break; + case I8272_READ_ID: /* READ ID */ + TRACE_PRINT(CMD_MSG, ("I8272: " ADDRESS_FORMAT + " READ ID Drive %d result ST0=%02x ST1=%02x ST2=%02x C=%02x H=%02x R=%02x N=%02x" + NLP, PCX, i8272_info->sel_drive, i8272_info->result[0], + i8272_info->result[1],i8272_info->result[2],i8272_info->result[3], + i8272_info->result[4],i8272_info->result[5],i8272_info->result[6])); + break; + + default: + break; + } + } + + + if(i8272_info->result_len != 0) { + i8272_info->fdc_phase ++; + } else { + i8272_info->fdc_phase = 0; + } + + i8272_info->result_index = 0; + } + + + break; + } + + cData = 0x00; + + return (cData); +} + +static uint8 I8272_Setup_Cmd(uint8 fdc_cmd) +{ + uint8 result = 0; + + switch(fdc_cmd) { + case I8272_READ_DATA: + case I8272_WRITE_DATA: + case I8272_READ_DELETED_DATA: + case I8272_WRITE_DELETED_DATA: + case I8272_READ_TRACK: + case I8272_SCAN_LOW_EQUAL: + case I8272_SCAN_HIGH_EQUAL: + case I8272_SCAN_EQUAL: + i8272_info->cmd_len = 9; + i8272_info->result_len = 7; + break; + case I8272_READ_ID: /* READ ID */ + i8272_info->cmd_len = 2; + i8272_info->result_len = 7; + break; + case I8272_RECALIBRATE: /* RECALIBRATE */ + i8272_info->cmd_len = 2; + i8272_info->result_len = 0; + break; + case I8272_FORMAT_TRACK: /* FORMAT A TRACK */ + i8272_info->cmd_len = 6; + i8272_info->result_len = 7; + break; + case I8272_SENSE_INTR_STATUS: /* SENSE INTERRUPT STATUS */ + i8272_info->cmd_len = 1; + i8272_info->result_len = 2; + break; + case I8272_SPECIFY: /* SPECIFY */ + i8272_info->cmd_len = 3; + i8272_info->result_len = 0; + break; + case I8272_SENSE_DRIVE_STATUS: /* SENSE DRIVE STATUS */ + i8272_info->cmd_len = 2; + i8272_info->result_len = 1; + break; + case I8272_SEEK: /* SEEK */ + i8272_info->cmd_len = 3; + i8272_info->result_len = 0; + break; + default: /* INVALID */ + i8272_info->cmd_len = 1; + i8272_info->result_len = 1; + result = -1; + break; + } + return (result); +} + diff --git a/AltairZ80/i8272.h b/AltairZ80/i8272.h new file mode 100644 index 00000000..c3fce099 --- /dev/null +++ b/AltairZ80/i8272.h @@ -0,0 +1,49 @@ +/************************************************************************* + * * + * $Id: i8272.h 1759 2008-01-05 04:36:46Z hharte $ * + * * + * Copyright (c) 2007-2008 Howard M. Harte. * + * http://www.hartetec.com * + * * + * 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 HOWARD M. HARTE 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 Howard M. Harte shall * + * not be used in advertising or otherwise to promote the sale, use or * + * other dealings in this Software without prior written authorization * + * Howard M. Harte. * + * * + * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. * + * * + * Module Description: * + * Generic Intel 8272 Disk Controller module for SIMH. * + * * + * Environment: * + * User mode only * + * * + *************************************************************************/ + +extern t_stat i8272_attach(UNIT *uptr, char *cptr); +extern t_stat i8272_detach(UNIT *uptr); +extern uint8 I8272_Set_DMA(const uint32 dma_addr); +extern uint8 I8272_Read(const uint32 Addr); +extern uint8 I8272_Write(const uint32 Addr, uint8 cData); + +#define I8272_FDC_MSR 0 /* R=FDC Main Status Register, W=Drive Select Register */ +#define I8272_FDC_DATA 1 /* R/W FDC Data Register */ diff --git a/AltairZ80/i86.h b/AltairZ80/i86.h new file mode 100644 index 00000000..06e4c8e3 --- /dev/null +++ b/AltairZ80/i86.h @@ -0,0 +1,296 @@ +/* + * Dos/PC Emulator + * Copyright (C) 1991 Jim Hudgens + * + * + * The file is part of GDE. + * + * GDE is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * GDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GDE; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* 8086 support structs and definitions */ +/* definition of the registers */ + +/* general EAX,EBX,ECX, EDX type registers. + Note that for portability, and speed, the issue of byte + swapping is not addressed in the registers. All registers + are stored in the default format available on the + host machine. The only critical issue is that the + registers should line up EXACTLY in the same manner as + they do in the 386. That is: + + EAX & 0xff === AL + EAX & 0xffff == AX + + etc. The result is that alot of the calculations can then be + done using the native instruction set fully. +*/ + +/* Endian Logic +Priority 1: If LOWFIRST is defined, use it. LOWFIRST must be 1 if the + lower part of a 16 bit quantity comes first in memory, otherwise + LOWFIRST must be 0 +Priority 2: If __BIG_ENDIAN__ is defined, use it to define LOWFIRST accordingly +Priority 3: OS 9 on Macintosh needs LOWFIRST 0 +Priority 4: Use LOWFIRST 1 as default +*/ + +#ifndef LOWFIRST +#ifdef __BIG_ENDIAN__ +#if __BIG_ENDIAN__ +#define LOWFIRST 0 +#else +#define LOWFIRST 1 +#endif +#elif defined (__MWERKS__) && defined (macintosh) +#define LOWFIRST 0 +#else +#define LOWFIRST 1 +#endif +#endif + +#if LOWFIRST +typedef struct { uint16 x_reg; } I16_reg_t; +typedef struct { uint8 l_reg, h_reg; } I8_reg_t; +#else +typedef struct { uint16 x_reg; } I16_reg_t; +typedef struct { uint8 h_reg, l_reg; } I8_reg_t; +#endif + +typedef union +{ + I16_reg_t I16_reg; + I8_reg_t I8_reg; +} i386_general_register; + +struct i386_general_regs +{ + i386_general_register A, B, C, D; +}; + +typedef struct i386_general_regs Gen_reg_t; + +struct i386_special_regs +{ + i386_general_register SP, BP, SI, DI, IP; + uint32 FLAGS; +}; + +/* + * segment registers here represent the 16 bit quantities + * CS, DS, ES, SS + * + * segment pointers --- used to speed up the expressions: + * q = m->R_CSP + m->R_IP; + * fetched = *q; + * m->R_IP += 1; + * compared to: + * fetched = GetBYTEExtended(((uint32)m->R_CS << 4) + (m->R_IP++)); + * Save at least one shift, more if doing two byte moves. + */ +struct i386_segment_regs +{ + uint16 CS, DS, SS, ES, FS, GS; +}; + +/* 8 bit registers */ +#define R_AH Gn_regs.A.I8_reg.h_reg +#define R_AL Gn_regs.A.I8_reg.l_reg +#define R_BH Gn_regs.B.I8_reg.h_reg +#define R_BL Gn_regs.B.I8_reg.l_reg +#define R_CH Gn_regs.C.I8_reg.h_reg +#define R_CL Gn_regs.C.I8_reg.l_reg +#define R_DH Gn_regs.D.I8_reg.h_reg +#define R_DL Gn_regs.D.I8_reg.l_reg + +/* 16 bit registers */ +#define R_AX Gn_regs.A.I16_reg.x_reg +#define R_BX Gn_regs.B.I16_reg.x_reg +#define R_CX Gn_regs.C.I16_reg.x_reg +#define R_DX Gn_regs.D.I16_reg.x_reg + +/* special registers */ +#define R_SP Sp_regs.SP.I16_reg.x_reg +#define R_BP Sp_regs.BP.I16_reg.x_reg +#define R_SI Sp_regs.SI.I16_reg.x_reg +#define R_DI Sp_regs.DI.I16_reg.x_reg +#define R_IP Sp_regs.IP.I16_reg.x_reg +#define R_FLG Sp_regs.FLAGS + +/* segment registers */ +#define R_CS Sg_regs.CS +#define R_DS Sg_regs.DS +#define R_SS Sg_regs.SS +#define R_ES Sg_regs.ES + +/* 8088 has top 4 bits of the flags set to 1 */ +/* Also, bit#1 is set. This is (not well) documented behavior. */ +/* see note in userman.tex about the subtleties of dealing with */ +/* code which attempts to detect the host processor. */ +/* This is def'd as F_ALWAYS_ON */ +#define F_ALWAYS_ON (0xf002) /* flag bits always on */ + +/* following bits masked in to a 16bit quantity */ +#define F_CF 0x1 /* CARRY flag */ +#define F_PF 0x4 /* PARITY flag */ +#define F_AF 0x10 /* AUX flag */ +#define F_ZF 0x40 /* ZERO flag */ +#define F_SF 0x80 /* SIGN flag */ +#define F_TF 0x100 /* TRAP flag */ +#define F_IF 0x200 /* INTERRUPT ENABLE flag */ +#define F_DF 0x400 /* DIR flag */ +#define F_OF 0x800 /* OVERFLOW flag */ + +/* + * DEFINE A MASK FOR ONLY THOSE FLAG BITS WE WILL EVER PASS BACK + * (via PUSHF) + */ +#define F_MSK (F_CF|F_PF|F_AF|F_ZF|F_SF|F_TF|F_IF|F_DF|F_OF) + +#define TOGGLE_FLAG(M,FLAG) (M)->R_FLG ^= FLAG +#define SET_FLAG(M,FLAG) (M)->R_FLG |= FLAG +#define CLEAR_FLAG(M, FLAG) (M)->R_FLG &= ~FLAG +#define ACCESS_FLAG(M,FLAG) ((M)->R_FLG & (FLAG)) + +#define CONDITIONAL_SET_FLAG(COND,M,FLAG) \ + if (COND) SET_FLAG(M,FLAG); else CLEAR_FLAG(M,FLAG) + +/* emulator machine state. */ +/* segment usage control */ +#define SYSMODE_SEG_DS_SS 0x01 +#define SYSMODE_SEGOVR_CS 0x02 +#define SYSMODE_SEGOVR_DS 0x04 +#define SYSMODE_SEGOVR_ES 0x08 +#define SYSMODE_SEGOVR_SS 0x10 + +#define SYSMODE_SEGMASK (SYSMODE_SEG_DS_SS | SYSMODE_SEGOVR_CS | \ + SYSMODE_SEGOVR_DS | SYSMODE_SEGOVR_ES | SYSMODE_SEGOVR_SS) + +#define SYSMODE_PREFIX_REPE 0x20 +#define SYSMODE_PREFIX_REPNE 0x40 + +#define INTR_SYNCH 0x1 +#define INTR_HALTED 0x4 +#define INTR_ILLEGAL_OPCODE 0x8 + +/* INSTRUCTION DECODING STUFF */ +#define FETCH_DECODE_MODRM(m,mod,rh,rl) fetch_decode_modrm(m,&mod,&rh,&rl) +#define DECODE_RM_BYTE_REGISTER(m,r) decode_rm_byte_register(m,r) +#define DECODE_RM_WORD_REGISTER(m,r) decode_rm_word_register(m,r) +#define DECODE_CLEAR_SEGOVR(m) m->sysmode &= ~(SYSMODE_SEGMASK) + +typedef struct pc_env PC_ENV; +struct pc_env +{ + /* The registers!! */ + struct i386_general_regs Gn_regs; + struct i386_special_regs Sp_regs; + struct i386_segment_regs Sg_regs; + /* our flags structrure. This contains information on + REPE prefix 2 bits repe,repne + SEGMENT overrides 5 bits normal,DS,SS,CS,ES + Delayed flag set 3 bits (zero, signed, parity) + reserved 6 bits + interrupt # 8 bits instruction raised interrupt + BIOS video segregs 4 bits + Interrupt Pending 1 bits + Extern interrupt 1 bits + Halted 1 bits + */ + long sysmode; + uint8 intno; +}; + +/* GLOBAL */ +volatile int intr; + +void halt_sys (PC_ENV *sys); +void fetch_decode_modrm (PC_ENV *m, uint16 *mod, uint16 *regh, uint16 *regl); +uint8 *decode_rm_byte_register (PC_ENV *m, int reg); +uint16 *decode_rm_word_register (PC_ENV *m, int reg); +uint16 *decode_rm_seg_register (PC_ENV *m, int reg); +uint8 fetch_byte_imm (PC_ENV *m); +uint16 fetch_word_imm (PC_ENV *m); +uint16 decode_rm00_address (PC_ENV *m, int rm); +uint16 decode_rm01_address (PC_ENV *m, int rm); +uint16 decode_rm10_address (PC_ENV *m, int rm); +uint8 fetch_data_byte (PC_ENV *m, uint16 offset); +uint8 fetch_data_byte_abs (PC_ENV *m, uint16 segment, uint16 offset); +uint16 fetch_data_word (PC_ENV *m, uint16 offset); +uint16 fetch_data_word_abs (PC_ENV *m, uint16 segment, uint16 offset); +void store_data_byte (PC_ENV *m, uint16 offset, uint8 val); +void store_data_byte_abs (PC_ENV *m, uint16 segment, uint16 offset, uint8 val); +void store_data_word (PC_ENV *m, uint16 offset, uint16 val); +void store_data_word_abs (PC_ENV *m, uint16 segment, uint16 offset, uint16 val); + +typedef void (*OP)(PC_ENV *m); +extern OP i86_optab[256]; + +/* PRIMITIVE OPERATIONS */ + +uint8 aad_word (PC_ENV *m, uint16 d); +uint16 aam_word (PC_ENV *m, uint8 d); +uint8 adc_byte (PC_ENV *m, uint8 d, uint8 s); +uint16 adc_word (PC_ENV *m, uint16 d, uint16 s); +uint8 add_byte (PC_ENV *m, uint8 d, uint8 s); +uint16 add_word (PC_ENV *m, uint16 d, uint16 s); +uint8 and_byte (PC_ENV *m, uint8 d, uint8 s); +uint16 and_word (PC_ENV *m, uint16 d, uint16 s); +uint8 cmp_byte (PC_ENV *m, uint8 d, uint8 s); +uint16 cmp_word (PC_ENV *m, uint16 d, uint16 s); +uint8 dec_byte (PC_ENV *m, uint8 d); +uint16 dec_word (PC_ENV *m, uint16 d); +uint8 inc_byte (PC_ENV *m, uint8 d); +uint16 inc_word (PC_ENV *m, uint16 d); +uint8 or_byte (PC_ENV *m, uint8 d, uint8 s); +uint16 or_word (PC_ENV *m, uint16 d, uint16 s); +uint8 neg_byte (PC_ENV *m, uint8 s); +uint16 neg_word (PC_ENV *m, uint16 s); +uint8 not_byte (PC_ENV *m, uint8 s); +uint16 not_word (PC_ENV *m, uint16 s); +uint16 mem_access_word (PC_ENV *m, int addr); +void push_word (PC_ENV *m, uint16 w); +uint16 pop_word (PC_ENV *m); +uint8 rcl_byte (PC_ENV *m, uint8 d, uint8 s); +uint16 rcl_word (PC_ENV *m, uint16 d, uint16 s); +uint8 rcr_byte (PC_ENV *m, uint8 d, uint8 s); +uint16 rcr_word (PC_ENV *m, uint16 d, uint16 s); +uint8 rol_byte (PC_ENV *m, uint8 d, uint8 s); +uint16 rol_word (PC_ENV *m, uint16 d, uint16 s); +uint8 ror_byte (PC_ENV *m, uint8 d, uint8 s); +uint16 ror_word (PC_ENV *m, uint16 d, uint16 s); +uint8 shl_byte (PC_ENV *m, uint8 d, uint8 s) ; +uint16 shl_word (PC_ENV *m, uint16 d, uint16 s); +uint8 shr_byte (PC_ENV *m, uint8 d, uint8 s); +uint16 shr_word (PC_ENV *m, uint16 d, uint16 s); +uint8 sar_byte (PC_ENV *m, uint8 d, uint8 s); +uint16 sar_word (PC_ENV *m, uint16 d, uint16 s); +uint8 sbb_byte (PC_ENV *m, uint8 d, uint8 s); +uint16 sbb_word (PC_ENV *m, uint16 d, uint16 s); +uint8 sub_byte (PC_ENV *m, uint8 d, uint8 s); +uint16 sub_word (PC_ENV *m, uint16 d, uint16 s); +void test_byte (PC_ENV *m, uint8 d, uint8 s); +void test_word (PC_ENV *m, uint16 d, uint16 s); +uint8 xor_byte (PC_ENV *m, uint8 d, uint8 s); +uint16 xor_word (PC_ENV *m, uint16 d, uint16 s); +void imul_byte (PC_ENV *m, uint8 s); +void imul_word (PC_ENV *m, uint16 s); +void mul_byte (PC_ENV *m, uint8 s); +void mul_word (PC_ENV *m, uint16 s); +void idiv_byte (PC_ENV *m, uint8 s); +void idiv_word (PC_ENV *m, uint16 s); +void div_byte (PC_ENV *m, uint8 s); +void div_word (PC_ENV *m, uint16 s); diff --git a/AltairZ80/i86_decode.c b/AltairZ80/i86_decode.c new file mode 100644 index 00000000..81291596 --- /dev/null +++ b/AltairZ80/i86_decode.c @@ -0,0 +1,941 @@ +/* + * Dos/PC Emulator + * Copyright (C) 1991 Jim Hudgens + * + * + * The file is part of GDE. + * + * GDE is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * GDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GDE; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "altairz80_defs.h" +#include "i86.h" + +extern uint32 GetBYTEExtended(register uint32 Addr); +extern void PutBYTEExtended(register uint32 Addr, const register uint32 Value); +extern char messageBuffer[]; +extern void printMessage(void); +extern int32 AX_S; /* AX register (8086) */ +extern int32 BX_S; /* BX register (8086) */ +extern int32 CX_S; /* CX register (8086) */ +extern int32 DX_S; /* DX register (8086) */ +extern int32 CS_S; /* CS register (8086) */ +extern int32 DS_S; /* DS register (8086) */ +extern int32 ES_S; /* ES register (8086) */ +extern int32 SS_S; /* SS register (8086) */ +extern int32 DI_S; /* DI register (8086) */ +extern int32 SI_S; /* SI register (8086) */ +extern int32 BP_S; /* BP register (8086) */ +extern int32 SP8086_S; /* SP register (8086) */ +extern int32 IP_S; /* IP register (8086) */ +extern int32 FLAGS_S; /* flags register (8086) */ +extern int32 PC_S; /* PC register (8080/Z80/8086), 20 bit */ +extern int32 sim_interval; +extern uint32 PCX; /* external view of PC */ +extern uint32 sim_brk_summ; +extern UNIT cpu_unit; + +void i86_intr_raise(PC_ENV *m,uint8 intrnum); +void cpu8086reset(void); +t_stat sim_instr_8086(void); + +/* $Log: $ + * Revision 0.05 1992/04/12 23:16:42 hudgens + * Many changes. Added support for the QUICK_FETCH option, + * so that memory accesses are faster. Now compiles with gcc -Wall + * and gcc -traditional and Sun cc. + * + * Revision 0.04 1991/07/30 01:59:56 hudgens + * added copyright. + * + * Revision 0.03 1991/06/03 01:02:09 hudgens + * fixed minor problems due to unsigned to signed short integer + * promotions. + * + * Revision 0.02 1991/03/31 01:29:39 hudgens + * Fixed segment handling (overrides, default segment accessed) in + * routines decode_rmXX_address and the {fetch,store}_data_{byte,word}. + * + * Revision 0.01 1991/03/30 21:59:49 hudgens + * Initial checkin. + * + * + */ + +/* this file includes subroutines which do: + stuff involving decoding instruction formats. + stuff involving accessess of immediate data via IP. + etc. +*/ + +static void i86_intr_handle(PC_ENV *m) +{ uint16 tmp; + uint8 intno; + if (intr & INTR_SYNCH) /* raised by something */ + { + intno = m->intno; + tmp = (uint16) mem_access_word(m, intno * 4); + { + tmp = m->R_FLG; + push_word(m, tmp); + CLEAR_FLAG(m, F_IF); + CLEAR_FLAG(m, F_TF); + /* [JCE] If we're interrupting between a segment override (or REP override) + * and the following instruction, decrease IP to get back to the prefix */ + if (m->sysmode & (SYSMODE_SEGMASK | SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) + { + --m->R_IP; + } + /* [JCE] CS and IP were the wrong way round... */ + push_word(m, m->R_CS); + push_word(m, m->R_IP); + tmp = mem_access_word(m, intno * 4); + m->R_IP = tmp; + tmp = mem_access_word(m, intno * 4 + 2); + m->R_CS = tmp; + } + intr &= ~INTR_SYNCH; /* [JCE] Dealt with, reset flag */ + } + /* The interrupt code can't pick up the segment override status. */ + DECODE_CLEAR_SEGOVR(m); +} + +void i86_intr_raise(PC_ENV *m,uint8 intrnum) +{ + m->intno = intrnum; + intr |= INTR_SYNCH; +} + +static PC_ENV cpu8086; + +static void setViewRegisters(void) { + FLAGS_S = cpu8086.R_FLG; + AX_S = cpu8086.R_AX; + BX_S = cpu8086.R_BX; + CX_S = cpu8086.R_CX; + DX_S = cpu8086.R_DX; + SP8086_S = cpu8086.R_SP; + BP_S = cpu8086.R_BP; + SI_S = cpu8086.R_SI; + DI_S = cpu8086.R_DI; + ES_S = cpu8086.R_ES; + CS_S = cpu8086.R_CS; + SS_S = cpu8086.R_SS; + DS_S = cpu8086.R_DS; + IP_S = cpu8086.R_IP; +} + +static void setCPURegisters(void) { + cpu8086.R_FLG = FLAGS_S; + cpu8086.R_AX = AX_S; + cpu8086.R_BX = BX_S; + cpu8086.R_CX = CX_S; + cpu8086.R_DX = DX_S; + cpu8086.R_SP = SP8086_S; + cpu8086.R_BP = BP_S; + cpu8086.R_SI = SI_S; + cpu8086.R_DI = DI_S; + cpu8086.R_ES = ES_S; + cpu8086.R_CS = CS_S; + cpu8086.R_SS = SS_S; + cpu8086.R_DS = DS_S; + cpu8086.R_IP = IP_S; +} + +void cpu8086reset(void) { + cpu8086.R_AX = 0x1961; + if ((cpu8086.R_AH != 0x19) || (cpu8086.R_AL != 0x61)) { + printf("Fatal endian error - make sure to compile with '#define LOWFIRST %i'\n", 1 - LOWFIRST); + exit(1); + } + /* 16 bit registers */ + cpu8086.R_AX = 0; + cpu8086.R_BX = 0; + cpu8086.R_CX = 0; + cpu8086.R_DX = 0; + /* special registers */ + cpu8086.R_SP = 0; + cpu8086.R_BP = 0; + cpu8086.R_SI = 0; + cpu8086.R_DI = 0; + cpu8086.R_IP = 0; + cpu8086.R_FLG = F_ALWAYS_ON; + /* segment registers */ + cpu8086.R_CS = 0; + cpu8086.R_DS = 0; + cpu8086.R_SS = 0; + cpu8086.R_ES = 0; + setViewRegisters(); +} + +static uint32 getFullPC(void) { + return cpu8086.R_IP + (cpu8086.R_CS << 4); +} + +t_stat sim_instr_8086(void) { + t_stat reason = SCPE_OK; + uint8 op1; + int32 newIP; + setCPURegisters(); + intr = 0; + newIP = PC_S - 16 * CS_S; + if ((0 <= newIP) && (newIP <= 0xffff)) cpu8086.R_IP = newIP; + else { + if (CS_S != ((PC_S & 0xf0000) >> 4)) { + cpu8086.R_CS = (PC_S & 0xf0000) >> 4; + if (cpu_unit.flags & UNIT_CPU_VERBOSE) { + MESSAGE_2("Segment register CS set to %04x", cpu8086.R_CS); + } + } + cpu8086.R_IP = PC_S & 0xffff; + } + while (TRUE) { /* loop until halted */ + if (sim_interval <= 0) { /* check clock queue */ +#if !UNIX_PLATFORM + if ((reason = sim_os_poll_kbd()) == SCPE_STOP) /* poll on platforms without reliable signalling */ + break; +#endif + if ( (reason = sim_process_event()) ) break; + } + if (sim_brk_summ && sim_brk_test(getFullPC(), SWMASK('E'))) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; + } + PCX = getFullPC(); + op1 = GetBYTEExtended((((uint32)cpu8086.R_CS<<4) + cpu8086.R_IP) & 0xFFFFF); + if (sim_brk_summ && sim_brk_test(op1, (1u << SIM_BKPT_V_SPC) | SWMASK('I'))) { /* instruction breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; + } + sim_interval--; + cpu8086.R_IP++; + (*(i86_optab[op1]))(&cpu8086); + if (intr & INTR_HALTED) { + reason = STOP_HALT; + intr &= ~INTR_HALTED; + break; + } + if (intr & INTR_ILLEGAL_OPCODE) { + intr &= ~INTR_ILLEGAL_OPCODE; + if (cpu_unit.flags & UNIT_CPU_OPSTOP) { + reason = STOP_OPCODE; + break; + } + } + if (((intr & INTR_SYNCH) && (cpu8086.intno == 0 || cpu8086.intno == 2)) || + (ACCESS_FLAG(&cpu8086, F_IF))) { + /* [JCE] Reversed the sense of this ACCESS_FLAG; it's set for interrupts + enabled, not interrupts blocked i.e. either not blockable (intr 0 or 2) + or the IF flag not set so interrupts not blocked */ + /* hharte: if a segment override exists, then treat that as "atomic" and do not handle + * an interrupt until the override is cleared. + * Not sure if this is the way an 8086 really works, need to find out for sure. + * Also, what about the REPE prefix? + */ + if((cpu8086.sysmode & SYSMODE_SEGMASK) == 0) { + i86_intr_handle(&cpu8086); + } + } + } + PC_S = (reason == STOP_HALT) | (reason == STOP_OPCODE) ? PCX : getFullPC(); + setViewRegisters(); + return reason; +} + +void halt_sys(PC_ENV *m) +{ + intr |= INTR_HALTED; +} + +/* once the instruction is fetched, an optional byte follows which + has 3 fields encoded in it. This routine fetches the byte + and breaks into the three fields. + This has been changed, in an attempt to reduce the amount of + executed code for this frequently executed subroutine. If this + works, then it may pay to somehow inline it. + */ + +#ifdef NOTDEF +/* this code generated the following table */ +main() +{ int i; + printf("\n\nstruct modrm{ uint8 mod,rh,rl;} modrmtab[] = {\n"); + for (i=0; i<256; i++) + { + printf("{%d,%d,%d}, ",((i&0xc0)>>6),((i&0x38)>>3),(i&0x07)); + if (i%4==3) + printf("/* %d to %d */\n",i&0xfc,i); + } + printf("};\n\n"); +} +#endif + +struct modrm { uint16 mod, rh, rl; }; +static struct modrm modrmtab[] = { + {0,0,0}, {0,0,1}, {0,0,2}, {0,0,3}, /* 0 to 3 */ + {0,0,4}, {0,0,5}, {0,0,6}, {0,0,7}, /* 4 to 7 */ + {0,1,0}, {0,1,1}, {0,1,2}, {0,1,3}, /* 8 to 11 */ + {0,1,4}, {0,1,5}, {0,1,6}, {0,1,7}, /* 12 to 15 */ + {0,2,0}, {0,2,1}, {0,2,2}, {0,2,3}, /* 16 to 19 */ + {0,2,4}, {0,2,5}, {0,2,6}, {0,2,7}, /* 20 to 23 */ + {0,3,0}, {0,3,1}, {0,3,2}, {0,3,3}, /* 24 to 27 */ + {0,3,4}, {0,3,5}, {0,3,6}, {0,3,7}, /* 28 to 31 */ + {0,4,0}, {0,4,1}, {0,4,2}, {0,4,3}, /* 32 to 35 */ + {0,4,4}, {0,4,5}, {0,4,6}, {0,4,7}, /* 36 to 39 */ + {0,5,0}, {0,5,1}, {0,5,2}, {0,5,3}, /* 40 to 43 */ + {0,5,4}, {0,5,5}, {0,5,6}, {0,5,7}, /* 44 to 47 */ + {0,6,0}, {0,6,1}, {0,6,2}, {0,6,3}, /* 48 to 51 */ + {0,6,4}, {0,6,5}, {0,6,6}, {0,6,7}, /* 52 to 55 */ + {0,7,0}, {0,7,1}, {0,7,2}, {0,7,3}, /* 56 to 59 */ + {0,7,4}, {0,7,5}, {0,7,6}, {0,7,7}, /* 60 to 63 */ + {1,0,0}, {1,0,1}, {1,0,2}, {1,0,3}, /* 64 to 67 */ + {1,0,4}, {1,0,5}, {1,0,6}, {1,0,7}, /* 68 to 71 */ + {1,1,0}, {1,1,1}, {1,1,2}, {1,1,3}, /* 72 to 75 */ + {1,1,4}, {1,1,5}, {1,1,6}, {1,1,7}, /* 76 to 79 */ + {1,2,0}, {1,2,1}, {1,2,2}, {1,2,3}, /* 80 to 83 */ + {1,2,4}, {1,2,5}, {1,2,6}, {1,2,7}, /* 84 to 87 */ + {1,3,0}, {1,3,1}, {1,3,2}, {1,3,3}, /* 88 to 91 */ + {1,3,4}, {1,3,5}, {1,3,6}, {1,3,7}, /* 92 to 95 */ + {1,4,0}, {1,4,1}, {1,4,2}, {1,4,3}, /* 96 to 99 */ + {1,4,4}, {1,4,5}, {1,4,6}, {1,4,7}, /* 100 to 103 */ + {1,5,0}, {1,5,1}, {1,5,2}, {1,5,3}, /* 104 to 107 */ + {1,5,4}, {1,5,5}, {1,5,6}, {1,5,7}, /* 108 to 111 */ + {1,6,0}, {1,6,1}, {1,6,2}, {1,6,3}, /* 112 to 115 */ + {1,6,4}, {1,6,5}, {1,6,6}, {1,6,7}, /* 116 to 119 */ + {1,7,0}, {1,7,1}, {1,7,2}, {1,7,3}, /* 120 to 123 */ + {1,7,4}, {1,7,5}, {1,7,6}, {1,7,7}, /* 124 to 127 */ + {2,0,0}, {2,0,1}, {2,0,2}, {2,0,3}, /* 128 to 131 */ + {2,0,4}, {2,0,5}, {2,0,6}, {2,0,7}, /* 132 to 135 */ + {2,1,0}, {2,1,1}, {2,1,2}, {2,1,3}, /* 136 to 139 */ + {2,1,4}, {2,1,5}, {2,1,6}, {2,1,7}, /* 140 to 143 */ + {2,2,0}, {2,2,1}, {2,2,2}, {2,2,3}, /* 144 to 147 */ + {2,2,4}, {2,2,5}, {2,2,6}, {2,2,7}, /* 148 to 151 */ + {2,3,0}, {2,3,1}, {2,3,2}, {2,3,3}, /* 152 to 155 */ + {2,3,4}, {2,3,5}, {2,3,6}, {2,3,7}, /* 156 to 159 */ + {2,4,0}, {2,4,1}, {2,4,2}, {2,4,3}, /* 160 to 163 */ + {2,4,4}, {2,4,5}, {2,4,6}, {2,4,7}, /* 164 to 167 */ + {2,5,0}, {2,5,1}, {2,5,2}, {2,5,3}, /* 168 to 171 */ + {2,5,4}, {2,5,5}, {2,5,6}, {2,5,7}, /* 172 to 175 */ + {2,6,0}, {2,6,1}, {2,6,2}, {2,6,3}, /* 176 to 179 */ + {2,6,4}, {2,6,5}, {2,6,6}, {2,6,7}, /* 180 to 183 */ + {2,7,0}, {2,7,1}, {2,7,2}, {2,7,3}, /* 184 to 187 */ + {2,7,4}, {2,7,5}, {2,7,6}, {2,7,7}, /* 188 to 191 */ + {3,0,0}, {3,0,1}, {3,0,2}, {3,0,3}, /* 192 to 195 */ + {3,0,4}, {3,0,5}, {3,0,6}, {3,0,7}, /* 196 to 199 */ + {3,1,0}, {3,1,1}, {3,1,2}, {3,1,3}, /* 200 to 203 */ + {3,1,4}, {3,1,5}, {3,1,6}, {3,1,7}, /* 204 to 207 */ + {3,2,0}, {3,2,1}, {3,2,2}, {3,2,3}, /* 208 to 211 */ + {3,2,4}, {3,2,5}, {3,2,6}, {3,2,7}, /* 212 to 215 */ + {3,3,0}, {3,3,1}, {3,3,2}, {3,3,3}, /* 216 to 219 */ + {3,3,4}, {3,3,5}, {3,3,6}, {3,3,7}, /* 220 to 223 */ + {3,4,0}, {3,4,1}, {3,4,2}, {3,4,3}, /* 224 to 227 */ + {3,4,4}, {3,4,5}, {3,4,6}, {3,4,7}, /* 228 to 231 */ + {3,5,0}, {3,5,1}, {3,5,2}, {3,5,3}, /* 232 to 235 */ + {3,5,4}, {3,5,5}, {3,5,6}, {3,5,7}, /* 236 to 239 */ + {3,6,0}, {3,6,1}, {3,6,2}, {3,6,3}, /* 240 to 243 */ + {3,6,4}, {3,6,5}, {3,6,6}, {3,6,7}, /* 244 to 247 */ + {3,7,0}, {3,7,1}, {3,7,2}, {3,7,3}, /* 248 to 251 */ + {3,7,4}, {3,7,5}, {3,7,6}, {3,7,7}, /* 252 to 255 */ +}; + +void fetch_decode_modrm(PC_ENV *m, uint16 *mod, uint16 *regh, uint16 *regl) +{ uint8 fetched; + register struct modrm *p; + /* do the fetch in real mode. Shift the CS segment register + over by 4 bits, and add in the IP register. Index into + the system memory. + */ + /* [JCE] Wrap at 1Mb (the A20 gate) */ + fetched = GetBYTEExtended(((m->R_CS << 4) + (m->R_IP++)) & 0xFFFFF); + +#ifdef NOTDEF + *mod = ((fetched&0xc0)>>6); + *regh= ((fetched&0x38)>>3); + *regl= (fetched&0x7); +#else + p = modrmtab + fetched; + *mod = p->mod; + *regh= p->rh; + *regl= p->rl; +#endif + +} + +/* + return a pointer to the register given by the R/RM field of + the modrm byte, for byte operands. + Also enables the decoding of instructions. +*/ +uint8 *decode_rm_byte_register(PC_ENV *m, int reg) +{ + switch(reg) + { + case 0: + return &m->R_AL; + break; + case 1: + return &m->R_CL; + break; + case 2: + return &m->R_DL; + break; + case 3: + return &m->R_BL; + break; + case 4: + return &m->R_AH; + break; + case 5: + return &m->R_CH; + break; + case 6: + return &m->R_DH; + break; + case 7: + return &m->R_BH; + break; + } + halt_sys(m); + return NULL; /* NOT REACHED OR REACHED ON ERROR */ +} + +/* + return a pointer to the register given by the R/RM field of + the modrm byte, for word operands. + Also enables the decoding of instructions. +*/ +uint16 *decode_rm_word_register(PC_ENV *m, int reg) +{ + switch(reg) + { + case 0: + return &m->R_AX; + break; + case 1: + return &m->R_CX; + break; + case 2: + return &m->R_DX; + break; + case 3: + return &m->R_BX; + break; + case 4: + return &m->R_SP; + break; + case 5: + return &m->R_BP; + break; + case 6: + return &m->R_SI; + break; + case 7: + return &m->R_DI; + break; + } + halt_sys(m); + return NULL; /* NOTREACHED OR REACHED ON ERROR*/ +} + +/* + return a pointer to the register given by the R/RM field of + the modrm byte, for word operands, modified from above + for the weirdo special case of segreg operands. + Also enables the decoding of instructions. +*/ +uint16 *decode_rm_seg_register(PC_ENV *m, int reg) +{ + switch(reg) + { + case 0: + return &m->R_ES; + break; + case 1: + return &m->R_CS; + break; + case 2: + return &m->R_SS; + break; + case 3: + return &m->R_DS; + break; + case 4: + case 5: + case 6: + case 7: + break; + } + halt_sys(m); + return NULL; /* NOT REACHED OR REACHED ON ERROR */ +} + +/* once the instruction is fetched, an optional byte follows which + has 3 fields encoded in it. This routine fetches the byte + and breaks into the three fields. +*/ +uint8 fetch_byte_imm(PC_ENV *m) +{ + uint8 fetched; + /* do the fetch in real mode. Shift the CS segment register + over by 4 bits, and add in the IP register. Index into + the system memory. + */ + /* [JCE] Wrap at 1Mb (the A20 gate) */ + fetched = GetBYTEExtended((((uint32)m->R_CS << 4) + (m->R_IP++)) & 0xFFFFF); + return fetched; +} + +uint16 fetch_word_imm(PC_ENV *m) +{ + uint16 fetched; + /* do the fetch in real mode. Shift the CS segment register + over by 4 bits, and add in the IP register. Index into + the system PC_ENVory. + */ + /* [JCE] Wrap at 1Mb (the A20 gate) */ + fetched = GetBYTEExtended((((uint32)m->R_CS << 4) + (m->R_IP++)) & 0xFFFFF); + fetched |= (GetBYTEExtended((((uint32)m->R_CS << 4) + (m->R_IP++)) & 0xFFFFF) << 8); + return fetched; +} + +/* + return the offset given by mod=00 addressing. + Also enables the decoding of instructions. +*/ +uint16 decode_rm00_address(PC_ENV *m, int rm) +{ + uint16 offset; + /* note the code which specifies the corresponding segment (ds vs ss) + below in the case of [BP+..]. The assumption here is that at the + point that this subroutine is called, the bit corresponding to + SYSMODE_SEG_DS_SS will be zero. After every instruction + except the segment override instructions, this bit (as well + as any bits indicating segment overrides) will be clear. So + if a SS access is needed, set this bit. Otherwise, DS access + occurs (unless any of the segment override bits are set). + */ + switch(rm) + { + case 0: + return (int16)m->R_BX + (int16)m->R_SI; + break; + case 1: + return (int16)m->R_BX + (int16)m->R_DI; + break; + case 2: + m->sysmode |= SYSMODE_SEG_DS_SS; + return (int16)m->R_BP + (int16)m->R_SI; + break; + case 3: + m->sysmode |= SYSMODE_SEG_DS_SS; + return (int16)m->R_BP + (int16)m->R_DI; + break; + case 4: + return m->R_SI; + break; + case 5: + return m->R_DI; + break; + case 6: + offset = (int16)fetch_word_imm(m); + return offset; + break; + case 7: + return m->R_BX; + } + halt_sys(m); + return 0; +} + +/* + return the offset given by mod=01 addressing. + Also enables the decoding of instructions. +*/ +uint16 decode_rm01_address(PC_ENV *m, int rm) +{ + int8 displacement; + /* note comment on decode_rm00_address above */ + displacement = (int8)fetch_byte_imm(m); /* !!!! Check this */ + switch(rm) + { + case 0: + return (int16)m->R_BX + (int16)m->R_SI + displacement; + break; + case 1: + return (int16)m->R_BX + (int16)m->R_DI + displacement; + break; + case 2: + m->sysmode |= SYSMODE_SEG_DS_SS; + return (int16)m->R_BP + (int16)m->R_SI + displacement; + break; + case 3: + m->sysmode |= SYSMODE_SEG_DS_SS; + return (int16)m->R_BP + (int16)m->R_DI + displacement; + break; + case 4: + return (int16)m->R_SI + displacement; + break; + case 5: + return (int16)m->R_DI + displacement; + break; + case 6: + m->sysmode |= SYSMODE_SEG_DS_SS; + return (int16)m->R_BP + displacement; + break; + case 7: + return (int16)m->R_BX + displacement; + break; + } + halt_sys(m); + return 0; /* SHOULD NOT HAPPEN */ +} + +/* + return the offset given by mod=01 addressing. + Also enables the decoding of instructions. +*/ +uint16 decode_rm10_address(PC_ENV *m, int rm) +{ + int16 displacement; + /* note comment on decode_rm00_address above */ + displacement = (int16)fetch_word_imm(m); + switch(rm) + { + case 0: + return (int16)m->R_BX + (int16)m->R_SI + displacement; + break; + case 1: + return (int16)m->R_BX + (int16)m->R_DI + displacement; + break; + case 2: + m->sysmode |= SYSMODE_SEG_DS_SS; + return (int16)m->R_BP + (int16)m->R_SI + displacement; + break; + case 3: + m->sysmode |= SYSMODE_SEG_DS_SS; + return (int16)m->R_BP + (int16)m->R_DI + displacement; + break; + case 4: + return (int16)m->R_SI + displacement; + break; + case 5: + return (int16)m->R_DI + displacement; + break; + case 6: + m->sysmode |= SYSMODE_SEG_DS_SS; + return (int16)m->R_BP + displacement; + break; + case 7: + return (int16)m->R_BX + displacement; + break; + } + halt_sys(m); + return 0; + /*NOTREACHED */ +} + +/* fetch a byte of data, given an offset, the current register set, + and a descriptor for memory. +*/ +uint8 fetch_data_byte(PC_ENV *m, uint16 offset) +{ + register uint8 value; + /* this code originally completely broken, and never showed + up since the DS segments === SS segment in all test cases. + It had been originally assumed, that all access to data would + involve the DS register unless there was a segment override. + Not so. Address modes such as -3[BP] or 10[BP+SI] all + refer to addresses relative to the SS. So, at the minimum, + all decodings of addressing modes would have to set/clear + a bit describing whether the access is relative to DS or SS. + That is the function of the cpu-state-varible m->sysmode. + There are several potential states: + repe prefix seen (handled elsewhere) + repne prefix seen (ditto) + cs segment override + ds segment override + es segment override + ss segment override + ds/ss select (in absense of override) + Each of the above 7 items are handled with a bit in the sysmode + field. + The latter 5 can be implemented as a simple state machine: + */ + switch(m->sysmode & SYSMODE_SEGMASK) + { + case 0: + /* default case: use ds register */ + value = GetBYTEExtended(((uint32)m->R_DS<<4) + offset); + break; + case SYSMODE_SEG_DS_SS: + /* non-overridden, use ss register */ + /* [JCE] Wrap at 1Mb (the A20 gate) */ + value = GetBYTEExtended((((uint32)m->R_SS << 4) + offset) & 0xFFFFF); + break; + case SYSMODE_SEGOVR_CS: + /* ds overridden */ + case SYSMODE_SEGOVR_CS|SYSMODE_SEG_DS_SS: + /* ss overridden, use cs register */ + /* [JCE] Wrap at 1Mb (the A20 gate) */ + value = GetBYTEExtended((((uint32)m->R_CS << 4) + offset) & 0xFFFFF); + break; + case SYSMODE_SEGOVR_DS: + /* ds overridden --- shouldn't happen, but hey. */ + case SYSMODE_SEGOVR_DS|SYSMODE_SEG_DS_SS: + /* ss overridden, use ds register */ + /* [JCE] Wrap at 1Mb (the A20 gate) */ + value = GetBYTEExtended((((uint32)m->R_DS << 4) + offset) & 0xFFFFF); + break; + case SYSMODE_SEGOVR_ES: + /* ds overridden */ + case SYSMODE_SEGOVR_ES|SYSMODE_SEG_DS_SS: + /* ss overridden, use es register */ + /* [JCE] Wrap at 1Mb (the A20 gate) */ + value = GetBYTEExtended((((uint32)m->R_ES << 4) + offset) & 0xFFFFF); + break; + case SYSMODE_SEGOVR_SS: + /* ds overridden */ + case SYSMODE_SEGOVR_SS|SYSMODE_SEG_DS_SS: + /* ss overridden, use ss register === should not happen */ + /* [JCE] Wrap at 1Mb (the A20 gate) */ + value = GetBYTEExtended((((uint32)m->R_SS << 4) + offset) & 0xFFFFF); + break; + default: + printf("error: should not happen: multiple overrides. " NLP); + value = 0; + halt_sys(m); + } + return value; +} + +/* fetch a byte of data, given an offset, the current register set, + and a descriptor for memory. +*/ +uint8 fetch_data_byte_abs(PC_ENV *m, uint16 segment, uint16 offset) +{ + register uint8 value; + uint32 addr; + /* note, cannot change this, since we do not know the ID of the segment. */ +/* [JCE] Simulate wrap at top of memory (the A20 gate) */ +/* addr = (segment << 4) + offset; */ + addr = ((segment << 4) + offset) & 0xFFFFF; + value = GetBYTEExtended(addr); + return value; +} + +/* fetch a byte of data, given an offset, the current register set, + and a descriptor for memory. +*/ +uint16 fetch_data_word(PC_ENV *m, uint16 offset) +{ + uint16 value; + /* See note above in fetch_data_byte. */ + switch(m->sysmode & SYSMODE_SEGMASK) + { + case 0: + /* default case: use ds register */ + /* [JCE] Wrap at 1Mb (the A20 gate) */ + value = GetBYTEExtended((((uint32)m->R_DS << 4) + offset) & 0xFFFFF) + | (GetBYTEExtended((((uint32)m->R_DS << 4) + + (uint16)(offset + 1)) & 0xFFFFF) << 8); + break; + case SYSMODE_SEG_DS_SS: + /* non-overridden, use ss register */ + /* [JCE] Wrap at 1Mb (the A20 gate) */ + value = GetBYTEExtended((((uint32)m->R_SS << 4) + offset) & 0xFFFFF) + | (GetBYTEExtended((((uint32)m->R_SS << 4) + + (uint16)(offset + 1)) & 0xFFFFF) << 8); + break; + case SYSMODE_SEGOVR_CS: + /* ds overridden */ + case SYSMODE_SEGOVR_CS|SYSMODE_SEG_DS_SS: + /* ss overridden, use cs register */ + /* [JCE] Wrap at 1Mb (the A20 gate) */ + value = GetBYTEExtended((((uint32)m->R_CS << 4) + offset) & 0xFFFFF) + | (GetBYTEExtended((((uint32)m->R_CS << 4) + + (uint16)(offset + 1)) & 0xFFFFF) << 8); + break; + case SYSMODE_SEGOVR_DS: + /* ds overridden --- shouldn't happen, but hey. */ + case SYSMODE_SEGOVR_DS|SYSMODE_SEG_DS_SS: + /* ss overridden, use ds register */ + /* [JCE] Wrap at 1Mb (the A20 gate) */ + value = GetBYTEExtended((((uint32)m->R_DS << 4) + offset) & 0xFFFFF) + | (GetBYTEExtended((((uint32)m->R_DS << 4) + + (uint16)(offset + 1)) & 0xFFFFF) << 8); + break; + case SYSMODE_SEGOVR_ES: + /* ds overridden */ + case SYSMODE_SEGOVR_ES|SYSMODE_SEG_DS_SS: + /* ss overridden, use es register */ + value = GetBYTEExtended((((uint32)m->R_ES << 4) + offset) & 0xFFFFF) + | (GetBYTEExtended((((uint32)m->R_ES << 4) + + (uint16)(offset + 1)) & 0xFFFFF) << 8); + break; + case SYSMODE_SEGOVR_SS: + /* ds overridden */ + case SYSMODE_SEGOVR_SS|SYSMODE_SEG_DS_SS: + /* ss overridden, use ss register === should not happen */ + value = GetBYTEExtended((((uint32)m->R_SS << 4) + offset) & 0xFFFFF) + | (GetBYTEExtended((((uint32)m->R_SS << 4) + + (uint16)(offset + 1)) & 0xFFFFF) << 8); + break; + default: + printf("error: should not happen: multiple overrides. " NLP); + value = 0; + halt_sys(m); + } + return value; +} + +/* fetch a byte of data, given an offset, the current register set, + and a descriptor for memory. +*/ +uint16 fetch_data_word_abs(PC_ENV *m, uint16 segment, uint16 offset) +{ + uint16 value; + uint32 addr; +/* [JCE] Simulate wrap at top of memory (the A20 gate) */ +/* addr = (segment << 4) + offset; */ + addr = ((segment << 4) + offset) & 0xFFFFF; + value = GetBYTEExtended(addr) | (GetBYTEExtended(addr + 1) << 8); + return value; +} + +/* Store a byte of data, given an offset, the current register set, + and a descriptor for memory. +*/ +void store_data_byte(PC_ENV *m, uint16 offset, uint8 val) +{ + /* See note above in fetch_data_byte. */ + uint32 addr; + register uint16 segment; + switch(m->sysmode & SYSMODE_SEGMASK) + { + case 0: + /* default case: use ds register */ + segment = m->R_DS; + break; + case SYSMODE_SEG_DS_SS: + /* non-overridden, use ss register */ + segment = m->R_SS; + break; + case SYSMODE_SEGOVR_CS: + /* ds overridden */ + case SYSMODE_SEGOVR_CS|SYSMODE_SEG_DS_SS: + /* ss overridden, use cs register */ + segment = m->R_CS; + break; + case SYSMODE_SEGOVR_DS: + /* ds overridden --- shouldn't happen, but hey. */ + case SYSMODE_SEGOVR_DS|SYSMODE_SEG_DS_SS: + /* ss overridden, use ds register */ + segment = m->R_DS; + break; + case SYSMODE_SEGOVR_ES: + /* ds overridden */ + case SYSMODE_SEGOVR_ES|SYSMODE_SEG_DS_SS: + /* ss overridden, use es register */ + segment = m->R_ES; + break; + case SYSMODE_SEGOVR_SS: + /* ds overridden */ + case SYSMODE_SEGOVR_SS|SYSMODE_SEG_DS_SS: + /* ss overridden, use ss register === should not happen */ + segment = m->R_SS; + break; + default: + printf("error: should not happen: multiple overrides. " NLP); + segment = 0; + halt_sys(m); + } +/* [JCE] Simulate wrap at top of memory (the A20 gate) */ +/* addr = (segment << 4) + offset; */ + addr = (((uint32)segment << 4) + offset) & 0xFFFFF; + PutBYTEExtended(addr, val); +} + +void store_data_byte_abs(PC_ENV *m, uint16 segment, uint16 offset, uint8 val) +{ + register uint32 addr; +/* [JCE] Simulate wrap at top of memory (the A20 gate) */ +/* addr = (segment << 4) + offset; */ + addr = (((uint32)segment << 4) + offset) & 0xFFFFF; + PutBYTEExtended(addr, val); +} + +/* Store a word of data, given an offset, the current register set, + and a descriptor for memory. +*/ +void store_data_word(PC_ENV *m, uint16 offset, uint16 val) +{ + register uint32 addr; + register uint16 segment; + /* See note above in fetch_data_byte. */ + switch(m->sysmode & SYSMODE_SEGMASK) + { + case 0: + /* default case: use ds register */ + segment = m->R_DS; + break; + case SYSMODE_SEG_DS_SS: + /* non-overridden, use ss register */ + segment = m->R_SS; + break; + case SYSMODE_SEGOVR_CS: + /* ds overridden */ + case SYSMODE_SEGOVR_CS|SYSMODE_SEG_DS_SS: + /* ss overridden, use cs register */ + segment = m->R_CS; + break; + case SYSMODE_SEGOVR_DS: + /* ds overridden --- shouldn't happen, but hey. */ + case SYSMODE_SEGOVR_DS|SYSMODE_SEG_DS_SS: + /* ss overridden, use ds register */ + segment = m->R_DS; + break; + case SYSMODE_SEGOVR_ES: + /* ds overridden */ + case SYSMODE_SEGOVR_ES|SYSMODE_SEG_DS_SS: + /* ss overridden, use es register */ + segment = m->R_ES; + break; + case SYSMODE_SEGOVR_SS: + /* ds overridden */ + case SYSMODE_SEGOVR_SS|SYSMODE_SEG_DS_SS: + /* ss overridden, use ss register === should not happen */ + segment = m->R_SS; + break; + default: + printf("error: should not happen: multiple overrides." NLP); + segment = 0; + halt_sys(m); + } +/* [JCE] Simulate wrap at top of memory (the A20 gate) */ +/* addr = (segment << 4) + offset; */ + addr = (((uint32)segment << 4) + offset) & 0xFFFFF; + PutBYTEExtended(addr, val & 0xff); + PutBYTEExtended(addr + 1, val >> 8); +} + +void store_data_word_abs(PC_ENV *m, uint16 segment, uint16 offset, uint16 val) +{ + register uint32 addr; + /* [JCE] Wrap at top of memory */ + addr = ((segment << 4) + offset) & 0xFFFFF; + PutBYTEExtended(addr, val & 0xff); + PutBYTEExtended(addr + 1, val >> 8); +} diff --git a/AltairZ80/i86_ops.c b/AltairZ80/i86_ops.c new file mode 100644 index 00000000..145e35f0 --- /dev/null +++ b/AltairZ80/i86_ops.c @@ -0,0 +1,5487 @@ +/* + * Dos/PC Emulator + * Copyright (C) 1991 Jim Hudgens + * + * + * The file is part of GDE. + * + * GDE is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * GDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GDE; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "altairz80_defs.h" +#include "i86.h" + +extern void out(const uint32 Port, const uint32 Value); +extern uint32 in(const uint32 Port); + +/* $Log: i86_ops.c,v $ + * Revision 0.11 1991/07/30 02:02:04 hudgens + * added copyright. + * + * Revision 0.10 1991/07/21 18:22:08 hudgens + * Fixed problem with scans, which was the result of the loop break + * condition being incorrect when used in conjunction with the repe + * or repne prefixes. Eureka. pkzip/pkunzip now compress/decompress + * correctly. + * + * Revision 0.9 1991/07/21 03:33:18 hudgens + * fixed popf so that it appears to be the same as an 8088 popf, and always + * sets the high 4 bits of the flags. + * + * Revision 0.8 1991/07/21 01:44:11 hudgens + * fixed aad and aam instructions. + * + * Revision 0.7 1991/07/21 00:31:24 hudgens + * Fixed iret so that it works correctly. + * + * Revision 0.6 1991/07/20 16:54:50 hudgens + * removed the 8087 coprocessor operations. Moved to i87_ops.c + * + * Revision 0.5 1991/07/17 03:50:10 hudgens + * Minor modifications. + * + * Revision 0.4 1991/06/18 02:48:41 hudgens + * Fixed a problem with scasb and scasw. + * + * Revision 0.3 1991/06/03 01:01:10 hudgens + * fixed minor problems due to unsigned to signed short integer + * promotions. + * + * Revision 0.2 1991/03/31 01:32:10 hudgens + * fixed segment handling. Added calls to DECODE_CLEAR_SEGOVR in + * many places in the code. Should work much better now. + * + * Revision 0.1 1991/03/30 21:15:48 hudgens + * Initial checkin to RCS. + * + * + */ + +/* 2/23/91 fixed decode for operand x87. */ + +/* partially mechanically generated file....(based on the optable) */ +/* + There are approximately 250 subroutines in here, which correspond + to the 256 byte-"opcodes" found on the 8086. The table which + dispatches this is found in the files optab.[ch]. + + Each opcode proc has a comment preceeding it which gives it's table + address. Several opcodes are missing (undefined) in the table. + + Each proc includes information for decoding (DECODE_PRINTF and + and misc functions ( + Many of the procedures are *VERY* similar in coding. This has + allowed for a very large amount of code to be generated in a fairly + short amount of time (i.e. cut, paste, and modify). + The result is that much of the code below could + have been folded into subroutines for a large reduction in size of + this file. The downside would be that there would be a penalty in + execution speed. The file could also have been *MUCH* larger by + inlining certain functions which were called. This could have + resulted even faster execution. The prime directive I used to decide + whether to inline the code or to modularize it, was basically: 1) no + unnecessary subroutine calls, 2) no routines more than about 200 lines + in size, and 3) modularize any code that I might not get right the first + time. The fetch_* subroutines fall into the latter category. The + The decode_* fall into the second category. The coding of the + "switch(mod){ .... }" in many of the subroutines below falls into the + first category. Especially, the coding of {add,and,or,sub,...}_{byte,word} + subroutines are an especially glaring case of the third guideline. + Since so much of the code is cloned from other modules (compare + opcode #00 to opcode #01), making the basic operations subroutine calls + is especially important; otherwise mistakes in coding an "add" + would represent a nightmare in maintenance. + + So, without further ado, ... +*/ + +extern char parity_tab[]; + +static void i86op_illegal_op(PC_ENV *m) +{ + intr |= INTR_ILLEGAL_OPCODE; +} + +/*opcode=0x00*/ +static void i86op_add_byte_RM_R(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg,*srcreg; + uint16 destoffset; + uint8 destval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + destval = add_byte(m, destval, *srcreg); + store_data_byte(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + destval = add_byte(m, destval, *srcreg); + store_data_byte(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + destval = add_byte(m, destval, *srcreg); + store_data_byte(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rl); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + *destreg = add_byte(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x01*/ +static void i86op_add_word_RM_R(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg,*srcreg; + uint16 destoffset; + uint16 destval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + destval = add_word(m, destval, *srcreg); + store_data_word(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + destval = add_word(m, destval, *srcreg); + store_data_word(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + destval = add_word(m, destval, *srcreg); + store_data_word(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rl); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + *destreg = add_word(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x02*/ +static void i86op_add_byte_R_RM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg,*srcreg; + uint16 srcoffset; + uint8 srcval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm00_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + *destreg = add_byte(m, *destreg, srcval); + break; + case 1: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm01_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + *destreg = add_byte(m, *destreg, srcval); + break; + case 2: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm10_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + *destreg = add_byte(m, * destreg, srcval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcreg = DECODE_RM_BYTE_REGISTER(m,rl); + *destreg = add_byte(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x03*/ +static void i86op_add_word_R_RM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg,*srcreg; + uint16 srcoffset; + uint16 srcval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm00_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = add_word(m, *destreg, srcval); + break; + case 1: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm01_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = add_word(m, *destreg, srcval); + break; + case 2: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm10_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = add_word(m, *destreg, srcval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcreg = DECODE_RM_WORD_REGISTER(m,rl); + *destreg = add_word(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x04*/ +static void i86op_add_byte_AL_IMM(PC_ENV *m) +{ + uint8 srcval; + srcval = fetch_byte_imm(m); + m->R_AL = add_byte(m, m->R_AL, srcval); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x05*/ +static void i86op_add_word_AX_IMM(PC_ENV *m) +{ + uint16 srcval; + srcval = fetch_word_imm(m); + m->R_AX = add_word(m, m->R_AX, srcval); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x06*/ +static void i86op_push_ES(PC_ENV *m) +{ + push_word(m,m->R_ES); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x07*/ +static void i86op_pop_ES(PC_ENV *m) +{ + m->R_ES = pop_word(m); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x08*/ +static void i86op_or_byte_RM_R(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg,*srcreg; + uint16 destoffset; + uint8 destval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + destval = or_byte(m, destval, *srcreg); + store_data_byte(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + destval = or_byte(m, destval, *srcreg); + store_data_byte(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + destval = or_byte(m, destval, *srcreg); + store_data_byte(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rl); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + *destreg = or_byte(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x09*/ +static void i86op_or_word_RM_R(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg,*srcreg; + uint16 destoffset; + uint16 destval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + destval = or_word(m, destval, *srcreg); + store_data_word(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + destval = or_word(m, destval, *srcreg); + store_data_word(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + destval = or_word(m, destval, *srcreg); + store_data_word(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rl); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + *destreg = or_word(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x0a*/ +static void i86op_or_byte_R_RM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg,*srcreg; + uint16 srcoffset; + uint8 srcval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm00_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + *destreg = or_byte(m, *destreg, srcval); + break; + case 1: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm01_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + *destreg = or_byte(m, *destreg, srcval); + break; + case 2: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm10_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + *destreg = or_byte(m, * destreg, srcval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcreg = DECODE_RM_BYTE_REGISTER(m,rl); + *destreg = or_byte(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x0b*/ +static void i86op_or_word_R_RM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg,*srcreg; + uint16 srcoffset; + uint16 srcval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm00_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = or_word(m, *destreg, srcval); + break; + case 1: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm01_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = or_word(m, *destreg, srcval); + break; + case 2: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm10_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = or_word(m, *destreg, srcval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcreg = DECODE_RM_WORD_REGISTER(m,rl); + *destreg = or_word(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x0c*/ +static void i86op_or_byte_AL_IMM(PC_ENV *m) +{ + uint8 srcval; + srcval = fetch_byte_imm(m); + m->R_AL = or_byte(m, m->R_AL, srcval); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x0d*/ +static void i86op_or_word_AX_IMM(PC_ENV *m) +{ + uint16 srcval; + srcval = fetch_word_imm(m); + m->R_AX = or_word(m, m->R_AX, srcval); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x0e*/ +static void i86op_push_CS(PC_ENV *m) +{ + push_word(m,m->R_CS); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x0f === ILLEGAL OP*/ + +/*opcode=0x10*/ +static void i86op_adc_byte_RM_R(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg,*srcreg; + uint16 destoffset; + uint8 destval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + destval = adc_byte(m, destval, *srcreg); + store_data_byte(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + destval = adc_byte(m, destval, *srcreg); + store_data_byte(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + destval = adc_byte(m, destval, *srcreg); + store_data_byte(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rl); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + *destreg = adc_byte(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x11*/ +static void i86op_adc_word_RM_R(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg,*srcreg; + uint16 destoffset; + uint16 destval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + destval = adc_word(m, destval, *srcreg); + store_data_word(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + destval = adc_word(m, destval, *srcreg); + store_data_word(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + destval = adc_word(m, destval, *srcreg); + store_data_word(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rl); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + *destreg = adc_word(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x12*/ +static void i86op_adc_byte_R_RM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg,*srcreg; + uint16 srcoffset; + uint8 srcval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm00_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + *destreg = adc_byte(m, *destreg, srcval); + break; + case 1: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm01_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + *destreg = adc_byte(m, *destreg, srcval); + break; + case 2: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm10_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + *destreg = adc_byte(m, * destreg, srcval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcreg = DECODE_RM_BYTE_REGISTER(m,rl); + *destreg = adc_byte(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x13*/ +static void i86op_adc_word_R_RM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg,*srcreg; + uint16 srcoffset; + uint16 srcval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm00_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = adc_word(m, *destreg, srcval); + break; + case 1: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm01_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = adc_word(m, *destreg, srcval); + break; + case 2: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm10_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = adc_word(m, *destreg, srcval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcreg = DECODE_RM_WORD_REGISTER(m,rl); + *destreg = adc_word(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x14*/ +static void i86op_adc_byte_AL_IMM(PC_ENV *m) +{ + uint8 srcval; + srcval = fetch_byte_imm(m); + m->R_AL = adc_byte(m, m->R_AL, srcval); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x15*/ +static void i86op_adc_word_AX_IMM(PC_ENV *m) +{ + uint16 srcval; + srcval = fetch_word_imm(m); + m->R_AX = adc_word(m, m->R_AX, srcval); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x16*/ +static void i86op_push_SS(PC_ENV *m) +{ + push_word(m,m->R_SS); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x17*/ +static void i86op_pop_SS(PC_ENV *m) +{ + m->R_SS = pop_word(m); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x18*/ +static void i86op_sbb_byte_RM_R(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg,*srcreg; + uint16 destoffset; + uint8 destval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + destval = sbb_byte(m, destval, *srcreg); + store_data_byte(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + destval = sbb_byte(m, destval, *srcreg); + store_data_byte(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + destval = sbb_byte(m, destval, *srcreg); + store_data_byte(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rl); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + *destreg = sbb_byte(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x19*/ +static void i86op_sbb_word_RM_R(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg,*srcreg; + uint16 destoffset; + uint16 destval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + destval = sbb_word(m, destval, *srcreg); + store_data_word(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + destval = sbb_word(m, destval, *srcreg); + store_data_word(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + destval = sbb_word(m, destval, *srcreg); + store_data_word(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rl); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + *destreg = sbb_word(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x1a*/ +static void i86op_sbb_byte_R_RM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg,*srcreg; + uint16 srcoffset; + uint8 srcval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm00_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + *destreg = sbb_byte(m, *destreg, srcval); + break; + case 1: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm01_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + *destreg = sbb_byte(m, *destreg, srcval); + break; + case 2: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm10_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + *destreg = sbb_byte(m, * destreg, srcval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcreg = DECODE_RM_BYTE_REGISTER(m,rl); + *destreg = sbb_byte(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x1b*/ +static void i86op_sbb_word_R_RM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg,*srcreg; + uint16 srcoffset; + uint16 srcval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm00_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = sbb_word(m, *destreg, srcval); + break; + case 1: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm01_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = sbb_word(m, *destreg, srcval); + break; + case 2: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm10_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = sbb_word(m, *destreg, srcval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcreg = DECODE_RM_WORD_REGISTER(m,rl); + *destreg = sbb_word(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x1c*/ +static void i86op_sbb_byte_AL_IMM(PC_ENV *m) +{ + uint8 srcval; + srcval = fetch_byte_imm(m); + m->R_AL = sbb_byte(m, m->R_AL, srcval); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x1d*/ +static void i86op_sbb_word_AX_IMM(PC_ENV *m) +{ + uint16 srcval; + srcval = fetch_word_imm(m); + m->R_AX = sbb_word(m, m->R_AX, srcval); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x1e*/ +static void i86op_push_DS(PC_ENV *m) +{ + push_word(m,m->R_DS); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x1f*/ +static void i86op_pop_DS(PC_ENV *m) +{ + m->R_DS = pop_word(m); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x20*/ +static void i86op_and_byte_RM_R(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg,*srcreg; + uint16 destoffset; + uint8 destval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + destval = and_byte(m, destval, *srcreg); + store_data_byte(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + destval = and_byte(m, destval, *srcreg); + store_data_byte(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + destval = and_byte(m, destval, *srcreg); + store_data_byte(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rl); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + *destreg = and_byte(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x21*/ +static void i86op_and_word_RM_R(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg,*srcreg; + uint16 destoffset; + uint16 destval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + destval = and_word(m, destval, *srcreg); + store_data_word(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + destval = and_word(m, destval, *srcreg); + store_data_word(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + destval = and_word(m, destval, *srcreg); + store_data_word(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rl); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + *destreg = and_word(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x22*/ +static void i86op_and_byte_R_RM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg,*srcreg; + uint16 srcoffset; + uint8 srcval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm00_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + *destreg = and_byte(m, *destreg, srcval); + break; + case 1: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm01_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + *destreg = and_byte(m, *destreg, srcval); + break; + case 2: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm10_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + *destreg = and_byte(m, * destreg, srcval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcreg = DECODE_RM_BYTE_REGISTER(m,rl); + *destreg = and_byte(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x23*/ +static void i86op_and_word_R_RM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg,*srcreg; + uint16 srcoffset; + uint16 srcval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm00_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = and_word(m, *destreg, srcval); + break; + case 1: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm01_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = and_word(m, *destreg, srcval); + break; + case 2: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm10_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = and_word(m, *destreg, srcval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcreg = DECODE_RM_WORD_REGISTER(m,rl); + *destreg = and_word(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x24*/ +static void i86op_and_byte_AL_IMM(PC_ENV *m) +{ + uint8 srcval; + srcval = fetch_byte_imm(m); + m->R_AL = and_byte(m, m->R_AL, srcval); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x25*/ +static void i86op_and_word_AX_IMM(PC_ENV *m) +{ + uint16 srcval; + srcval = fetch_word_imm(m); + m->R_AX = and_word(m, m->R_AX, srcval); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x26*/ +static void i86op_segovr_ES(PC_ENV *m) +{ + m->sysmode |= SYSMODE_SEGOVR_ES; + /* note the lack of DECODE_CLEAR_SEGOVR(r) + since, here is one of 4 opcode subroutines we do not + want to do this. + */ +} + +/*opcode=0x27*/ +static void i86op_daa(PC_ENV *m) +{ + uint16 dbyte; + dbyte = m->R_AL; + if (ACCESS_FLAG(m,F_AF)|| (dbyte&0xf) > 9) + { + dbyte += 6; + if (dbyte&0x100) + SET_FLAG(m, F_CF); + SET_FLAG(m, F_AF); + } + else + CLEAR_FLAG(m, F_AF); + if (ACCESS_FLAG(m,F_CF) || (dbyte&0xf0) > 0x90) + { + dbyte += 0x60; + SET_FLAG(m, F_CF); + } + else + CLEAR_FLAG(m, F_CF); + m->R_AL = (uint8) dbyte; + CONDITIONAL_SET_FLAG((m->R_AL & 0x80),m,F_SF); + CONDITIONAL_SET_FLAG((m->R_AL == 0), m,F_ZF); + CONDITIONAL_SET_FLAG((parity_tab[m->R_AL]),m,F_PF); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x28*/ +static void i86op_sub_byte_RM_R(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg,*srcreg; + uint16 destoffset; + uint8 destval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + destval = sub_byte(m, destval, *srcreg); + store_data_byte(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + destval = sub_byte(m, destval, *srcreg); + store_data_byte(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + destval = sub_byte(m, destval, *srcreg); + store_data_byte(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rl); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + *destreg = sub_byte(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x29*/ +static void i86op_sub_word_RM_R(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg,*srcreg; + uint16 destoffset; + uint16 destval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + destval = sub_word(m, destval, *srcreg); + store_data_word(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + destval = sub_word(m, destval, *srcreg); + store_data_word(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + destval = sub_word(m, destval, *srcreg); + store_data_word(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rl); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + *destreg = sub_word(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x2a*/ +static void i86op_sub_byte_R_RM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg,*srcreg; + uint16 srcoffset; + uint8 srcval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm00_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + *destreg = sub_byte(m, *destreg, srcval); + break; + case 1: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm01_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + *destreg = sub_byte(m, *destreg, srcval); + break; + case 2: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm10_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + *destreg = sub_byte(m, * destreg, srcval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcreg = DECODE_RM_BYTE_REGISTER(m,rl); + *destreg = sub_byte(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x2b*/ +static void i86op_sub_word_R_RM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg,*srcreg; + uint16 srcoffset; + uint16 srcval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm00_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = sub_word(m, *destreg, srcval); + break; + case 1: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm01_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = sub_word(m, *destreg, srcval); + break; + case 2: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm10_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = sub_word(m, *destreg, srcval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcreg = DECODE_RM_WORD_REGISTER(m,rl); + *destreg = sub_word(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x2c*/ +static void i86op_sub_byte_AL_IMM(PC_ENV *m) +{ + uint8 srcval; + srcval = fetch_byte_imm(m); + m->R_AL = sub_byte(m, m->R_AL, srcval); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x2d*/ +static void i86op_sub_word_AX_IMM(PC_ENV *m) +{ + uint16 srcval; + srcval = fetch_word_imm(m); + m->R_AX = sub_word(m, m->R_AX, srcval); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x2e*/ +static void i86op_segovr_CS(PC_ENV *m) +{ + m->sysmode |= SYSMODE_SEGOVR_CS; + /* note no DECODE_CLEAR_SEGOVER here. */ +} + +/*opcode=0x2f*/ +static void i86op_das(PC_ENV *m) +{ + uint16 dbyte; + dbyte = m->R_AL; + if ( ACCESS_FLAG(m,F_AF) || (dbyte&0xf) > 9) + { + dbyte -= 6; + if (dbyte&0x100) /* XXXXX --- this is WRONG */ + SET_FLAG(m, F_CF); + SET_FLAG(m, F_AF); + } + else + CLEAR_FLAG(m, F_AF); + if (ACCESS_FLAG(m,F_CF) || (dbyte&0xf0) > 0x90) + { + dbyte -= 0x60; + SET_FLAG(m, F_CF); + } + else + CLEAR_FLAG(m, F_CF); + m->R_AL = (uint8) dbyte; + CONDITIONAL_SET_FLAG(m->R_AL & 0x80,m,F_SF); + CONDITIONAL_SET_FLAG(m->R_AL == 0,m,F_ZF); + CONDITIONAL_SET_FLAG(parity_tab[m->R_AL],m,F_PF); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x30*/ +static void i86op_xor_byte_RM_R(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg,*srcreg; + uint16 destoffset; + uint8 destval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + destval = xor_byte(m, destval, *srcreg); + store_data_byte(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + destval = xor_byte(m, destval, *srcreg); + store_data_byte(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + destval = xor_byte(m, destval, *srcreg); + store_data_byte(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rl); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + *destreg = xor_byte(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x31*/ +static void i86op_xor_word_RM_R(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg,*srcreg; + uint16 destoffset; + uint16 destval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + destval = xor_word(m, destval, *srcreg); + store_data_word(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + destval = xor_word(m, destval, *srcreg); + store_data_word(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + destval = xor_word(m, destval, *srcreg); + store_data_word(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rl); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + *destreg = xor_word(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x32*/ +static void i86op_xor_byte_R_RM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg,*srcreg; + uint16 srcoffset; + uint8 srcval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm00_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + *destreg = xor_byte(m, *destreg, srcval); + break; + case 1: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm01_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + *destreg = xor_byte(m, *destreg, srcval); + break; + case 2: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm10_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + *destreg = xor_byte(m, *destreg, srcval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcreg = DECODE_RM_BYTE_REGISTER(m,rl); + *destreg = xor_byte(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x33*/ +static void i86op_xor_word_R_RM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg,*srcreg; + uint16 srcoffset; + uint16 srcval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm00_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = xor_word(m, *destreg, srcval); + break; + case 1: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm01_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = xor_word(m, *destreg, srcval); + break; + case 2: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm10_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = xor_word(m, *destreg, srcval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcreg = DECODE_RM_WORD_REGISTER(m,rl); + *destreg = xor_word(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x34*/ +static void i86op_xor_byte_AL_IMM(PC_ENV *m) +{ + uint8 srcval; + srcval = fetch_byte_imm(m); + m->R_AL = xor_byte(m, m->R_AL, srcval); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x35*/ +static void i86op_xor_word_AX_IMM(PC_ENV *m) +{ + uint16 srcval; + srcval = fetch_word_imm(m); + m->R_AX = xor_word(m, m->R_AX, srcval); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x36*/ +static void i86op_segovr_SS(PC_ENV *m) +{ + m->sysmode |= SYSMODE_SEGOVR_SS; + /* no DECODE_CLEAR_SEGOVER ! */ +} + +/*opcode=0x37*/ +static void i86op_aaa(PC_ENV *m) +{ + if ( (m->R_AL & 0xf) > 0x9 || ACCESS_FLAG(m,F_AF)) + { + m->R_AL += 0x6; + m->R_AH += 1; + SET_FLAG(m, F_AF); + SET_FLAG(m, F_CF); + } + else + { + CLEAR_FLAG(m, F_CF); + CLEAR_FLAG(m, F_AF); + } + m->R_AL &= 0xf; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x38*/ +static void i86op_cmp_byte_RM_R(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg,*srcreg; + uint16 destoffset; + uint8 destval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + cmp_byte(m, destval, *srcreg); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + cmp_byte(m, destval, *srcreg); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + cmp_byte(m, destval, *srcreg); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rl); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + cmp_byte(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x39*/ +static void i86op_cmp_word_RM_R(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg,*srcreg; + uint16 destoffset; + uint16 destval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + cmp_word(m, destval, *srcreg); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + cmp_word(m, destval, *srcreg); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + cmp_word(m, destval, *srcreg); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rl); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + cmp_word(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x3a*/ +static void i86op_cmp_byte_R_RM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg,*srcreg; + uint16 srcoffset; + uint8 srcval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm00_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + cmp_byte(m, *destreg, srcval); + break; + case 1: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm01_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + cmp_byte(m, *destreg, srcval); + break; + case 2: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm10_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + cmp_byte(m, * destreg, srcval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcreg = DECODE_RM_BYTE_REGISTER(m,rl); + cmp_byte(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x3b*/ +static void i86op_cmp_word_R_RM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg,*srcreg; + uint16 srcoffset; + uint16 srcval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm00_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + cmp_word(m, *destreg, srcval); + break; + case 1: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm01_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + cmp_word(m, *destreg, srcval); + break; + case 2: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm10_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + cmp_word(m, *destreg, srcval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcreg = DECODE_RM_WORD_REGISTER(m,rl); + cmp_word(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x3c*/ +static void i86op_cmp_byte_AL_IMM(PC_ENV *m) +{ + uint8 srcval; + srcval = fetch_byte_imm(m); + cmp_byte(m, m->R_AL, srcval); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x3d*/ +static void i86op_cmp_word_AX_IMM(PC_ENV *m) +{ + uint16 srcval; + srcval = fetch_word_imm(m); + cmp_word(m, m->R_AX, srcval); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x3e*/ +static void i86op_segovr_DS(PC_ENV *m) +{ + m->sysmode |= SYSMODE_SEGOVR_DS; + /* NO DECODE_CLEAR_SEGOVR! */ +} + +/*opcode=0x3f*/ +static void i86op_aas(PC_ENV *m) +{ + /* ???? Check out the subtraction here. Will this ?ever? cause + the contents of R_AL or R_AH to be affected incorrectly since + they are being subtracted from *and* are unsigned. + Should put an assertion in here. + */ + if ( (m->R_AL & 0xf) > 0x9 || ACCESS_FLAG(m,F_AF)) + { + m->R_AL -= 0x6; + m->R_AH -= 1; + SET_FLAG(m, F_AF); + SET_FLAG(m, F_CF); + } + else + { + CLEAR_FLAG(m, F_CF); + CLEAR_FLAG(m, F_AF); + } + m->R_AL &= 0xf; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x40*/ +static void i86op_inc_AX(PC_ENV *m) +{ + m->R_AX = inc_word(m,m->R_AX); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x41*/ +static void i86op_inc_CX(PC_ENV *m) +{ + m->R_CX = inc_word(m,m->R_CX); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x42*/ +static void i86op_inc_DX(PC_ENV *m) +{ + m->R_DX = inc_word(m,m->R_DX); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x43*/ +static void i86op_inc_BX(PC_ENV *m) +{ + m->R_BX = inc_word(m,m->R_BX); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x44*/ +static void i86op_inc_SP(PC_ENV *m) +{ + m->R_SP = inc_word(m,m->R_SP); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x45*/ +static void i86op_inc_BP(PC_ENV *m) +{ + m->R_BP = inc_word(m,m->R_BP); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x46*/ +static void i86op_inc_SI(PC_ENV *m) +{ + m->R_SI = inc_word(m,m->R_SI); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x47*/ +static void i86op_inc_DI(PC_ENV *m) +{ + m->R_DI = inc_word(m,m->R_DI); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x48*/ +static void i86op_dec_AX(PC_ENV *m) +{ + m->R_AX = dec_word(m,m->R_AX); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x49*/ +static void i86op_dec_CX(PC_ENV *m) +{ + m->R_CX = dec_word(m,m->R_CX); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x4a*/ +static void i86op_dec_DX(PC_ENV *m) +{ + m->R_DX = dec_word(m,m->R_DX); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x4b*/ +static void i86op_dec_BX(PC_ENV *m) +{ + m->R_BX = dec_word(m,m->R_BX); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x4c*/ +static void i86op_dec_SP(PC_ENV *m) +{ + m->R_SP = dec_word(m,m->R_SP); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x4d*/ +static void i86op_dec_BP(PC_ENV *m) +{ + m->R_BP = dec_word(m,m->R_BP); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x4e*/ +static void i86op_dec_SI(PC_ENV *m) +{ + m->R_SI = dec_word(m,m->R_SI); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x4f*/ +static void i86op_dec_DI(PC_ENV *m) +{ + m->R_DI = dec_word(m,m->R_DI); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x50*/ +static void i86op_push_AX(PC_ENV *m) +{ + push_word(m,m->R_AX); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x51*/ +static void i86op_push_CX(PC_ENV *m) +{ + push_word(m,m->R_CX); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x52*/ +static void i86op_push_DX(PC_ENV *m) +{ + push_word(m,m->R_DX); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x53*/ +static void i86op_push_BX(PC_ENV *m) +{ + push_word(m,m->R_BX); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x54*/ +static void i86op_push_SP(PC_ENV *m) +{ + /* .... Note this weirdness: One book I have access to + claims that the value pushed here is actually sp-2. I.e. + it decrements the stackpointer, and then pushes it. The 286 + I have does it this way. Changing this causes many problems.*/ + /* changed to push SP-2, since this *IS* how a 8088 does this */ + push_word(m,m->R_SP-2); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x55*/ +static void i86op_push_BP(PC_ENV *m) +{ + push_word(m,m->R_BP); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x56*/ +static void i86op_push_SI(PC_ENV *m) +{ + push_word(m,m->R_SI); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x57*/ +static void i86op_push_DI(PC_ENV *m) +{ + push_word(m,m->R_DI); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x58*/ +static void i86op_pop_AX(PC_ENV *m) +{ + m->R_AX = pop_word(m); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x59*/ +static void i86op_pop_CX(PC_ENV *m) +{ + m->R_CX = pop_word(m); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x5a*/ +static void i86op_pop_DX(PC_ENV *m) +{ + m->R_DX = pop_word(m); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x5b*/ +static void i86op_pop_BX(PC_ENV *m) +{ + m->R_BX = pop_word(m); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x5c*/ +static void i86op_pop_SP(PC_ENV *m) +{ + m->R_SP = pop_word(m); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x5d*/ +static void i86op_pop_BP(PC_ENV *m) +{ + m->R_BP = pop_word(m); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x5e*/ +static void i86op_pop_SI(PC_ENV *m) +{ + m->R_SI = pop_word(m); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x5f*/ +static void i86op_pop_DI(PC_ENV *m) +{ + m->R_DI = pop_word(m); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x60 ILLEGAL OP, calls i86op_illegal_op() */ +/*opcode=0x61 ILLEGAL OP, calls i86op_illegal_op() */ +/*opcode=0x62 ILLEGAL OP, calls i86op_illegal_op() */ +/*opcode=0x63 ILLEGAL OP, calls i86op_illegal_op() */ +/*opcode=0x64 ILLEGAL OP, calls i86op_illegal_op() */ +/*opcode=0x65 ILLEGAL OP, calls i86op_illegal_op() */ +/*opcode=0x66 ILLEGAL OP, calls i86op_illegal_op() */ +/*opcode=0x67 ILLEGAL OP, calls i86op_illegal_op() */ +/*opcode=0x68 ILLEGAL OP, calls i86op_illegal_op() */ +/*opcode=0x69 ILLEGAL OP, calls i86op_illegal_op() */ +/*opcode=0x6a ILLEGAL OP, calls i86op_illegal_op() */ +/*opcode=0x6b ILLEGAL OP, calls i86op_illegal_op() */ +/*opcode=0x6c ILLEGAL OP, calls i86op_illegal_op() */ +/*opcode=0x6d ILLEGAL OP, calls i86op_illegal_op() */ +/*opcode=0x6e ILLEGAL OP, calls i86op_illegal_op() */ +/*opcode=0x6f ILLEGAL OP, calls i86op_illegal_op() */ + +/*opcode=0x70*/ +static void i86op_jump_near_O(PC_ENV *m) +{ + int8 offset; + uint16 target; + /* jump to byte offset if overflow flag is set */ + offset = (int8) fetch_byte_imm(m); + target = (int16)(m->R_IP) + offset; + if (ACCESS_FLAG(m,F_OF)) + m->R_IP = target; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x71*/ +static void i86op_jump_near_NO(PC_ENV *m) +{ + int8 offset; + uint16 target; + /* jump to byte offset if overflow is not set */ + offset = (int8) fetch_byte_imm(m); + target = (int16)(m->R_IP) + offset; + if (!ACCESS_FLAG(m,F_OF)) + m->R_IP = target; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x72*/ +static void i86op_jump_near_B(PC_ENV *m) +{ + int8 offset; + uint16 target; + /* jump to byte offset if carry flag is set. */ + offset = (int8)fetch_byte_imm(m); /* sign extended ??? */ + target = (int16)(m->R_IP) + offset; + if (ACCESS_FLAG(m, F_CF)) + m->R_IP = target; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x73*/ +static void i86op_jump_near_NB(PC_ENV *m) +{ + int8 offset; + uint16 target; + /* jump to byte offset if carry flag is clear. */ + offset = (int8)fetch_byte_imm(m); /* sign extended ??? */ + target = (int16)(m->R_IP) + offset; + if (!ACCESS_FLAG(m,F_CF)) + m->R_IP = target; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x74*/ +static void i86op_jump_near_Z(PC_ENV *m) +{ + int8 offset; + uint16 target; + /* jump to byte offset if zero flag is set. */ + offset = (int8)fetch_byte_imm(m); + target = (int16)(m->R_IP) + offset; + if (ACCESS_FLAG(m, F_ZF)) + m->R_IP = target; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x75*/ +static void i86op_jump_near_NZ(PC_ENV *m) +{ + int8 offset; + uint16 target; + /* jump to byte offset if zero flag is clear. */ + offset = (int8)fetch_byte_imm(m); + target = (int16)(m->R_IP) + offset; + if (!ACCESS_FLAG(m, F_ZF)) + m->R_IP = target; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x76*/ +static void i86op_jump_near_BE(PC_ENV *m) +{ + int8 offset; + uint16 target; + /* jump to byte offset if carry flag is set or if the zero + flag is set. */ + offset = (int8)fetch_byte_imm(m); + target = (int16)(m->R_IP) + offset; + if (ACCESS_FLAG(m,F_CF) || ACCESS_FLAG(m,F_ZF)) + m->R_IP = target; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x77*/ +static void i86op_jump_near_NBE(PC_ENV *m) +{ + int8 offset; + uint16 target; + /* jump to byte offset if carry flag is clear and if the zero + flag is clear */ + offset = (int8)fetch_byte_imm(m); + target = (int16)(m->R_IP) + offset; + if (!(ACCESS_FLAG(m,F_CF)||ACCESS_FLAG(m,F_ZF))) + m->R_IP = target; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x78*/ +static void i86op_jump_near_S(PC_ENV *m) +{ + int8 offset; + uint16 target; + /* jump to byte offset if sign flag is set */ + offset = (int8)fetch_byte_imm(m); + target = (int16)(m->R_IP) + offset; + if (ACCESS_FLAG(m,F_SF)) + m->R_IP = target; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x79*/ +static void i86op_jump_near_NS(PC_ENV *m) +{ + int8 offset; + uint16 target; + /* jump to byte offset if sign flag is clear */ + offset = (int8)fetch_byte_imm(m); + target = (int16)(m->R_IP) + offset; + if (!ACCESS_FLAG(m,F_SF)) + m->R_IP = target; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x7a*/ +static void i86op_jump_near_P(PC_ENV *m) +{ + int8 offset; + uint16 target; + /* jump to byte offset if parity flag is set (even parity) */ + offset = (int8)fetch_byte_imm(m); + target = (int16)(m->R_IP) + offset; + if (ACCESS_FLAG(m, F_PF)) + m->R_IP = target; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x7b*/ +static void i86op_jump_near_NP(PC_ENV *m) +{ + int8 offset; + uint16 target; + /* jump to byte offset if parity flag is clear (odd parity) */ + offset = (int8)fetch_byte_imm(m); + target = (int16)(m->R_IP) + offset; + if (!ACCESS_FLAG(m, F_PF)) + m->R_IP = target; + DECODE_CLEAR_SEGOVR(m); +} + +/* JHH fixed till here... */ + +/*opcode=0x7c*/ +static void i86op_jump_near_L(PC_ENV *m) +{ + int8 offset; + uint16 target; + int sf,of; + /* jump to byte offset if sign flag not equal to overflow flag. */ + offset = (int8)fetch_byte_imm(m); + target = (int16)(m->R_IP) + offset; + /* note: + * this is the simplest expression i could think of which + * expresses SF != OF. m->R_FLG&F_SF either equals x80 or x00. + * Similarly m->R_FLG&F_OF either equals x800 or x000. + * The former shifted right by 7 puts a 1 or 0 in bit 0. + * The latter shifter right by 11 puts a 1 or 0 in bit 0. + * if the two expressions are the same, i.e. equal, then + * a zero results from the xor. If they are not equal, + * then a 1 results, and the jump is taken. + */ + sf = ACCESS_FLAG(m,F_SF) != 0; + of = ACCESS_FLAG(m,F_OF) != 0; + /* was: if ( ((m->R_FLG & F_SF)>>7) ^ ((m->R_FLG & F_OF) >> 11))*/ + if (sf ^ of) + m->R_IP = target; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x7d*/ +static void i86op_jump_near_NL(PC_ENV *m) +{ + int8 offset; + uint16 target; + int sf,of; + /* jump to byte offset if sign flag not equal to overflow flag. */ + offset = (int8)fetch_byte_imm(m); + target = (int16)(m->R_IP) + offset; + sf = ACCESS_FLAG(m,F_SF) != 0; + of = ACCESS_FLAG(m,F_OF) != 0; + /* note: inverse of above, but using == instead of xor. */ + /* was: if (((m->R_FLG & F_SF)>>7) == ((m->R_FLG & F_OF) >> 11))*/ + if (sf == of) + m->R_IP = target; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x7e*/ +static void i86op_jump_near_LE(PC_ENV *m) +{ + int8 offset; + uint16 target; + int sf,of; + /* jump to byte offset if sign flag not equal to overflow flag + or the zero flag is set */ + offset = (int8)fetch_byte_imm(m); + target = (int16)(m->R_IP) + offset; + sf = ACCESS_FLAG(m,F_SF) != 0; + of = ACCESS_FLAG(m,F_OF) != 0; + /* note: modification of JL */ + /* sf != of */ + /* was: if ((((m->R_FLG & F_SF)>>7) ^ ((m->R_FLG & F_OF) >> 11)) + || (m->R_FLG & F_ZF) ) */ + if ( (sf ^ of) || ACCESS_FLAG(m,F_ZF)) + m->R_IP = target; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x7f*/ +static void i86op_jump_near_NLE(PC_ENV *m) +{ + int8 offset; + uint16 target; + int sf,of; + /* jump to byte offset if sign flag equal to overflow flag. + and the zero flag is clear*/ + offset = (int8)fetch_byte_imm(m); + target = (int16)(m->R_IP) + offset; + sf = ACCESS_FLAG(m,F_SF) != 0; + of = ACCESS_FLAG(m,F_OF) != 0; + +/* if (((m->R_FLG & F_SF)>>7) == ((m->R_FLG & F_OF) >> 11) + && (!(m->R_FLG & F_ZF))) */ + if ( ( sf == of ) && !ACCESS_FLAG(m,F_ZF)) + m->R_IP = target; + DECODE_CLEAR_SEGOVR(m); +} + +static uint8 (*opc80_byte_operation[])(PC_ENV *m,uint8 d,uint8 s) = +{ + add_byte,/*00*/ + or_byte, /*01*/ + adc_byte,/*02*/ + sbb_byte,/*03*/ + and_byte,/*04*/ + sub_byte,/*05*/ + xor_byte,/*06*/ + cmp_byte,/*07*/ +}; + +/*opcode=0x80*/ +static void i86op_opc80_byte_RM_IMM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg; + uint16 destoffset; + uint8 imm; + uint8 destval; + /* weirdo special case instruction format. Part of the + opcode held below in "RH". Doubly nested case would + result, except that the decoded instruction + */ + FETCH_DECODE_MODRM(m,mod,rh,rl); + /* know operation, decode the mod byte to find the addressing + mode. */ + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_byte(m,destoffset); + imm = fetch_byte_imm(m); + destval = (*opc80_byte_operation[rh])(m, destval, imm); + if (rh != 7) store_data_byte(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_byte(m,destoffset); + imm = fetch_byte_imm(m); + destval = (*opc80_byte_operation[rh])(m, destval, imm); + if (rh != 7) store_data_byte(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_byte(m,destoffset); + imm = fetch_byte_imm(m); + destval = (*opc80_byte_operation[rh])(m, destval, imm); + if (rh != 7) store_data_byte(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rl); + imm = fetch_byte_imm(m); + destval = (*opc80_byte_operation[rh])(m, *destreg, imm); + if (rh != 7) *destreg = destval; + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +static uint16 (*opc81_word_operation[])(PC_ENV *m,uint16 d,uint16 s) = +{ add_word,/*00*/ + or_word, /*01*/ + adc_word,/*02*/ + sbb_word,/*03*/ + and_word,/*04*/ + sub_word,/*05*/ + xor_word,/*06*/ + cmp_word,/*07*/ +}; + +/*opcode=0x81*/ +static void i86op_opc81_word_RM_IMM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg; + uint16 destoffset; + uint16 imm; + uint16 destval; + /* weirdo special case instruction format. Part of the + opcode held below in "RH". Doubly nested case would + result, except that the decoded instruction + */ + FETCH_DECODE_MODRM(m,mod,rh,rl); + /* know operation, decode the mod byte to find the addressing + mode. */ + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_word(m,destoffset); + imm = fetch_word_imm(m); + destval = (*opc81_word_operation[rh])(m, destval, imm); + if (rh != 7) store_data_word(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_word(m,destoffset); + imm = fetch_word_imm(m); + destval = (*opc81_word_operation[rh])(m, destval, imm); + if (rh != 7) store_data_word(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_word(m,destoffset); + imm = fetch_word_imm(m); + destval = (*opc81_word_operation[rh])(m, destval, imm); + if (rh != 7) store_data_word(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rl); + imm = fetch_word_imm(m); + destval = (*opc81_word_operation[rh])(m, *destreg, imm); + if (rh != 7) *destreg = destval; + break; + } + DECODE_CLEAR_SEGOVR(m); + } + +static uint8 (*opc82_byte_operation[])(PC_ENV *m,uint8 s,uint8 d) = +{ + add_byte,/*00*/ + or_byte, /*01*/ /*YYY UNUSED ????*/ + adc_byte,/*02*/ + sbb_byte,/*03*/ + and_byte,/*04*/ /*YYY UNUSED ????*/ + sub_byte,/*05*/ + xor_byte,/*06*/ /*YYY UNUSED ????*/ + cmp_byte,/*07*/ +}; + +/*opcode=0x82*/ +static void i86op_opc82_byte_RM_IMM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg; + uint16 destoffset; + uint8 imm; + uint8 destval; + /* weirdo special case instruction format. Part of the + opcode held below in "RH". Doubly nested case would + result, except that the decoded instruction + Similar to opcode 81, except that the immediate byte + is sign extended to a word length. + */ + FETCH_DECODE_MODRM(m,mod,rh,rl); + /* know operation, decode the mod byte to find the addressing + mode. */ + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_byte(m,destoffset); + imm = fetch_byte_imm(m); + destval = (*opc82_byte_operation[rh])(m, destval, imm); + if (rh != 7) store_data_byte(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_byte(m,destoffset); + imm = fetch_byte_imm(m); + destval = (*opc82_byte_operation[rh])(m, destval, imm); + if (rh != 7) store_data_byte(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_byte(m,destoffset); + imm = fetch_byte_imm(m); + destval = (*opc82_byte_operation[rh])(m, destval, imm); + if (rh != 7) store_data_byte(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rl); + imm = fetch_byte_imm(m); + destval = (*opc82_byte_operation[rh])(m, *destreg, imm); + if (rh != 7) *destreg = destval; + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +static uint16 (*opc83_word_operation[])(PC_ENV *m,uint16 s,uint16 d) = +{ + add_word,/*00*/ + or_word, /*01*/ /*YYY UNUSED ????*/ + adc_word,/*02*/ + sbb_word,/*03*/ + and_word,/*04*/ /*YYY UNUSED ????*/ + sub_word,/*05*/ + xor_word,/*06*/ /*YYY UNUSED ????*/ + cmp_word,/*07*/ +}; + +/*opcode=0x83*/ +static void i86op_opc83_word_RM_IMM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg; + uint16 destoffset; + uint16 imm; + uint16 destval; + /* weirdo special case instruction format. Part of the + opcode held below in "RH". Doubly nested case would + result, except that the decoded instruction + Similar to opcode 81, except that the immediate byte + is sign extended to a word length. + */ + FETCH_DECODE_MODRM(m,mod,rh,rl); + /* know operation, decode the mod byte to find the addressing + mode. */ + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_word(m,destoffset); + imm = (int8)fetch_byte_imm(m); + destval = (*opc83_word_operation[rh])(m, destval, imm); + if (rh != 7) store_data_word(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_word(m,destoffset); + imm = (int8)fetch_byte_imm(m); + destval = (*opc83_word_operation[rh])(m, destval, imm); + if (rh != 7) store_data_word(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_word(m,destoffset); + imm = (int8) fetch_byte_imm(m); + destval = (*opc83_word_operation[rh])(m, destval, imm); + if (rh != 7) store_data_word(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rl); + imm = (int8) fetch_byte_imm(m); + destval = (*opc83_word_operation[rh])(m, *destreg, imm); + if (rh != 7) *destreg = destval; + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x84*/ +static void i86op_test_byte_RM_R(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg,*srcreg; + uint16 destoffset; + uint8 destval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + test_byte(m, destval, *srcreg); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + test_byte(m, destval, *srcreg); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + test_byte(m, destval, *srcreg); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rl); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + test_byte(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); + } + +/*opcode=0x85*/ +static void i86op_test_word_RM_R(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg,*srcreg; + uint16 destoffset; + uint16 destval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + test_word(m, destval, *srcreg); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + test_word(m, destval, *srcreg); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + test_word(m, destval, *srcreg); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rl); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + test_word(m, *destreg, *srcreg); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x86*/ +static void i86op_xchg_byte_RM_R(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg,*srcreg; + uint16 destoffset; + uint8 destval; + uint8 tmp; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + tmp = *srcreg; + *srcreg = destval; + destval = tmp; + store_data_byte(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + tmp = *srcreg; + *srcreg = destval; + destval = tmp; + store_data_byte(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_byte(m,destoffset); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + tmp = *srcreg; + *srcreg = destval; + destval = tmp; + store_data_byte(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rl); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + tmp = *srcreg; + *srcreg = *destreg; + *destreg = tmp; + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x87*/ +static void i86op_xchg_word_RM_R(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg,*srcreg; + uint16 destoffset; + uint16 destval; + uint16 tmp; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + tmp = *srcreg; + *srcreg = destval; + destval = tmp; + store_data_word(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + tmp = *srcreg; + *srcreg = destval; + destval = tmp; + store_data_word(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_word(m,destoffset); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + tmp = *srcreg; + *srcreg = destval; + destval = tmp; + store_data_word(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rl); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + tmp = *srcreg; + *srcreg = *destreg; + *destreg = tmp; + break; + } + DECODE_CLEAR_SEGOVR(m); + } + +/*opcode=0x88*/ +static void i86op_mov_byte_RM_R(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg,*srcreg; + uint16 destoffset; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + store_data_byte(m,destoffset,*srcreg); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + store_data_byte(m,destoffset,*srcreg); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + store_data_byte(m,destoffset,*srcreg); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rl); + srcreg = DECODE_RM_BYTE_REGISTER(m,rh); + *destreg = *srcreg; + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x89*/ +static void i86op_mov_word_RM_R(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg,*srcreg; + uint16 destoffset; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + store_data_word(m,destoffset,*srcreg); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + store_data_word(m,destoffset,*srcreg); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + store_data_word(m,destoffset,*srcreg); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rl); + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + *destreg = *srcreg; + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x8a*/ +static void i86op_mov_byte_R_RM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg,*srcreg; + uint16 srcoffset; + uint8 srcval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm00_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + *destreg = srcval; + break; + case 1: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm01_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + *destreg = srcval; + break; + case 2: + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcoffset=decode_rm10_address(m,rl); + srcval = fetch_data_byte(m,srcoffset); + *destreg = srcval; + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rh); + srcreg = DECODE_RM_BYTE_REGISTER(m,rl); + *destreg = *srcreg; + break; + } + DECODE_CLEAR_SEGOVR(m); +} + + /*opcode=0x8b*/ +static void i86op_mov_word_R_RM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg,*srcreg; + uint16 srcoffset; + uint16 srcval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm00_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = srcval; + break; + case 1: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm01_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = srcval; + break; + case 2: + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm10_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = srcval; + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rh); + srcreg = DECODE_RM_WORD_REGISTER(m,rl); + *destreg = *srcreg; + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x8c*/ +static void i86op_mov_word_RM_SR(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg,*srcreg; + uint16 destoffset; + uint16 destval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + srcreg = decode_rm_seg_register(m,rh); + destval = *srcreg; + store_data_word(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + srcreg = decode_rm_seg_register(m,rh); + destval = *srcreg; + store_data_word(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + srcreg = decode_rm_seg_register(m,rh); + destval = *srcreg; + store_data_word(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rl); + srcreg = decode_rm_seg_register(m,rh); + *destreg = *srcreg; + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x8d*/ +static void i86op_lea_word_R_M(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *srcreg; + uint16 destoffset; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + destoffset=decode_rm00_address(m,rl); + *srcreg = destoffset; + break; + case 1: + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + destoffset=decode_rm01_address(m,rl); + *srcreg = destoffset; + break; + case 2: + srcreg = DECODE_RM_WORD_REGISTER(m,rh); + destoffset=decode_rm10_address(m,rl); + *srcreg = destoffset; + break; + case 3: /* register to register */ + /* undefined. Do nothing. */ + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x8e*/ +static void i86op_mov_word_SR_RM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg,*srcreg; + uint16 srcoffset; + uint16 srcval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destreg = decode_rm_seg_register(m,rh); + srcoffset=decode_rm00_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = srcval; + break; + case 1: + destreg = decode_rm_seg_register(m,rh); + srcoffset=decode_rm01_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = srcval; + break; + case 2: + destreg = decode_rm_seg_register(m,rh); + srcoffset = decode_rm10_address(m,rl); + srcval = fetch_data_word(m,srcoffset); + *destreg = srcval; + break; + case 3: /* register to register */ + destreg = decode_rm_seg_register(m,rh); + srcreg = DECODE_RM_WORD_REGISTER(m,rl); + *destreg = *srcreg; + break; + } + /*\ + * clean up, and reset all the R_xSP pointers to the correct + * locations. This is about 3x too much overhead (doing all the + * segreg ptrs when only one is needed, but this instruction + * *cannot* be that common, and this isn't too much work anyway. + \*/ + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x8f*/ +static void i86op_pop_RM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg; + uint16 destoffset; + uint16 destval; + FETCH_DECODE_MODRM(m,mod,rh,rl); + if (rh != 0) + { + halt_sys(m); + } + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = pop_word( m); + store_data_word(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = pop_word(m); + store_data_word(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = pop_word(m); + store_data_word(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rl); + *destreg = pop_word(m); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x90*/ +static void i86op_nop(PC_ENV *m) +{ + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x91*/ +static void i86op_xchg_word_AX_CX(PC_ENV *m) +{ + uint16 tmp; + tmp = m->R_AX; + m->R_AX = m->R_CX; + m->R_CX = tmp; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x92*/ +static void i86op_xchg_word_AX_DX(PC_ENV *m) +{ + uint16 tmp; + tmp = m->R_AX; + m->R_AX = m->R_DX; + m->R_DX = tmp; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x93*/ +static void i86op_xchg_word_AX_BX(PC_ENV *m) +{ + uint16 tmp; + tmp = m->R_AX; + m->R_AX = m->R_BX; + m->R_BX = tmp; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x94*/ +static void i86op_xchg_word_AX_SP(PC_ENV *m) +{ + uint16 tmp; + tmp = m->R_AX; + m->R_AX = m->R_SP; + m->R_SP = tmp; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x95*/ +static void i86op_xchg_word_AX_BP(PC_ENV *m) +{ + uint16 tmp; + tmp = m->R_AX; + m->R_AX = m->R_BP; + m->R_BP = tmp; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x96*/ +static void i86op_xchg_word_AX_SI(PC_ENV *m) +{ + uint16 tmp; + tmp = m->R_AX; + m->R_AX = m->R_SI; + m->R_SI = tmp; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x97*/ +static void i86op_xchg_word_AX_DI(PC_ENV *m) +{ + uint16 tmp; + tmp = m->R_AX; + m->R_AX = m->R_DI; + m->R_DI = tmp; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x98*/ +static void i86op_cbw(PC_ENV *m) +{ + if (m->R_AL & 0x80) + { + m->R_AH = 0xff; + } + else + { + m->R_AH = 0x0; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x99*/ +static void i86op_cwd(PC_ENV *m) +{ + if (m->R_AX & 0x8000) + { + m->R_DX = 0xffff; + } + else + { + m->R_DX = 0x0; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x9a*/ +static void i86op_call_far_IMM(PC_ENV *m) +{ + uint16 farseg,faroff; + faroff = fetch_word_imm(m); + farseg = fetch_word_imm(m); + /* XXX + HOOKED INTERRUPT VECTORS CALLING INTO OUR "BIOS" + WILL CAUSE PROBLEMS UNLESS ALL INTERSEGMENT STUFF IS + CHECKED FOR BIOS ACCESS. CHECK NEEDED HERE. + FOR MOMENT, LET IT ALONE. + */ + push_word(m,m->R_CS); + m->R_CS = farseg; + push_word(m,m->R_IP); + m->R_IP = faroff; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x9b*/ +static void i86op_wait(PC_ENV *m) +{ + /* NADA. */ + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x9c*/ +static void i86op_pushf_word(PC_ENV *m) +{ + uint16 flags; + flags = m->R_FLG; + /* clear out *all* bits not representing flags */ + flags &= F_MSK; + /* TURN ON CHARACTERISTIC BITS OF FLAG FOR 8088 */ + flags |= F_ALWAYS_ON; + push_word(m,flags); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x9d*/ +static void i86op_popf_word(PC_ENV *m) +{ + m->R_FLG = pop_word(m); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x9e*/ +static void i86op_sahf(PC_ENV *m) +{ + /* clear the lower bits of the flag register */ + m->R_FLG &= 0xffffff00; + /* or in the AH register into the flags register */ + m->R_FLG |= m->R_AH; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0x9f*/ +static void i86op_lahf(PC_ENV *m) +{ + m->R_AH = m->R_FLG & 0xff; + /*undocumented TC++ behavior??? Nope. It's documented, but + you have too look real hard to notice it. */ + m->R_AH |= 0x2; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xa0*/ +static void i86op_mov_AL_M_IMM(PC_ENV *m) +{ + uint16 offset; + uint8 destval; + offset = fetch_word_imm(m); + destval = fetch_data_byte(m,offset); + m->R_AL = destval; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xa1*/ +static void i86op_mov_AX_M_IMM(PC_ENV *m) +{ + uint16 offset; + uint16 destval; + offset = fetch_word_imm(m); + destval = fetch_data_word(m,offset); + m->R_AX = destval; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xa2*/ +static void i86op_mov_M_AL_IMM(PC_ENV *m) +{ + uint16 offset; + offset = fetch_word_imm(m); + store_data_byte(m,offset,m->R_AL); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xa3*/ +static void i86op_mov_M_AX_IMM(PC_ENV *m) +{ + uint16 offset; + offset = fetch_word_imm(m); + store_data_word(m,offset,m->R_AX); + DECODE_CLEAR_SEGOVR(m); +} + +/* JHH CLEANED */ + +/*opcode=0xa4*/ +static void i86op_movs_byte(PC_ENV *m) +{ + uint8 val; + int inc; + if (ACCESS_FLAG(m,F_DF)) /* down */ + inc = -1; + else + inc = 1; + if (m->sysmode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) + { + /* dont care whether REPE or REPNE */ + /* move them until CX is ZERO. */ + while (m->R_CX != 0) + { + val = fetch_data_byte(m,m->R_SI); + store_data_byte_abs(m,m->R_ES,m->R_DI,val); + m->R_CX -= 1; + m->R_SI += inc; + m->R_DI += inc; + } + m->sysmode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } + else + { + val = fetch_data_byte(m,m->R_SI); + store_data_byte_abs(m,m->R_ES,m->R_DI,val); + m->R_SI += inc; + m->R_DI += inc; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xa5*/ +static void i86op_movs_word(PC_ENV *m) +{ + int16 val; + int inc; + if (ACCESS_FLAG(m, F_DF)) /* down */ + inc = -2; + else + inc = 2; + if (m->sysmode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) + { + /* dont care whether REPE or REPNE */ + /* move them until CX is ZERO. */ + while (m->R_CX != 0) + { + val = fetch_data_word(m,m->R_SI); + store_data_word_abs(m,m->R_ES,m->R_DI,val); + m->R_CX -= 1; + m->R_SI += inc; + m->R_DI += inc; + } + m->sysmode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } + else + { + val = fetch_data_word(m,m->R_SI); + store_data_word_abs(m,m->R_ES,m->R_DI,val); + m->R_SI += inc; + m->R_DI += inc; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xa6*/ +static void i86op_cmps_byte(PC_ENV *m) +{ + int8 val1,val2; + int inc; + if (ACCESS_FLAG(m,F_DF)) /* down */ + inc = -1; + else + inc = 1; + if (m->sysmode & SYSMODE_PREFIX_REPE) + { + /* REPE */ + /* move them until CX is ZERO. */ + while (m->R_CX != 0) + { + val1 = fetch_data_byte(m,m->R_SI); + val2 = fetch_data_byte_abs(m,m->R_ES,m->R_DI); + cmp_byte(m, val1,val2); + m->R_CX -= 1; + m->R_SI += inc; + m->R_DI += inc; + if (ACCESS_FLAG(m,F_ZF)==0) break; + } + m->sysmode &= ~SYSMODE_PREFIX_REPE; + } + else if (m->sysmode & SYSMODE_PREFIX_REPNE) + { + /* REPNE */ + /* move them until CX is ZERO. */ + while (m->R_CX != 0) + { + val1 = fetch_data_byte(m,m->R_SI); + val2 = fetch_data_byte_abs(m,m->R_ES,m->R_DI); + cmp_byte(m, val1,val2); + m->R_CX -= 1; + m->R_SI += inc; + m->R_DI += inc; + if (ACCESS_FLAG(m,F_ZF)) break; /* zero flag set means equal */ + } + m->sysmode &= ~SYSMODE_PREFIX_REPNE; + } + else + { + val1 = fetch_data_byte(m,m->R_SI); + val2 = fetch_data_byte_abs(m,m->R_ES,m->R_DI); + cmp_byte(m, val1,val2); + m->R_SI += inc; + m->R_DI += inc; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xa7*/ +static void i86op_cmps_word(PC_ENV *m) +{ + int16 val1,val2; + int inc; + if (ACCESS_FLAG(m,F_DF)) /* down */ + inc = -2; + else + inc = 2; + if (m->sysmode & SYSMODE_PREFIX_REPE) + { + /* REPE */ + /* move them until CX is ZERO. */ + while (m->R_CX != 0) + { + val1 = fetch_data_word(m,m->R_SI); + val2 = fetch_data_word_abs(m,m->R_ES,m->R_DI); + cmp_word(m, val1,val2); + m->R_CX -= 1; + m->R_SI += inc; + m->R_DI += inc; + if (ACCESS_FLAG(m,F_ZF)==0) break; + } + m->sysmode &= ~SYSMODE_PREFIX_REPE; + } + else if (m->sysmode & SYSMODE_PREFIX_REPNE) + { + /* REPNE */ + /* move them until CX is ZERO. */ + while (m->R_CX != 0) + { + val1 = fetch_data_word(m,m->R_SI); + val2 = fetch_data_word_abs(m,m->R_ES,m->R_DI); + cmp_word(m, val1,val2); + m->R_CX -= 1; + m->R_SI += inc; + m->R_DI += inc; + if (ACCESS_FLAG(m,F_ZF)) break; /* zero flag set means equal */ + } + m->sysmode &= ~SYSMODE_PREFIX_REPNE; + } + else + { + val1 = fetch_data_word(m,m->R_SI); + val2 = fetch_data_word_abs(m,m->R_ES,m->R_DI); + cmp_word(m, val1,val2); + m->R_SI += inc; + m->R_DI += inc; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xa8*/ +static void i86op_test_AL_IMM(PC_ENV *m) +{ + int imm; + imm = fetch_byte_imm(m); + test_byte(m, m->R_AL, imm); + DECODE_CLEAR_SEGOVR(m); + } + +/*opcode=0xa9*/ +static void i86op_test_AX_IMM(PC_ENV *m) +{ + int imm; + imm = fetch_word_imm(m); + test_word(m, m->R_AX, imm); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xaa*/ +static void i86op_stos_byte(PC_ENV *m) +{ + int inc; + if (ACCESS_FLAG(m, F_DF)) /* down */ + inc = -1; + else + inc = 1; + if (m->sysmode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) + { + /* dont care whether REPE or REPNE */ + /* move them until CX is ZERO. */ + while (m->R_CX != 0) + { + store_data_byte_abs(m,m->R_ES,m->R_DI,m->R_AL); + m->R_CX -= 1; + m->R_DI += inc; + } + m->sysmode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } + else + { + store_data_byte_abs(m,m->R_ES,m->R_DI,m->R_AL); + m->R_DI += inc; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xab*/ +static void i86op_stos_word(PC_ENV *m) +{ + int inc; + if (ACCESS_FLAG(m, F_DF)) /* down */ + inc = -2; + else + inc = 2; + if (m->sysmode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) + { + /* dont care whether REPE or REPNE */ + /* move them until CX is ZERO. */ + while (m->R_CX != 0) + { + store_data_word_abs(m,m->R_ES,m->R_DI,m->R_AX); + m->R_CX -= 1; + m->R_DI += inc; + } + m->sysmode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } + else + { + store_data_word_abs(m,m->R_ES,m->R_DI,m->R_AX); + m->R_DI += inc; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xac*/ +static void i86op_lods_byte(PC_ENV *m) +{ + int inc; + if (ACCESS_FLAG(m,F_DF)) /* down */ + inc = -1; + else + inc = 1; + if (m->sysmode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) + { + /* dont care whether REPE or REPNE */ + /* move them until CX is ZERO. */ + while (m->R_CX != 0) + { + m->R_AL = fetch_data_byte(m,m->R_SI); + m->R_CX -= 1; + m->R_SI += inc; + } + m->sysmode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } + else + { + m->R_AL = fetch_data_byte(m,m->R_SI); + m->R_SI += inc; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xad*/ +static void i86op_lods_word(PC_ENV *m) +{ + int inc; + if (ACCESS_FLAG(m,F_DF)) /* down */ + inc = -2; + else + inc = 2; + if (m->sysmode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) + { + /* dont care whether REPE or REPNE */ + /* move them until CX is ZERO. */ + while (m->R_CX != 0) + { + m->R_AX = fetch_data_word(m,m->R_SI); + m->R_CX -= 1; + m->R_SI += inc; + } + m->sysmode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE); + } + else + { + m->R_AX = fetch_data_word(m,m->R_SI); + m->R_SI += inc; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xae*/ +static void i86op_scas_byte(PC_ENV *m) +{ + int8 val2; + int inc; + if (ACCESS_FLAG(m,F_DF)) /* down */ + inc = -1; + else + inc = 1; + if (m->sysmode & SYSMODE_PREFIX_REPE) + { + /* REPE */ + /* move them until CX is ZERO. */ + while (m->R_CX != 0) + { + val2 = fetch_data_byte_abs(m,m->R_ES,m->R_DI); + cmp_byte(m, m->R_AL,val2); + m->R_CX -= 1; + m->R_DI += inc; + if (ACCESS_FLAG(m,F_ZF)==0) break; + } + m->sysmode &= ~SYSMODE_PREFIX_REPE; + } + else if (m->sysmode & SYSMODE_PREFIX_REPNE) + { + /* REPNE */ + /* move them until CX is ZERO. */ + while (m->R_CX != 0) + { + val2 = fetch_data_byte_abs(m,m->R_ES,m->R_DI); + cmp_byte(m, m->R_AL,val2); + m->R_CX -= 1; + m->R_DI += inc; + if (ACCESS_FLAG(m,F_ZF)) break; /* zero flag set means equal */ + } + m->sysmode &= ~SYSMODE_PREFIX_REPNE; + } + else + { + val2 = fetch_data_byte_abs(m,m->R_ES,m->R_DI); + cmp_byte(m, m->R_AL,val2); + m->R_DI += inc; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xaf*/ +static void i86op_scas_word(PC_ENV *m) +{ + int16 val2; + int inc; + if (ACCESS_FLAG(m, F_DF)) /* down */ + inc = -2; + else + inc = 2; + if (m->sysmode & SYSMODE_PREFIX_REPE) + { + /* REPE */ + /* move them until CX is ZERO. */ + while (m->R_CX != 0) + { + val2 = fetch_data_word_abs(m,m->R_ES,m->R_DI); + cmp_word(m,m->R_AX,val2); + m->R_CX -= 1; + m->R_DI += inc; + if (ACCESS_FLAG(m,F_ZF)==0) break; + } + m->sysmode &= ~SYSMODE_PREFIX_REPE; + } + else if (m->sysmode & SYSMODE_PREFIX_REPNE) + { + /* REPNE */ + /* move them until CX is ZERO. */ + while (m->R_CX != 0) + { + val2 = fetch_data_word_abs(m,m->R_ES,m->R_DI); + cmp_word(m, m->R_AX,val2); + m->R_CX -= 1; + m->R_DI += inc; + if (ACCESS_FLAG(m,F_ZF)) break; /* zero flag set means equal */ + } + m->sysmode &= ~SYSMODE_PREFIX_REPNE; + } + else + { + val2 = fetch_data_word_abs(m,m->R_ES,m->R_DI); + cmp_word(m, m->R_AX,val2); + m->R_DI += inc; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xb0*/ +static void i86op_mov_byte_AL_IMM(PC_ENV *m) +{ + uint8 imm; + imm = fetch_byte_imm(m); + m->R_AL = imm; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xb1*/ +static void i86op_mov_byte_CL_IMM(PC_ENV *m) +{ + uint8 imm; + imm = fetch_byte_imm(m); + m->R_CL = imm; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xb2*/ +static void i86op_mov_byte_DL_IMM(PC_ENV *m) +{ + uint8 imm; + imm = fetch_byte_imm(m); + m->R_DL = imm; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xb3*/ +static void i86op_mov_byte_BL_IMM(PC_ENV *m) +{ + uint8 imm; + imm = fetch_byte_imm(m); + m->R_BL = imm; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xb4*/ +static void i86op_mov_byte_AH_IMM(PC_ENV *m) +{ + uint8 imm; + imm = fetch_byte_imm(m); + m->R_AH = imm; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xb5*/ +static void i86op_mov_byte_CH_IMM(PC_ENV *m) +{ + uint8 imm; + imm = fetch_byte_imm(m); + m->R_CH = imm; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xb6*/ +static void i86op_mov_byte_DH_IMM(PC_ENV *m) +{ + uint8 imm; + imm = fetch_byte_imm(m); + m->R_DH = imm; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xb7*/ +static void i86op_mov_byte_BH_IMM(PC_ENV *m) +{ + uint8 imm; + imm = fetch_byte_imm(m); + m->R_BH = imm; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xb8*/ +static void i86op_mov_word_AX_IMM(PC_ENV *m) +{ + uint16 imm; + imm = fetch_word_imm(m); + m->R_AX = imm; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xb9*/ +static void i86op_mov_word_CX_IMM(PC_ENV *m) +{ + uint16 imm; + imm = fetch_word_imm(m); + m->R_CX = imm; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xba*/ +static void i86op_mov_word_DX_IMM(PC_ENV *m) +{ + uint16 imm; + imm = fetch_word_imm(m); + m->R_DX = imm; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xbb*/ +static void i86op_mov_word_BX_IMM(PC_ENV *m) +{ + uint16 imm; + imm = fetch_word_imm(m); + m->R_BX = imm; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xbc*/ +static void i86op_mov_word_SP_IMM(PC_ENV *m) +{ + uint16 imm; + imm = fetch_word_imm(m); + m->R_SP = imm; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xbd*/ +static void i86op_mov_word_BP_IMM(PC_ENV *m) +{ + uint16 imm; + imm = fetch_word_imm(m); + m->R_BP = imm; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xbe*/ +static void i86op_mov_word_SI_IMM(PC_ENV *m) +{ + uint16 imm; + imm = fetch_word_imm(m); + m->R_SI = imm; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xbf*/ +static void i86op_mov_word_DI_IMM(PC_ENV *m) +{ + uint16 imm; + imm = fetch_word_imm(m); + m->R_DI = imm; + DECODE_CLEAR_SEGOVR(m); +} + +/* c0 === ILLEGAL OPERAND */ +/* c1 === ILLEGAL OPERAND */ + +/*opcode=0xc2*/ +static void i86op_ret_near_IMM(PC_ENV *m) +{ + uint16 imm; + imm = fetch_word_imm(m); + m->R_IP = pop_word(m); + m->R_SP += imm; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xc3*/ +static void i86op_ret_near(PC_ENV *m) +{ + m->R_IP = pop_word(m); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xc4*/ +static void i86op_les_R_IMM(PC_ENV *m) +{ + uint16 mod,rh,rl; + uint16 *dstreg; + uint16 srcoffset; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + dstreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm00_address(m,rl); + *dstreg = fetch_data_word(m,srcoffset); + m->R_ES = fetch_data_word(m,srcoffset+2); + break; + case 1: + dstreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm01_address(m,rl); + *dstreg = fetch_data_word(m,srcoffset); + m->R_ES = fetch_data_word(m,srcoffset+2); + break; + case 2: + dstreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm10_address(m,rl); + *dstreg = fetch_data_word(m,srcoffset); + m->R_ES = fetch_data_word(m,srcoffset+2); + break; + case 3: /* register to register */ + /* UNDEFINED! */ + ; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xc5*/ +static void i86op_lds_R_IMM(PC_ENV *m) +{ + uint16 mod,rh,rl; + uint16 *dstreg; + uint16 srcoffset; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + dstreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm00_address(m,rl); + *dstreg = fetch_data_word(m,srcoffset); + m->R_DS = fetch_data_word(m,srcoffset+2); + break; + case 1: + dstreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm01_address(m,rl); + *dstreg = fetch_data_word(m,srcoffset); + m->R_DS = fetch_data_word(m,srcoffset+2); + break; + case 2: + dstreg = DECODE_RM_WORD_REGISTER(m,rh); + srcoffset=decode_rm10_address(m,rl); + *dstreg = fetch_data_word(m,srcoffset); + m->R_DS = fetch_data_word(m,srcoffset+2); + break; + case 3: /* register to register */ + /* UNDEFINED! */ + ; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xc6*/ +static void i86op_mov_byte_RM_IMM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg; + uint16 destoffset; + uint8 imm; + FETCH_DECODE_MODRM(m,mod,rh,rl); + if (rh != 0) + { + halt_sys(m); + } + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + imm = fetch_byte_imm(m); + store_data_byte(m,destoffset,imm); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + imm = fetch_byte_imm(m); + store_data_byte(m,destoffset,imm); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + imm = fetch_byte_imm(m); + store_data_byte(m,destoffset,imm); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rl); + imm = fetch_byte_imm(m); + *destreg = imm; + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xc7*/ +static void i86op_mov_word_RM_IMM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg; + uint16 destoffset; + uint16 imm; + FETCH_DECODE_MODRM(m,mod,rh,rl); + if (rh != 0) + { + halt_sys(m); + } + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + imm = fetch_word_imm(m); + store_data_word(m,destoffset,imm); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + imm = fetch_word_imm(m); + store_data_word(m,destoffset,imm); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + imm = fetch_word_imm(m); + store_data_word(m,destoffset,imm); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rl); + imm = fetch_word_imm(m); + *destreg = imm; + break; + } + DECODE_CLEAR_SEGOVR(m); + } + +/*opcode=0xc8 ILLEGAL OP*/ +/*opcode=0xc9 ILLEGAL OP*/ + +/*opcode=0xca*/ +static void i86op_ret_far_IMM(PC_ENV *m) +{ + uint16 imm; + imm = fetch_word_imm(m); + m->R_IP = pop_word(m); + m->R_CS = pop_word(m); + m->R_SP += imm; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xcb*/ +static void i86op_ret_far(PC_ENV *m) +{ + m->R_IP = pop_word(m); + m->R_CS = pop_word(m); + DECODE_CLEAR_SEGOVR(m); +} + +/* opcode=0xcc*/ +static void i86op_int3(PC_ENV *m) +{ + uint16 tmp; + tmp = (uint16) mem_access_word(m, 3 * 4); + /* access the segment register */ + { + tmp = m->R_FLG; + push_word(m, tmp); + CLEAR_FLAG(m, F_IF); + CLEAR_FLAG(m, F_TF); +/* [JCE] If we're interrupting between a segment override (or REP override) + * and the following instruction, decrease IP to get back to the prefix */ + if (m->sysmode & (SYSMODE_SEGMASK | + SYSMODE_PREFIX_REPE | + SYSMODE_PREFIX_REPNE)) + { + --m->R_IP; + } + push_word(m, m->R_CS); + push_word(m, m->R_IP); +/* [JCE] CS and IP were the wrong way round... */ + tmp = mem_access_word(m, 3 * 4); + m->R_IP = tmp; + tmp = mem_access_word(m, 3 * 4 + 2); + m->R_CS = tmp; + } + DECODE_CLEAR_SEGOVR(m); +} + +/* opcode=0xcd*/ +static void i86op_int_IMM(PC_ENV *m) +{ + uint16 tmp; + uint8 intnum; + intnum = fetch_byte_imm(m); + tmp = mem_access_word(m, intnum * 4); + { + tmp = m->R_FLG; + push_word(m, tmp); + CLEAR_FLAG(m, F_IF); + CLEAR_FLAG(m, F_TF); +/* [JCE] If we're interrupting between a segment override (or REP override) + * and the following instruction, decrease IP to get back to the prefix */ + if (m->sysmode & (SYSMODE_SEGMASK | + SYSMODE_PREFIX_REPE | + SYSMODE_PREFIX_REPNE)) + { + --m->R_IP; + } + push_word(m, m->R_CS); + push_word(m, m->R_IP); +/* [JCE] CS and IP were the wrong way round... */ + tmp = mem_access_word(m, intnum * 4); + m->R_IP = tmp; + tmp = mem_access_word(m, intnum * 4 + 2); + m->R_CS = tmp; + } + DECODE_CLEAR_SEGOVR(m); +} + +/* opcode=0xce*/ +static void i86op_into(PC_ENV *m) +{ + uint16 tmp; + if (ACCESS_FLAG(m,F_OF)) + { + tmp = mem_access_word(m, 4 * 4); + { + tmp = m->R_FLG; + push_word(m, tmp); + CLEAR_FLAG(m, F_IF); + CLEAR_FLAG(m, F_TF); +/* [JCE] If we're interrupting between a segment override (or REP override) + * and the following instruction, decrease IP to get back to the prefix */ + if (m->sysmode & (SYSMODE_SEGMASK | + SYSMODE_PREFIX_REPE | + SYSMODE_PREFIX_REPNE)) + { + --m->R_IP; + } + push_word(m, m->R_CS); + push_word(m, m->R_IP); +/* [JCE] CS and IP were the wrong way round... */ + tmp = mem_access_word(m, 4 * 4); + m->R_IP = tmp; + tmp = mem_access_word(m, 4 * 4 + 2); + m->R_CS = tmp; + } + } + DECODE_CLEAR_SEGOVR(m); +} + +/* opcode=0xcf*/ +static void i86op_iret(PC_ENV *m) +{ + m->R_IP = pop_word(m); + m->R_CS = pop_word(m); + m->R_FLG = pop_word(m); + DECODE_CLEAR_SEGOVR(m); +} + +static uint8 (*opcD0_byte_operation[])(PC_ENV *m,uint8 d, uint8 s) = + /* used by opcodes d0 and d2. */ +{ + rol_byte, + ror_byte, + rcl_byte, + rcr_byte, + shl_byte, + shr_byte, + shl_byte, /* sal_byte === shl_byte by definition */ + sar_byte, +}; + +/* opcode=0xd0*/ +static void i86op_opcD0_byte_RM_1(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg; + uint16 destoffset; + uint8 destval; + /* Yet another weirdo special case instruction format. Part of the + opcode held below in "RH". Doubly nested case would + result, except that the decoded instruction + */ + FETCH_DECODE_MODRM(m,mod,rh,rl); + /* know operation, decode the mod byte to find the addressing + mode. */ + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_byte(m,destoffset); + destval = (*opcD0_byte_operation[rh])(m, destval,1); + store_data_byte(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_byte(m,destoffset); + destval = (*opcD0_byte_operation[rh])(m, destval, 1); + store_data_byte(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_byte(m,destoffset); + destval = (*opcD0_byte_operation[rh])(m, destval, 1); + store_data_byte(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rl); + destval = (*opcD0_byte_operation[rh])(m, *destreg, 1); + *destreg = destval; + break; + } + DECODE_CLEAR_SEGOVR(m); + } + +static uint16 (*opcD1_word_operation[])(PC_ENV *m,uint16 s,uint16 d) = + /* used by opcodes d1 and d3. */ +{ rol_word, + ror_word, + rcl_word, + rcr_word, + shl_word, + shr_word, + shl_word, /* sal_byte === shl_byte by definition */ + sar_word, +}; + +/* opcode=0xd1*/ +static void i86op_opcD1_word_RM_1(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg; + uint16 destoffset; + uint16 destval; + /* Yet another weirdo special case instruction format. Part of the + opcode held below in "RH". Doubly nested case would + result, except that the decoded instruction + */ + FETCH_DECODE_MODRM(m,mod,rh,rl); + /* know operation, decode the mod byte to find the addressing + mode. */ + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_word(m,destoffset); + destval = (*opcD1_word_operation[rh])(m, destval,1); + store_data_word(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_word(m,destoffset); + destval = (*opcD1_word_operation[rh])(m, destval, 1); + store_data_word(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_word(m,destoffset); + destval = (*opcD1_word_operation[rh])(m, destval, 1); + store_data_word(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rl); + destval = (*opcD1_word_operation[rh])(m, *destreg, 1); + *destreg = destval; + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/* opcode=0xd2*/ +static void i86op_opcD2_byte_RM_CL(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg; + uint16 destoffset; + uint8 destval; + uint8 amt; + /* Yet another weirdo special case instruction format. Part of the + opcode held below in "RH". Doubly nested case would + result, except that the decoded instruction + */ + FETCH_DECODE_MODRM(m,mod,rh,rl); + amt = m->R_CL; + /* know operation, decode the mod byte to find the addressing + mode. */ + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_byte(m,destoffset); + destval = (*opcD0_byte_operation[rh])(m, destval,amt); + store_data_byte(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_byte(m,destoffset); + destval = (*opcD0_byte_operation[rh])(m, destval, amt); + store_data_byte(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_byte(m,destoffset); + destval = (*opcD0_byte_operation[rh])(m, destval, amt); + store_data_byte(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_BYTE_REGISTER(m,rl); + destval = (*opcD0_byte_operation[rh])(m, *destreg, amt); + *destreg = destval; + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/* opcode=0xd3*/ +static void i86op_opcD3_word_RM_CL(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg; + uint16 destoffset; + uint16 destval; + uint8 amt; + /* Yet another weirdo special case instruction format. Part of the + opcode held below in "RH". Doubly nested case would + result, except that the decoded instruction + */ + FETCH_DECODE_MODRM(m,mod,rh,rl); + amt = m->R_CL; + /* know operation, decode the mod byte to find the addressing + mode. */ + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_word(m,destoffset); + destval = (*opcD1_word_operation[rh])(m, destval, amt); + store_data_word(m,destoffset,destval); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_word(m,destoffset); + destval = (*opcD1_word_operation[rh])(m, destval, amt); + store_data_word(m,destoffset,destval); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_word(m,destoffset); + destval = (*opcD1_word_operation[rh])(m, destval, amt); + store_data_word(m,destoffset,destval); + break; + case 3: /* register to register */ + destreg = DECODE_RM_WORD_REGISTER(m,rl); + *destreg = (*opcD1_word_operation[rh])(m, *destreg, amt); + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +static void sys_fatal(int error, char *fmt, ...) +{ + va_list p; + va_start(p, fmt); + fprintf(stderr, "Fatal error: "); + if (error != 0) + { + fprintf(stderr, "<%d>",error); + fprintf(stderr,"%s",strerror(error)); + } + vfprintf(stderr, fmt, p); + va_end(p); + fprintf(stderr, NLP "Exiting..." NLP); + exit(1); +} + +/* opcode=0xd4*/ +static void i86op_aam(PC_ENV *m) +{ uint8 a; + a = fetch_byte_imm(m); /* this is a stupid encoding. */ + if (a != 10) sys_fatal(0,"error decoding aam" NLP); + /* note the type change here --- returning AL and AH in AX. */ + m->R_AX = aam_word(m,m->R_AL); + DECODE_CLEAR_SEGOVR(m); +} + +/* opcode=0xd5*/ +static void i86op_aad(PC_ENV *m) +{ uint8 a; + a = fetch_byte_imm(m); + m->R_AX = aad_word(m,m->R_AX); + DECODE_CLEAR_SEGOVR(m); +} + +/* opcode=0xd6 ILLEGAL OPCODE */ + +/* opcode=0xd7 */ +static void i86op_xlat(PC_ENV *m) +{ + uint16 addr; + addr = m->R_BX + (uint8)m->R_AL; + m->R_AL = fetch_data_byte(m,addr); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xe0*/ +static void i86op_loopne(PC_ENV *m) +{ + int16 ip; + ip = (int8)fetch_byte_imm(m); + ip += (int16)m->R_IP; + m->R_CX -= 1; + if (m->R_CX != 0 && !ACCESS_FLAG(m,F_ZF)) /* CX != 0 and !ZF */ + m->R_IP = ip; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xe1*/ +static void i86op_loope(PC_ENV *m) +{ + int16 ip; + ip = (int8)fetch_byte_imm(m); + ip += (int16)m->R_IP; + m->R_CX -= 1; + if (m->R_CX != 0 && ACCESS_FLAG(m,F_ZF)) /* CX != 0 and ZF */ + m->R_IP = ip; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xe2*/ +static void i86op_loop(PC_ENV *m) +{ + int16 ip; + ip = (int8)fetch_byte_imm(m); + ip += (int16)m->R_IP; + m->R_CX -= 1; + if (m->R_CX != 0) + m->R_IP = ip; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xe3*/ +static void i86op_jcxz(PC_ENV *m) +{ + int16 offset,target; + /* jump to byte offset if overflow flag is set */ + offset = (int8)fetch_byte_imm(m); /* sign extended ??? */ + target = (int16)m->R_IP + offset; + if (m->R_CX == 0) + m->R_IP = target; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xe4*/ +static void i86op_in_byte_AL_IMM(PC_ENV *m) +{ + uint8 port; + port = (uint8)fetch_byte_imm(m); + m->R_AL = in(port); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xe5*/ +static void i86op_in_word_AX_IMM(PC_ENV *m) +{ + uint8 port; + port = (uint8)fetch_byte_imm(m); + m->R_AX = in(port); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xe6*/ +static void i86op_out_byte_IMM_AL(PC_ENV *m) +{ + uint8 port; + port = (uint8)fetch_byte_imm(m); + out(port, m->R_AL); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xe7*/ +static void i86op_out_word_IMM_AX(PC_ENV *m) +{ + uint8 port; + port = (uint8)fetch_byte_imm(m); + out(port, m->R_AX); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xe8*/ +static void i86op_call_near_IMM(PC_ENV *m) +{ + int16 ip; + /* weird. Thought this was a signed disp! */ + ip = (int16)fetch_word_imm(m); + ip += (int16)m->R_IP; /* CHECK SIGN */ + push_word(m,m->R_IP); + m->R_IP = ip; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xe9*/ +static void i86op_jump_near_IMM(PC_ENV *m) +{ + int ip; + /* weird. Thought this was a signed disp too! */ + ip = (int16)fetch_word_imm(m); + ip += (int16)m->R_IP; /* CHECK SIGN */ + m->R_IP = ip; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xea*/ +static void i86op_jump_far_IMM(PC_ENV *m) +{ + uint16 cs,ip; + ip = fetch_word_imm(m); + cs = fetch_word_imm(m); + m->R_IP = ip; + m->R_CS = cs; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xeb*/ +static void i86op_jump_byte_IMM(PC_ENV *m) +{ + int8 offset; + uint16 target; + offset = (int8) fetch_byte_imm(m); /* CHECK */ +/* printf("jump byte imm offset=%d\n",offset);*/ + target = (int16) m->R_IP + offset; + m->R_IP = target; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xec*/ +static void i86op_in_byte_AL_DX(PC_ENV *m) +{ + m->R_AL = in(m->R_DX); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xed*/ +static void i86op_in_word_AX_DX(PC_ENV *m) +{ + m->R_AX = in(m->R_DX); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xee*/ +static void i86op_out_byte_DX_AL(PC_ENV *m) +{ + out(m->R_DX, m->R_AL); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xef*/ +static void i86op_out_word_DX_AX(PC_ENV *m) +{ + out(m->R_DX, m->R_AX); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xf0*/ +static void i86op_lock(PC_ENV *m) +{ + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xf1 ILLEGAL OPERATION*/ + +/*opcode=0xf2*/ +static void i86op_repne(PC_ENV *m) +{ + m->sysmode |= SYSMODE_PREFIX_REPNE; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xf3*/ +static void i86op_repe(PC_ENV *m) +{ + m->sysmode |= SYSMODE_PREFIX_REPE; + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xf4*/ +static void i86op_halt(PC_ENV *m) +{ + halt_sys(m); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xf5*/ +static void i86op_cmc(PC_ENV *m) +{ + /* complement the carry flag. */ + TOGGLE_FLAG(m,F_CF); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xf6*/ +static void i86op_opcF6_byte_RM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint8 *destreg; + uint16 destoffset; + uint8 destval,srcval; + /* long, drawn out code follows. Double switch for a total + of 32 cases. */ + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: /* mod=00 */ + switch(rh) + { + case 0: /* test byte imm */ + destoffset=decode_rm00_address(m,rl); + srcval = fetch_byte_imm(m); + destval = fetch_data_byte(m,destoffset); + test_byte(m, destval, srcval); + break; + case 1: + halt_sys(m); + break; + case 2: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_byte(m,destoffset); + destval = not_byte(m, destval); + store_data_byte(m,destoffset,destval); + break; + case 3: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_byte(m,destoffset); + destval = neg_byte(m, destval); + store_data_byte(m,destoffset,destval); + break; + case 4: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_byte(m,destoffset); + mul_byte(m, destval); + break; + case 5: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_byte(m,destoffset); + imul_byte(m, destval); + break; + case 6: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_byte(m,destoffset); + div_byte(m, destval); + break; + case 7: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_byte(m,destoffset); + idiv_byte(m, destval); + break; + } + break; /* end mod==00 */ + case 1: /* mod=01 */ + switch(rh) + { + case 0: /* test byte imm */ + destoffset=decode_rm01_address(m,rl); + srcval = fetch_byte_imm(m); + destval = fetch_data_byte(m,destoffset); + test_byte(m, destval, srcval); + break; + case 1: + halt_sys(m); + break; + case 2: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_byte(m,destoffset); + destval = not_byte(m, destval); + store_data_byte(m,destoffset,destval); + break; + case 3: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_byte(m,destoffset); + destval = neg_byte(m, destval); + store_data_byte(m,destoffset,destval); + break; + case 4: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_byte(m,destoffset); + mul_byte(m, destval); + break; + case 5: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_byte(m,destoffset); + imul_byte(m, destval); + break; + case 6: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_byte(m,destoffset); + div_byte(m, destval); + break; + case 7: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_byte(m,destoffset); + idiv_byte(m, destval); + break; + } + break; /* end mod==01 */ + case 2: /* mod=10 */ + switch(rh) + { + case 0: /* test byte imm */ + destoffset=decode_rm10_address(m,rl); + srcval = fetch_byte_imm(m); + destval = fetch_data_byte(m,destoffset); + test_byte(m, destval, srcval); + break; + case 1: + halt_sys(m); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_byte(m,destoffset); + destval = not_byte(m, destval); + store_data_byte(m,destoffset,destval); + break; + case 3: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_byte(m,destoffset); + destval = neg_byte(m, destval); + store_data_byte(m,destoffset,destval); + break; + case 4: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_byte(m,destoffset); + mul_byte(m, destval); + break; + case 5: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_byte(m,destoffset); + imul_byte(m, destval); + break; + case 6: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_byte(m,destoffset); + div_byte(m, destval); + break; + case 7: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_byte(m,destoffset); + idiv_byte(m, destval); + break; + } + break; /* end mod==10 */ + case 3: /* mod=11 */ + switch(rh) + { + case 0: /* test byte imm */ + destreg=DECODE_RM_BYTE_REGISTER(m,rl); + srcval = fetch_byte_imm(m); + test_byte(m, *destreg, srcval); + break; + case 1: + halt_sys(m); + break; + case 2: + destreg=DECODE_RM_BYTE_REGISTER(m,rl); + *destreg = not_byte(m, *destreg); + break; + case 3: + destreg=DECODE_RM_BYTE_REGISTER(m,rl); + *destreg = neg_byte(m, *destreg); + break; + case 4: + destreg=DECODE_RM_BYTE_REGISTER(m,rl); + mul_byte(m, *destreg); /*!!! */ + break; + case 5: + destreg=DECODE_RM_BYTE_REGISTER(m,rl); + imul_byte(m, *destreg); + break; + case 6: + destreg=DECODE_RM_BYTE_REGISTER(m,rl); + div_byte(m, *destreg); + break; + case 7: + destreg=DECODE_RM_BYTE_REGISTER(m,rl); + idiv_byte(m, *destreg); + break; + } + break; /* end mod==11 */ + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xf7*/ +static void i86op_opcF7_word_RM(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 *destreg; + uint16 destoffset; + uint16 destval,srcval; + /* long, drawn out code follows. Double switch for a total + of 32 cases. */ + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: /* mod=00 */ + switch(rh) + { + case 0: /* test word imm */ + destoffset=decode_rm00_address(m,rl); + srcval = fetch_word_imm(m); + destval = fetch_data_word(m,destoffset); + test_word(m, destval, srcval); + break; + case 1: + halt_sys(m); + break; + case 2: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_word(m,destoffset); + destval = not_word(m, destval); + store_data_word(m,destoffset,destval); + break; + case 3: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_word(m,destoffset); + destval = neg_word(m, destval); + store_data_word(m,destoffset,destval); + break; + case 4: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_word(m,destoffset); + mul_word(m, destval); + break; + case 5: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_word(m,destoffset); + imul_word(m, destval); + break; + case 6: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_word(m,destoffset); + div_word(m, destval); + break; + case 7: + destoffset=decode_rm00_address(m,rl); + destval = fetch_data_word(m,destoffset); + idiv_word(m, destval); + break; + } + break; /* end mod==00 */ + case 1: /* mod=01 */ + switch(rh) + { + case 0: /* test word imm */ + destoffset=decode_rm01_address(m,rl); + srcval = fetch_word_imm(m); + destval = fetch_data_word(m,destoffset); + test_word(m, destval, srcval); + break; + case 1: + halt_sys(m); + break; + case 2: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_word(m,destoffset); + destval = not_word(m, destval); + store_data_word(m,destoffset,destval); + break; + case 3: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_word(m,destoffset); + destval = neg_word(m, destval); + store_data_word(m,destoffset,destval); + break; + case 4: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_word(m,destoffset); + mul_word(m, destval); + break; + case 5: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_word(m,destoffset); + imul_word(m, destval); + break; + case 6: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_word(m,destoffset); + div_word(m, destval); + break; + case 7: + destoffset=decode_rm01_address(m,rl); + destval = fetch_data_word(m,destoffset); + idiv_word(m, destval); + break; + } + break; /* end mod==01 */ + case 2: /* mod=10 */ + switch(rh) + { + case 0: /* test word imm */ + destoffset=decode_rm10_address(m,rl); + srcval = fetch_word_imm(m); + destval = fetch_data_word(m,destoffset); + test_word(m, destval, srcval); + break; + case 1: + halt_sys(m); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_word(m,destoffset); + destval = not_word(m, destval); + store_data_word(m,destoffset,destval); + break; + case 3: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_word(m,destoffset); + destval = neg_word(m, destval); + store_data_word(m,destoffset,destval); + break; + case 4: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_word(m,destoffset); + mul_word(m, destval); + break; + case 5: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_word(m,destoffset); + imul_word(m, destval); + break; + case 6: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_word(m,destoffset); + div_word(m, destval); + break; + case 7: + destoffset=decode_rm10_address(m,rl); + destval = fetch_data_word(m,destoffset); + idiv_word(m, destval); + break; + } + break; /* end mod==10 */ + case 3: /* mod=11 */ + switch(rh) + { + case 0: /* test word imm */ + destreg=DECODE_RM_WORD_REGISTER(m,rl); + srcval = fetch_word_imm(m); + test_word(m, *destreg, srcval); + break; + case 1: + halt_sys(m); + break; + case 2: + destreg=DECODE_RM_WORD_REGISTER(m,rl); + *destreg = not_word(m, *destreg); + break; + case 3: + destreg=DECODE_RM_WORD_REGISTER(m,rl); + *destreg = neg_word(m, *destreg); + break; + case 4: + destreg=DECODE_RM_WORD_REGISTER(m,rl); + mul_word(m, *destreg); /*!!! */ + break; + case 5: + destreg=DECODE_RM_WORD_REGISTER(m,rl); + imul_word(m, *destreg); + break; + case 6: + destreg=DECODE_RM_WORD_REGISTER(m,rl); + div_word(m, *destreg); + break; + case 7: + destreg=DECODE_RM_WORD_REGISTER(m,rl); + idiv_word(m, *destreg); + break; + } + break; /* end mod==11 */ + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xf8*/ +static void i86op_clc(PC_ENV *m) +{ + /* clear the carry flag. */ + CLEAR_FLAG(m, F_CF); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xf9*/ +static void i86op_stc(PC_ENV *m) +{ + /* set the carry flag. */ + SET_FLAG(m, F_CF); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xfa*/ +static void i86op_cli(PC_ENV *m) +{ + /* clear interrupts. */ + CLEAR_FLAG(m, F_IF); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xfb*/ +static void i86op_sti(PC_ENV *m) +{ + /* enable interrupts. */ + SET_FLAG(m, F_IF); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xfc*/ +static void i86op_cld(PC_ENV *m) +{ + /* clear interrupts. */ + CLEAR_FLAG(m, F_DF); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xfd*/ +static void i86op_std(PC_ENV *m) +{ + /* clear interrupts. */ + SET_FLAG(m, F_DF); + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xfe*/ +static void i86op_opcFE_byte_RM(PC_ENV *m) +{ + /* Yet another damned special case instruction. */ + uint16 mod,rh,rl; + uint8 destval; + uint16 destoffset; + uint8 *destreg; + /* ARRGH, ANOTHER GODDAMN SPECIAL CASE INSTRUCTION!!! */ + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + switch (rh) + { + case 0: /* inc word ptr ... */ + destval = fetch_data_byte(m,destoffset); + destval = inc_byte(m,destval); + store_data_byte(m,destoffset,destval); + break; + case 1: /* dec word ptr ... */ + destval = fetch_data_byte(m,destoffset); + destval = dec_byte(m,destval); + store_data_byte(m,destoffset,destval); + break; + } + break; + case 1: + destoffset=decode_rm01_address(m,rl); + switch (rh) + { + case 0: + destval = fetch_data_byte(m,destoffset); + destval = inc_byte(m,destval); + store_data_byte(m,destoffset,destval); + break; + case 1: + destval = fetch_data_byte(m,destoffset); + destval = dec_byte(m,destval); + store_data_byte(m,destoffset,destval); + break; + } + break; + case 2: + destoffset=decode_rm10_address(m,rl); + switch (rh) + { + case 0: + destval = fetch_data_byte(m,destoffset); + destval = inc_byte(m,destval); + store_data_byte(m,destoffset,destval); + break; + case 1: + destval = fetch_data_byte(m,destoffset); + destval = dec_byte(m,destval); + store_data_byte(m,destoffset,destval); + break; + } + break; + case 3: + destreg = DECODE_RM_BYTE_REGISTER(m,rl); + switch (rh) + { + case 0: + *destreg = inc_byte(m,*destreg); + break; + case 1: + *destreg = dec_byte(m,*destreg); + break; + } + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/*opcode=0xff*/ +static void i86op_opcFF_word_RM(PC_ENV *m) +{ + uint16 mod,rh,rl; + uint16 destval,destval2; + uint16 destoffset; + uint16 *destreg; + /* ANOTHER DAMN SPECIAL CASE INSTRUCTION!!! */ + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + switch (rh) + { + case 0: /* inc word ptr ... */ + destval = fetch_data_word(m,destoffset); + destval = inc_word(m,destval); + store_data_word(m,destoffset,destval); + break; + case 1: /* dec word ptr ... */ + destval = fetch_data_word(m,destoffset); + destval = dec_word(m,destval); + store_data_word(m,destoffset,destval); + break; + case 2: /* call word ptr ... */ + destval = fetch_data_word(m,destoffset); + push_word(m,m->R_IP); + m->R_IP = destval; + break; + case 3: /* call far ptr ... */ + destval = fetch_data_word(m,destoffset); + destval2 = fetch_data_word(m,destoffset+2); + push_word(m,m->R_CS); + m->R_CS = destval2; + push_word(m,m->R_IP); + m->R_IP = destval; + break; + case 4: /* jmp word ptr ... */ + destval = fetch_data_word(m,destoffset); + m->R_IP = destval; + break; + case 5: /* jmp far ptr ... */ + destval = fetch_data_word(m,destoffset); + destval2 = fetch_data_word(m,destoffset+2); + m->R_IP = destval; + m->R_CS = destval2; + break; + case 6: /* push word ptr ... */ + destval = fetch_data_word(m,destoffset); + push_word(m,destval); + break; + } + break; + case 1: + destoffset=decode_rm01_address(m,rl); + switch (rh) + { + case 0: + destval = fetch_data_word(m,destoffset); + destval = inc_word(m,destval); + store_data_word(m,destoffset,destval); + break; + case 1: + destval = fetch_data_word(m,destoffset); + destval = dec_word(m,destval); + store_data_word(m,destoffset,destval); + break; + case 2: /* call word ptr ... */ + destval = fetch_data_word(m,destoffset); + push_word(m,m->R_IP); + m->R_IP = destval; + break; + case 3: /* call far ptr ... */ + destval = fetch_data_word(m,destoffset); + destval2 = fetch_data_word(m,destoffset+2); + push_word(m,m->R_CS); + m->R_CS = destval2; + push_word(m,m->R_IP); + m->R_IP = destval; + break; + case 4: /* jmp word ptr ... */ + destval = fetch_data_word(m,destoffset); + m->R_IP = destval; + break; + case 5: /* jmp far ptr ... */ + destval = fetch_data_word(m,destoffset); + destval2 = fetch_data_word(m,destoffset+2); + m->R_IP = destval; + m->R_CS = destval2; + break; + case 6: /* push word ptr ... */ + destval = fetch_data_word(m,destoffset); + push_word(m,destval); + break; + } + break; + case 2: + destoffset=decode_rm10_address(m,rl); + switch (rh) + { + case 0: + destval = fetch_data_word(m,destoffset); + destval = inc_word(m,destval); + store_data_word(m,destoffset,destval); + break; + case 1: + destval = fetch_data_word(m,destoffset); + destval = dec_word(m,destval); + store_data_word(m,destoffset,destval); + break; + case 2: /* call word ptr ... */ + destval = fetch_data_word(m,destoffset); + push_word(m,m->R_IP); + m->R_IP = destval; + break; + case 3: /* call far ptr ... */ + destval = fetch_data_word(m,destoffset); + destval2 = fetch_data_word(m,destoffset+2); + push_word(m,m->R_CS); + m->R_CS = destval2; + push_word(m,m->R_IP); + m->R_IP = destval; + break; + case 4: /* jmp word ptr ... */ + destval = fetch_data_word(m,destoffset); + m->R_IP = destval; + break; + case 5: /* jmp far ptr ... */ + destval = fetch_data_word(m,destoffset); + destval2 = fetch_data_word(m,destoffset+2); + m->R_IP = destval; + m->R_CS = destval2; + break; + case 6: /* push word ptr ... */ + destval = fetch_data_word(m,destoffset); + push_word(m,destval); + break; + } + break; + case 3: + destreg = DECODE_RM_WORD_REGISTER(m,rl); + switch (rh) + { + case 0: + *destreg = inc_word(m,*destreg); + break; + case 1: + *destreg = dec_word(m,*destreg); + break; + case 2: /* call word ptr ... */ + push_word(m,m->R_IP); + m->R_IP = *destreg; + break; + case 3: /* jmp far ptr ... */ + halt_sys(m); + break; + case 4: /* jmp ... */ + m->R_IP = (uint16)(*destreg); + break; + case 5: /* jmp far ptr ... */ + halt_sys(m); + break; + case 6: + push_word(m,*destreg); + break; + } + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/* opcode=0xd8*/ +static void i86op_esc_coprocess_d8(PC_ENV *m) +{ + DECODE_CLEAR_SEGOVR(m); +} + +/* opcode=0xd9*/ +static void i86op_esc_coprocess_d9(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 destoffset; + uint8 stkelem; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + break; + case 3: /* register to register */ + stkelem = (uint8) rl; + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/* opcode=0xda*/ +static void i86op_esc_coprocess_da(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 destoffset; + uint8 stkelem; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + break; + case 3: /* register to register */ + stkelem = (uint8) rl; + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/* opcode=0xdb*/ +static void i86op_esc_coprocess_db(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 destoffset; +/* uint8 stkelem;*/ + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + break; + case 3: /* register to register */ + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/* opcode=0xdc*/ +static void i86op_esc_coprocess_dc(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 destoffset; + uint8 stkelem; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + break; + case 3: /* register to register */ + stkelem = (uint8) rl; + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/* opcode=0xdd*/ +static void i86op_esc_coprocess_dd(PC_ENV *m) +{ + uint16 mod,rl,rh; + uint16 destoffset; + uint8 stkelem; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + break; + case 3: /* register to register */ + stkelem = (uint8) rl; + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/* opcode=0xde*/ +static void i86op_esc_coprocess_de(PC_ENV *m) + { + uint16 mod,rl,rh; + uint16 destoffset; + uint8 stkelem; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + break; + case 3: /* register to register */ + stkelem = (uint8) rl; + break; + } + DECODE_CLEAR_SEGOVR(m); +} + +/* opcode=0xdf*/ +static void i86op_esc_coprocess_df(PC_ENV *m) + { + uint16 mod,rl,rh; + uint16 destoffset; + uint8 stkelem; + FETCH_DECODE_MODRM(m,mod,rh,rl); + switch (mod) + { + case 0: + destoffset=decode_rm00_address(m,rl); + break; + case 1: + destoffset=decode_rm01_address(m,rl); + break; + case 2: + destoffset=decode_rm10_address(m,rl); + break; + case 3: /* register to register */ + stkelem = (uint8) rl; + break; + } + DECODE_CLEAR_SEGOVR(m); + } + +/* OPERAND TABLE */ + +OP i86_optab[256] = { + +/* 0x00 */ i86op_add_byte_RM_R, +/* 0x01 */ i86op_add_word_RM_R, +/* 0x02 */ i86op_add_byte_R_RM, +/* 0x03 */ i86op_add_word_R_RM, +/* 0x04 */ i86op_add_byte_AL_IMM, +/* 0x05 */ i86op_add_word_AX_IMM, +/* 0x06 */ i86op_push_ES, +/* 0x07 */ i86op_pop_ES, + +/* 0x08 */ i86op_or_byte_RM_R, +/* 0x09 */ i86op_or_word_RM_R, +/* 0x0a */ i86op_or_byte_R_RM, +/* 0x0b */ i86op_or_word_R_RM, +/* 0x0c */ i86op_or_byte_AL_IMM, +/* 0x0d */ i86op_or_word_AX_IMM, +/* 0x0e */ i86op_push_CS, +/* 0x0f */ i86op_illegal_op, + +/* 0x10 */ i86op_adc_byte_RM_R, +/* 0x11 */ i86op_adc_word_RM_R, +/* 0x12 */ i86op_adc_byte_R_RM, +/* 0x13 */ i86op_adc_word_R_RM, +/* 0x14 */ i86op_adc_byte_AL_IMM, +/* 0x15 */ i86op_adc_word_AX_IMM, +/* 0x16 */ i86op_push_SS, +/* 0x17 */ i86op_pop_SS, + +/* 0x18 */ i86op_sbb_byte_RM_R, +/* 0x19 */ i86op_sbb_word_RM_R, +/* 0x1a */ i86op_sbb_byte_R_RM, +/* 0x1b */ i86op_sbb_word_R_RM, +/* 0x1c */ i86op_sbb_byte_AL_IMM, +/* 0x1d */ i86op_sbb_word_AX_IMM, +/* 0x1e */ i86op_push_DS, +/* 0x1f */ i86op_pop_DS, + +/* 0x20 */ i86op_and_byte_RM_R, +/* 0x21 */ i86op_and_word_RM_R, +/* 0x22 */ i86op_and_byte_R_RM, +/* 0x23 */ i86op_and_word_R_RM, +/* 0x24 */ i86op_and_byte_AL_IMM, +/* 0x25 */ i86op_and_word_AX_IMM, +/* 0x26 */ i86op_segovr_ES, +/* 0x27 */ i86op_daa, + +/* 0x28 */ i86op_sub_byte_RM_R, +/* 0x29 */ i86op_sub_word_RM_R, +/* 0x2a */ i86op_sub_byte_R_RM, +/* 0x2b */ i86op_sub_word_R_RM, +/* 0x2c */ i86op_sub_byte_AL_IMM, +/* 0x2d */ i86op_sub_word_AX_IMM, +/* 0x2e */ i86op_segovr_CS, +/* 0x2f */ i86op_das, + +/* 0x30 */ i86op_xor_byte_RM_R, +/* 0x31 */ i86op_xor_word_RM_R, +/* 0x32 */ i86op_xor_byte_R_RM, +/* 0x33 */ i86op_xor_word_R_RM, +/* 0x34 */ i86op_xor_byte_AL_IMM, +/* 0x35 */ i86op_xor_word_AX_IMM, +/* 0x36 */ i86op_segovr_SS, +/* 0x37 */ i86op_aaa, + +/* 0x38 */ i86op_cmp_byte_RM_R, +/* 0x39 */ i86op_cmp_word_RM_R, +/* 0x3a */ i86op_cmp_byte_R_RM, +/* 0x3b */ i86op_cmp_word_R_RM, +/* 0x3c */ i86op_cmp_byte_AL_IMM, +/* 0x3d */ i86op_cmp_word_AX_IMM, +/* 0x3e */ i86op_segovr_DS, +/* 0x3f */ i86op_aas, + +/* 0x40 */ i86op_inc_AX, +/* 0x41 */ i86op_inc_CX, +/* 0x42 */ i86op_inc_DX, +/* 0x43 */ i86op_inc_BX, +/* 0x44 */ i86op_inc_SP, +/* 0x45 */ i86op_inc_BP, +/* 0x46 */ i86op_inc_SI, +/* 0x47 */ i86op_inc_DI, + +/* 0x48 */ i86op_dec_AX, +/* 0x49 */ i86op_dec_CX, +/* 0x4a */ i86op_dec_DX, +/* 0x4b */ i86op_dec_BX, +/* 0x4c */ i86op_dec_SP, +/* 0x4d */ i86op_dec_BP, +/* 0x4e */ i86op_dec_SI, +/* 0x4f */ i86op_dec_DI, + +/* 0x50 */ i86op_push_AX, +/* 0x51 */ i86op_push_CX, +/* 0x52 */ i86op_push_DX, +/* 0x53 */ i86op_push_BX, +/* 0x54 */ i86op_push_SP, +/* 0x55 */ i86op_push_BP, +/* 0x56 */ i86op_push_SI, +/* 0x57 */ i86op_push_DI, + +/* 0x58 */ i86op_pop_AX, +/* 0x59 */ i86op_pop_CX, +/* 0x5a */ i86op_pop_DX, +/* 0x5b */ i86op_pop_BX, +/* 0x5c */ i86op_pop_SP, +/* 0x5d */ i86op_pop_BP, +/* 0x5e */ i86op_pop_SI, +/* 0x5f */ i86op_pop_DI, + +/* 0x60 */ i86op_illegal_op, +/* 0x61 */ i86op_illegal_op, +/* 0x62 */ i86op_illegal_op, +/* 0x63 */ i86op_illegal_op, +/* 0x64 */ i86op_illegal_op, +/* 0x65 */ i86op_illegal_op, +/* 0x66 */ i86op_illegal_op, +/* 0x67 */ i86op_illegal_op, + +/* 0x68 */ i86op_illegal_op, +/* 0x69 */ i86op_illegal_op, +/* 0x6a */ i86op_illegal_op, +/* 0x6b */ i86op_illegal_op, +/* 0x6c */ i86op_illegal_op, +/* 0x6d */ i86op_illegal_op, +/* 0x6e */ i86op_illegal_op, +/* 0x6f */ i86op_illegal_op, + +/* 0x70 */ i86op_jump_near_O, +/* 0x71 */ i86op_jump_near_NO, +/* 0x72 */ i86op_jump_near_B, +/* 0x73 */ i86op_jump_near_NB, +/* 0x74 */ i86op_jump_near_Z, +/* 0x75 */ i86op_jump_near_NZ, +/* 0x76 */ i86op_jump_near_BE, +/* 0x77 */ i86op_jump_near_NBE, + +/* 0x78 */ i86op_jump_near_S, +/* 0x79 */ i86op_jump_near_NS, +/* 0x7a */ i86op_jump_near_P, +/* 0x7b */ i86op_jump_near_NP, +/* 0x7c */ i86op_jump_near_L, +/* 0x7d */ i86op_jump_near_NL, +/* 0x7e */ i86op_jump_near_LE, +/* 0x7f */ i86op_jump_near_NLE, + +/* 0x80 */ i86op_opc80_byte_RM_IMM, +/* 0x81 */ i86op_opc81_word_RM_IMM, +/* 0x82 */ i86op_opc82_byte_RM_IMM, +/* 0x83 */ i86op_opc83_word_RM_IMM, +/* 0x84 */ i86op_test_byte_RM_R, +/* 0x85 */ i86op_test_word_RM_R, +/* 0x86 */ i86op_xchg_byte_RM_R, +/* 0x87 */ i86op_xchg_word_RM_R, + +/* 0x88 */ i86op_mov_byte_RM_R, +/* 0x89 */ i86op_mov_word_RM_R, +/* 0x8a */ i86op_mov_byte_R_RM, +/* 0x8b */ i86op_mov_word_R_RM, +/* 0x8c */ i86op_mov_word_RM_SR, +/* 0x8d */ i86op_lea_word_R_M, +/* 0x8e */ i86op_mov_word_SR_RM, +/* 0x8f */ i86op_pop_RM, + +/* 0x90 */ i86op_nop, +/* 0x91 */ i86op_xchg_word_AX_CX, +/* 0x92 */ i86op_xchg_word_AX_DX, +/* 0x93 */ i86op_xchg_word_AX_BX, +/* 0x94 */ i86op_xchg_word_AX_SP, +/* 0x95 */ i86op_xchg_word_AX_BP , +/* 0x96 */ i86op_xchg_word_AX_SI , +/* 0x97 */ i86op_xchg_word_AX_DI , + +/* 0x98 */ i86op_cbw, +/* 0x99 */ i86op_cwd, +/* 0x9a */ i86op_call_far_IMM, +/* 0x9b */ i86op_wait, +/* 0x9c */ i86op_pushf_word, +/* 0x9d */ i86op_popf_word, +/* 0x9e */ i86op_sahf, +/* 0x9f */ i86op_lahf, + +/* 0xa0 */ i86op_mov_AL_M_IMM, +/* 0xa1 */ i86op_mov_AX_M_IMM, +/* 0xa2 */ i86op_mov_M_AL_IMM, +/* 0xa3 */ i86op_mov_M_AX_IMM, +/* 0xa4 */ i86op_movs_byte, +/* 0xa5 */ i86op_movs_word, +/* 0xa6 */ i86op_cmps_byte, +/* 0xa7 */ i86op_cmps_word, +/* 0xa8 */ i86op_test_AL_IMM, +/* 0xa9 */ i86op_test_AX_IMM, +/* 0xaa */ i86op_stos_byte, +/* 0xab */ i86op_stos_word, +/* 0xac */ i86op_lods_byte, +/* 0xad */ i86op_lods_word, +/* 0xac */ i86op_scas_byte, +/* 0xad */ i86op_scas_word, + +/* 0xb0 */ i86op_mov_byte_AL_IMM, +/* 0xb1 */ i86op_mov_byte_CL_IMM, +/* 0xb2 */ i86op_mov_byte_DL_IMM, +/* 0xb3 */ i86op_mov_byte_BL_IMM, +/* 0xb4 */ i86op_mov_byte_AH_IMM, +/* 0xb5 */ i86op_mov_byte_CH_IMM, +/* 0xb6 */ i86op_mov_byte_DH_IMM, +/* 0xb7 */ i86op_mov_byte_BH_IMM, + +/* 0xb8 */ i86op_mov_word_AX_IMM, +/* 0xb9 */ i86op_mov_word_CX_IMM, +/* 0xba */ i86op_mov_word_DX_IMM, +/* 0xbb */ i86op_mov_word_BX_IMM, +/* 0xbc */ i86op_mov_word_SP_IMM, +/* 0xbd */ i86op_mov_word_BP_IMM, +/* 0xbe */ i86op_mov_word_SI_IMM, +/* 0xbf */ i86op_mov_word_DI_IMM, + +/* 0xc0 */ i86op_illegal_op, +/* 0xc1 */ i86op_illegal_op, +/* 0xc2 */ i86op_ret_near_IMM, +/* 0xc3 */ i86op_ret_near, +/* 0xc4 */ i86op_les_R_IMM, +/* 0xc5 */ i86op_lds_R_IMM, +/* 0xc6 */ i86op_mov_byte_RM_IMM, +/* 0xc7 */ i86op_mov_word_RM_IMM, +/* 0xc8 */ i86op_illegal_op, +/* 0xc9 */ i86op_illegal_op, +/* 0xca */ i86op_ret_far_IMM, +/* 0xcb */ i86op_ret_far, +/* 0xcc */ i86op_int3, +/* 0xcd */ i86op_int_IMM, +/* 0xce */ i86op_into, +/* 0xcf */ i86op_iret, + +/* 0xd0 */ i86op_opcD0_byte_RM_1, +/* 0xd1 */ i86op_opcD1_word_RM_1, +/* 0xd2 */ i86op_opcD2_byte_RM_CL, +/* 0xd3 */ i86op_opcD3_word_RM_CL, +/* 0xd4 */ i86op_aam, +/* 0xd5 */ i86op_aad, +/* 0xd6 */ i86op_illegal_op, +/* 0xd7 */ i86op_xlat, +/* 0xd8 */ i86op_esc_coprocess_d8, +/* 0xd9 */ i86op_esc_coprocess_d9, +/* 0xda */ i86op_esc_coprocess_da, +/* 0xdb */ i86op_esc_coprocess_db, +/* 0xdc */ i86op_esc_coprocess_dc, +/* 0xdd */ i86op_esc_coprocess_dd, +/* 0xde */ i86op_esc_coprocess_de, +/* 0xdf */ i86op_esc_coprocess_df, + +/* 0xe0 */ i86op_loopne, +/* 0xe1 */ i86op_loope, +/* 0xe2 */ i86op_loop, +/* 0xe3 */ i86op_jcxz, +/* 0xe4 */ i86op_in_byte_AL_IMM, +/* 0xe5 */ i86op_in_word_AX_IMM, +/* 0xe6 */ i86op_out_byte_IMM_AL, +/* 0xe7 */ i86op_out_word_IMM_AX, + +/* 0xe8 */ i86op_call_near_IMM, +/* 0xe9 */ i86op_jump_near_IMM, +/* 0xea */ i86op_jump_far_IMM, +/* 0xeb */ i86op_jump_byte_IMM, +/* 0xec */ i86op_in_byte_AL_DX, +/* 0xed */ i86op_in_word_AX_DX, +/* 0xee */ i86op_out_byte_DX_AL, +/* 0xef */ i86op_out_word_DX_AX, + +/* 0xf0 */ i86op_lock, +/* 0xf1 */ i86op_illegal_op, +/* 0xf2 */ i86op_repne, +/* 0xf3 */ i86op_repe, +/* 0xf4 */ i86op_halt, +/* 0xf5 */ i86op_cmc, +/* 0xf6 */ i86op_opcF6_byte_RM, +/* 0xf7 */ i86op_opcF7_word_RM, + +/* 0xf8 */ i86op_clc, +/* 0xf9 */ i86op_stc, +/* 0xfa */ i86op_cli, +/* 0xfb */ i86op_sti, +/* 0xfc */ i86op_cld, +/* 0xfd */ i86op_std, +/* 0xfe */ i86op_opcFE_byte_RM, +/* 0xff */ i86op_opcFF_word_RM, + +}; diff --git a/AltairZ80/i86_prim_ops.c b/AltairZ80/i86_prim_ops.c new file mode 100644 index 00000000..a1fb769d --- /dev/null +++ b/AltairZ80/i86_prim_ops.c @@ -0,0 +1,1539 @@ +/* + * Dos/PC Emulator + * Copyright (C) 1991 Jim Hudgens + * + * + * The file is part of GDE. + * + * GDE is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * GDE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GDE; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "altairz80_defs.h" +#include "i86.h" + +extern uint32 GetBYTEExtended(register uint32 Addr); +extern void PutBYTEExtended(register uint32 Addr, const register uint32 Value); + +/* $Log: i86_prim_ops.c,v $ + * Revision 0.9 2003-01-10 23:33:10 jce + * fixed some more warnings under gcc -Wall + * + * Revision 0.8 1992/04/11 21:58:13 hudgens + * fixed some code causing warnings under gcc -Wall + * + * Revision 0.7 1991/07/30 02:04:34 hudgens + * added copyright. + * + * Revision 0.6 1991/07/21 16:50:37 hudgens + * fixed all flags in the bit shift and rotate instructions so that they + * finally agree. + * Also fixed the flags associated with IMUL and MUL instructions. + * + * Revision 0.5 1991/07/21 01:28:16 hudgens + * added support for aad and aam primitives. + * + * Revision 0.4 1991/07/20 22:26:25 hudgens + * fixed problem with sign extension in subroutine mem_access_word. + * + * Revision 0.3 1991/07/17 03:48:22 hudgens + * fixed bugs having to do with the setting of flags in the + * shift and rotate operations. Also, fixed sign extension problem + * with push_word and pop_word. + * + * Revision 0.2 1991/04/01 02:36:00 hudgens + * Fixed several nasty bugs dealing with flag setting in the subroutines + * sub_byte, sub_word, sbb_byte, sbb_word, and test_word. The results + * now agree with the PC on both of the testaopb and testaopw tests. + * + * Revision 0.1 1991/03/30 21:13:37 hudgens + * Initial checkin. + * + * + */ + +/* [JCE] Stop gcc -Wall complaining */ +void i86_intr_raise(PC_ENV *m, uint8 intrnum); + +/* the following table was generated using the following + code (running on an IBM AT, Turbo C++ 2.0), for all values of i + between 0 and 255. AL is loaded with i's value, and then the + operation "and al,al" sets the parity flag. The flags are pushed + onto the stack, and then popped back into AX. Then AX is + returned. So the value of each table entry represents the + parity of its index into the table. This results in a somewhat + faster mechanism for parity calculations than the straightforward + method. + andflags(i,res) int *res; { + int flags; + _AX = i; asm and al,al; asm pushf; *res = _AX; + asm pop ax; flags = _AX; return flags; + } + */ + +char parity_tab[] = { +/*0*/ 1, /*1*/ 0, /*2*/ 0, /*3*/ 1, +/*4*/ 0, /*5*/ 1, /*6*/ 1, /*7*/ 0, +/*8*/ 0, /*9*/ 1, /*a*/ 1, /*b*/ 0, +/*c*/ 1, /*d*/ 0, /*e*/ 0, /*f*/ 1, +/*10*/ 0, /*11*/ 1, /*12*/ 1, /*13*/ 0, +/*14*/ 1, /*15*/ 0, /*16*/ 0, /*17*/ 1, +/*18*/ 1, /*19*/ 0, /*1a*/ 0, /*1b*/ 1, +/*1c*/ 0, /*1d*/ 1, /*1e*/ 1, /*1f*/ 0, +/*20*/ 0, /*21*/ 1, /*22*/ 1, /*23*/ 0, +/*24*/ 1, /*25*/ 0, /*26*/ 0, /*27*/ 1, +/*28*/ 1, /*29*/ 0, /*2a*/ 0, /*2b*/ 1, +/*2c*/ 0, /*2d*/ 1, /*2e*/ 1, /*2f*/ 0, +/*30*/ 1, /*31*/ 0, /*32*/ 0, /*33*/ 1, +/*34*/ 0, /*35*/ 1, /*36*/ 1, /*37*/ 0, +/*38*/ 0, /*39*/ 1, /*3a*/ 1, /*3b*/ 0, +/*3c*/ 1, /*3d*/ 0, /*3e*/ 0, /*3f*/ 1, +/*40*/ 0, /*41*/ 1, /*42*/ 1, /*43*/ 0, +/*44*/ 1, /*45*/ 0, /*46*/ 0, /*47*/ 1, +/*48*/ 1, /*49*/ 0, /*4a*/ 0, /*4b*/ 1, +/*4c*/ 0, /*4d*/ 1, /*4e*/ 1, /*4f*/ 0, +/*50*/ 1, /*51*/ 0, /*52*/ 0, /*53*/ 1, +/*54*/ 0, /*55*/ 1, /*56*/ 1, /*57*/ 0, +/*58*/ 0, /*59*/ 1, /*5a*/ 1, /*5b*/ 0, +/*5c*/ 1, /*5d*/ 0, /*5e*/ 0, /*5f*/ 1, +/*60*/ 1, /*61*/ 0, /*62*/ 0, /*63*/ 1, +/*64*/ 0, /*65*/ 1, /*66*/ 1, /*67*/ 0, +/*68*/ 0, /*69*/ 1, /*6a*/ 1, /*6b*/ 0, +/*6c*/ 1, /*6d*/ 0, /*6e*/ 0, /*6f*/ 1, +/*70*/ 0, /*71*/ 1, /*72*/ 1, /*73*/ 0, +/*74*/ 1, /*75*/ 0, /*76*/ 0, /*77*/ 1, +/*78*/ 1, /*79*/ 0, /*7a*/ 0, /*7b*/ 1, +/*7c*/ 0, /*7d*/ 1, /*7e*/ 1, /*7f*/ 0, +/*80*/ 0, /*81*/ 1, /*82*/ 1, /*83*/ 0, +/*84*/ 1, /*85*/ 0, /*86*/ 0, /*87*/ 1, +/*88*/ 1, /*89*/ 0, /*8a*/ 0, /*8b*/ 1, +/*8c*/ 0, /*8d*/ 1, /*8e*/ 1, /*8f*/ 0, +/*90*/ 1, /*91*/ 0, /*92*/ 0, /*93*/ 1, +/*94*/ 0, /*95*/ 1, /*96*/ 1, /*97*/ 0, +/*98*/ 0, /*99*/ 1, /*9a*/ 1, /*9b*/ 0, +/*9c*/ 1, /*9d*/ 0, /*9e*/ 0, /*9f*/ 1, +/*a0*/ 1, /*a1*/ 0, /*a2*/ 0, /*a3*/ 1, +/*a4*/ 0, /*a5*/ 1, /*a6*/ 1, /*a7*/ 0, +/*a8*/ 0, /*a9*/ 1, /*aa*/ 1, /*ab*/ 0, +/*ac*/ 1, /*ad*/ 0, /*ae*/ 0, /*af*/ 1, +/*b0*/ 0, /*b1*/ 1, /*b2*/ 1, /*b3*/ 0, +/*b4*/ 1, /*b5*/ 0, /*b6*/ 0, /*b7*/ 1, +/*b8*/ 1, /*b9*/ 0, /*ba*/ 0, /*bb*/ 1, +/*bc*/ 0, /*bd*/ 1, /*be*/ 1, /*bf*/ 0, +/*c0*/ 1, /*c1*/ 0, /*c2*/ 0, /*c3*/ 1, +/*c4*/ 0, /*c5*/ 1, /*c6*/ 1, /*c7*/ 0, +/*c8*/ 0, /*c9*/ 1, /*ca*/ 1, /*cb*/ 0, +/*cc*/ 1, /*cd*/ 0, /*ce*/ 0, /*cf*/ 1, +/*d0*/ 0, /*d1*/ 1, /*d2*/ 1, /*d3*/ 0, +/*d4*/ 1, /*d5*/ 0, /*d6*/ 0, /*d7*/ 1, +/*d8*/ 1, /*d9*/ 0, /*da*/ 0, /*db*/ 1, +/*dc*/ 0, /*dd*/ 1, /*de*/ 1, /*df*/ 0, +/*e0*/ 0, /*e1*/ 1, /*e2*/ 1, /*e3*/ 0, +/*e4*/ 1, /*e5*/ 0, /*e6*/ 0, /*e7*/ 1, +/*e8*/ 1, /*e9*/ 0, /*ea*/ 0, /*eb*/ 1, +/*ec*/ 0, /*ed*/ 1, /*ee*/ 1, /*ef*/ 0, +/*f0*/ 1, /*f1*/ 0, /*f2*/ 0, /*f3*/ 1, +/*f4*/ 0, /*f5*/ 1, /*f6*/ 1, /*f7*/ 0, +/*f8*/ 0, /*f9*/ 1, /*fa*/ 1, /*fb*/ 0, +/*fc*/ 1, /*fd*/ 0, /*fe*/ 0, /*ff*/ 1, +}; + +char xor_0x3_tab[] = { 0, 1, 1, 0 }; + +/* CARRY CHAIN CALCULATION. + This represents a somewhat expensive calculation which is + apparently required to emulate the setting of the OF and + AF flag. The latter is not so important, but the former is. + The overflow flag is the XOR of the top two bits of the + carry chain for an addition (similar for subtraction). + Since we do not want to simulate the addition in a bitwise + manner, we try to calculate the carry chain given the + two operands and the result. + + So, given the following table, which represents the + addition of two bits, we can derive a formula for + the carry chain. + + a b cin r cout + 0 0 0 0 0 + 0 0 1 1 0 + 0 1 0 1 0 + 0 1 1 0 1 + 1 0 0 1 0 + 1 0 1 0 1 + 1 1 0 0 1 + 1 1 1 1 1 + + Construction of table for cout: + + ab + r \ 00 01 11 10 + |------------------ + 0 | 0 1 1 1 + 1 | 0 0 1 0 + + By inspection, one gets: cc = ab + r'(a + b) + + That represents alot of operations, but NO CHOICE.... + +BORROW CHAIN CALCULATION. + The following table represents the + subtraction of two bits, from which we can derive a formula for + the borrow chain. + + a b bin r bout + 0 0 0 0 0 + 0 0 1 1 1 + 0 1 0 1 1 + 0 1 1 0 1 + 1 0 0 1 0 + 1 0 1 0 0 + 1 1 0 0 0 + 1 1 1 1 1 + + Construction of table for cout: + + ab + r \ 00 01 11 10 + |------------------ + 0 | 0 1 0 0 + 1 | 1 1 1 0 + + By inspection, one gets: bc = a'b + r(a' + b) + + */ + +uint8 aad_word(PC_ENV *m, uint16 d) +{ + uint16 l; + uint8 hb,lb; + hb = (d>>8)&0xff; + lb = (d&0xff); + l = lb + 10 * hb; + CONDITIONAL_SET_FLAG(l & 0x80, m, F_SF); + CONDITIONAL_SET_FLAG(l == 0, m, F_ZF); + CONDITIONAL_SET_FLAG(parity_tab[l & 0xff], m, F_PF); + return (uint8) l; +} + +uint16 aam_word(PC_ENV *m, uint8 d) +{ + uint16 h,l; + h = d / 10; + l = d % 10; + l |= (h<<8); + CONDITIONAL_SET_FLAG(l & 0x80, m, F_SF); + CONDITIONAL_SET_FLAG(l == 0, m, F_ZF); + CONDITIONAL_SET_FLAG(parity_tab[l & 0xff], m, F_PF); + return l; +} + +uint8 adc_byte(PC_ENV *m, uint8 d, uint8 s) +{ + register uint16 res; /* all operands in native machine order */ + register uint16 cc; + if (ACCESS_FLAG(m,F_CF) ) + res = 1 + d + s; + else + res = d + s; + CONDITIONAL_SET_FLAG(res & 0x100, m, F_CF); + CONDITIONAL_SET_FLAG((res&0xff)==0, m, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80, m, F_SF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + /* calculate the carry chain SEE NOTE AT TOP.*/ + cc = (s & d) | ((~res) & (s | d)); + CONDITIONAL_SET_FLAG(xor_0x3_tab[(cc>>6)&0x3], m, F_OF); + CONDITIONAL_SET_FLAG(cc&0x8, m, F_AF); + return (uint8) res; +} + +uint16 adc_word(PC_ENV *m, uint16 d, uint16 s) +{ + register uint32 res; /* all operands in native machine order */ + register uint32 cc; + if (ACCESS_FLAG(m,F_CF) ) + res = 1 + d + s; + else + res = d + s; + /* set the carry flag to be bit 8 */ + CONDITIONAL_SET_FLAG(res & 0x10000, m, F_CF); + CONDITIONAL_SET_FLAG((res&0xffff)==0, m, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, m, F_SF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + /* calculate the carry chain SEE NOTE AT TOP.*/ + cc = (s & d) | ((~res) & (s | d)); + CONDITIONAL_SET_FLAG(xor_0x3_tab[(cc>>14)&0x3], m, F_OF); + CONDITIONAL_SET_FLAG(cc&0x8, m, F_AF); + return res; +} + +/* Given flags=f, and bytes d (dest) and s (source) + perform the add and set the flags and the result back to + *d. USE NATIVE MACHINE ORDER... +*/ +uint8 add_byte(PC_ENV *m, uint8 d, uint8 s) +{ + register uint16 res; /* all operands in native machine order */ + register uint16 cc; + res = d + s; + /* set the carry flag to be bit 8 */ + CONDITIONAL_SET_FLAG(res & 0x100, m, F_CF); + CONDITIONAL_SET_FLAG((res&0xff)==0, m, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80, m, F_SF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + /* calculate the carry chain SEE NOTE AT TOP.*/ + cc = (s & d) | ((~res) & (s | d)); + CONDITIONAL_SET_FLAG(xor_0x3_tab[(cc>>6)&0x3], m, F_OF); + CONDITIONAL_SET_FLAG(cc&0x8, m, F_AF); + return (uint8) res; +} + +/* Given flags=f, and bytes d (dest) and s (source) + perform the add and set the flags and the result back to + *d. USE NATIVE MACHINE ORDER... +*/ +uint16 add_word(PC_ENV *m, uint16 d, uint16 s) +{ + register uint32 res; /* all operands in native machine order */ + register uint32 cc; + res = d + s; + /* set the carry flag to be bit 8 */ + CONDITIONAL_SET_FLAG(res & 0x10000, m, F_CF); + CONDITIONAL_SET_FLAG((res&0xffff)==0, m, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, m, F_SF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + /* calculate the carry chain SEE NOTE AT TOP.*/ + cc = (s & d) | ((~res) & (s | d)); + CONDITIONAL_SET_FLAG(xor_0x3_tab[(cc>>14)&0x3], m, F_OF); + CONDITIONAL_SET_FLAG(cc&0x8, m, F_AF); + return res; +} + +/* + Flags m->R_FLG, dest *d, source *s, do a bitwise and of the + source and destination, and then store back to the + destination. Size=byte. +*/ +uint8 and_byte(PC_ENV *m, uint8 d, uint8 s) +{ + register uint8 res; /* all operands in native machine order */ + res = d & s; + /* set the flags */ + CLEAR_FLAG(m, F_OF); + CLEAR_FLAG(m, F_CF); + CONDITIONAL_SET_FLAG(res&0x80, m, F_SF); + CONDITIONAL_SET_FLAG(res==0, m, F_ZF); + CONDITIONAL_SET_FLAG(parity_tab[res], m, F_PF); + return res; +} + +/* + Flags m->R_FLG, dest *d, source *s, do a bitwise and of the + source and destination, and then store back to the + destination. Size=byte. +*/ +uint16 and_word(PC_ENV *m, uint16 d, uint16 s) +{ + register uint16 res; /* all operands in native machine order */ + res = d & s; + /* set the flags */ + CLEAR_FLAG(m, F_OF); + CLEAR_FLAG(m, F_CF); + CONDITIONAL_SET_FLAG(res&0x8000, m, F_SF); + CONDITIONAL_SET_FLAG(res==0, m, F_ZF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + return res; +} + +uint8 cmp_byte(PC_ENV *m, uint8 d, uint8 s) +{ + register uint32 res; /* all operands in native machine order */ + register uint32 bc; + res = d - s; + CLEAR_FLAG(m, F_CF); + CONDITIONAL_SET_FLAG(res&0x80, m, F_SF); + CONDITIONAL_SET_FLAG((res&0xff)==0, m, F_ZF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + /* calculate the borrow chain. See note at top */ + bc= (res&(~d|s))|(~d&s); + CONDITIONAL_SET_FLAG(bc&0x80,m, F_CF); + CONDITIONAL_SET_FLAG(xor_0x3_tab[(bc>>6)&0x3], m, F_OF); + CONDITIONAL_SET_FLAG(bc&0x8, m, F_AF); + return d; /* long story why this is needed. Look at opcode + 0x80 in ops.c, for an idea why this is necessary.*/ +} + +uint16 cmp_word(PC_ENV *m, uint16 d, uint16 s) +{ + register uint32 res; /* all operands in native machine order */ + register uint32 bc; + res = d - s; + CONDITIONAL_SET_FLAG(res&0x8000, m, F_SF); + CONDITIONAL_SET_FLAG((res&0xffff)==0, m, F_ZF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + /* calculate the borrow chain. See note at top */ + bc= (res&(~d|s))|(~d&s); + CONDITIONAL_SET_FLAG(bc&0x8000,m, F_CF); + CONDITIONAL_SET_FLAG(xor_0x3_tab[(bc>>14)&0x3], m, F_OF); + CONDITIONAL_SET_FLAG(bc&0x8, m, F_AF); + return d; +} + +uint8 dec_byte(PC_ENV *m, uint8 d) +{ + register uint32 res; /* all operands in native machine order */ + register uint32 bc; + res = d - 1; + CONDITIONAL_SET_FLAG(res&0x80, m, F_SF); + CONDITIONAL_SET_FLAG((res&0xff)==0, m, F_ZF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + /* calculate the borrow chain. See note at top */ + /* based on sub_byte, uses s==1. */ + bc= (res&(~d|1))|(~d&1); + /* carry flag unchanged */ + CONDITIONAL_SET_FLAG(xor_0x3_tab[(bc>>6)&0x3], m, F_OF); + CONDITIONAL_SET_FLAG(bc&0x8, m, F_AF); + return res; +} + +uint16 dec_word(PC_ENV *m, uint16 d) +{ + register uint32 res; /* all operands in native machine order */ + register uint32 bc; + res = d - 1; + CONDITIONAL_SET_FLAG(res&0x8000, m, F_SF); + CONDITIONAL_SET_FLAG((res&0xffff)==0, m, F_ZF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + /* calculate the borrow chain. See note at top */ + /* based on the sub_byte routine, with s==1 */ + bc= (res&(~d|1))|(~d&1); + /* carry flag unchanged */ + CONDITIONAL_SET_FLAG(xor_0x3_tab[(bc>>14)&0x3], m, F_OF); + CONDITIONAL_SET_FLAG(bc&0x8, m, F_AF); + return res; +} + +/* Given flags=f, and byte d (dest) + perform the inc and set the flags and the result back to + d. USE NATIVE MACHINE ORDER... +*/ +uint8 inc_byte(PC_ENV *m, uint8 d) +{ + register uint32 res; /* all operands in native machine order */ + register uint32 cc; + res = d + 1; + CONDITIONAL_SET_FLAG((res&0xff)==0, m, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80, m, F_SF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + /* calculate the carry chain SEE NOTE AT TOP.*/ + cc = ((1 & d) | (~res)) & (1 | d); + CONDITIONAL_SET_FLAG(xor_0x3_tab[(cc>>6)&0x3], m, F_OF); + CONDITIONAL_SET_FLAG(cc&0x8, m, F_AF); + return res; +} + +/* Given flags=f, and byte d (dest) + perform the inc and set the flags and the result back to + *d. USE NATIVE MACHINE ORDER... +*/ +uint16 inc_word(PC_ENV *m, uint16 d) +{ + register uint32 res; /* all operands in native machine order */ + register uint32 cc; + res = d + 1; + CONDITIONAL_SET_FLAG((res&0xffff)==0, m, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, m, F_SF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + /* calculate the carry chain SEE NOTE AT TOP.*/ + cc = (1 & d) | ((~res) & (1 | d)); + CONDITIONAL_SET_FLAG(xor_0x3_tab[(cc>>14)&0x3], m, F_OF); + CONDITIONAL_SET_FLAG(cc&0x8, m, F_AF); + return res ; +} + +uint8 or_byte(PC_ENV *m, uint8 d, uint8 s) +{ + register uint8 res; /* all operands in native machine order */ + res = d | s; + CLEAR_FLAG(m, F_OF); + CLEAR_FLAG(m, F_CF); + CONDITIONAL_SET_FLAG(res&0x80, m, F_SF); + CONDITIONAL_SET_FLAG(res==0, m, F_ZF); + CONDITIONAL_SET_FLAG(parity_tab[res], m, F_PF); + return res; +} + +uint16 or_word(PC_ENV *m, uint16 d, uint16 s) +{ + register uint16 res; /* all operands in native machine order */ + res = d | s; + /* set the carry flag to be bit 8 */ + CLEAR_FLAG(m, F_OF); + CLEAR_FLAG(m, F_CF); + CONDITIONAL_SET_FLAG(res&0x8000, m, F_SF); + CONDITIONAL_SET_FLAG(res==0, m, F_ZF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + return res; +} + +uint8 neg_byte(PC_ENV *m, uint8 s) +{ + register uint8 res; + register uint8 bc; + CONDITIONAL_SET_FLAG(s!=0, m, F_CF); + res = -s; + CONDITIONAL_SET_FLAG((res&0xff)==0, m, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80, m, F_SF); + CONDITIONAL_SET_FLAG(parity_tab[res], m, F_PF); + /* calculate the borrow chain --- modified such that d=0. + substitutiing d=0 into bc= res&(~d|s)|(~d&s); + (the one used for sub) and simplifying, since ~d=0xff..., + ~d|s == 0xffff..., and res&0xfff... == res. Similarly + ~d&s == s. So the simplified result is:*/ + bc= res|s; + CONDITIONAL_SET_FLAG(xor_0x3_tab[(bc>>6)&0x3], m, F_OF); + CONDITIONAL_SET_FLAG(bc&0x8, m, F_AF); + return res; +} + +uint16 neg_word(PC_ENV *m, uint16 s) +{ + register uint16 res; + register uint16 bc; + CONDITIONAL_SET_FLAG(s!=0, m, F_CF); + res = -s; + CONDITIONAL_SET_FLAG((res&0xffff)==0, m, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, m, F_SF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + /* calculate the borrow chain --- modified such that d=0. + substitutiing d=0 into bc= res&(~d|s)|(~d&s); + (the one used for sub) and simplifying, since ~d=0xff..., + ~d|s == 0xffff..., and res&0xfff... == res. Similarly + ~d&s == s. So the simplified result is:*/ + bc= res|s; + CONDITIONAL_SET_FLAG(xor_0x3_tab[(bc>>6)&0x3], m, F_OF); + CONDITIONAL_SET_FLAG(bc&0x8, m, F_AF); + return res; +} + +uint8 not_byte(PC_ENV *m, uint8 s) +{ + return ~s; +} + +uint16 not_word(PC_ENV *m, uint16 s) +{ + return ~s; +} + +/* access stuff from absolute location in memory. + no segment registers are involved. + */ +uint16 mem_access_word(PC_ENV *m, int addr) +{ + /* Load in two steps. Native byte order independent */ + return GetBYTEExtended(addr) | (GetBYTEExtended(addr + 1) << 8); +} + +/* given the register_set r, and memory descriptor m, + and word w, push w onto the stack. + w ASSUMED IN NATIVE MACHINE ORDER. Doesn't matter in this case??? + */ +void push_word(PC_ENV *m, uint16 w) +{ + m->R_SP --; + PutBYTEExtended((m->R_SS << 4) + m->R_SP, w >> 8); + m->R_SP --; + PutBYTEExtended((m->R_SS << 4) + m->R_SP, w & 0xff); +} + +/* given the memory descriptor m, + and word w, pop word from the stack. + */ +uint16 pop_word(PC_ENV *m) +{ + register uint16 res; + res = GetBYTEExtended((m->R_SS << 4) + m->R_SP); + m->R_SP++; + res |= GetBYTEExtended((m->R_SS << 4) + m->R_SP) << 8; + m->R_SP++; + return res; +} + +/***************************************************************** + BEGIN region consisting of bit shifts and rotates, + much of which may be wrong. Large hirsute factor. +*****************************************************************/ +uint8 rcl_byte(PC_ENV *m, uint8 d, uint8 s) +{ + register uint32 res, cnt, mask,cf; + /* s is the rotate distance. It varies from 0 - 8. */ + /* have + CF B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0 + want to rotate through the carry by "s" bits. We could + loop, but that's inefficient. So the width is 9, + and we split into three parts: + The new carry flag (was B_n) + the stuff in B_n-1 .. B_0 + the stuff in B_7 .. B_n+1 + The new rotate is done mod 9, and given this, + for a rotation of n bits (mod 9) the new carry flag is + then located n bits from the MSB. The low part is + then shifted up cnt bits, and the high part is or'd + in. Using CAPS for new values, and lowercase for the + original values, this can be expressed as: + IF n > 0 + 1) CF <- b_(8-n) + 2) B_(7) .. B_(n) <- b_(8-(n+1)) .. b_0 + 3) B_(n-1) <- cf + 4) B_(n-2) .. B_0 <- b_7 .. b_(8-(n-1)) + I think this is correct. + */ + res = d; + /* [JCE] Extra brackets to stop gcc -Wall moaning */ + if ((cnt = s % 9)) /* not a typo, do nada if cnt==0 */ + { + /* extract the new CARRY FLAG. */ + /* CF <- b_(8-n) */ + cf = (d >> (8-cnt)) & 0x1; + /* get the low stuff which rotated + into the range B_7 .. B_cnt */ + /* B_(7) .. B_(n) <- b_(8-(n+1)) .. b_0 */ + /* note that the right hand side done by the mask */ + res = (d << cnt) & 0xff; + /* now the high stuff which rotated around + into the positions B_cnt-2 .. B_0 */ + /* B_(n-2) .. B_0 <- b_7 .. b_(8-(n-1)) */ + /* shift it downward, 7-(n-2) = 9-n positions. + and mask off the result before or'ing in. + */ + mask = (1<<(cnt-1)) - 1; + res |= (d >> (9-cnt)) & mask; + /* if the carry flag was set, or it in. */ + if (ACCESS_FLAG(m,F_CF)) /* carry flag is set */ + { + /* B_(n-1) <- cf */ + res |= 1 << (cnt-1); + } + /* set the new carry flag, based on the variable "cf" */ + CONDITIONAL_SET_FLAG(cf, m, F_CF); + /* OVERFLOW is set *IFF* cnt==1, then it is the + xor of CF and the most significant bit. Blecck. */ + /* parenthesized this expression since it appears to + be causing OF to be misset */ + CONDITIONAL_SET_FLAG(cnt==1&& + xor_0x3_tab[cf+((res>>6)&0x2)], + m, F_OF); + } + return res & 0xff; +} + +uint16 rcl_word(PC_ENV *m, uint16 d, uint16 s) +{ + register uint32 res, cnt, mask,cf; + /* see analysis above. */ + /* width here is 16 bits + carry bit */ + res = d; + /* [JCE] Extra brackets to stop gcc -Wall moaning */ + if ((cnt = s % 17)) /* not a typo, do nada if cnt==0 */ + { + /* extract the new CARRY FLAG. */ + /* CF <- b_(16-n) */ + cf = (d >> (16-cnt)) & 0x1; + /* get the low stuff which rotated + into the range B_15 .. B_cnt */ + /* B_(15) .. B_(n) <- b_(16-(n+1)) .. b_0 */ + /* note that the right hand side done by the mask */ + res = (d << cnt) & 0xffff; + /* now the high stuff which rotated around + into the positions B_cnt-2 .. B_0 */ + /* B_(n-2) .. B_0 <- b_15 .. b_(16-(n-1)) */ + /* shift it downward, 15-(n-2) = 17-n positions. + and mask off the result before or'ing in. + */ + mask = (1<<(cnt-1)) - 1; + res |= (d >> (17-cnt)) & mask; + /* if the carry flag was set, or it in. */ + if (ACCESS_FLAG(m, F_CF)) /* carry flag is set */ + { + /* B_(n-1) <- cf */ + res |= 1 << (cnt-1); + } + /* set the new carry flag, based on the variable "cf" */ + CONDITIONAL_SET_FLAG(cf, m, F_CF); + /* OVERFLOW is set *IFF* cnt==1, then it is the + xor of CF and the most significant bit. Blecck. + Note that we're forming a 2 bit word here to index + into the table. The expression cf+(res>>14)&0x2 + represents the two bit word b_15 CF. + */ + /* parenthesized following expression... */ + CONDITIONAL_SET_FLAG(cnt==1&&xor_0x3_tab[cf+((res>>14)&0x2)], + m, F_OF); + } + return res & 0xffff; +} + +uint8 rcr_byte(PC_ENV *m, uint8 d, uint8 s) +{ + uint8 res, cnt; + uint8 mask, cf, ocf = 0; + /* rotate right through carry */ + /* + s is the rotate distance. It varies from 0 - 8. + d is the byte object rotated. + have + CF B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0 + The new rotate is done mod 9, and given this, + for a rotation of n bits (mod 9) the new carry flag is + then located n bits from the LSB. The low part is + then shifted up cnt bits, and the high part is or'd + in. Using CAPS for new values, and lowercase for the + original values, this can be expressed as: + IF n > 0 + 1) CF <- b_(n-1) + 2) B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n) + 3) B_(8-n) <- cf + 4) B_(7) .. B_(8-(n-1)) <- b_(n-2) .. b_(0) + I think this is correct. + */ + res = d; + /* [JCE] Extra brackets to stop gcc -Wall moaning */ + if ((cnt = s % 9)) /* not a typo, do nada if cnt==0 */ + { + /* extract the new CARRY FLAG. */ + /* CF <- b_(n-1) */ + if (cnt == 1) + { + cf = d & 0x1; + /* note hackery here. Access_flag(..) evaluates to either + 0 if flag not set + non-zero if flag is set. + doing access_flag(..) != 0 casts that into either + 0..1 in any representation of the flags register + (i.e. packed bit array or unpacked.) + */ + ocf = ACCESS_FLAG(m,F_CF) != 0; + } + else + cf = (d >> (cnt-1)) & 0x1; + /* B_(8-(n+1)) .. B_(0) <- b_(7) .. b_n */ + /* note that the right hand side done by the mask + This is effectively done by shifting the + object to the right. The result must be masked, + in case the object came in and was treated + as a negative number. Needed???*/ + mask = (1<<(8-cnt))-1; + res = (d >> cnt) & mask; + /* now the high stuff which rotated around + into the positions B_cnt-2 .. B_0 */ + /* B_(7) .. B_(8-(n-1)) <- b_(n-2) .. b_(0) */ + /* shift it downward, 7-(n-2) = 9-n positions. + and mask off the result before or'ing in. + */ + res |= (d << (9-cnt)); + /* if the carry flag was set, or it in. */ + if (ACCESS_FLAG(m,F_CF)) /* carry flag is set */ + { + /* B_(8-n) <- cf */ + res |= 1 << (8 - cnt); + } + /* set the new carry flag, based on the variable "cf" */ + CONDITIONAL_SET_FLAG(cf, m, F_CF); + /* OVERFLOW is set *IFF* cnt==1, then it is the + xor of CF and the most significant bit. Blecck. */ + /* parenthesized... */ + if (cnt == 1) + { /* [JCE] Explicit braces to stop gcc -Wall moaning */ + CONDITIONAL_SET_FLAG(xor_0x3_tab[ocf+((d>>6)&0x2)], + m, F_OF); + } + } + return res; +} + +uint16 rcr_word(PC_ENV *m, uint16 d, uint16 s) +{ + uint16 res, cnt; + uint16 mask, cf, ocf = 0; + /* rotate right through carry */ + /* + s is the rotate distance. It varies from 0 - 8. + d is the byte object rotated. + have + CF B_15 ... B_0 + The new rotate is done mod 17, and given this, + for a rotation of n bits (mod 17) the new carry flag is + then located n bits from the LSB. The low part is + then shifted up cnt bits, and the high part is or'd + in. Using CAPS for new values, and lowercase for the + original values, this can be expressed as: + IF n > 0 + 1) CF <- b_(n-1) + 2) B_(16-(n+1)) .. B_(0) <- b_(15) .. b_(n) + 3) B_(16-n) <- cf + 4) B_(15) .. B_(16-(n-1)) <- b_(n-2) .. b_(0) + I think this is correct. + */ + res = d; + /* [JCE] Extra brackets to stop gcc -Wall moaning */ + if ((cnt = s % 17)) /* not a typo, do nada if cnt==0 */ + { + /* extract the new CARRY FLAG. */ + /* CF <- b_(n-1) */ + if (cnt==1) + { + cf = d & 0x1; + /* see note above on teh byte version */ + ocf = ACCESS_FLAG(m,F_CF) != 0; + } + else + cf = (d >> (cnt-1)) & 0x1; + /* B_(16-(n+1)) .. B_(0) <- b_(15) .. b_n */ + /* note that the right hand side done by the mask + This is effectively done by shifting the + object to the right. The result must be masked, + in case the object came in and was treated + as a negative number. Needed???*/ + mask = (1<<(16-cnt))-1; + res = (d >> cnt) & mask; + /* now the high stuff which rotated around + into the positions B_cnt-2 .. B_0 */ + /* B_(15) .. B_(16-(n-1)) <- b_(n-2) .. b_(0) */ + /* shift it downward, 15-(n-2) = 17-n positions. + and mask off the result before or'ing in. + */ + res |= (d << (17-cnt)); + /* if the carry flag was set, or it in. */ + if (ACCESS_FLAG(m,F_CF)) /* carry flag is set */ + { + /* B_(16-n) <- cf */ + res |= 1 << (16 - cnt); + } + /* set the new carry flag, based on the variable "cf" */ + CONDITIONAL_SET_FLAG(cf, m, F_CF); + /* OVERFLOW is set *IFF* cnt==1, then it is the + xor of CF and the most significant bit. Blecck. */ + if (cnt==1) + { /* [JCE] Explicit braces to stop gcc -Wall moaning */ + CONDITIONAL_SET_FLAG(xor_0x3_tab[ocf+((d>>14)&0x2)], + m, F_OF); + } + } + return res; +} + +uint8 rol_byte(PC_ENV *m, uint8 d, uint8 s) +{ + register uint32 res, cnt, mask; + /* rotate left */ + /* + s is the rotate distance. It varies from 0 - 8. + d is the byte object rotated. + have + CF B_7 ... B_0 + The new rotate is done mod 8. + Much simpler than the "rcl" or "rcr" operations. + IF n > 0 + 1) B_(7) .. B_(n) <- b_(8-(n+1)) .. b_(0) + 2) B_(n-1) .. B_(0) <- b_(7) .. b_(8-n) + I think this is correct. + */ + res =d; + /* [JCE] Extra brackets to stop gcc -Wall moaning */ + if ((cnt = s % 8)) /* not a typo, do nada if cnt==0 */ + { + /* B_(7) .. B_(n) <- b_(8-(n+1)) .. b_(0) */ + res = (d << cnt); + /* B_(n-1) .. B_(0) <- b_(7) .. b_(8-n) */ + mask = (1 << cnt) - 1; + res |= (d >> (8-cnt)) & mask; + /* set the new carry flag, Note that it is the low order + bit of the result!!! */ + CONDITIONAL_SET_FLAG(res&0x1, m, F_CF); + /* OVERFLOW is set *IFF* cnt==1, then it is the + xor of CF and the most significant bit. Blecck. */ + CONDITIONAL_SET_FLAG(cnt==1 && + xor_0x3_tab[(res&0x1)+((res>>6)&0x2)], + m, F_OF); + } + return res&0xff; +} + +uint16 rol_word(PC_ENV *m, uint16 d, uint16 s) +{ + register uint32 res, cnt, mask; + /* rotate left */ + /* + s is the rotate distance. It varies from 0 - 8. + d is the byte object rotated. + have + CF B_15 ... B_0 + The new rotate is done mod 8. + Much simpler than the "rcl" or "rcr" operations. + IF n > 0 + 1) B_(15) .. B_(n) <- b_(16-(n+1)) .. b_(0) + 2) B_(n-1) .. B_(0) <- b_(16) .. b_(16-n) + I think this is correct. + */ + res = d; + /* [JCE] Extra brackets to stop gcc -Wall moaning */ + if ((cnt = s % 16)) /* not a typo, do nada if cnt==0 */ + { + /* B_(16) .. B_(n) <- b_(16-(n+1)) .. b_(0) */ + res = (d << cnt); + /* B_(n-1) .. B_(0) <- b_(15) .. b_(16-n) */ + mask = (1 << cnt) - 1; + res |= (d >> (16-cnt)) & mask; + /* set the new carry flag, Note that it is the low order + bit of the result!!! */ + CONDITIONAL_SET_FLAG(res&0x1, m, F_CF); + /* OVERFLOW is set *IFF* cnt==1, then it is the + xor of CF and the most significant bit. Blecck. */ + CONDITIONAL_SET_FLAG(cnt==1 && + xor_0x3_tab[(res&0x1)+((res>>14)&0x2)], + m, F_OF); + } + return res&0xffff; +} + +uint8 ror_byte(PC_ENV *m, uint8 d, uint8 s) +{ + register uint32 res, cnt, mask; + /* rotate right */ + /* + s is the rotate distance. It varies from 0 - 8. + d is the byte object rotated. + have + B_7 ... B_0 + The rotate is done mod 8. + IF n > 0 + 1) B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n) + 2) B_(7) .. B_(8-n) <- b_(n-1) .. b_(0) + */ + res = d; + /* [JCE] Extra brackets to stop gcc -Wall moaning */ + if ((cnt = s % 8)) /* not a typo, do nada if cnt==0 */ + { + /* B_(7) .. B_(8-n) <- b_(n-1) .. b_(0)*/ + res = (d << (8-cnt)); + /* B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n) */ + mask = (1 << (8-cnt)) - 1; + res |= (d >> (cnt)) & mask; + /* set the new carry flag, Note that it is the low order + bit of the result!!! */ + CONDITIONAL_SET_FLAG(res&0x80, m, F_CF); + /* OVERFLOW is set *IFF* cnt==1, then it is the + xor of the two most significant bits. Blecck. */ + CONDITIONAL_SET_FLAG(cnt==1 && + xor_0x3_tab[(res>>6)&0x3], + m, F_OF); + } + return res&0xff; +} + +uint16 ror_word(PC_ENV *m, uint16 d, uint16 s) +{ + register uint32 res, cnt, mask; + /* rotate right */ + /* + s is the rotate distance. It varies from 0 - 8. + d is the byte object rotated. + have + B_15 ... B_0 + The rotate is done mod 16. + IF n > 0 + 1) B_(16-(n+1)) .. B_(0) <- b_(15) .. b_(n) + 2) B_(15) .. B_(16-n) <- b_(n-1) .. b_(0) + I think this is correct. + */ + res =d ; + /* [JCE] Extra brackets to stop gcc -Wall moaning */ + if ((cnt = s % 16)) /* not a typo, do nada if cnt==0 */ + { + /* B_(15) .. B_(16-n) <- b_(n-1) .. b_(0)*/ + res = (d << (16-cnt)); + /* B_(16-(n+1)) .. B_(0) <- b_(15) .. b_(n) */ + mask = (1 << (16-cnt)) - 1; + res |= (d >> (cnt)) & mask; + /* set the new carry flag, Note that it is the low order + bit of the result!!! */ + CONDITIONAL_SET_FLAG(res&0x8000, m, F_CF); + /* OVERFLOW is set *IFF* cnt==1, then it is the + xor of CF and the most significant bit. Blecck. */ + CONDITIONAL_SET_FLAG(cnt==1 && + xor_0x3_tab[(res>>14)&0x3], + m, F_OF); + } + return res & 0xffff; +} + +uint8 shl_byte(PC_ENV *m, uint8 d, uint8 s) +{ + uint32 cnt,res,cf; + if (s < 8) + { + cnt = s % 8; + /* last bit shifted out goes into carry flag */ + if (cnt>0) + { + res = d << cnt; + cf = d & (1<<(8-cnt)); + CONDITIONAL_SET_FLAG(cf, m, F_CF); + CONDITIONAL_SET_FLAG((res&0xff)==0, m, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80, m, F_SF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + } + else + { + res = (uint8)d; + } + if (cnt == 1) + { + /* Needs simplification. */ + CONDITIONAL_SET_FLAG( + (((res&0x80)==0x80) ^ + (ACCESS_FLAG(m,F_CF) != 0)) , + /* was (m->R_FLG&F_CF)==F_CF)), */ + m, F_OF); + } + else + { + CLEAR_FLAG(m,F_OF); + } + } + else + { + res = 0; + CLEAR_FLAG(m,F_CF); + CLEAR_FLAG(m,F_OF); + CLEAR_FLAG(m,F_SF); + CLEAR_FLAG(m,F_PF); + SET_FLAG(m,F_ZF); + } + return res&0xff; +} + +uint16 shl_word(PC_ENV *m, uint16 d, uint16 s) +{ + uint32 cnt,res,cf; + if (s < 16) + { + cnt = s % 16; + if (cnt > 0) + { + res = d << cnt; + /* last bit shifted out goes into carry flag */ + cf = d & (1<<(16-cnt)); + CONDITIONAL_SET_FLAG(cf, m, F_CF); + CONDITIONAL_SET_FLAG((res&0xffff)==0, m, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, m, F_SF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + } + else + { + res = (uint16)d; + } + if (cnt == 1) + { + /* Needs simplification. */ + CONDITIONAL_SET_FLAG( + (((res&0x8000)==0x8000) ^ + (ACCESS_FLAG(m,F_CF) != 0)), + /*((m&F_CF)==F_CF)),*/ + m, F_OF); + } + else + { + CLEAR_FLAG(m,F_OF); + } + } + else + { + res = 0; + CLEAR_FLAG(m,F_CF); + CLEAR_FLAG(m,F_OF); + SET_FLAG(m,F_ZF); + CLEAR_FLAG(m,F_SF); + CLEAR_FLAG(m,F_PF); + } + return res&0xffff; +} + +uint8 shr_byte(PC_ENV *m, uint8 d, uint8 s) +{ + uint32 cnt,res,cf,mask; + if (s < 8) + { + cnt = s % 8; + if (cnt > 0) + { + mask = (1<<(8-cnt))-1; + cf = d & (1<<(cnt-1)); + res = (d >> cnt) & mask; + CONDITIONAL_SET_FLAG(cf, m, F_CF); + CONDITIONAL_SET_FLAG((res&0xff)==0, m, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x80, m, F_SF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + } + else + { + res = (uint8) d; + } + if (cnt == 1) + { + CONDITIONAL_SET_FLAG( + xor_0x3_tab[(res>>6)&0x3], m, F_OF); + } + else + { + CLEAR_FLAG(m,F_OF); + } + } + else + { + res = 0; + CLEAR_FLAG(m,F_CF); + CLEAR_FLAG(m,F_OF); + SET_FLAG(m,F_ZF); + CLEAR_FLAG(m,F_SF); + CLEAR_FLAG(m,F_PF); + } + return res&0xff; +} + +uint16 shr_word(PC_ENV *m, uint16 d, uint16 s) +{ + uint32 cnt,res,cf,mask; + res = d; + if (s < 16) + { + cnt = s % 16; + if (cnt > 0) + { + mask = (1<<(16-cnt))-1; + cf = d & (1<<(cnt-1)); + res = (d >> cnt) & mask; + CONDITIONAL_SET_FLAG(cf, m, F_CF); + CONDITIONAL_SET_FLAG((res&0xffff)==0, m, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, m, F_SF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + } + else + { + res = d; + } + if (cnt == 1) + { + CONDITIONAL_SET_FLAG( + xor_0x3_tab[(res>>14)&0x3], m, F_OF); + } + else + { + CLEAR_FLAG(m,F_OF); + } + } + else + { + res = 0; + CLEAR_FLAG(m,F_CF); + CLEAR_FLAG(m,F_OF); + SET_FLAG(m,F_ZF); + CLEAR_FLAG(m,F_SF); + CLEAR_FLAG(m,F_PF); + } + return res&0xffff; +} + +/* XXXX ??? flags may be wrong??? */ +uint8 sar_byte(PC_ENV *m, uint8 d, uint8 s) +{ + uint32 cnt,res,cf,mask,sf; + res = d; + sf = d & 0x80; + cnt = s % 8; + if(cnt > 0 && cnt < 8) + { + mask = (1<<(8-cnt))-1; + cf = d & (1<<(cnt-1)); + res = (d >> cnt) & mask; + CONDITIONAL_SET_FLAG(cf, m, F_CF); + if (sf) + { + res |= ~mask; + } + CONDITIONAL_SET_FLAG((res&0xff)==0, m, F_ZF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + CONDITIONAL_SET_FLAG(res & 0x80, m, F_SF); + } + else if (cnt >= 8) + { + if (sf) + { + res = 0xff; + SET_FLAG(m,F_CF); + CLEAR_FLAG(m,F_ZF); + SET_FLAG(m, F_SF); + SET_FLAG(m, F_PF); + } + else + { + res = 0; + CLEAR_FLAG(m,F_CF); + SET_FLAG(m,F_ZF); + CLEAR_FLAG(m, F_SF); + CLEAR_FLAG(m, F_PF); + } + } + return res&0xff; +} + +uint16 sar_word(PC_ENV *m, uint16 d, uint16 s) +{ + uint32 cnt, res, cf, mask, sf; + sf = d & 0x8000; + cnt = s % 16; + res = d; + if (cnt > 0 && cnt < 16) + { + mask = (1<<(16-cnt))-1; + cf = d & (1<<(cnt-1)); + res = (d >> cnt) & mask; + CONDITIONAL_SET_FLAG(cf, m, F_CF); + if (sf) + { + res |= ~mask; + } + CONDITIONAL_SET_FLAG((res&0xffff)==0, m, F_ZF); + CONDITIONAL_SET_FLAG(res & 0x8000, m, F_SF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + } + else if (cnt >= 16) + { + if (sf) + { + res = 0xffff; + SET_FLAG(m,F_CF); + CLEAR_FLAG(m,F_ZF); + SET_FLAG(m, F_SF); + SET_FLAG(m, F_PF); + } + else + { + res = 0; + CLEAR_FLAG(m,F_CF); + SET_FLAG(m,F_ZF); + CLEAR_FLAG(m, F_SF); + CLEAR_FLAG(m, F_PF); + } + } + return res&0xffff; +} + +uint8 sbb_byte(PC_ENV *m, uint8 d, uint8 s) +{ + register uint32 res; /* all operands in native machine order */ + register uint32 bc; + if (ACCESS_FLAG(m,F_CF) ) + res = d - s - 1; + else + res = d - s; + CONDITIONAL_SET_FLAG(res&0x80, m, F_SF); + CONDITIONAL_SET_FLAG((res&0xff)==0, m, F_ZF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + /* calculate the borrow chain. See note at top */ + bc= (res&(~d|s))|(~d&s); + CONDITIONAL_SET_FLAG(bc&0x80,m, F_CF); + CONDITIONAL_SET_FLAG(xor_0x3_tab[(bc>>6)&0x3], m, F_OF); + CONDITIONAL_SET_FLAG(bc&0x8, m, F_AF); + return res & 0xff; +} + +uint16 sbb_word(PC_ENV *m, uint16 d, uint16 s) +{ + register uint32 res; /* all operands in native machine order */ + register uint32 bc; + if (ACCESS_FLAG(m,F_CF)) + res = d - s - 1; + else + res = d - s; + CONDITIONAL_SET_FLAG(res&0x8000, m, F_SF); + CONDITIONAL_SET_FLAG((res&0xffff)==0, m, F_ZF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + /* calculate the borrow chain. See note at top */ + bc= (res&(~d|s))|(~d&s); + CONDITIONAL_SET_FLAG(bc&0x8000,m, F_CF); + CONDITIONAL_SET_FLAG(xor_0x3_tab[(bc>>14)&0x3], m, F_OF); + CONDITIONAL_SET_FLAG(bc&0x8, m, F_AF); + return res & 0xffff; +} + +uint8 sub_byte(PC_ENV *m, uint8 d, uint8 s) +{ + register uint32 res; /* all operands in native machine order */ + register uint32 bc; + res = d - s; + CONDITIONAL_SET_FLAG(res&0x80, m, F_SF); + CONDITIONAL_SET_FLAG((res&0xff)==0, m, F_ZF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + /* calculate the borrow chain. See note at top */ + bc= (res&(~d|s))|(~d&s); + CONDITIONAL_SET_FLAG(bc&0x80,m, F_CF); + CONDITIONAL_SET_FLAG(xor_0x3_tab[(bc>>6)&0x3], m, F_OF); + CONDITIONAL_SET_FLAG(bc&0x8, m, F_AF); + return res & 0xff; +} + +uint16 sub_word(PC_ENV *m, uint16 d, uint16 s) +{ + register uint32 res; /* all operands in native machine order */ + register uint32 bc; + res = d - s; + CONDITIONAL_SET_FLAG(res&0x8000, m, F_SF); + CONDITIONAL_SET_FLAG((res&0xffff)==0, m, F_ZF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + /* calculate the borrow chain. See note at top */ + bc= (res&(~d|s))|(~d&s); + CONDITIONAL_SET_FLAG(bc&0x8000,m, F_CF); + CONDITIONAL_SET_FLAG(xor_0x3_tab[(bc>>14)&0x3], m, F_OF); + CONDITIONAL_SET_FLAG(bc&0x8, m, F_AF); + return res & 0xffff; +} + +void test_byte(PC_ENV *m, uint8 d, uint8 s) +{ + register uint32 res; /* all operands in native machine order */ + res = d & s; + CLEAR_FLAG(m, F_OF); + CONDITIONAL_SET_FLAG(res&0x80, m, F_SF); + CONDITIONAL_SET_FLAG(res==0, m, F_ZF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + /* AF == dont care*/ + CLEAR_FLAG(m, F_CF); +} + +void test_word(PC_ENV *m, uint16 d, uint16 s) +{ + register uint32 res; /* all operands in native machine order */ + res = d & s; + CLEAR_FLAG(m, F_OF); + CONDITIONAL_SET_FLAG(res&0x8000, m, F_SF); + CONDITIONAL_SET_FLAG(res==0, m, F_ZF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + /* AF == dont care*/ + CLEAR_FLAG(m, F_CF); +} + +uint8 xor_byte(PC_ENV *m, uint8 d, uint8 s) +{ + register uint8 res; /* all operands in native machine order */ + res = d ^ s; + CLEAR_FLAG(m, F_OF); + CONDITIONAL_SET_FLAG(res&0x80, m, F_SF); + CONDITIONAL_SET_FLAG(res==0, m, F_ZF); + CONDITIONAL_SET_FLAG(parity_tab[res], m, F_PF); + CLEAR_FLAG(m, F_CF); + return res; +} + +uint16 xor_word(PC_ENV *m, uint16 d, uint16 s) +{ + register uint16 res; /* all operands in native machine order */ + res = d ^ s; + /* set the carry flag to be bit 8 */ + CLEAR_FLAG(m, F_OF); + CONDITIONAL_SET_FLAG(res&0x8000, m, F_SF); + CONDITIONAL_SET_FLAG(res==0, m, F_ZF); + CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF); + CLEAR_FLAG(m, F_CF); + return res; +} + +void imul_byte(PC_ENV *m, uint8 s) +{ + int16 res = (int8)m->R_AL * (int8)s; + m->R_AX = res; + /* Undef --- Can't hurt */ + CONDITIONAL_SET_FLAG(res&0x8000,m,F_SF); + CONDITIONAL_SET_FLAG(res==0,m,F_ZF); + if (m->R_AH == 0 || m->R_AH == 0xff) + { + CLEAR_FLAG(m, F_CF); + CLEAR_FLAG(m, F_OF); + } + else + { + SET_FLAG(m, F_CF); + SET_FLAG(m, F_OF); + } +} + +void imul_word(PC_ENV *m, uint16 s) +{ + int32 res = (int16)m->R_AX * (int16)s; + m->R_AX = res & 0xffff; + m->R_DX = (res >> 16) & 0xffff; + /* Undef --- Can't hurt */ + CONDITIONAL_SET_FLAG(res&0x80000000,m,F_SF); + CONDITIONAL_SET_FLAG(res==0,m,F_ZF); + if (m->R_DX == 0 || m->R_DX == 0xffff) + { + CLEAR_FLAG(m, F_CF); + CLEAR_FLAG(m, F_OF); + } + else + { + SET_FLAG(m, F_CF); + SET_FLAG(m, F_OF); + } +} + +void mul_byte(PC_ENV *m, uint8 s) +{ + uint16 res = m->R_AL * s; + m->R_AX = res; + /* Undef --- Can't hurt */ + CLEAR_FLAG(m,F_SF); + CONDITIONAL_SET_FLAG(res==0,m,F_ZF); + if (m->R_AH == 0) + { + CLEAR_FLAG(m, F_CF); + CLEAR_FLAG(m, F_OF); + } + else + { + SET_FLAG(m, F_CF); + SET_FLAG(m, F_OF); + } +} + +void mul_word(PC_ENV *m, uint16 s) +{ + uint32 res = m->R_AX * s; + /* Undef --- Can't hurt */ + CLEAR_FLAG(m,F_SF); + CONDITIONAL_SET_FLAG(res==0,m,F_ZF); + m->R_AX = res & 0xffff; + m->R_DX = (res >> 16) & 0xffff; + if (m->R_DX == 0) + { + CLEAR_FLAG(m, F_CF); + CLEAR_FLAG(m, F_OF); + } + else + { + SET_FLAG(m, F_CF); + SET_FLAG(m, F_OF); + } +} + +void idiv_byte(PC_ENV *m, uint8 s) +{ + int32 dvd,div,mod; + dvd = (int16)m->R_AX; + if (s == 0) + { + i86_intr_raise(m,0); + return; + } + div = dvd / (int8)s; + mod = dvd % (int8)s; + if (abs(div) > 0x7f) + { + i86_intr_raise(m,0); + return; + } + /* Undef --- Can't hurt */ + CONDITIONAL_SET_FLAG(div&0x80,m,F_SF); + CONDITIONAL_SET_FLAG(div==0,m,F_ZF); + m->R_AL = (int8)div; + m->R_AH = (int8)mod; +} + +void idiv_word(PC_ENV *m, uint16 s) +{ + int32 dvd,dvs,div,mod; + dvd = m->R_DX; + dvd = (dvd << 16) | m->R_AX; + if (s == 0) + { + i86_intr_raise(m,0); + return; + } + dvs = (int16)s; + div = dvd / dvs; + mod = dvd % dvs; + if (abs(div) > 0x7fff) + { + i86_intr_raise(m,0); + return; + } + /* Undef --- Can't hurt */ + CONDITIONAL_SET_FLAG(div&0x8000,m,F_SF); + CONDITIONAL_SET_FLAG(div==0,m,F_ZF); +/* debug_printf(m, "\n%d/%d=%d,%d\n",dvd,dvs,div,mod); */ + m->R_AX = div; + m->R_DX = mod; +} + +void div_byte(PC_ENV *m, uint8 s) +{ + uint32 dvd,dvs,div,mod; + dvs = s; + dvd = m->R_AX; + if (s == 0) + { + i86_intr_raise(m,0); + return; + } + div = dvd / dvs; + mod = dvd % dvs; + if (abs(div) > 0xff) + { + i86_intr_raise(m,0); + return; + } + /* Undef --- Can't hurt */ + CLEAR_FLAG(m,F_SF); + CONDITIONAL_SET_FLAG(div==0,m,F_ZF); + m->R_AL = (uint8)div; + m->R_AH = (uint8)mod; +} + +void div_word(PC_ENV *m, uint16 s) +{ + uint32 dvd,dvs,div,mod; + dvd = m->R_DX; + dvd = (dvd << 16) | m->R_AX; + dvs = s; + if (dvs == 0) + { + i86_intr_raise(m,0); + return; + } + div = dvd / dvs; + mod = dvd % dvs; +/* printf("dvd=%x dvs=%x -> div=%x mod=%x\n",dvd, dvs,div, mod);*/ + if (abs(div) > 0xffff) + { + i86_intr_raise(m,0); + return; + } + /* Undef --- Can't hurt */ + CLEAR_FLAG(m,F_SF); + CONDITIONAL_SET_FLAG(div==0,m,F_ZF); + m->R_AX = div; + m->R_DX = mod; +} diff --git a/AltairZ80/insns.h b/AltairZ80/insns.h new file mode 100644 index 00000000..f63c0d48 --- /dev/null +++ b/AltairZ80/insns.h @@ -0,0 +1,670 @@ +/* insns.h header file for insns.c + * $Id: insns.h,v 1.1 2004/02/11 19:01:38 perrin Exp $ + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +#ifndef NASM_INSNS_H +#define NASM_INSNS_H + +/* This file is auto-generated from insns.dat by insns.pl - don't edit it */ + +/* This file in included by nasm.h */ + +/* Instruction names */ +enum { + I_AAA, + I_AAD, + I_AAM, + I_AAS, + I_ADC, + I_ADD, + I_ADDPD, + I_ADDPS, + I_ADDSD, + I_ADDSS, + I_ADDSUBPD, + I_ADDSUBPS, + I_AND, + I_ANDNPD, + I_ANDNPS, + I_ANDPD, + I_ANDPS, + I_ARPL, + I_BOUND, + I_BSF, + I_BSR, + I_BSWAP, + I_BT, + I_BTC, + I_BTR, + I_BTS, + I_CALL, + I_CBW, + I_CDQ, + I_CLC, + I_CLD, + I_CLFLUSH, + I_CLI, + I_CLTS, + I_CMC, + I_CMP, + I_CMPEQPD, + I_CMPEQPS, + I_CMPEQSD, + I_CMPEQSS, + I_CMPLEPD, + I_CMPLEPS, + I_CMPLESD, + I_CMPLESS, + I_CMPLTPD, + I_CMPLTPS, + I_CMPLTSD, + I_CMPLTSS, + I_CMPNEQPD, + I_CMPNEQPS, + I_CMPNEQSD, + I_CMPNEQSS, + I_CMPNLEPD, + I_CMPNLEPS, + I_CMPNLESD, + I_CMPNLESS, + I_CMPNLTPD, + I_CMPNLTPS, + I_CMPNLTSD, + I_CMPNLTSS, + I_CMPORDPD, + I_CMPORDPS, + I_CMPORDSD, + I_CMPORDSS, + I_CMPPD, + I_CMPPS, + I_CMPSB, + I_CMPSD, + I_CMPSS, + I_CMPSW, + I_CMPUNORDPD, + I_CMPUNORDPS, + I_CMPUNORDSD, + I_CMPUNORDSS, + I_CMPXCHG, + I_CMPXCHG486, + I_CMPXCHG8B, + I_COMISD, + I_COMISS, + I_CPUID, + I_CVTDQ2PD, + I_CVTDQ2PS, + I_CVTPD2DQ, + I_CVTPD2PI, + I_CVTPD2PS, + I_CVTPI2PD, + I_CVTPI2PS, + I_CVTPS2DQ, + I_CVTPS2PD, + I_CVTPS2PI, + I_CVTSD2SI, + I_CVTSD2SS, + I_CVTSI2SD, + I_CVTSI2SS, + I_CVTSS2SD, + I_CVTSS2SI, + I_CVTTPD2DQ, + I_CVTTPD2PI, + I_CVTTPS2DQ, + I_CVTTPS2PI, + I_CVTTSD2SI, + I_CVTTSS2SI, + I_CWD, + I_CWDE, + I_DAA, + I_DAS, + I_DB, + I_DD, + I_DEC, + I_DIV, + I_DIVPD, + I_DIVPS, + I_DIVSD, + I_DIVSS, + I_DQ, + I_DT, + I_DW, + I_EMMS, + I_ENTER, + I_EQU, + I_F2XM1, + I_FABS, + I_FADD, + I_FADDP, + I_FBLD, + I_FBSTP, + I_FCHS, + I_FCLEX, + I_FCMOVB, + I_FCMOVBE, + I_FCMOVE, + I_FCMOVNB, + I_FCMOVNBE, + I_FCMOVNE, + I_FCMOVNU, + I_FCMOVU, + I_FCOM, + I_FCOMI, + I_FCOMIP, + I_FCOMP, + I_FCOMPP, + I_FCOS, + I_FDECSTP, + I_FDISI, + I_FDIV, + I_FDIVP, + I_FDIVR, + I_FDIVRP, + I_FEMMS, + I_FENI, + I_FFREE, + I_FFREEP, + I_FIADD, + I_FICOM, + I_FICOMP, + I_FIDIV, + I_FIDIVR, + I_FILD, + I_FIMUL, + I_FINCSTP, + I_FINIT, + I_FIST, + I_FISTP, + I_FISTTP, + I_FISUB, + I_FISUBR, + I_FLD, + I_FLD1, + I_FLDCW, + I_FLDENV, + I_FLDL2E, + I_FLDL2T, + I_FLDLG2, + I_FLDLN2, + I_FLDPI, + I_FLDZ, + I_FMUL, + I_FMULP, + I_FNCLEX, + I_FNDISI, + I_FNENI, + I_FNINIT, + I_FNOP, + I_FNSAVE, + I_FNSTCW, + I_FNSTENV, + I_FNSTSW, + I_FPATAN, + I_FPREM, + I_FPREM1, + I_FPTAN, + I_FRNDINT, + I_FRSTOR, + I_FSAVE, + I_FSCALE, + I_FSETPM, + I_FSIN, + I_FSINCOS, + I_FSQRT, + I_FST, + I_FSTCW, + I_FSTENV, + I_FSTP, + I_FSTSW, + I_FSUB, + I_FSUBP, + I_FSUBR, + I_FSUBRP, + I_FTST, + I_FUCOM, + I_FUCOMI, + I_FUCOMIP, + I_FUCOMP, + I_FUCOMPP, + I_FWAIT, + I_FXAM, + I_FXCH, + I_FXRSTOR, + I_FXSAVE, + I_FXTRACT, + I_FYL2X, + I_FYL2XP1, + I_HADDPD, + I_HADDPS, + I_HLT, + I_HSUBPD, + I_HSUBPS, + I_IBTS, + I_ICEBP, + I_IDIV, + I_IMUL, + I_IN, + I_INC, + I_INCBIN, + I_INSB, + I_INSD, + I_INSW, + I_INT, + I_INT01, + I_INT03, + I_INT1, + I_INT3, + I_INTO, + I_INVD, + I_INVLPG, + I_IRET, + I_IRETD, + I_IRETW, + I_JCXZ, + I_JECXZ, + I_JMP, + I_JMPE, + I_LAHF, + I_LAR, + I_LDDQU, + I_LDMXCSR, + I_LDS, + I_LEA, + I_LEAVE, + I_LES, + I_LFENCE, + I_LFS, + I_LGDT, + I_LGS, + I_LIDT, + I_LLDT, + I_LMSW, + I_LOADALL, + I_LOADALL286, + I_LODSB, + I_LODSD, + I_LODSW, + I_LOOP, + I_LOOPE, + I_LOOPNE, + I_LOOPNZ, + I_LOOPZ, + I_LSL, + I_LSS, + I_LTR, + I_MASKMOVDQU, + I_MASKMOVQ, + I_MAXPD, + I_MAXPS, + I_MAXSD, + I_MAXSS, + I_MFENCE, + I_MINPD, + I_MINPS, + I_MINSD, + I_MINSS, + I_MONITOR, + I_MOV, + I_MOVAPD, + I_MOVAPS, + I_MOVD, + I_MOVDDUP, + I_MOVDQ2Q, + I_MOVDQA, + I_MOVDQU, + I_MOVHLPS, + I_MOVHPD, + I_MOVHPS, + I_MOVLHPS, + I_MOVLPD, + I_MOVLPS, + I_MOVMSKPD, + I_MOVMSKPS, + I_MOVNTDQ, + I_MOVNTI, + I_MOVNTPD, + I_MOVNTPS, + I_MOVNTQ, + I_MOVQ, + I_MOVQ2DQ, + I_MOVSB, + I_MOVSD, + I_MOVSHDUP, + I_MOVSLDUP, + I_MOVSS, + I_MOVSW, + I_MOVSX, + I_MOVUPD, + I_MOVUPS, + I_MOVZX, + I_MUL, + I_MULPD, + I_MULPS, + I_MULSD, + I_MULSS, + I_MWAIT, + I_NEG, + I_NOP, + I_NOT, + I_OR, + I_ORPD, + I_ORPS, + I_OUT, + I_OUTSB, + I_OUTSD, + I_OUTSW, + I_PACKSSDW, + I_PACKSSWB, + I_PACKUSWB, + I_PADDB, + I_PADDD, + I_PADDQ, + I_PADDSB, + I_PADDSIW, + I_PADDSW, + I_PADDUSB, + I_PADDUSW, + I_PADDW, + I_PAND, + I_PANDN, + I_PAUSE, + I_PAVEB, + I_PAVGB, + I_PAVGUSB, + I_PAVGW, + I_PCMPEQB, + I_PCMPEQD, + I_PCMPEQW, + I_PCMPGTB, + I_PCMPGTD, + I_PCMPGTW, + I_PDISTIB, + I_PEXTRW, + I_PF2ID, + I_PF2IW, + I_PFACC, + I_PFADD, + I_PFCMPEQ, + I_PFCMPGE, + I_PFCMPGT, + I_PFMAX, + I_PFMIN, + I_PFMUL, + I_PFNACC, + I_PFPNACC, + I_PFRCP, + I_PFRCPIT1, + I_PFRCPIT2, + I_PFRSQIT1, + I_PFRSQRT, + I_PFSUB, + I_PFSUBR, + I_PI2FD, + I_PI2FW, + I_PINSRW, + I_PMACHRIW, + I_PMADDWD, + I_PMAGW, + I_PMAXSW, + I_PMAXUB, + I_PMINSW, + I_PMINUB, + I_PMOVMSKB, + I_PMULHRIW, + I_PMULHRWA, + I_PMULHRWC, + I_PMULHUW, + I_PMULHW, + I_PMULLW, + I_PMULUDQ, + I_PMVGEZB, + I_PMVLZB, + I_PMVNZB, + I_PMVZB, + I_POP, + I_POPA, + I_POPAD, + I_POPAW, + I_POPF, + I_POPFD, + I_POPFW, + I_POR, + I_PREFETCH, + I_PREFETCHNTA, + I_PREFETCHT0, + I_PREFETCHT1, + I_PREFETCHT2, + I_PREFETCHW, + I_PSADBW, + I_PSHUFD, + I_PSHUFHW, + I_PSHUFLW, + I_PSHUFW, + I_PSLLD, + I_PSLLDQ, + I_PSLLQ, + I_PSLLW, + I_PSRAD, + I_PSRAW, + I_PSRLD, + I_PSRLDQ, + I_PSRLQ, + I_PSRLW, + I_PSUBB, + I_PSUBD, + I_PSUBQ, + I_PSUBSB, + I_PSUBSIW, + I_PSUBSW, + I_PSUBUSB, + I_PSUBUSW, + I_PSUBW, + I_PSWAPD, + I_PUNPCKHBW, + I_PUNPCKHDQ, + I_PUNPCKHQDQ, + I_PUNPCKHWD, + I_PUNPCKLBW, + I_PUNPCKLDQ, + I_PUNPCKLQDQ, + I_PUNPCKLWD, + I_PUSH, + I_PUSHA, + I_PUSHAD, + I_PUSHAW, + I_PUSHF, + I_PUSHFD, + I_PUSHFW, + I_PXOR, + I_RCL, + I_RCPPS, + I_RCPSS, + I_RCR, + I_RDMSR, + I_RDPMC, + I_RDSHR, + I_RDTSC, + I_RESB, + I_RESD, + I_RESQ, + I_REST, + I_RESW, + I_RET, + I_RETF, + I_RETN, + I_ROL, + I_ROR, + I_RSDC, + I_RSLDT, + I_RSM, + I_RSQRTPS, + I_RSQRTSS, + I_RSTS, + I_SAHF, + I_SAL, + I_SALC, + I_SAR, + I_SBB, + I_SCASB, + I_SCASD, + I_SCASW, + I_SFENCE, + I_SGDT, + I_SHL, + I_SHLD, + I_SHR, + I_SHRD, + I_SHUFPD, + I_SHUFPS, + I_SIDT, + I_SLDT, + I_SMI, + I_SMINT, + I_SMINTOLD, + I_SMSW, + I_SQRTPD, + I_SQRTPS, + I_SQRTSD, + I_SQRTSS, + I_STC, + I_STD, + I_STI, + I_STMXCSR, + I_STOSB, + I_STOSD, + I_STOSW, + I_STR, + I_SUB, + I_SUBPD, + I_SUBPS, + I_SUBSD, + I_SUBSS, + I_SVDC, + I_SVLDT, + I_SVTS, + I_SYSCALL, + I_SYSENTER, + I_SYSEXIT, + I_SYSRET, + I_TEST, + I_UCOMISD, + I_UCOMISS, + I_UD0, + I_UD1, + I_UD2, + I_UMOV, + I_UNPCKHPD, + I_UNPCKHPS, + I_UNPCKLPD, + I_UNPCKLPS, + I_VERR, + I_VERW, + I_WAIT, + I_WBINVD, + I_WRMSR, + I_WRSHR, + I_XADD, + I_XBTS, + I_XCHG, + I_XLAT, + I_XLATB, + I_XOR, + I_XORPD, + I_XORPS, + I_XSTORE, + I_CMOVcc, + I_Jcc, + I_SETcc +}; + +#define MAX_INSLEN 11 + +/* max length of any instruction, register name etc. */ +#if MAX_INSLEN > 9 /* MAX_INSLEN defined in insnsi.h */ +#define MAX_KEYWORD MAX_INSLEN +#else +#define MAX_KEYWORD 9 +#endif + +struct itemplate { + int opcode; /* the token, passed from "parser.c" */ + int operands; /* number of operands */ + long opd[3]; /* bit flags for operand types */ + const char *code; /* the code it assembles to */ + unsigned long flags; /* some flags */ +}; + +/* + * this define is used to signify the end of an itemplate + */ +#define ITEMPLATE_END {-1,-1,{-1,-1,-1},NULL,0} + +/* + * Instruction template flags. These specify which processor + * targets the instruction is eligible for, whether it is + * privileged or undocumented, and also specify extra error + * checking on the matching of the instruction. + * + * IF_SM stands for Size Match: any operand whose size is not + * explicitly specified by the template is `really' intended to be + * the same size as the first size-specified operand. + * Non-specification is tolerated in the input instruction, but + * _wrong_ specification is not. + * + * IF_SM2 invokes Size Match on only the first _two_ operands, for + * three-operand instructions such as SHLD: it implies that the + * first two operands must match in size, but that the third is + * required to be _unspecified_. + * + * IF_SB invokes Size Byte: operands with unspecified size in the + * template are really bytes, and so no non-byte specification in + * the input instruction will be tolerated. IF_SW similarly invokes + * Size Word, and IF_SD invokes Size Doubleword. + * + * (The default state if neither IF_SM nor IF_SM2 is specified is + * that any operand with unspecified size in the template is + * required to have unspecified size in the instruction too...) + */ + +#define IF_SM 0x00000001UL /* size match */ +#define IF_SM2 0x00000002UL /* size match first two operands */ +#define IF_SB 0x00000004UL /* unsized operands can't be non-byte */ +#define IF_SW 0x00000008UL /* unsized operands can't be non-word */ +#define IF_SD 0x00000010UL /* unsized operands can't be nondword */ +#define IF_AR0 0x00000020UL /* SB, SW, SD applies to argument 0 */ +#define IF_AR1 0x00000040UL /* SB, SW, SD applies to argument 1 */ +#define IF_AR2 0x00000060UL /* SB, SW, SD applies to argument 2 */ +#define IF_ARMASK 0x00000060UL /* mask for unsized argument spec */ +#define IF_PRIV 0x00000100UL /* it's a privileged instruction */ +#define IF_SMM 0x00000200UL /* it's only valid in SMM */ +#define IF_PROT 0x00000400UL /* it's protected mode only */ +#define IF_UNDOC 0x00001000UL /* it's an undocumented instruction */ +#define IF_FPU 0x00002000UL /* it's an FPU instruction */ +#define IF_MMX 0x00004000UL /* it's an MMX instruction */ +#define IF_3DNOW 0x00008000UL /* it's a 3DNow! instruction */ +#define IF_SSE 0x00010000UL /* it's a SSE (KNI, MMX2) instruction */ +#define IF_SSE2 0x00020000UL /* it's a SSE2 instruction */ +#define IF_SSE3 0x00040000UL /* it's a SSE3 (PNI) instruction */ +#define IF_PMASK 0xFF000000UL /* the mask for processor types */ +#define IF_PLEVEL 0x0F000000UL /* the mask for processor instr. level */ + /* also the highest possible processor */ +#define IF_PFMASK 0xF001FF00UL /* the mask for disassembly "prefer" */ +#define IF_8086 0x00000000UL /* 8086 instruction */ +#define IF_186 0x01000000UL /* 186+ instruction */ +#define IF_286 0x02000000UL /* 286+ instruction */ +#define IF_386 0x03000000UL /* 386+ instruction */ +#define IF_486 0x04000000UL /* 486+ instruction */ +#define IF_PENT 0x05000000UL /* Pentium instruction */ +#define IF_P6 0x06000000UL /* P6 instruction */ +#define IF_KATMAI 0x07000000UL /* Katmai instructions */ +#define IF_WILLAMETTE 0x08000000UL /* Willamette instructions */ +#define IF_PRESCOTT 0x09000000UL /* Prescott instructions */ +#define IF_IA64 0x0F000000UL /* IA64 instructions */ +#define IF_CYRIX 0x10000000UL /* Cyrix-specific instruction */ +#define IF_AMD 0x20000000UL /* AMD-specific instruction */ + +#endif diff --git a/AltairZ80/insnsa.c b/AltairZ80/insnsa.c new file mode 100644 index 00000000..ba4d70d7 --- /dev/null +++ b/AltairZ80/insnsa.c @@ -0,0 +1,4443 @@ +/* This file auto-generated from insns.dat by insns.pl - don't edit it */ + +#include "nasm.h" +#include "insns.h" + +static struct itemplate instrux_AAA[] = { + {I_AAA, 0, {0,0,0}, "\1\x37", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_AAD[] = { + {I_AAD, 0, {0,0,0}, "\2\xD5\x0A", IF_8086}, + {I_AAD, 1, {IMMEDIATE,0,0}, "\1\xD5\24", IF_8086|IF_SB}, + ITEMPLATE_END +}; + +static struct itemplate instrux_AAM[] = { + {I_AAM, 0, {0,0,0}, "\2\xD4\x0A", IF_8086}, + {I_AAM, 1, {IMMEDIATE,0,0}, "\1\xD4\24", IF_8086|IF_SB}, + ITEMPLATE_END +}; + +static struct itemplate instrux_AAS[] = { + {I_AAS, 0, {0,0,0}, "\1\x3F", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_ADC[] = { + {I_ADC, 2, {MEMORY,REG8,0}, "\300\1\x10\101", IF_8086|IF_SM}, + {I_ADC, 2, {REG8,REG8,0}, "\1\x10\101", IF_8086}, + {I_ADC, 2, {MEMORY,REG16,0}, "\320\300\1\x11\101", IF_8086|IF_SM}, + {I_ADC, 2, {REG16,REG16,0}, "\320\1\x11\101", IF_8086}, + {I_ADC, 2, {MEMORY,REG32,0}, "\321\300\1\x11\101", IF_386|IF_SM}, + {I_ADC, 2, {REG32,REG32,0}, "\321\1\x11\101", IF_386}, + {I_ADC, 2, {REG8,MEMORY,0}, "\301\1\x12\110", IF_8086|IF_SM}, + {I_ADC, 2, {REG8,REG8,0}, "\1\x12\110", IF_8086}, + {I_ADC, 2, {REG16,MEMORY,0}, "\320\301\1\x13\110", IF_8086|IF_SM}, + {I_ADC, 2, {REG16,REG16,0}, "\320\1\x13\110", IF_8086}, + {I_ADC, 2, {REG32,MEMORY,0}, "\321\301\1\x13\110", IF_386|IF_SM}, + {I_ADC, 2, {REG32,REG32,0}, "\321\1\x13\110", IF_386}, + {I_ADC, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\202\15", IF_8086}, + {I_ADC, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\202\15", IF_386}, + {I_ADC, 2, {REG_AL,IMMEDIATE,0}, "\1\x14\21", IF_8086|IF_SM}, + {I_ADC, 2, {REG_AX,SBYTE,0}, "\320\1\x83\202\15", IF_8086|IF_SM}, + {I_ADC, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x15\31", IF_8086|IF_SM}, + {I_ADC, 2, {REG_EAX,SBYTE,0}, "\321\1\x83\202\15", IF_386|IF_SM}, + {I_ADC, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x15\41", IF_386|IF_SM}, + {I_ADC, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\202\21", IF_8086|IF_SM}, + {I_ADC, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\202\131", IF_8086|IF_SM}, + {I_ADC, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\202\141", IF_386|IF_SM}, + {I_ADC, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\202\21", IF_8086|IF_SM}, + {I_ADC, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\202\131", IF_8086|IF_SM}, + {I_ADC, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\202\141", IF_386|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_ADD[] = { + {I_ADD, 2, {MEMORY,REG8,0}, "\300\17\101", IF_8086|IF_SM}, + {I_ADD, 2, {REG8,REG8,0}, "\17\101", IF_8086}, + {I_ADD, 2, {MEMORY,REG16,0}, "\320\300\1\x01\101", IF_8086|IF_SM}, + {I_ADD, 2, {REG16,REG16,0}, "\320\1\x01\101", IF_8086}, + {I_ADD, 2, {MEMORY,REG32,0}, "\321\300\1\x01\101", IF_386|IF_SM}, + {I_ADD, 2, {REG32,REG32,0}, "\321\1\x01\101", IF_386}, + {I_ADD, 2, {REG8,MEMORY,0}, "\301\1\x02\110", IF_8086|IF_SM}, + {I_ADD, 2, {REG8,REG8,0}, "\1\x02\110", IF_8086}, + {I_ADD, 2, {REG16,MEMORY,0}, "\320\301\1\x03\110", IF_8086|IF_SM}, + {I_ADD, 2, {REG16,REG16,0}, "\320\1\x03\110", IF_8086}, + {I_ADD, 2, {REG32,MEMORY,0}, "\321\301\1\x03\110", IF_386|IF_SM}, + {I_ADD, 2, {REG32,REG32,0}, "\321\1\x03\110", IF_386}, + {I_ADD, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\200\15", IF_8086}, + {I_ADD, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\200\15", IF_386}, + {I_ADD, 2, {REG_AL,IMMEDIATE,0}, "\1\x04\21", IF_8086|IF_SM}, + {I_ADD, 2, {REG_AX,SBYTE,0}, "\320\1\x83\200\15", IF_8086|IF_SM}, + {I_ADD, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x05\31", IF_8086|IF_SM}, + {I_ADD, 2, {REG_EAX,SBYTE,0}, "\321\1\x83\200\15", IF_386|IF_SM}, + {I_ADD, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x05\41", IF_386|IF_SM}, + {I_ADD, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\200\21", IF_8086|IF_SM}, + {I_ADD, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\200\131", IF_8086|IF_SM}, + {I_ADD, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\200\141", IF_386|IF_SM}, + {I_ADD, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\200\21", IF_8086|IF_SM}, + {I_ADD, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\200\131", IF_8086|IF_SM}, + {I_ADD, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\200\141", IF_386|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_ADDPD[] = { + {I_ADDPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\x58\110", IF_WILLAMETTE|IF_SSE2}, + {I_ADDPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\x58\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_ADDPS[] = { + {I_ADDPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x58\110", IF_KATMAI|IF_SSE}, + {I_ADDPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x58\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_ADDSD[] = { + {I_ADDSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\x58\110", IF_WILLAMETTE|IF_SSE2}, + {I_ADDSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\x58\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_ADDSS[] = { + {I_ADDSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x58\110", IF_KATMAI|IF_SSE}, + {I_ADDSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x58\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_ADDSUBPD[] = { + {I_ADDSUBPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD0\110", IF_PRESCOTT|IF_SSE3|IF_SM}, + {I_ADDSUBPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD0\110", IF_PRESCOTT|IF_SSE3}, + ITEMPLATE_END +}; + +static struct itemplate instrux_ADDSUBPS[] = { + {I_ADDSUBPS, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\xD0\110", IF_PRESCOTT|IF_SSE3|IF_SM}, + {I_ADDSUBPS, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\xD0\110", IF_PRESCOTT|IF_SSE3}, + ITEMPLATE_END +}; + +static struct itemplate instrux_AND[] = { + {I_AND, 2, {MEMORY,REG8,0}, "\300\1\x20\101", IF_8086|IF_SM}, + {I_AND, 2, {REG8,REG8,0}, "\1\x20\101", IF_8086}, + {I_AND, 2, {MEMORY,REG16,0}, "\320\300\1\x21\101", IF_8086|IF_SM}, + {I_AND, 2, {REG16,REG16,0}, "\320\1\x21\101", IF_8086}, + {I_AND, 2, {MEMORY,REG32,0}, "\321\300\1\x21\101", IF_386|IF_SM}, + {I_AND, 2, {REG32,REG32,0}, "\321\1\x21\101", IF_386}, + {I_AND, 2, {REG8,MEMORY,0}, "\301\1\x22\110", IF_8086|IF_SM}, + {I_AND, 2, {REG8,REG8,0}, "\1\x22\110", IF_8086}, + {I_AND, 2, {REG16,MEMORY,0}, "\320\301\1\x23\110", IF_8086|IF_SM}, + {I_AND, 2, {REG16,REG16,0}, "\320\1\x23\110", IF_8086}, + {I_AND, 2, {REG32,MEMORY,0}, "\321\301\1\x23\110", IF_386|IF_SM}, + {I_AND, 2, {REG32,REG32,0}, "\321\1\x23\110", IF_386}, + {I_AND, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\204\15", IF_8086}, + {I_AND, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\204\15", IF_386}, + {I_AND, 2, {REG_AL,IMMEDIATE,0}, "\1\x24\21", IF_8086|IF_SM}, + {I_AND, 2, {REG_AX,SBYTE,0}, "\320\1\x83\204\15", IF_8086|IF_SM}, + {I_AND, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x25\31", IF_8086|IF_SM}, + {I_AND, 2, {REG_EAX,SBYTE,0}, "\321\1\x83\204\15", IF_386|IF_SM}, + {I_AND, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x25\41", IF_386|IF_SM}, + {I_AND, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\204\21", IF_8086|IF_SM}, + {I_AND, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\204\131", IF_8086|IF_SM}, + {I_AND, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\204\141", IF_386|IF_SM}, + {I_AND, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\204\21", IF_8086|IF_SM}, + {I_AND, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\204\131", IF_8086|IF_SM}, + {I_AND, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\204\141", IF_386|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_ANDNPD[] = { + {I_ANDNPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\x55\110", IF_WILLAMETTE|IF_SSE2}, + {I_ANDNPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\x55\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_ANDNPS[] = { + {I_ANDNPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x55\110", IF_KATMAI|IF_SSE}, + {I_ANDNPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x55\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_ANDPD[] = { + {I_ANDPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\x54\110", IF_WILLAMETTE|IF_SSE2}, + {I_ANDPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\x54\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_ANDPS[] = { + {I_ANDPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x54\110", IF_KATMAI|IF_SSE}, + {I_ANDPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x54\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_ARPL[] = { + {I_ARPL, 2, {MEMORY,REG16,0}, "\300\1\x63\101", IF_286|IF_PROT|IF_SM}, + {I_ARPL, 2, {REG16,REG16,0}, "\1\x63\101", IF_286|IF_PROT}, + ITEMPLATE_END +}; + +static struct itemplate instrux_BOUND[] = { + {I_BOUND, 2, {REG16,MEMORY,0}, "\320\301\1\x62\110", IF_186}, + {I_BOUND, 2, {REG32,MEMORY,0}, "\321\301\1\x62\110", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_BSF[] = { + {I_BSF, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xBC\110", IF_386|IF_SM}, + {I_BSF, 2, {REG16,REG16,0}, "\320\2\x0F\xBC\110", IF_386}, + {I_BSF, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xBC\110", IF_386|IF_SM}, + {I_BSF, 2, {REG32,REG32,0}, "\321\2\x0F\xBC\110", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_BSR[] = { + {I_BSR, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xBD\110", IF_386|IF_SM}, + {I_BSR, 2, {REG16,REG16,0}, "\320\2\x0F\xBD\110", IF_386}, + {I_BSR, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xBD\110", IF_386|IF_SM}, + {I_BSR, 2, {REG32,REG32,0}, "\321\2\x0F\xBD\110", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_BSWAP[] = { + {I_BSWAP, 1, {REG32,0,0}, "\321\1\x0F\10\xC8", IF_486}, + ITEMPLATE_END +}; + +static struct itemplate instrux_BT[] = { + {I_BT, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xA3\101", IF_386|IF_SM}, + {I_BT, 2, {REG16,REG16,0}, "\320\2\x0F\xA3\101", IF_386}, + {I_BT, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xA3\101", IF_386|IF_SM}, + {I_BT, 2, {REG32,REG32,0}, "\321\2\x0F\xA3\101", IF_386}, + {I_BT, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\2\x0F\xBA\204\25", IF_386|IF_SB}, + {I_BT, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\2\x0F\xBA\204\25", IF_386|IF_SB}, + ITEMPLATE_END +}; + +static struct itemplate instrux_BTC[] = { + {I_BTC, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xBB\101", IF_386|IF_SM}, + {I_BTC, 2, {REG16,REG16,0}, "\320\2\x0F\xBB\101", IF_386}, + {I_BTC, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xBB\101", IF_386|IF_SM}, + {I_BTC, 2, {REG32,REG32,0}, "\321\2\x0F\xBB\101", IF_386}, + {I_BTC, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\2\x0F\xBA\207\25", IF_386|IF_SB}, + {I_BTC, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\2\x0F\xBA\207\25", IF_386|IF_SB}, + ITEMPLATE_END +}; + +static struct itemplate instrux_BTR[] = { + {I_BTR, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xB3\101", IF_386|IF_SM}, + {I_BTR, 2, {REG16,REG16,0}, "\320\2\x0F\xB3\101", IF_386}, + {I_BTR, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xB3\101", IF_386|IF_SM}, + {I_BTR, 2, {REG32,REG32,0}, "\321\2\x0F\xB3\101", IF_386}, + {I_BTR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\2\x0F\xBA\206\25", IF_386|IF_SB}, + {I_BTR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\2\x0F\xBA\206\25", IF_386|IF_SB}, + ITEMPLATE_END +}; + +static struct itemplate instrux_BTS[] = { + {I_BTS, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xAB\101", IF_386|IF_SM}, + {I_BTS, 2, {REG16,REG16,0}, "\320\2\x0F\xAB\101", IF_386}, + {I_BTS, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xAB\101", IF_386|IF_SM}, + {I_BTS, 2, {REG32,REG32,0}, "\321\2\x0F\xAB\101", IF_386}, + {I_BTS, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\2\x0F\xBA\205\25", IF_386|IF_SB}, + {I_BTS, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\2\x0F\xBA\205\25", IF_386|IF_SB}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CALL[] = { + {I_CALL, 1, {IMMEDIATE,0,0}, "\322\1\xE8\64", IF_8086}, + {I_CALL, 1, {IMMEDIATE|NEAR,0,0}, "\322\1\xE8\64", IF_8086}, + {I_CALL, 1, {IMMEDIATE|FAR,0,0}, "\322\1\x9A\34\37", IF_8086}, + {I_CALL, 1, {IMMEDIATE|BITS16,0,0}, "\320\1\xE8\64", IF_8086}, + {I_CALL, 1, {IMMEDIATE|BITS16|NEAR,0,0}, "\320\1\xE8\64", IF_8086}, + {I_CALL, 1, {IMMEDIATE|BITS16|FAR,0,0}, "\320\1\x9A\34\37", IF_8086}, + {I_CALL, 1, {IMMEDIATE|BITS32,0,0}, "\321\1\xE8\64", IF_386}, + {I_CALL, 1, {IMMEDIATE|BITS32|NEAR,0,0}, "\321\1\xE8\64", IF_386}, + {I_CALL, 1, {IMMEDIATE|BITS32|FAR,0,0}, "\321\1\x9A\34\37", IF_386}, + {I_CALL, 2, {IMMEDIATE|COLON,IMMEDIATE,0}, "\322\1\x9A\35\30", IF_8086}, + {I_CALL, 2, {IMMEDIATE|BITS16|COLON,IMMEDIATE,0}, "\320\1\x9A\31\30", IF_8086}, + {I_CALL, 2, {IMMEDIATE|COLON,IMMEDIATE|BITS16,0}, "\320\1\x9A\31\30", IF_8086}, + {I_CALL, 2, {IMMEDIATE|BITS32|COLON,IMMEDIATE,0}, "\321\1\x9A\41\30", IF_386}, + {I_CALL, 2, {IMMEDIATE|COLON,IMMEDIATE|BITS32,0}, "\321\1\x9A\41\30", IF_386}, + {I_CALL, 1, {MEMORY|FAR,0,0}, "\322\300\1\xFF\203", IF_8086}, + {I_CALL, 1, {MEMORY|BITS16|FAR,0,0}, "\320\300\1\xFF\203", IF_8086}, + {I_CALL, 1, {MEMORY|BITS32|FAR,0,0}, "\321\300\1\xFF\203", IF_386}, + {I_CALL, 1, {MEMORY|NEAR,0,0}, "\322\300\1\xFF\202", IF_8086}, + {I_CALL, 1, {MEMORY|BITS16|NEAR,0,0}, "\320\300\1\xFF\202", IF_8086}, + {I_CALL, 1, {MEMORY|BITS32|NEAR,0,0}, "\321\300\1\xFF\202", IF_386}, + {I_CALL, 1, {REG16,0,0}, "\320\300\1\xFF\202", IF_8086}, + {I_CALL, 1, {REG32,0,0}, "\321\300\1\xFF\202", IF_386}, + {I_CALL, 1, {MEMORY,0,0}, "\322\300\1\xFF\202", IF_8086}, + {I_CALL, 1, {MEMORY|BITS16,0,0}, "\320\300\1\xFF\202", IF_8086}, + {I_CALL, 1, {MEMORY|BITS32,0,0}, "\321\300\1\xFF\202", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CBW[] = { + {I_CBW, 0, {0,0,0}, "\320\1\x98", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CDQ[] = { + {I_CDQ, 0, {0,0,0}, "\321\1\x99", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CLC[] = { + {I_CLC, 0, {0,0,0}, "\1\xF8", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CLD[] = { + {I_CLD, 0, {0,0,0}, "\1\xFC", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CLFLUSH[] = { + {I_CLFLUSH, 1, {MEMORY,0,0}, "\300\2\x0F\xAE\207", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CLI[] = { + {I_CLI, 0, {0,0,0}, "\1\xFA", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CLTS[] = { + {I_CLTS, 0, {0,0,0}, "\2\x0F\x06", IF_286|IF_PRIV}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMC[] = { + {I_CMC, 0, {0,0,0}, "\1\xF5", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMP[] = { + {I_CMP, 2, {MEMORY,REG8,0}, "\300\1\x38\101", IF_8086|IF_SM}, + {I_CMP, 2, {REG8,REG8,0}, "\1\x38\101", IF_8086}, + {I_CMP, 2, {MEMORY,REG16,0}, "\320\300\1\x39\101", IF_8086|IF_SM}, + {I_CMP, 2, {REG16,REG16,0}, "\320\1\x39\101", IF_8086}, + {I_CMP, 2, {MEMORY,REG32,0}, "\321\300\1\x39\101", IF_386|IF_SM}, + {I_CMP, 2, {REG32,REG32,0}, "\321\1\x39\101", IF_386}, + {I_CMP, 2, {REG8,MEMORY,0}, "\301\1\x3A\110", IF_8086|IF_SM}, + {I_CMP, 2, {REG8,REG8,0}, "\1\x3A\110", IF_8086}, + {I_CMP, 2, {REG16,MEMORY,0}, "\320\301\1\x3B\110", IF_8086|IF_SM}, + {I_CMP, 2, {REG16,REG16,0}, "\320\1\x3B\110", IF_8086}, + {I_CMP, 2, {REG32,MEMORY,0}, "\321\301\1\x3B\110", IF_386|IF_SM}, + {I_CMP, 2, {REG32,REG32,0}, "\321\1\x3B\110", IF_386}, + {I_CMP, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\207\15", IF_8086}, + {I_CMP, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\207\15", IF_386}, + {I_CMP, 2, {REG_AL,IMMEDIATE,0}, "\1\x3C\21", IF_8086|IF_SM}, + {I_CMP, 2, {REG_AX,SBYTE,0}, "\320\1\x83\207\15", IF_8086|IF_SM}, + {I_CMP, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x3D\31", IF_8086|IF_SM}, + {I_CMP, 2, {REG_EAX,SBYTE,0}, "\321\1\x83\207\15", IF_386|IF_SM}, + {I_CMP, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x3D\41", IF_386|IF_SM}, + {I_CMP, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\207\21", IF_8086|IF_SM}, + {I_CMP, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\207\131", IF_8086|IF_SM}, + {I_CMP, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\207\141", IF_386|IF_SM}, + {I_CMP, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\207\21", IF_8086|IF_SM}, + {I_CMP, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\207\131", IF_8086|IF_SM}, + {I_CMP, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\207\141", IF_386|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPEQPD[] = { + {I_CMPEQPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x00", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_CMPEQPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x00", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPEQPS[] = { + {I_CMPEQPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x00", IF_KATMAI|IF_SSE}, + {I_CMPEQPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x00", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPEQSD[] = { + {I_CMPEQSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x00", IF_WILLAMETTE|IF_SSE2}, + {I_CMPEQSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x00", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPEQSS[] = { + {I_CMPEQSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x00", IF_KATMAI|IF_SSE}, + {I_CMPEQSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x00", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPLEPD[] = { + {I_CMPLEPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x02", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_CMPLEPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x02", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPLEPS[] = { + {I_CMPLEPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x02", IF_KATMAI|IF_SSE}, + {I_CMPLEPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x02", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPLESD[] = { + {I_CMPLESD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x02", IF_WILLAMETTE|IF_SSE2}, + {I_CMPLESD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x02", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPLESS[] = { + {I_CMPLESS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x02", IF_KATMAI|IF_SSE}, + {I_CMPLESS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x02", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPLTPD[] = { + {I_CMPLTPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x01", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_CMPLTPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x01", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPLTPS[] = { + {I_CMPLTPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x01", IF_KATMAI|IF_SSE}, + {I_CMPLTPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x01", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPLTSD[] = { + {I_CMPLTSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x01", IF_WILLAMETTE|IF_SSE2}, + {I_CMPLTSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x01", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPLTSS[] = { + {I_CMPLTSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x01", IF_KATMAI|IF_SSE}, + {I_CMPLTSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x01", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPNEQPD[] = { + {I_CMPNEQPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x04", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_CMPNEQPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x04", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPNEQPS[] = { + {I_CMPNEQPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x04", IF_KATMAI|IF_SSE}, + {I_CMPNEQPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x04", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPNEQSD[] = { + {I_CMPNEQSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x04", IF_WILLAMETTE|IF_SSE2}, + {I_CMPNEQSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x04", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPNEQSS[] = { + {I_CMPNEQSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x04", IF_KATMAI|IF_SSE}, + {I_CMPNEQSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x04", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPNLEPD[] = { + {I_CMPNLEPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x06", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_CMPNLEPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x06", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPNLEPS[] = { + {I_CMPNLEPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x06", IF_KATMAI|IF_SSE}, + {I_CMPNLEPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x06", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPNLESD[] = { + {I_CMPNLESD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x06", IF_WILLAMETTE|IF_SSE2}, + {I_CMPNLESD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x06", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPNLESS[] = { + {I_CMPNLESS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x06", IF_KATMAI|IF_SSE}, + {I_CMPNLESS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x06", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPNLTPD[] = { + {I_CMPNLTPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x05", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_CMPNLTPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x05", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPNLTPS[] = { + {I_CMPNLTPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x05", IF_KATMAI|IF_SSE}, + {I_CMPNLTPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x05", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPNLTSD[] = { + {I_CMPNLTSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x05", IF_WILLAMETTE|IF_SSE2}, + {I_CMPNLTSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x05", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPNLTSS[] = { + {I_CMPNLTSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x05", IF_KATMAI|IF_SSE}, + {I_CMPNLTSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x05", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPORDPD[] = { + {I_CMPORDPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x07", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_CMPORDPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x07", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPORDPS[] = { + {I_CMPORDPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x07", IF_KATMAI|IF_SSE}, + {I_CMPORDPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x07", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPORDSD[] = { + {I_CMPORDSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x07", IF_WILLAMETTE|IF_SSE2}, + {I_CMPORDSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x07", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPORDSS[] = { + {I_CMPORDSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x07", IF_KATMAI|IF_SSE}, + {I_CMPORDSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x07", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPPD[] = { + {I_CMPPD, 3, {XMMREG,XMMREG,IMMEDIATE}, "\331\3\x66\x0F\xC2\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, + {I_CMPPD, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\331\3\x66\x0F\xC2\110\26", IF_WILLAMETTE|IF_SSE2|IF_SM2|IF_SB|IF_AR2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPPS[] = { + {I_CMPPS, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\331\2\x0F\xC2\110\26", IF_KATMAI|IF_SSE|IF_SB|IF_AR2}, + {I_CMPPS, 3, {XMMREG,XMMREG,IMMEDIATE}, "\331\2\x0F\xC2\110\26", IF_KATMAI|IF_SSE|IF_SB|IF_AR2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPSB[] = { + {I_CMPSB, 0, {0,0,0}, "\332\1\xA6", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPSD[] = { + {I_CMPSD, 0, {0,0,0}, "\332\321\1\xA7", IF_386}, + {I_CMPSD, 3, {XMMREG,XMMREG,IMMEDIATE}, "\331\3\xF2\x0F\xC2\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, + {I_CMPSD, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\331\3\xF2\x0F\xC2\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPSS[] = { + {I_CMPSS, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\333\2\x0F\xC2\110\26", IF_KATMAI|IF_SSE|IF_SB|IF_AR2}, + {I_CMPSS, 3, {XMMREG,XMMREG,IMMEDIATE}, "\333\2\x0F\xC2\110\26", IF_KATMAI|IF_SSE|IF_SB|IF_AR2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPSW[] = { + {I_CMPSW, 0, {0,0,0}, "\332\320\1\xA7", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPUNORDPD[] = { + {I_CMPUNORDPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x03", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_CMPUNORDPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x03", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPUNORDPS[] = { + {I_CMPUNORDPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x03", IF_KATMAI|IF_SSE}, + {I_CMPUNORDPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x03", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPUNORDSD[] = { + {I_CMPUNORDSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x03", IF_WILLAMETTE|IF_SSE2}, + {I_CMPUNORDSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x03", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPUNORDSS[] = { + {I_CMPUNORDSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x03", IF_KATMAI|IF_SSE}, + {I_CMPUNORDSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x03", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPXCHG[] = { + {I_CMPXCHG, 2, {MEMORY,REG8,0}, "\300\2\x0F\xB0\101", IF_PENT|IF_SM}, + {I_CMPXCHG, 2, {REG8,REG8,0}, "\2\x0F\xB0\101", IF_PENT}, + {I_CMPXCHG, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xB1\101", IF_PENT|IF_SM}, + {I_CMPXCHG, 2, {REG16,REG16,0}, "\320\2\x0F\xB1\101", IF_PENT}, + {I_CMPXCHG, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xB1\101", IF_PENT|IF_SM}, + {I_CMPXCHG, 2, {REG32,REG32,0}, "\321\2\x0F\xB1\101", IF_PENT}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPXCHG486[] = { + {I_CMPXCHG486, 2, {MEMORY,REG8,0}, "\300\2\x0F\xA6\101", IF_486|IF_SM|IF_UNDOC}, + {I_CMPXCHG486, 2, {REG8,REG8,0}, "\2\x0F\xA6\101", IF_486|IF_UNDOC}, + {I_CMPXCHG486, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xA7\101", IF_486|IF_SM|IF_UNDOC}, + {I_CMPXCHG486, 2, {REG16,REG16,0}, "\320\2\x0F\xA7\101", IF_486|IF_UNDOC}, + {I_CMPXCHG486, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xA7\101", IF_486|IF_SM|IF_UNDOC}, + {I_CMPXCHG486, 2, {REG32,REG32,0}, "\321\2\x0F\xA7\101", IF_486|IF_UNDOC}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMPXCHG8B[] = { + {I_CMPXCHG8B, 1, {MEMORY,0,0}, "\300\2\x0F\xC7\201", IF_PENT}, + ITEMPLATE_END +}; + +static struct itemplate instrux_COMISD[] = { + {I_COMISD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\x2F\110", IF_WILLAMETTE|IF_SSE2}, + {I_COMISD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\x2F\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_COMISS[] = { + {I_COMISS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x2F\110", IF_KATMAI|IF_SSE}, + {I_COMISS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x2F\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CPUID[] = { + {I_CPUID, 0, {0,0,0}, "\2\x0F\xA2", IF_PENT}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CVTDQ2PD[] = { + {I_CVTDQ2PD, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xE6\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTDQ2PD, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xE6\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CVTDQ2PS[] = { + {I_CVTDQ2PS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x5B\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTDQ2PS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x5B\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CVTPD2DQ[] = { + {I_CVTPD2DQ, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\xE6\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTPD2DQ, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\xE6\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CVTPD2PI[] = { + {I_CVTPD2PI, 2, {MMXREG,XMMREG,0}, "\3\x66\x0F\x2D\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTPD2PI, 2, {MMXREG,MEMORY,0}, "\301\3\x66\x0F\x2D\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CVTPD2PS[] = { + {I_CVTPD2PS, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTPD2PS, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CVTPI2PD[] = { + {I_CVTPI2PD, 2, {XMMREG,MMXREG,0}, "\3\x66\x0F\x2A\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTPI2PD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x2A\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CVTPI2PS[] = { + {I_CVTPI2PS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x2A\110", IF_KATMAI|IF_SSE|IF_MMX}, + {I_CVTPI2PS, 2, {XMMREG,MMXREG,0}, "\331\2\x0F\x2A\110", IF_KATMAI|IF_SSE|IF_MMX}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CVTPS2DQ[] = { + {I_CVTPS2DQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x5B\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTPS2DQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x5B\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CVTPS2PD[] = { + {I_CVTPS2PD, 2, {XMMREG,XMMREG,0}, "\2\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTPS2PD, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CVTPS2PI[] = { + {I_CVTPS2PI, 2, {MMXREG,MEMORY,0}, "\301\331\2\x0F\x2D\110", IF_KATMAI|IF_SSE|IF_MMX}, + {I_CVTPS2PI, 2, {MMXREG,XMMREG,0}, "\331\2\x0F\x2D\110", IF_KATMAI|IF_SSE|IF_MMX}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CVTSD2SI[] = { + {I_CVTSD2SI, 2, {REG32,XMMREG,0}, "\3\xF2\x0F\x2D\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTSD2SI, 2, {REG32,MEMORY,0}, "\301\3\xF2\x0F\x2D\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CVTSD2SS[] = { + {I_CVTSD2SS, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTSD2SS, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CVTSI2SD[] = { + {I_CVTSI2SD, 2, {XMMREG,REG32,0}, "\3\xF2\x0F\x2A\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTSI2SD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x2A\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CVTSI2SS[] = { + {I_CVTSI2SS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x2A\110", IF_KATMAI|IF_SSE|IF_SD|IF_AR1}, + {I_CVTSI2SS, 2, {XMMREG,REG32,0}, "\333\2\x0F\x2A\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CVTSS2SD[] = { + {I_CVTSS2SD, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTSS2SD, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CVTSS2SI[] = { + {I_CVTSS2SI, 2, {REG32,MEMORY,0}, "\301\333\2\x0F\x2D\110", IF_KATMAI|IF_SSE}, + {I_CVTSS2SI, 2, {REG32,XMMREG,0}, "\333\2\x0F\x2D\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CVTTPD2DQ[] = { + {I_CVTTPD2DQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE6\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTTPD2DQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE6\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CVTTPD2PI[] = { + {I_CVTTPD2PI, 2, {MMXREG,XMMREG,0}, "\3\x66\x0F\x2C\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTTPD2PI, 2, {MMXREG,MEMORY,0}, "\301\3\x66\x0F\x2C\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CVTTPS2DQ[] = { + {I_CVTTPS2DQ, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x5B\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTTPS2DQ, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x5B\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CVTTPS2PI[] = { + {I_CVTTPS2PI, 2, {MMXREG,MEMORY,0}, "\301\331\2\x0F\x2C\110", IF_KATMAI|IF_SSE|IF_MMX}, + {I_CVTTPS2PI, 2, {MMXREG,XMMREG,0}, "\331\2\x0F\x2C\110", IF_KATMAI|IF_SSE|IF_MMX}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CVTTSD2SI[] = { + {I_CVTTSD2SI, 2, {REG32,XMMREG,0}, "\3\xF2\x0F\x2C\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTTSD2SI, 2, {REG32,MEMORY,0}, "\301\3\xF2\x0F\x2C\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CVTTSS2SI[] = { + {I_CVTTSS2SI, 2, {REG32,MEMORY,0}, "\301\333\2\x0F\x2C\110", IF_KATMAI|IF_SSE}, + {I_CVTTSS2SI, 2, {REG32,XMMREG,0}, "\333\2\x0F\x2C\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CWD[] = { + {I_CWD, 0, {0,0,0}, "\320\1\x99", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CWDE[] = { + {I_CWDE, 0, {0,0,0}, "\321\1\x98", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_DAA[] = { + {I_DAA, 0, {0,0,0}, "\1\x27", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_DAS[] = { + {I_DAS, 0, {0,0,0}, "\1\x2F", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_DB[] = { + ITEMPLATE_END +}; + +static struct itemplate instrux_DD[] = { + ITEMPLATE_END +}; + +static struct itemplate instrux_DEC[] = { + {I_DEC, 1, {REG16,0,0}, "\320\10\x48", IF_8086}, + {I_DEC, 1, {REG32,0,0}, "\321\10\x48", IF_386}, + {I_DEC, 1, {REGMEM|BITS8,0,0}, "\300\1\xFE\201", IF_8086}, + {I_DEC, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xFF\201", IF_8086}, + {I_DEC, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xFF\201", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_DIV[] = { + {I_DIV, 1, {REGMEM|BITS8,0,0}, "\300\1\xF6\206", IF_8086}, + {I_DIV, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xF7\206", IF_8086}, + {I_DIV, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xF7\206", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_DIVPD[] = { + {I_DIVPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x5E\110", IF_WILLAMETTE|IF_SSE2}, + {I_DIVPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x5E\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_DIVPS[] = { + {I_DIVPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x5E\110", IF_KATMAI|IF_SSE}, + {I_DIVPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x5E\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_DIVSD[] = { + {I_DIVSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x5E\110", IF_WILLAMETTE|IF_SSE2}, + {I_DIVSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x5E\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_DIVSS[] = { + {I_DIVSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x5E\110", IF_KATMAI|IF_SSE}, + {I_DIVSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x5E\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_DQ[] = { + ITEMPLATE_END +}; + +static struct itemplate instrux_DT[] = { + ITEMPLATE_END +}; + +static struct itemplate instrux_DW[] = { + ITEMPLATE_END +}; + +static struct itemplate instrux_EMMS[] = { + {I_EMMS, 0, {0,0,0}, "\2\x0F\x77", IF_PENT|IF_MMX}, + ITEMPLATE_END +}; + +static struct itemplate instrux_ENTER[] = { + {I_ENTER, 2, {IMMEDIATE,IMMEDIATE,0}, "\1\xC8\30\25", IF_186}, + ITEMPLATE_END +}; + +static struct itemplate instrux_EQU[] = { + {I_EQU, 1, {IMMEDIATE,0,0}, "\0", IF_8086}, + {I_EQU, 2, {IMMEDIATE|COLON,IMMEDIATE,0}, "\0", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_F2XM1[] = { + {I_F2XM1, 0, {0,0,0}, "\2\xD9\xF0", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FABS[] = { + {I_FABS, 0, {0,0,0}, "\2\xD9\xE1", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FADD[] = { + {I_FADD, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\200", IF_8086|IF_FPU}, + {I_FADD, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\200", IF_8086|IF_FPU}, + {I_FADD, 1, {FPUREG|TO,0,0}, "\1\xDC\10\xC0", IF_8086|IF_FPU}, + {I_FADD, 1, {FPUREG,0,0}, "\1\xD8\10\xC0", IF_8086|IF_FPU}, + {I_FADD, 2, {FPUREG,FPU0,0}, "\1\xDC\10\xC0", IF_8086|IF_FPU}, + {I_FADD, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xC0", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FADDP[] = { + {I_FADDP, 1, {FPUREG,0,0}, "\1\xDE\10\xC0", IF_8086|IF_FPU}, + {I_FADDP, 2, {FPUREG,FPU0,0}, "\1\xDE\10\xC0", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FBLD[] = { + {I_FBLD, 1, {MEMORY|BITS80,0,0}, "\300\1\xDF\204", IF_8086|IF_FPU}, + {I_FBLD, 1, {MEMORY,0,0}, "\300\1\xDF\204", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FBSTP[] = { + {I_FBSTP, 1, {MEMORY|BITS80,0,0}, "\300\1\xDF\206", IF_8086|IF_FPU}, + {I_FBSTP, 1, {MEMORY,0,0}, "\300\1\xDF\206", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FCHS[] = { + {I_FCHS, 0, {0,0,0}, "\2\xD9\xE0", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FCLEX[] = { + {I_FCLEX, 0, {0,0,0}, "\3\x9B\xDB\xE2", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FCMOVB[] = { + {I_FCMOVB, 1, {FPUREG,0,0}, "\1\xDA\10\xC0", IF_P6|IF_FPU}, + {I_FCMOVB, 2, {FPU0,FPUREG,0}, "\1\xDA\11\xC0", IF_P6|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FCMOVBE[] = { + {I_FCMOVBE, 1, {FPUREG,0,0}, "\1\xDA\10\xD0", IF_P6|IF_FPU}, + {I_FCMOVBE, 2, {FPU0,FPUREG,0}, "\1\xDA\11\xD0", IF_P6|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FCMOVE[] = { + {I_FCMOVE, 1, {FPUREG,0,0}, "\1\xDA\10\xC8", IF_P6|IF_FPU}, + {I_FCMOVE, 2, {FPU0,FPUREG,0}, "\1\xDA\11\xC8", IF_P6|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FCMOVNB[] = { + {I_FCMOVNB, 1, {FPUREG,0,0}, "\1\xDB\10\xC0", IF_P6|IF_FPU}, + {I_FCMOVNB, 2, {FPU0,FPUREG,0}, "\1\xDB\11\xC0", IF_P6|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FCMOVNBE[] = { + {I_FCMOVNBE, 1, {FPUREG,0,0}, "\1\xDB\10\xD0", IF_P6|IF_FPU}, + {I_FCMOVNBE, 2, {FPU0,FPUREG,0}, "\1\xDB\11\xD0", IF_P6|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FCMOVNE[] = { + {I_FCMOVNE, 1, {FPUREG,0,0}, "\1\xDB\10\xC8", IF_P6|IF_FPU}, + {I_FCMOVNE, 2, {FPU0,FPUREG,0}, "\1\xDB\11\xC8", IF_P6|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FCMOVNU[] = { + {I_FCMOVNU, 1, {FPUREG,0,0}, "\1\xDB\10\xD8", IF_P6|IF_FPU}, + {I_FCMOVNU, 2, {FPU0,FPUREG,0}, "\1\xDB\11\xD8", IF_P6|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FCMOVU[] = { + {I_FCMOVU, 1, {FPUREG,0,0}, "\1\xDA\10\xD8", IF_P6|IF_FPU}, + {I_FCMOVU, 2, {FPU0,FPUREG,0}, "\1\xDA\11\xD8", IF_P6|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FCOM[] = { + {I_FCOM, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\202", IF_8086|IF_FPU}, + {I_FCOM, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\202", IF_8086|IF_FPU}, + {I_FCOM, 1, {FPUREG,0,0}, "\1\xD8\10\xD0", IF_8086|IF_FPU}, + {I_FCOM, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xD0", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FCOMI[] = { + {I_FCOMI, 1, {FPUREG,0,0}, "\1\xDB\10\xF0", IF_P6|IF_FPU}, + {I_FCOMI, 2, {FPU0,FPUREG,0}, "\1\xDB\11\xF0", IF_P6|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FCOMIP[] = { + {I_FCOMIP, 1, {FPUREG,0,0}, "\1\xDF\10\xF0", IF_P6|IF_FPU}, + {I_FCOMIP, 2, {FPU0,FPUREG,0}, "\1\xDF\11\xF0", IF_P6|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FCOMP[] = { + {I_FCOMP, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\203", IF_8086|IF_FPU}, + {I_FCOMP, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\203", IF_8086|IF_FPU}, + {I_FCOMP, 1, {FPUREG,0,0}, "\1\xD8\10\xD8", IF_8086|IF_FPU}, + {I_FCOMP, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xD8", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FCOMPP[] = { + {I_FCOMPP, 0, {0,0,0}, "\2\xDE\xD9", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FCOS[] = { + {I_FCOS, 0, {0,0,0}, "\2\xD9\xFF", IF_386|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FDECSTP[] = { + {I_FDECSTP, 0, {0,0,0}, "\2\xD9\xF6", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FDISI[] = { + {I_FDISI, 0, {0,0,0}, "\3\x9B\xDB\xE1", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FDIV[] = { + {I_FDIV, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\206", IF_8086|IF_FPU}, + {I_FDIV, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\206", IF_8086|IF_FPU}, + {I_FDIV, 1, {FPUREG|TO,0,0}, "\1\xDC\10\xF8", IF_8086|IF_FPU}, + {I_FDIV, 2, {FPUREG,FPU0,0}, "\1\xDC\10\xF8", IF_8086|IF_FPU}, + {I_FDIV, 1, {FPUREG,0,0}, "\1\xD8\10\xF0", IF_8086|IF_FPU}, + {I_FDIV, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xF0", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FDIVP[] = { + {I_FDIVP, 2, {FPUREG,FPU0,0}, "\1\xDE\10\xF8", IF_8086|IF_FPU}, + {I_FDIVP, 1, {FPUREG,0,0}, "\1\xDE\10\xF8", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FDIVR[] = { + {I_FDIVR, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\207", IF_8086|IF_FPU}, + {I_FDIVR, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\207", IF_8086|IF_FPU}, + {I_FDIVR, 1, {FPUREG|TO,0,0}, "\1\xDC\10\xF0", IF_8086|IF_FPU}, + {I_FDIVR, 2, {FPUREG,FPU0,0}, "\1\xDC\10\xF0", IF_8086|IF_FPU}, + {I_FDIVR, 1, {FPUREG,0,0}, "\1\xD8\10\xF8", IF_8086|IF_FPU}, + {I_FDIVR, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xF8", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FDIVRP[] = { + {I_FDIVRP, 1, {FPUREG,0,0}, "\1\xDE\10\xF0", IF_8086|IF_FPU}, + {I_FDIVRP, 2, {FPUREG,FPU0,0}, "\1\xDE\10\xF0", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FEMMS[] = { + {I_FEMMS, 0, {0,0,0}, "\2\x0F\x0E", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FENI[] = { + {I_FENI, 0, {0,0,0}, "\3\x9B\xDB\xE0", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FFREE[] = { + {I_FFREE, 1, {FPUREG,0,0}, "\1\xDD\10\xC0", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FFREEP[] = { + {I_FFREEP, 1, {FPUREG,0,0}, "\1\xDF\10\xC0", IF_286|IF_FPU|IF_UNDOC}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FIADD[] = { + {I_FIADD, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\200", IF_8086|IF_FPU}, + {I_FIADD, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\200", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FICOM[] = { + {I_FICOM, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\202", IF_8086|IF_FPU}, + {I_FICOM, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\202", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FICOMP[] = { + {I_FICOMP, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\203", IF_8086|IF_FPU}, + {I_FICOMP, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\203", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FIDIV[] = { + {I_FIDIV, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\206", IF_8086|IF_FPU}, + {I_FIDIV, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\206", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FIDIVR[] = { + {I_FIDIVR, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\207", IF_8086|IF_FPU}, + {I_FIDIVR, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\207", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FILD[] = { + {I_FILD, 1, {MEMORY|BITS32,0,0}, "\300\1\xDB\200", IF_8086|IF_FPU}, + {I_FILD, 1, {MEMORY|BITS16,0,0}, "\300\1\xDF\200", IF_8086|IF_FPU}, + {I_FILD, 1, {MEMORY|BITS64,0,0}, "\300\1\xDF\205", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FIMUL[] = { + {I_FIMUL, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\201", IF_8086|IF_FPU}, + {I_FIMUL, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\201", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FINCSTP[] = { + {I_FINCSTP, 0, {0,0,0}, "\2\xD9\xF7", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FINIT[] = { + {I_FINIT, 0, {0,0,0}, "\3\x9B\xDB\xE3", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FIST[] = { + {I_FIST, 1, {MEMORY|BITS32,0,0}, "\300\1\xDB\202", IF_8086|IF_FPU}, + {I_FIST, 1, {MEMORY|BITS16,0,0}, "\300\1\xDF\202", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FISTP[] = { + {I_FISTP, 1, {MEMORY|BITS32,0,0}, "\300\1\xDB\203", IF_8086|IF_FPU}, + {I_FISTP, 1, {MEMORY|BITS16,0,0}, "\300\1\xDF\203", IF_8086|IF_FPU}, + {I_FISTP, 1, {MEMORY|BITS64,0,0}, "\300\1\xDF\207", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FISTTP[] = { + {I_FISTTP, 1, {MEMORY|BITS32,0,0}, "\300\1\xDD\201", IF_PRESCOTT|IF_FPU}, + {I_FISTTP, 1, {MEMORY|BITS16,0,0}, "\300\1\xDB\201", IF_PRESCOTT|IF_FPU}, + {I_FISTTP, 1, {MEMORY|BITS64,0,0}, "\300\1\xDF\201", IF_PRESCOTT|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FISUB[] = { + {I_FISUB, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\204", IF_8086|IF_FPU}, + {I_FISUB, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\204", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FISUBR[] = { + {I_FISUBR, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\205", IF_8086|IF_FPU}, + {I_FISUBR, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\205", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FLD[] = { + {I_FLD, 1, {MEMORY|BITS32,0,0}, "\300\1\xD9\200", IF_8086|IF_FPU}, + {I_FLD, 1, {MEMORY|BITS64,0,0}, "\300\1\xDD\200", IF_8086|IF_FPU}, + {I_FLD, 1, {MEMORY|BITS80,0,0}, "\300\1\xDB\205", IF_8086|IF_FPU}, + {I_FLD, 1, {FPUREG,0,0}, "\1\xD9\10\xC0", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FLD1[] = { + {I_FLD1, 0, {0,0,0}, "\2\xD9\xE8", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FLDCW[] = { + {I_FLDCW, 1, {MEMORY,0,0}, "\300\1\xD9\205", IF_8086|IF_FPU|IF_SW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FLDENV[] = { + {I_FLDENV, 1, {MEMORY,0,0}, "\300\1\xD9\204", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FLDL2E[] = { + {I_FLDL2E, 0, {0,0,0}, "\2\xD9\xEA", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FLDL2T[] = { + {I_FLDL2T, 0, {0,0,0}, "\2\xD9\xE9", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FLDLG2[] = { + {I_FLDLG2, 0, {0,0,0}, "\2\xD9\xEC", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FLDLN2[] = { + {I_FLDLN2, 0, {0,0,0}, "\2\xD9\xED", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FLDPI[] = { + {I_FLDPI, 0, {0,0,0}, "\2\xD9\xEB", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FLDZ[] = { + {I_FLDZ, 0, {0,0,0}, "\2\xD9\xEE", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FMUL[] = { + {I_FMUL, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\201", IF_8086|IF_FPU}, + {I_FMUL, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\201", IF_8086|IF_FPU}, + {I_FMUL, 1, {FPUREG|TO,0,0}, "\1\xDC\10\xC8", IF_8086|IF_FPU}, + {I_FMUL, 2, {FPUREG,FPU0,0}, "\1\xDC\10\xC8", IF_8086|IF_FPU}, + {I_FMUL, 1, {FPUREG,0,0}, "\1\xD8\10\xC8", IF_8086|IF_FPU}, + {I_FMUL, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xC8", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FMULP[] = { + {I_FMULP, 1, {FPUREG,0,0}, "\1\xDE\10\xC8", IF_8086|IF_FPU}, + {I_FMULP, 2, {FPUREG,FPU0,0}, "\1\xDE\10\xC8", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FNCLEX[] = { + {I_FNCLEX, 0, {0,0,0}, "\2\xDB\xE2", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FNDISI[] = { + {I_FNDISI, 0, {0,0,0}, "\2\xDB\xE1", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FNENI[] = { + {I_FNENI, 0, {0,0,0}, "\2\xDB\xE0", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FNINIT[] = { + {I_FNINIT, 0, {0,0,0}, "\2\xDB\xE3", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FNOP[] = { + {I_FNOP, 0, {0,0,0}, "\2\xD9\xD0", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FNSAVE[] = { + {I_FNSAVE, 1, {MEMORY,0,0}, "\300\1\xDD\206", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FNSTCW[] = { + {I_FNSTCW, 1, {MEMORY,0,0}, "\300\1\xD9\207", IF_8086|IF_FPU|IF_SW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FNSTENV[] = { + {I_FNSTENV, 1, {MEMORY,0,0}, "\300\1\xD9\206", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FNSTSW[] = { + {I_FNSTSW, 1, {MEMORY,0,0}, "\300\1\xDD\207", IF_8086|IF_FPU|IF_SW}, + {I_FNSTSW, 1, {REG_AX,0,0}, "\2\xDF\xE0", IF_286|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FPATAN[] = { + {I_FPATAN, 0, {0,0,0}, "\2\xD9\xF3", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FPREM[] = { + {I_FPREM, 0, {0,0,0}, "\2\xD9\xF8", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FPREM1[] = { + {I_FPREM1, 0, {0,0,0}, "\2\xD9\xF5", IF_386|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FPTAN[] = { + {I_FPTAN, 0, {0,0,0}, "\2\xD9\xF2", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FRNDINT[] = { + {I_FRNDINT, 0, {0,0,0}, "\2\xD9\xFC", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FRSTOR[] = { + {I_FRSTOR, 1, {MEMORY,0,0}, "\300\1\xDD\204", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FSAVE[] = { + {I_FSAVE, 1, {MEMORY,0,0}, "\300\2\x9B\xDD\206", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FSCALE[] = { + {I_FSCALE, 0, {0,0,0}, "\2\xD9\xFD", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FSETPM[] = { + {I_FSETPM, 0, {0,0,0}, "\2\xDB\xE4", IF_286|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FSIN[] = { + {I_FSIN, 0, {0,0,0}, "\2\xD9\xFE", IF_386|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FSINCOS[] = { + {I_FSINCOS, 0, {0,0,0}, "\2\xD9\xFB", IF_386|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FSQRT[] = { + {I_FSQRT, 0, {0,0,0}, "\2\xD9\xFA", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FST[] = { + {I_FST, 1, {MEMORY|BITS32,0,0}, "\300\1\xD9\202", IF_8086|IF_FPU}, + {I_FST, 1, {MEMORY|BITS64,0,0}, "\300\1\xDD\202", IF_8086|IF_FPU}, + {I_FST, 1, {FPUREG,0,0}, "\1\xDD\10\xD0", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FSTCW[] = { + {I_FSTCW, 1, {MEMORY,0,0}, "\300\2\x9B\xD9\207", IF_8086|IF_FPU|IF_SW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FSTENV[] = { + {I_FSTENV, 1, {MEMORY,0,0}, "\300\2\x9B\xD9\206", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FSTP[] = { + {I_FSTP, 1, {MEMORY|BITS32,0,0}, "\300\1\xD9\203", IF_8086|IF_FPU}, + {I_FSTP, 1, {MEMORY|BITS64,0,0}, "\300\1\xDD\203", IF_8086|IF_FPU}, + {I_FSTP, 1, {MEMORY|BITS80,0,0}, "\300\1\xDB\207", IF_8086|IF_FPU}, + {I_FSTP, 1, {FPUREG,0,0}, "\1\xDD\10\xD8", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FSTSW[] = { + {I_FSTSW, 1, {MEMORY,0,0}, "\300\2\x9B\xDD\207", IF_8086|IF_FPU|IF_SW}, + {I_FSTSW, 1, {REG_AX,0,0}, "\3\x9B\xDF\xE0", IF_286|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FSUB[] = { + {I_FSUB, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\204", IF_8086|IF_FPU}, + {I_FSUB, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\204", IF_8086|IF_FPU}, + {I_FSUB, 1, {FPUREG|TO,0,0}, "\1\xDC\10\xE8", IF_8086|IF_FPU}, + {I_FSUB, 2, {FPUREG,FPU0,0}, "\1\xDC\10\xE8", IF_8086|IF_FPU}, + {I_FSUB, 1, {FPUREG,0,0}, "\1\xD8\10\xE0", IF_8086|IF_FPU}, + {I_FSUB, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xE0", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FSUBP[] = { + {I_FSUBP, 1, {FPUREG,0,0}, "\1\xDE\10\xE8", IF_8086|IF_FPU}, + {I_FSUBP, 2, {FPUREG,FPU0,0}, "\1\xDE\10\xE8", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FSUBR[] = { + {I_FSUBR, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\205", IF_8086|IF_FPU}, + {I_FSUBR, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\205", IF_8086|IF_FPU}, + {I_FSUBR, 1, {FPUREG|TO,0,0}, "\1\xDC\10\xE0", IF_8086|IF_FPU}, + {I_FSUBR, 2, {FPUREG,FPU0,0}, "\1\xDC\10\xE0", IF_8086|IF_FPU}, + {I_FSUBR, 1, {FPUREG,0,0}, "\1\xD8\10\xE8", IF_8086|IF_FPU}, + {I_FSUBR, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xE8", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FSUBRP[] = { + {I_FSUBRP, 1, {FPUREG,0,0}, "\1\xDE\10\xE0", IF_8086|IF_FPU}, + {I_FSUBRP, 2, {FPUREG,FPU0,0}, "\1\xDE\10\xE0", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FTST[] = { + {I_FTST, 0, {0,0,0}, "\2\xD9\xE4", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FUCOM[] = { + {I_FUCOM, 1, {FPUREG,0,0}, "\1\xDD\10\xE0", IF_386|IF_FPU}, + {I_FUCOM, 2, {FPU0,FPUREG,0}, "\1\xDD\11\xE0", IF_386|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FUCOMI[] = { + {I_FUCOMI, 1, {FPUREG,0,0}, "\1\xDB\10\xE8", IF_P6|IF_FPU}, + {I_FUCOMI, 2, {FPU0,FPUREG,0}, "\1\xDB\11\xE8", IF_P6|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FUCOMIP[] = { + {I_FUCOMIP, 1, {FPUREG,0,0}, "\1\xDF\10\xE8", IF_P6|IF_FPU}, + {I_FUCOMIP, 2, {FPU0,FPUREG,0}, "\1\xDF\11\xE8", IF_P6|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FUCOMP[] = { + {I_FUCOMP, 1, {FPUREG,0,0}, "\1\xDD\10\xE8", IF_386|IF_FPU}, + {I_FUCOMP, 2, {FPU0,FPUREG,0}, "\1\xDD\11\xE8", IF_386|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FUCOMPP[] = { + {I_FUCOMPP, 0, {0,0,0}, "\2\xDA\xE9", IF_386|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FWAIT[] = { + {I_FWAIT, 0, {0,0,0}, "\1\x9B", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FXAM[] = { + {I_FXAM, 0, {0,0,0}, "\2\xD9\xE5", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FXCH[] = { + {I_FXCH, 0, {0,0,0}, "\2\xD9\xC9", IF_8086|IF_FPU}, + {I_FXCH, 1, {FPUREG,0,0}, "\1\xD9\10\xC8", IF_8086|IF_FPU}, + {I_FXCH, 2, {FPUREG,FPU0,0}, "\1\xD9\10\xC8", IF_8086|IF_FPU}, + {I_FXCH, 2, {FPU0,FPUREG,0}, "\1\xD9\11\xC8", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FXRSTOR[] = { + {I_FXRSTOR, 1, {MEMORY,0,0}, "\300\2\x0F\xAE\201", IF_P6|IF_SSE|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FXSAVE[] = { + {I_FXSAVE, 1, {MEMORY,0,0}, "\300\2\x0F\xAE\200", IF_P6|IF_SSE|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FXTRACT[] = { + {I_FXTRACT, 0, {0,0,0}, "\2\xD9\xF4", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FYL2X[] = { + {I_FYL2X, 0, {0,0,0}, "\2\xD9\xF1", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_FYL2XP1[] = { + {I_FYL2XP1, 0, {0,0,0}, "\2\xD9\xF9", IF_8086|IF_FPU}, + ITEMPLATE_END +}; + +static struct itemplate instrux_HADDPD[] = { + {I_HADDPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x7C\110", IF_PRESCOTT|IF_SSE3|IF_SM}, + {I_HADDPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x7C\110", IF_PRESCOTT|IF_SSE3}, + ITEMPLATE_END +}; + +static struct itemplate instrux_HADDPS[] = { + {I_HADDPS, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x7C\110", IF_PRESCOTT|IF_SSE3|IF_SM}, + {I_HADDPS, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x7C\110", IF_PRESCOTT|IF_SSE3}, + ITEMPLATE_END +}; + +static struct itemplate instrux_HLT[] = { + {I_HLT, 0, {0,0,0}, "\1\xF4", IF_8086|IF_PRIV}, + ITEMPLATE_END +}; + +static struct itemplate instrux_HSUBPD[] = { + {I_HSUBPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x7D\110", IF_PRESCOTT|IF_SSE3|IF_SM}, + {I_HSUBPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x7D\110", IF_PRESCOTT|IF_SSE3}, + ITEMPLATE_END +}; + +static struct itemplate instrux_HSUBPS[] = { + {I_HSUBPS, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x7D\110", IF_PRESCOTT|IF_SSE3|IF_SM}, + {I_HSUBPS, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x7D\110", IF_PRESCOTT|IF_SSE3}, + ITEMPLATE_END +}; + +static struct itemplate instrux_IBTS[] = { + {I_IBTS, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xA7\101", IF_386|IF_SW|IF_UNDOC}, + {I_IBTS, 2, {REG16,REG16,0}, "\320\2\x0F\xA7\101", IF_386|IF_UNDOC}, + {I_IBTS, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xA7\101", IF_386|IF_SD|IF_UNDOC}, + {I_IBTS, 2, {REG32,REG32,0}, "\321\2\x0F\xA7\101", IF_386|IF_UNDOC}, + ITEMPLATE_END +}; + +static struct itemplate instrux_ICEBP[] = { + {I_ICEBP, 0, {0,0,0}, "\1\xF1", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_IDIV[] = { + {I_IDIV, 1, {REGMEM|BITS8,0,0}, "\300\1\xF6\207", IF_8086}, + {I_IDIV, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xF7\207", IF_8086}, + {I_IDIV, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xF7\207", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_IMUL[] = { + {I_IMUL, 1, {REGMEM|BITS8,0,0}, "\300\1\xF6\205", IF_8086}, + {I_IMUL, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xF7\205", IF_8086}, + {I_IMUL, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xF7\205", IF_386}, + {I_IMUL, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xAF\110", IF_386|IF_SM}, + {I_IMUL, 2, {REG16,REG16,0}, "\320\2\x0F\xAF\110", IF_386}, + {I_IMUL, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xAF\110", IF_386|IF_SM}, + {I_IMUL, 2, {REG32,REG32,0}, "\321\2\x0F\xAF\110", IF_386}, + {I_IMUL, 3, {REG16,MEMORY,IMMEDIATE|BITS8}, "\320\301\1\x6B\110\16", IF_186|IF_SM}, + {I_IMUL, 3, {REG16,MEMORY,SBYTE}, "\320\301\1\x6B\110\16", IF_186|IF_SM}, + {I_IMUL, 3, {REG16,MEMORY,IMMEDIATE|BITS16}, "\320\301\1\x69\110\32", IF_186|IF_SM}, + {I_IMUL, 3, {REG16,MEMORY,IMMEDIATE}, "\320\301\135\1\x69\110\132", IF_186|IF_SM}, + {I_IMUL, 3, {REG16,REG16,IMMEDIATE|BITS8}, "\320\1\x6B\110\16", IF_186}, + {I_IMUL, 3, {REG16,REG16,SBYTE}, "\320\1\x6B\110\16", IF_186|IF_SM}, + {I_IMUL, 3, {REG16,REG16,IMMEDIATE|BITS16}, "\320\1\x69\110\32", IF_186}, + {I_IMUL, 3, {REG16,REG16,IMMEDIATE}, "\320\135\1\x69\110\132", IF_186|IF_SM}, + {I_IMUL, 3, {REG32,MEMORY,IMMEDIATE|BITS8}, "\321\301\1\x6B\110\16", IF_386|IF_SM}, + {I_IMUL, 3, {REG32,MEMORY,SBYTE}, "\321\301\1\x6B\110\16", IF_386|IF_SM}, + {I_IMUL, 3, {REG32,MEMORY,IMMEDIATE|BITS32}, "\321\301\1\x69\110\42", IF_386|IF_SM}, + {I_IMUL, 3, {REG32,MEMORY,IMMEDIATE}, "\321\301\145\1\x69\110\142", IF_386|IF_SM}, + {I_IMUL, 3, {REG32,REG32,IMMEDIATE|BITS8}, "\321\1\x6B\110\16", IF_386}, + {I_IMUL, 3, {REG32,REG32,SBYTE}, "\321\1\x6B\110\16", IF_386|IF_SM}, + {I_IMUL, 3, {REG32,REG32,IMMEDIATE|BITS32}, "\321\1\x69\110\42", IF_386}, + {I_IMUL, 3, {REG32,REG32,IMMEDIATE}, "\321\145\1\x69\110\142", IF_386|IF_SM}, + {I_IMUL, 2, {REG16,IMMEDIATE|BITS8,0}, "\320\1\x6B\100\15", IF_186}, + {I_IMUL, 2, {REG16,SBYTE,0}, "\320\1\x6B\100\15", IF_186|IF_SM}, + {I_IMUL, 2, {REG16,IMMEDIATE|BITS16,0}, "\320\1\x69\100\31", IF_186}, + {I_IMUL, 2, {REG16,IMMEDIATE,0}, "\320\134\1\x69\100\131", IF_186|IF_SM}, + {I_IMUL, 2, {REG32,IMMEDIATE|BITS8,0}, "\321\1\x6B\100\15", IF_386}, + {I_IMUL, 2, {REG32,SBYTE,0}, "\321\1\x6B\100\15", IF_386|IF_SM}, + {I_IMUL, 2, {REG32,IMMEDIATE|BITS32,0}, "\321\1\x69\100\41", IF_386}, + {I_IMUL, 2, {REG32,IMMEDIATE,0}, "\321\144\1\x69\100\141", IF_386|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_IN[] = { + {I_IN, 2, {REG_AL,IMMEDIATE,0}, "\1\xE4\25", IF_8086|IF_SB}, + {I_IN, 2, {REG_AX,IMMEDIATE,0}, "\320\1\xE5\25", IF_8086|IF_SB}, + {I_IN, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\xE5\25", IF_386|IF_SB}, + {I_IN, 2, {REG_AL,REG_DX,0}, "\1\xEC", IF_8086}, + {I_IN, 2, {REG_AX,REG_DX,0}, "\320\1\xED", IF_8086}, + {I_IN, 2, {REG_EAX,REG_DX,0}, "\321\1\xED", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_INC[] = { + {I_INC, 1, {REG16,0,0}, "\320\10\x40", IF_8086}, + {I_INC, 1, {REG32,0,0}, "\321\10\x40", IF_386}, + {I_INC, 1, {REGMEM|BITS8,0,0}, "\300\1\xFE\200", IF_8086}, + {I_INC, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xFF\200", IF_8086}, + {I_INC, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xFF\200", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_INCBIN[] = { + ITEMPLATE_END +}; + +static struct itemplate instrux_INSB[] = { + {I_INSB, 0, {0,0,0}, "\1\x6C", IF_186}, + ITEMPLATE_END +}; + +static struct itemplate instrux_INSD[] = { + {I_INSD, 0, {0,0,0}, "\321\1\x6D", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_INSW[] = { + {I_INSW, 0, {0,0,0}, "\320\1\x6D", IF_186}, + ITEMPLATE_END +}; + +static struct itemplate instrux_INT[] = { + {I_INT, 1, {IMMEDIATE,0,0}, "\1\xCD\24", IF_8086|IF_SB}, + ITEMPLATE_END +}; + +static struct itemplate instrux_INT01[] = { + {I_INT01, 0, {0,0,0}, "\1\xF1", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_INT03[] = { + {I_INT03, 0, {0,0,0}, "\1\xCC", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_INT1[] = { + {I_INT1, 0, {0,0,0}, "\1\xF1", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_INT3[] = { + {I_INT3, 0, {0,0,0}, "\1\xCC", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_INTO[] = { + {I_INTO, 0, {0,0,0}, "\1\xCE", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_INVD[] = { + {I_INVD, 0, {0,0,0}, "\2\x0F\x08", IF_486|IF_PRIV}, + ITEMPLATE_END +}; + +static struct itemplate instrux_INVLPG[] = { + {I_INVLPG, 1, {MEMORY,0,0}, "\300\2\x0F\x01\207", IF_486|IF_PRIV}, + ITEMPLATE_END +}; + +static struct itemplate instrux_IRET[] = { + {I_IRET, 0, {0,0,0}, "\322\1\xCF", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_IRETD[] = { + {I_IRETD, 0, {0,0,0}, "\321\1\xCF", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_IRETW[] = { + {I_IRETW, 0, {0,0,0}, "\320\1\xCF", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_JCXZ[] = { + {I_JCXZ, 1, {IMMEDIATE,0,0}, "\310\1\xE3\50", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_JECXZ[] = { + {I_JECXZ, 1, {IMMEDIATE,0,0}, "\311\1\xE3\50", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_JMP[] = { + {I_JMP, 1, {IMMEDIATE|SHORT,0,0}, "\1\xEB\50", IF_8086}, + {I_JMP, 1, {IMMEDIATE,0,0}, "\371\1\xEB\50", IF_8086}, + {I_JMP, 1, {IMMEDIATE,0,0}, "\322\1\xE9\64", IF_8086}, + {I_JMP, 1, {IMMEDIATE|NEAR,0,0}, "\322\1\xE9\64", IF_8086}, + {I_JMP, 1, {IMMEDIATE|FAR,0,0}, "\322\1\xEA\34\37", IF_8086}, + {I_JMP, 1, {IMMEDIATE|BITS16,0,0}, "\320\1\xE9\64", IF_8086}, + {I_JMP, 1, {IMMEDIATE|BITS16|NEAR,0,0}, "\320\1\xE9\64", IF_8086}, + {I_JMP, 1, {IMMEDIATE|BITS16|FAR,0,0}, "\320\1\xEA\34\37", IF_8086}, + {I_JMP, 1, {IMMEDIATE|BITS32,0,0}, "\321\1\xE9\64", IF_386}, + {I_JMP, 1, {IMMEDIATE|BITS32|NEAR,0,0}, "\321\1\xE9\64", IF_386}, + {I_JMP, 1, {IMMEDIATE|BITS32|FAR,0,0}, "\321\1\xEA\34\37", IF_386}, + {I_JMP, 2, {IMMEDIATE|COLON,IMMEDIATE,0}, "\322\1\xEA\35\30", IF_8086}, + {I_JMP, 2, {IMMEDIATE|BITS16|COLON,IMMEDIATE,0}, "\320\1\xEA\31\30", IF_8086}, + {I_JMP, 2, {IMMEDIATE|COLON,IMMEDIATE|BITS16,0}, "\320\1\xEA\31\30", IF_8086}, + {I_JMP, 2, {IMMEDIATE|BITS32|COLON,IMMEDIATE,0}, "\321\1\xEA\41\30", IF_386}, + {I_JMP, 2, {IMMEDIATE|COLON,IMMEDIATE|BITS32,0}, "\321\1\xEA\41\30", IF_386}, + {I_JMP, 1, {MEMORY|FAR,0,0}, "\322\300\1\xFF\205", IF_8086}, + {I_JMP, 1, {MEMORY|BITS16|FAR,0,0}, "\320\300\1\xFF\205", IF_8086}, + {I_JMP, 1, {MEMORY|BITS32|FAR,0,0}, "\321\300\1\xFF\205", IF_386}, + {I_JMP, 1, {MEMORY|NEAR,0,0}, "\322\300\1\xFF\204", IF_8086}, + {I_JMP, 1, {MEMORY|BITS16|NEAR,0,0}, "\320\300\1\xFF\204", IF_8086}, + {I_JMP, 1, {MEMORY|BITS32|NEAR,0,0}, "\321\300\1\xFF\204", IF_386}, + {I_JMP, 1, {REG16,0,0}, "\320\300\1\xFF\204", IF_8086}, + {I_JMP, 1, {REG32,0,0}, "\321\300\1\xFF\204", IF_386}, + {I_JMP, 1, {MEMORY,0,0}, "\322\300\1\xFF\204", IF_8086}, + {I_JMP, 1, {MEMORY|BITS16,0,0}, "\320\300\1\xFF\204", IF_8086}, + {I_JMP, 1, {MEMORY|BITS32,0,0}, "\321\300\1\xFF\204", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_JMPE[] = { + {I_JMPE, 1, {IMMEDIATE,0,0}, "\322\2\x0F\xB8\64", IF_IA64}, + {I_JMPE, 1, {IMMEDIATE|BITS16,0,0}, "\320\2\x0F\xB8\64", IF_IA64}, + {I_JMPE, 1, {IMMEDIATE|BITS32,0,0}, "\321\2\x0F\xB8\64", IF_IA64}, + {I_JMPE, 1, {REGMEM|BITS16,0,0}, "\320\2\x0F\x00\206", IF_IA64}, + {I_JMPE, 1, {REGMEM|BITS32,0,0}, "\321\2\x0F\x00\206", IF_IA64}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LAHF[] = { + {I_LAHF, 0, {0,0,0}, "\1\x9F", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LAR[] = { + {I_LAR, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\x02\110", IF_286|IF_PROT|IF_SM}, + {I_LAR, 2, {REG16,REG16,0}, "\320\2\x0F\x02\110", IF_286|IF_PROT}, + {I_LAR, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\x02\110", IF_386|IF_PROT|IF_SM}, + {I_LAR, 2, {REG32,REG32,0}, "\321\2\x0F\x02\110", IF_386|IF_PROT}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LDDQU[] = { + {I_LDDQU, 2, {XMMREG,MEMORY,0}, "\3\xF2\x0F\xF0\110", IF_PRESCOTT|IF_SSE3}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LDMXCSR[] = { + {I_LDMXCSR, 1, {MEMORY,0,0}, "\300\2\x0F\xAE\202", IF_KATMAI|IF_SSE|IF_SD}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LDS[] = { + {I_LDS, 2, {REG16,MEMORY,0}, "\320\301\1\xC5\110", IF_8086}, + {I_LDS, 2, {REG32,MEMORY,0}, "\321\301\1\xC5\110", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LEA[] = { + {I_LEA, 2, {REG16,MEMORY,0}, "\320\301\1\x8D\110", IF_8086}, + {I_LEA, 2, {REG32,MEMORY,0}, "\321\301\1\x8D\110", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LEAVE[] = { + {I_LEAVE, 0, {0,0,0}, "\1\xC9", IF_186}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LES[] = { + {I_LES, 2, {REG16,MEMORY,0}, "\320\301\1\xC4\110", IF_8086}, + {I_LES, 2, {REG32,MEMORY,0}, "\321\301\1\xC4\110", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LFENCE[] = { + {I_LFENCE, 0, {0,0,0}, "\3\x0F\xAE\xE8", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LFS[] = { + {I_LFS, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xB4\110", IF_386}, + {I_LFS, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xB4\110", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LGDT[] = { + {I_LGDT, 1, {MEMORY,0,0}, "\300\2\x0F\x01\202", IF_286|IF_PRIV}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LGS[] = { + {I_LGS, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xB5\110", IF_386}, + {I_LGS, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xB5\110", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LIDT[] = { + {I_LIDT, 1, {MEMORY,0,0}, "\300\2\x0F\x01\203", IF_286|IF_PRIV}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LLDT[] = { + {I_LLDT, 1, {MEMORY,0,0}, "\300\1\x0F\17\202", IF_286|IF_PROT|IF_PRIV}, + {I_LLDT, 1, {MEMORY|BITS16,0,0}, "\300\1\x0F\17\202", IF_286|IF_PROT|IF_PRIV}, + {I_LLDT, 1, {REG16,0,0}, "\1\x0F\17\202", IF_286|IF_PROT|IF_PRIV}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LMSW[] = { + {I_LMSW, 1, {MEMORY,0,0}, "\300\2\x0F\x01\206", IF_286|IF_PRIV}, + {I_LMSW, 1, {MEMORY|BITS16,0,0}, "\300\2\x0F\x01\206", IF_286|IF_PRIV}, + {I_LMSW, 1, {REG16,0,0}, "\2\x0F\x01\206", IF_286|IF_PRIV}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LOADALL[] = { + {I_LOADALL, 0, {0,0,0}, "\2\x0F\x07", IF_386|IF_UNDOC}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LOADALL286[] = { + {I_LOADALL286, 0, {0,0,0}, "\2\x0F\x05", IF_286|IF_UNDOC}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LODSB[] = { + {I_LODSB, 0, {0,0,0}, "\1\xAC", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LODSD[] = { + {I_LODSD, 0, {0,0,0}, "\321\1\xAD", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LODSW[] = { + {I_LODSW, 0, {0,0,0}, "\320\1\xAD", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LOOP[] = { + {I_LOOP, 1, {IMMEDIATE,0,0}, "\312\1\xE2\50", IF_8086}, + {I_LOOP, 2, {IMMEDIATE,REG_CX,0}, "\310\1\xE2\50", IF_8086}, + {I_LOOP, 2, {IMMEDIATE,REG_ECX,0}, "\311\1\xE2\50", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LOOPE[] = { + {I_LOOPE, 1, {IMMEDIATE,0,0}, "\312\1\xE1\50", IF_8086}, + {I_LOOPE, 2, {IMMEDIATE,REG_CX,0}, "\310\1\xE1\50", IF_8086}, + {I_LOOPE, 2, {IMMEDIATE,REG_ECX,0}, "\311\1\xE1\50", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LOOPNE[] = { + {I_LOOPNE, 1, {IMMEDIATE,0,0}, "\312\1\xE0\50", IF_8086}, + {I_LOOPNE, 2, {IMMEDIATE,REG_CX,0}, "\310\1\xE0\50", IF_8086}, + {I_LOOPNE, 2, {IMMEDIATE,REG_ECX,0}, "\311\1\xE0\50", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LOOPNZ[] = { + {I_LOOPNZ, 1, {IMMEDIATE,0,0}, "\312\1\xE0\50", IF_8086}, + {I_LOOPNZ, 2, {IMMEDIATE,REG_CX,0}, "\310\1\xE0\50", IF_8086}, + {I_LOOPNZ, 2, {IMMEDIATE,REG_ECX,0}, "\311\1\xE0\50", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LOOPZ[] = { + {I_LOOPZ, 1, {IMMEDIATE,0,0}, "\312\1\xE1\50", IF_8086}, + {I_LOOPZ, 2, {IMMEDIATE,REG_CX,0}, "\310\1\xE1\50", IF_8086}, + {I_LOOPZ, 2, {IMMEDIATE,REG_ECX,0}, "\311\1\xE1\50", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LSL[] = { + {I_LSL, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\x03\110", IF_286|IF_PROT|IF_SM}, + {I_LSL, 2, {REG16,REG16,0}, "\320\2\x0F\x03\110", IF_286|IF_PROT}, + {I_LSL, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\x03\110", IF_386|IF_PROT|IF_SM}, + {I_LSL, 2, {REG32,REG32,0}, "\321\2\x0F\x03\110", IF_386|IF_PROT}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LSS[] = { + {I_LSS, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xB2\110", IF_386}, + {I_LSS, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xB2\110", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_LTR[] = { + {I_LTR, 1, {MEMORY,0,0}, "\300\1\x0F\17\203", IF_286|IF_PROT|IF_PRIV}, + {I_LTR, 1, {MEMORY|BITS16,0,0}, "\300\1\x0F\17\203", IF_286|IF_PROT|IF_PRIV}, + {I_LTR, 1, {REG16,0,0}, "\1\x0F\17\203", IF_286|IF_PROT|IF_PRIV}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MASKMOVDQU[] = { + {I_MASKMOVDQU, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF7\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MASKMOVQ[] = { + {I_MASKMOVQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF7\110", IF_KATMAI|IF_MMX}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MAXPD[] = { + {I_MAXPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x5F\110", IF_WILLAMETTE|IF_SSE2}, + {I_MAXPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x5F\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MAXPS[] = { + {I_MAXPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x5F\110", IF_KATMAI|IF_SSE}, + {I_MAXPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x5F\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MAXSD[] = { + {I_MAXSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x5F\110", IF_WILLAMETTE|IF_SSE2}, + {I_MAXSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x5F\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MAXSS[] = { + {I_MAXSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x5F\110", IF_KATMAI|IF_SSE}, + {I_MAXSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x5F\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MFENCE[] = { + {I_MFENCE, 0, {0,0,0}, "\3\x0F\xAE\xF0", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MINPD[] = { + {I_MINPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x5D\110", IF_WILLAMETTE|IF_SSE2}, + {I_MINPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x5D\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MINPS[] = { + {I_MINPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x5D\110", IF_KATMAI|IF_SSE}, + {I_MINPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x5D\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MINSD[] = { + {I_MINSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x5D\110", IF_WILLAMETTE|IF_SSE2}, + {I_MINSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x5D\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MINSS[] = { + {I_MINSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x5D\110", IF_KATMAI|IF_SSE}, + {I_MINSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x5D\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MONITOR[] = { + {I_MONITOR, 0, {0,0,0}, "\3\x0F\x01\xC8", IF_PRESCOTT}, + {I_MONITOR, 3, {REG_EAX,REG_ECX,REG_EDX}, "\3\x0F\x01\xC8", IF_PRESCOTT}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOV[] = { + {I_MOV, 2, {MEMORY,REG_SREG,0}, "\300\1\x8C\101", IF_8086|IF_SM}, + {I_MOV, 2, {REG16,REG_SREG,0}, "\320\1\x8C\101", IF_8086}, + {I_MOV, 2, {REG32,REG_SREG,0}, "\321\1\x8C\101", IF_386}, + {I_MOV, 2, {REG_SREG,MEMORY,0}, "\301\1\x8E\110", IF_8086|IF_SM}, + {I_MOV, 2, {REG_SREG,REG16,0}, "\1\x8E\110", IF_8086}, + {I_MOV, 2, {REG_SREG,REG32,0}, "\1\x8E\110", IF_386}, + {I_MOV, 2, {REG_AL,MEM_OFFS,0}, "\301\1\xA0\45", IF_8086|IF_SM}, + {I_MOV, 2, {REG_AX,MEM_OFFS,0}, "\301\320\1\xA1\45", IF_8086|IF_SM}, + {I_MOV, 2, {REG_EAX,MEM_OFFS,0}, "\301\321\1\xA1\45", IF_386|IF_SM}, + {I_MOV, 2, {MEM_OFFS,REG_AL,0}, "\300\1\xA2\44", IF_8086|IF_SM}, + {I_MOV, 2, {MEM_OFFS,REG_AX,0}, "\300\320\1\xA3\44", IF_8086|IF_SM}, + {I_MOV, 2, {MEM_OFFS,REG_EAX,0}, "\300\321\1\xA3\44", IF_386|IF_SM}, + {I_MOV, 2, {REG32,REG_CREG,0}, "\2\x0F\x20\101", IF_386|IF_PRIV}, + {I_MOV, 2, {REG32,REG_DREG,0}, "\2\x0F\x21\101", IF_386|IF_PRIV}, + {I_MOV, 2, {REG32,REG_TREG,0}, "\2\x0F\x24\101", IF_386|IF_PRIV}, + {I_MOV, 2, {REG_CREG,REG32,0}, "\2\x0F\x22\110", IF_386|IF_PRIV}, + {I_MOV, 2, {REG_DREG,REG32,0}, "\2\x0F\x23\110", IF_386|IF_PRIV}, + {I_MOV, 2, {REG_TREG,REG32,0}, "\2\x0F\x26\110", IF_386|IF_PRIV}, + {I_MOV, 2, {MEMORY,REG8,0}, "\300\1\x88\101", IF_8086|IF_SM}, + {I_MOV, 2, {REG8,REG8,0}, "\1\x88\101", IF_8086}, + {I_MOV, 2, {MEMORY,REG16,0}, "\320\300\1\x89\101", IF_8086|IF_SM}, + {I_MOV, 2, {REG16,REG16,0}, "\320\1\x89\101", IF_8086}, + {I_MOV, 2, {MEMORY,REG32,0}, "\321\300\1\x89\101", IF_386|IF_SM}, + {I_MOV, 2, {REG32,REG32,0}, "\321\1\x89\101", IF_386}, + {I_MOV, 2, {REG8,MEMORY,0}, "\301\1\x8A\110", IF_8086|IF_SM}, + {I_MOV, 2, {REG8,REG8,0}, "\1\x8A\110", IF_8086}, + {I_MOV, 2, {REG16,MEMORY,0}, "\320\301\1\x8B\110", IF_8086|IF_SM}, + {I_MOV, 2, {REG16,REG16,0}, "\320\1\x8B\110", IF_8086}, + {I_MOV, 2, {REG32,MEMORY,0}, "\321\301\1\x8B\110", IF_386|IF_SM}, + {I_MOV, 2, {REG32,REG32,0}, "\321\1\x8B\110", IF_386}, + {I_MOV, 2, {REG8,IMMEDIATE,0}, "\10\xB0\21", IF_8086|IF_SM}, + {I_MOV, 2, {REG16,IMMEDIATE,0}, "\320\10\xB8\31", IF_8086|IF_SM}, + {I_MOV, 2, {REG32,IMMEDIATE,0}, "\321\10\xB8\41", IF_386|IF_SM}, + {I_MOV, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC6\200\21", IF_8086|IF_SM}, + {I_MOV, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC7\200\31", IF_8086|IF_SM}, + {I_MOV, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC7\200\41", IF_386|IF_SM}, + {I_MOV, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\xC6\200\21", IF_8086|IF_SM}, + {I_MOV, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\1\xC7\200\31", IF_8086|IF_SM}, + {I_MOV, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\1\xC7\200\41", IF_386|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVAPD[] = { + {I_MOVAPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x28\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVAPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x29\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVAPD, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x29\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_MOVAPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x28\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVAPS[] = { + {I_MOVAPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x28\110", IF_KATMAI|IF_SSE}, + {I_MOVAPS, 2, {MEMORY,XMMREG,0}, "\300\2\x0F\x29\101", IF_KATMAI|IF_SSE}, + {I_MOVAPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x28\110", IF_KATMAI|IF_SSE}, + {I_MOVAPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x29\101", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVD[] = { + {I_MOVD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x6E\110", IF_PENT|IF_MMX|IF_SD}, + {I_MOVD, 2, {MMXREG,REG32,0}, "\2\x0F\x6E\110", IF_PENT|IF_MMX}, + {I_MOVD, 2, {MEMORY,MMXREG,0}, "\300\2\x0F\x7E\101", IF_PENT|IF_MMX|IF_SD}, + {I_MOVD, 2, {REG32,MMXREG,0}, "\2\x0F\x7E\101", IF_PENT|IF_MMX}, + {I_MOVD, 2, {XMMREG,REG32,0}, "\3\x66\x0F\x6E\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVD, 2, {REG32,XMMREG,0}, "\3\x66\x0F\x7E\101", IF_WILLAMETTE|IF_SSE2}, + {I_MOVD, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x7E\101", IF_WILLAMETTE|IF_SSE2}, + {I_MOVD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x6E\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVDDUP[] = { + {I_MOVDDUP, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x12\110", IF_PRESCOTT|IF_SSE3}, + {I_MOVDDUP, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x12\110", IF_PRESCOTT|IF_SSE3}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVDQ2Q[] = { + {I_MOVDQ2Q, 2, {MMXREG,XMMREG,0}, "\3\xF2\x0F\xD6\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVDQA[] = { + {I_MOVDQA, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x6F\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVDQA, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x7F\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_MOVDQA, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x6F\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_MOVDQA, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x7F\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVDQU[] = { + {I_MOVDQU, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x6F\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVDQU, 2, {MEMORY,XMMREG,0}, "\333\300\2\x0F\x7F\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_MOVDQU, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x6F\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_MOVDQU, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x7F\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVHLPS[] = { + {I_MOVHLPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x12\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVHPD[] = { + {I_MOVHPD, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x17\101", IF_WILLAMETTE|IF_SSE2}, + {I_MOVHPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x16\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVHPS[] = { + {I_MOVHPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x16\110", IF_KATMAI|IF_SSE}, + {I_MOVHPS, 2, {MEMORY,XMMREG,0}, "\300\2\x0F\x17\101", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVLHPS[] = { + {I_MOVLHPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x16\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVLPD[] = { + {I_MOVLPD, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x13\101", IF_WILLAMETTE|IF_SSE2}, + {I_MOVLPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x12\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVLPS[] = { + {I_MOVLPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x12\110", IF_KATMAI|IF_SSE}, + {I_MOVLPS, 2, {MEMORY,XMMREG,0}, "\300\2\x0F\x13\101", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVMSKPD[] = { + {I_MOVMSKPD, 2, {REG32,XMMREG,0}, "\3\x66\x0F\x50\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVMSKPS[] = { + {I_MOVMSKPS, 2, {REG32,XMMREG,0}, "\2\x0F\x50\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVNTDQ[] = { + {I_MOVNTDQ, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\xE7\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVNTI[] = { + {I_MOVNTI, 2, {MEMORY,REG32,0}, "\300\2\x0F\xC3\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVNTPD[] = { + {I_MOVNTPD, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x2B\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVNTPS[] = { + {I_MOVNTPS, 2, {MEMORY,XMMREG,0}, "\300\2\x0F\x2B\101", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVNTQ[] = { + {I_MOVNTQ, 2, {MEMORY,MMXREG,0}, "\300\2\x0F\xE7\101", IF_KATMAI|IF_MMX|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVQ[] = { + {I_MOVQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x6F\110", IF_PENT|IF_MMX|IF_SM}, + {I_MOVQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\x6F\110", IF_PENT|IF_MMX}, + {I_MOVQ, 2, {MEMORY,MMXREG,0}, "\300\2\x0F\x7F\101", IF_PENT|IF_MMX|IF_SM}, + {I_MOVQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\x7F\101", IF_PENT|IF_MMX}, + {I_MOVQ, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x7E\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD6\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVQ, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\xD6\101", IF_WILLAMETTE|IF_SSE2}, + {I_MOVQ, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x7E\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVQ2DQ[] = { + {I_MOVQ2DQ, 2, {XMMREG,MMXREG,0}, "\333\2\x0F\xD6\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVSB[] = { + {I_MOVSB, 0, {0,0,0}, "\1\xA4", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVSD[] = { + {I_MOVSD, 0, {0,0,0}, "\321\1\xA5", IF_386}, + {I_MOVSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x10\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x11\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVSD, 2, {MEMORY,XMMREG,0}, "\300\3\xF2\x0F\x11\101", IF_WILLAMETTE|IF_SSE2}, + {I_MOVSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x10\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVSHDUP[] = { + {I_MOVSHDUP, 2, {XMMREG,MEMORY,0}, "\301\3\xF3\x0F\x16\110", IF_PRESCOTT|IF_SSE3}, + {I_MOVSHDUP, 2, {XMMREG,XMMREG,0}, "\3\xF3\x0F\x16\110", IF_PRESCOTT|IF_SSE3}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVSLDUP[] = { + {I_MOVSLDUP, 2, {XMMREG,MEMORY,0}, "\301\3\xF3\x0F\x12\110", IF_PRESCOTT|IF_SSE3}, + {I_MOVSLDUP, 2, {XMMREG,XMMREG,0}, "\3\xF3\x0F\x12\110", IF_PRESCOTT|IF_SSE3}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVSS[] = { + {I_MOVSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x10\110", IF_KATMAI|IF_SSE}, + {I_MOVSS, 2, {MEMORY,XMMREG,0}, "\300\333\2\x0F\x11\101", IF_KATMAI|IF_SSE}, + {I_MOVSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x10\110", IF_KATMAI|IF_SSE}, + {I_MOVSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x11\101", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVSW[] = { + {I_MOVSW, 0, {0,0,0}, "\320\1\xA5", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVSX[] = { + {I_MOVSX, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xBE\110", IF_386|IF_SB}, + {I_MOVSX, 2, {REG16,REG8,0}, "\320\2\x0F\xBE\110", IF_386}, + {I_MOVSX, 2, {REG32,REGMEM|BITS8,0}, "\321\301\2\x0F\xBE\110", IF_386}, + {I_MOVSX, 2, {REG32,REGMEM|BITS16,0}, "\321\301\2\x0F\xBF\110", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVUPD[] = { + {I_MOVUPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x10\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVUPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x11\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVUPD, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x11\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_MOVUPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x10\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVUPS[] = { + {I_MOVUPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x10\110", IF_KATMAI|IF_SSE}, + {I_MOVUPS, 2, {MEMORY,XMMREG,0}, "\300\331\2\x0F\x11\101", IF_KATMAI|IF_SSE}, + {I_MOVUPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x10\110", IF_KATMAI|IF_SSE}, + {I_MOVUPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x11\101", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MOVZX[] = { + {I_MOVZX, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xB6\110", IF_386|IF_SB}, + {I_MOVZX, 2, {REG16,REG8,0}, "\320\2\x0F\xB6\110", IF_386}, + {I_MOVZX, 2, {REG32,REGMEM|BITS8,0}, "\321\301\2\x0F\xB6\110", IF_386}, + {I_MOVZX, 2, {REG32,REGMEM|BITS16,0}, "\321\301\2\x0F\xB7\110", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MUL[] = { + {I_MUL, 1, {REGMEM|BITS8,0,0}, "\300\1\xF6\204", IF_8086}, + {I_MUL, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xF7\204", IF_8086}, + {I_MUL, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xF7\204", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MULPD[] = { + {I_MULPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x59\110", IF_WILLAMETTE|IF_SSE2}, + {I_MULPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x59\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MULPS[] = { + {I_MULPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x59\110", IF_KATMAI|IF_SSE}, + {I_MULPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x59\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MULSD[] = { + {I_MULSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x59\110", IF_WILLAMETTE|IF_SSE2}, + {I_MULSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x59\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MULSS[] = { + {I_MULSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x59\110", IF_KATMAI|IF_SSE}, + {I_MULSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x59\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_MWAIT[] = { + {I_MWAIT, 0, {0,0,0}, "\3\x0F\x01\xC9", IF_PRESCOTT}, + {I_MWAIT, 2, {REG_EAX,REG_ECX,0}, "\3\x0F\x01\xC9", IF_PRESCOTT}, + ITEMPLATE_END +}; + +static struct itemplate instrux_NEG[] = { + {I_NEG, 1, {REGMEM|BITS8,0,0}, "\300\1\xF6\203", IF_8086}, + {I_NEG, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xF7\203", IF_8086}, + {I_NEG, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xF7\203", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_NOP[] = { + {I_NOP, 0, {0,0,0}, "\1\x90", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_NOT[] = { + {I_NOT, 1, {REGMEM|BITS8,0,0}, "\300\1\xF6\202", IF_8086}, + {I_NOT, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xF7\202", IF_8086}, + {I_NOT, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xF7\202", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_OR[] = { + {I_OR, 2, {MEMORY,REG8,0}, "\300\1\x08\101", IF_8086|IF_SM}, + {I_OR, 2, {REG8,REG8,0}, "\1\x08\101", IF_8086}, + {I_OR, 2, {MEMORY,REG16,0}, "\320\300\1\x09\101", IF_8086|IF_SM}, + {I_OR, 2, {REG16,REG16,0}, "\320\1\x09\101", IF_8086}, + {I_OR, 2, {MEMORY,REG32,0}, "\321\300\1\x09\101", IF_386|IF_SM}, + {I_OR, 2, {REG32,REG32,0}, "\321\1\x09\101", IF_386}, + {I_OR, 2, {REG8,MEMORY,0}, "\301\1\x0A\110", IF_8086|IF_SM}, + {I_OR, 2, {REG8,REG8,0}, "\1\x0A\110", IF_8086}, + {I_OR, 2, {REG16,MEMORY,0}, "\320\301\1\x0B\110", IF_8086|IF_SM}, + {I_OR, 2, {REG16,REG16,0}, "\320\1\x0B\110", IF_8086}, + {I_OR, 2, {REG32,MEMORY,0}, "\321\301\1\x0B\110", IF_386|IF_SM}, + {I_OR, 2, {REG32,REG32,0}, "\321\1\x0B\110", IF_386}, + {I_OR, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\201\15", IF_8086}, + {I_OR, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\201\15", IF_386}, + {I_OR, 2, {REG_AL,IMMEDIATE,0}, "\1\x0C\21", IF_8086|IF_SM}, + {I_OR, 2, {REG_AX,SBYTE,0}, "\320\1\x83\201\15", IF_8086|IF_SM}, + {I_OR, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x0D\31", IF_8086|IF_SM}, + {I_OR, 2, {REG_EAX,SBYTE,0}, "\321\1\x83\201\15", IF_386|IF_SM}, + {I_OR, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x0D\41", IF_386|IF_SM}, + {I_OR, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\201\21", IF_8086|IF_SM}, + {I_OR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\201\131", IF_8086|IF_SM}, + {I_OR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\201\141", IF_386|IF_SM}, + {I_OR, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\201\21", IF_8086|IF_SM}, + {I_OR, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\201\131", IF_8086|IF_SM}, + {I_OR, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\201\141", IF_386|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_ORPD[] = { + {I_ORPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x56\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_ORPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x56\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_ORPS[] = { + {I_ORPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x56\110", IF_KATMAI|IF_SSE}, + {I_ORPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x56\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_OUT[] = { + {I_OUT, 2, {IMMEDIATE,REG_AL,0}, "\1\xE6\24", IF_8086|IF_SB}, + {I_OUT, 2, {IMMEDIATE,REG_AX,0}, "\320\1\xE7\24", IF_8086|IF_SB}, + {I_OUT, 2, {IMMEDIATE,REG_EAX,0}, "\321\1\xE7\24", IF_386|IF_SB}, + {I_OUT, 2, {REG_DX,REG_AL,0}, "\1\xEE", IF_8086}, + {I_OUT, 2, {REG_DX,REG_AX,0}, "\320\1\xEF", IF_8086}, + {I_OUT, 2, {REG_DX,REG_EAX,0}, "\321\1\xEF", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_OUTSB[] = { + {I_OUTSB, 0, {0,0,0}, "\1\x6E", IF_186}, + ITEMPLATE_END +}; + +static struct itemplate instrux_OUTSD[] = { + {I_OUTSD, 0, {0,0,0}, "\321\1\x6F", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_OUTSW[] = { + {I_OUTSW, 0, {0,0,0}, "\320\1\x6F", IF_186}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PACKSSDW[] = { + {I_PACKSSDW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x6B\110", IF_PENT|IF_MMX|IF_SM}, + {I_PACKSSDW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x6B\110", IF_PENT|IF_MMX}, + {I_PACKSSDW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x6B\110", IF_WILLAMETTE|IF_SSE2}, + {I_PACKSSDW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x6B\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PACKSSWB[] = { + {I_PACKSSWB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x63\110", IF_PENT|IF_MMX|IF_SM}, + {I_PACKSSWB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x63\110", IF_PENT|IF_MMX}, + {I_PACKSSWB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x63\110", IF_WILLAMETTE|IF_SSE2}, + {I_PACKSSWB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x63\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PACKUSWB[] = { + {I_PACKUSWB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x67\110", IF_PENT|IF_MMX|IF_SM}, + {I_PACKUSWB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x67\110", IF_PENT|IF_MMX}, + {I_PACKUSWB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x67\110", IF_WILLAMETTE|IF_SSE2}, + {I_PACKUSWB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x67\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PADDB[] = { + {I_PADDB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xFC\110", IF_PENT|IF_MMX|IF_SM}, + {I_PADDB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xFC\110", IF_PENT|IF_MMX}, + {I_PADDB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xFC\110", IF_WILLAMETTE|IF_SSE2}, + {I_PADDB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xFC\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PADDD[] = { + {I_PADDD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xFE\110", IF_PENT|IF_MMX|IF_SM}, + {I_PADDD, 2, {MMXREG,MMXREG,0}, "\2\x0F\xFE\110", IF_PENT|IF_MMX}, + {I_PADDD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xFE\110", IF_WILLAMETTE|IF_SSE2}, + {I_PADDD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xFE\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PADDQ[] = { + {I_PADDQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD4\110", IF_WILLAMETTE|IF_SSE2}, + {I_PADDQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD4\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PADDQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD4\110", IF_WILLAMETTE|IF_SSE2}, + {I_PADDQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD4\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PADDSB[] = { + {I_PADDSB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xEC\110", IF_PENT|IF_MMX|IF_SM}, + {I_PADDSB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xEC\110", IF_PENT|IF_MMX}, + {I_PADDSB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xEC\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PADDSB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xEC\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PADDSIW[] = { + {I_PADDSIW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x51\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, + {I_PADDSIW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x51\110", IF_PENT|IF_MMX|IF_CYRIX}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PADDSW[] = { + {I_PADDSW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xED\110", IF_PENT|IF_MMX|IF_SM}, + {I_PADDSW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xED\110", IF_PENT|IF_MMX}, + {I_PADDSW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xED\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PADDSW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xED\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PADDUSB[] = { + {I_PADDUSB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xDC\110", IF_PENT|IF_MMX|IF_SM}, + {I_PADDUSB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xDC\110", IF_PENT|IF_MMX}, + {I_PADDUSB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xDC\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PADDUSB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xDC\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PADDUSW[] = { + {I_PADDUSW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xDD\110", IF_PENT|IF_MMX|IF_SM}, + {I_PADDUSW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xDD\110", IF_PENT|IF_MMX}, + {I_PADDUSW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xDD\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PADDUSW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xDD\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PADDW[] = { + {I_PADDW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xFD\110", IF_PENT|IF_MMX|IF_SM}, + {I_PADDW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xFD\110", IF_PENT|IF_MMX}, + {I_PADDW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xFD\110", IF_WILLAMETTE|IF_SSE2}, + {I_PADDW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xFD\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PAND[] = { + {I_PAND, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xDB\110", IF_PENT|IF_MMX|IF_SM}, + {I_PAND, 2, {MMXREG,MMXREG,0}, "\2\x0F\xDB\110", IF_PENT|IF_MMX}, + {I_PAND, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xDB\110", IF_WILLAMETTE|IF_SSE2}, + {I_PAND, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xDB\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PANDN[] = { + {I_PANDN, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xDF\110", IF_PENT|IF_MMX|IF_SM}, + {I_PANDN, 2, {MMXREG,MMXREG,0}, "\2\x0F\xDF\110", IF_PENT|IF_MMX}, + {I_PANDN, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xDF\110", IF_WILLAMETTE|IF_SSE2}, + {I_PANDN, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xDF\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PAUSE[] = { + {I_PAUSE, 0, {0,0,0}, "\333\1\x90", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PAVEB[] = { + {I_PAVEB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x50\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, + {I_PAVEB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x50\110", IF_PENT|IF_MMX|IF_CYRIX}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PAVGB[] = { + {I_PAVGB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE0\110", IF_KATMAI|IF_MMX}, + {I_PAVGB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE0\110", IF_KATMAI|IF_MMX|IF_SM}, + {I_PAVGB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE0\110", IF_WILLAMETTE|IF_SSE2}, + {I_PAVGB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE0\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PAVGUSB[] = { + {I_PAVGUSB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xBF", IF_PENT|IF_3DNOW|IF_SM}, + {I_PAVGUSB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xBF", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PAVGW[] = { + {I_PAVGW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE3\110", IF_KATMAI|IF_MMX}, + {I_PAVGW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE3\110", IF_KATMAI|IF_MMX|IF_SM}, + {I_PAVGW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE3\110", IF_WILLAMETTE|IF_SSE2}, + {I_PAVGW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE3\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PCMPEQB[] = { + {I_PCMPEQB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x74\110", IF_PENT|IF_MMX|IF_SM}, + {I_PCMPEQB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x74\110", IF_PENT|IF_MMX}, + {I_PCMPEQB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x74\110", IF_WILLAMETTE|IF_SSE2}, + {I_PCMPEQB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x74\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PCMPEQD[] = { + {I_PCMPEQD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x76\110", IF_PENT|IF_MMX|IF_SM}, + {I_PCMPEQD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x76\110", IF_PENT|IF_MMX}, + {I_PCMPEQD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x76\110", IF_WILLAMETTE|IF_SSE2}, + {I_PCMPEQD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x76\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PCMPEQW[] = { + {I_PCMPEQW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x75\110", IF_PENT|IF_MMX|IF_SM}, + {I_PCMPEQW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x75\110", IF_PENT|IF_MMX}, + {I_PCMPEQW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x75\110", IF_WILLAMETTE|IF_SSE2}, + {I_PCMPEQW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x75\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PCMPGTB[] = { + {I_PCMPGTB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x64\110", IF_PENT|IF_MMX|IF_SM}, + {I_PCMPGTB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x64\110", IF_PENT|IF_MMX}, + {I_PCMPGTB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x64\110", IF_WILLAMETTE|IF_SSE2}, + {I_PCMPGTB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x64\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PCMPGTD[] = { + {I_PCMPGTD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x66\110", IF_PENT|IF_MMX|IF_SM}, + {I_PCMPGTD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x66\110", IF_PENT|IF_MMX}, + {I_PCMPGTD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x66\110", IF_WILLAMETTE|IF_SSE2}, + {I_PCMPGTD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x66\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PCMPGTW[] = { + {I_PCMPGTW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x65\110", IF_PENT|IF_MMX|IF_SM}, + {I_PCMPGTW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x65\110", IF_PENT|IF_MMX}, + {I_PCMPGTW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x65\110", IF_WILLAMETTE|IF_SSE2}, + {I_PCMPGTW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x65\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PDISTIB[] = { + {I_PDISTIB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x54\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PEXTRW[] = { + {I_PEXTRW, 3, {REG32,MMXREG,IMMEDIATE}, "\2\x0F\xC5\110\26", IF_KATMAI|IF_MMX|IF_SB|IF_AR2}, + {I_PEXTRW, 3, {REG32,XMMREG,IMMEDIATE}, "\3\x66\x0F\xC5\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PF2ID[] = { + {I_PF2ID, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x1D", IF_PENT|IF_3DNOW|IF_SM}, + {I_PF2ID, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x1D", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PF2IW[] = { + {I_PF2IW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x1C", IF_PENT|IF_3DNOW|IF_SM}, + {I_PF2IW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x1C", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PFACC[] = { + {I_PFACC, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xAE", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFACC, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xAE", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PFADD[] = { + {I_PFADD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x9E", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFADD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x9E", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PFCMPEQ[] = { + {I_PFCMPEQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xB0", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFCMPEQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xB0", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PFCMPGE[] = { + {I_PFCMPGE, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x90", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFCMPGE, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x90", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PFCMPGT[] = { + {I_PFCMPGT, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xA0", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFCMPGT, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xA0", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PFMAX[] = { + {I_PFMAX, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xA4", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFMAX, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xA4", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PFMIN[] = { + {I_PFMIN, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x94", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFMIN, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x94", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PFMUL[] = { + {I_PFMUL, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xB4", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFMUL, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xB4", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PFNACC[] = { + {I_PFNACC, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x8A", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFNACC, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x8A", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PFPNACC[] = { + {I_PFPNACC, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x8E", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFPNACC, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x8E", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PFRCP[] = { + {I_PFRCP, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x96", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFRCP, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x96", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PFRCPIT1[] = { + {I_PFRCPIT1, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xA6", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFRCPIT1, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xA6", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PFRCPIT2[] = { + {I_PFRCPIT2, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xB6", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFRCPIT2, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xB6", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PFRSQIT1[] = { + {I_PFRSQIT1, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xA7", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFRSQIT1, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xA7", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PFRSQRT[] = { + {I_PFRSQRT, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x97", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFRSQRT, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x97", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PFSUB[] = { + {I_PFSUB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x9A", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFSUB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x9A", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PFSUBR[] = { + {I_PFSUBR, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xAA", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFSUBR, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xAA", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PI2FD[] = { + {I_PI2FD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x0D", IF_PENT|IF_3DNOW|IF_SM}, + {I_PI2FD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x0D", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PI2FW[] = { + {I_PI2FW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x0C", IF_PENT|IF_3DNOW|IF_SM}, + {I_PI2FW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x0C", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PINSRW[] = { + {I_PINSRW, 3, {MMXREG,REG16,IMMEDIATE}, "\2\x0F\xC4\110\26", IF_KATMAI|IF_MMX|IF_SB|IF_AR2}, + {I_PINSRW, 3, {MMXREG,REG32,IMMEDIATE}, "\2\x0F\xC4\110\26", IF_KATMAI|IF_MMX|IF_SB|IF_AR2}, + {I_PINSRW, 3, {MMXREG,MEMORY,IMMEDIATE}, "\301\2\x0F\xC4\110\26", IF_KATMAI|IF_MMX|IF_SB|IF_AR2}, + {I_PINSRW, 3, {MMXREG,MEMORY|BITS16,IMMEDIATE}, "\301\2\x0F\xC4\110\26", IF_KATMAI|IF_MMX|IF_SB|IF_AR2}, + {I_PINSRW, 3, {XMMREG,REG16,IMMEDIATE}, "\3\x66\x0F\xC4\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, + {I_PINSRW, 3, {XMMREG,REG32,IMMEDIATE}, "\3\x66\x0F\xC4\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, + {I_PINSRW, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\3\x66\x0F\xC4\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, + {I_PINSRW, 3, {XMMREG,MEMORY|BITS16,IMMEDIATE}, "\301\3\x66\x0F\xC4\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PMACHRIW[] = { + {I_PMACHRIW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x5E\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PMADDWD[] = { + {I_PMADDWD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF5\110", IF_PENT|IF_MMX|IF_SM}, + {I_PMADDWD, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF5\110", IF_PENT|IF_MMX}, + {I_PMADDWD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF5\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PMADDWD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF5\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PMAGW[] = { + {I_PMAGW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x52\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, + {I_PMAGW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x52\110", IF_PENT|IF_MMX|IF_CYRIX}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PMAXSW[] = { + {I_PMAXSW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xEE\110", IF_KATMAI|IF_MMX}, + {I_PMAXSW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xEE\110", IF_KATMAI|IF_MMX|IF_SM}, + {I_PMAXSW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xEE\110", IF_WILLAMETTE|IF_SSE2}, + {I_PMAXSW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xEE\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PMAXUB[] = { + {I_PMAXUB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xDE\110", IF_KATMAI|IF_MMX}, + {I_PMAXUB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xDE\110", IF_KATMAI|IF_MMX|IF_SM}, + {I_PMAXUB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xDE\110", IF_WILLAMETTE|IF_SSE2}, + {I_PMAXUB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xDE\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PMINSW[] = { + {I_PMINSW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xEA\110", IF_KATMAI|IF_MMX}, + {I_PMINSW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xEA\110", IF_KATMAI|IF_MMX|IF_SM}, + {I_PMINSW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xEA\110", IF_WILLAMETTE|IF_SSE2}, + {I_PMINSW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xEA\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PMINUB[] = { + {I_PMINUB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xDA\110", IF_KATMAI|IF_MMX}, + {I_PMINUB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xDA\110", IF_KATMAI|IF_MMX|IF_SM}, + {I_PMINUB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xDA\110", IF_WILLAMETTE|IF_SSE2}, + {I_PMINUB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xDA\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PMOVMSKB[] = { + {I_PMOVMSKB, 2, {REG32,MMXREG,0}, "\2\x0F\xD7\110", IF_KATMAI|IF_MMX}, + {I_PMOVMSKB, 2, {REG32,XMMREG,0}, "\3\x66\x0F\xD7\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PMULHRIW[] = { + {I_PMULHRIW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x5D\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, + {I_PMULHRIW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x5D\110", IF_PENT|IF_MMX|IF_CYRIX}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PMULHRWA[] = { + {I_PMULHRWA, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\1\xB7", IF_PENT|IF_3DNOW|IF_SM}, + {I_PMULHRWA, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\1\xB7", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PMULHRWC[] = { + {I_PMULHRWC, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x59\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, + {I_PMULHRWC, 2, {MMXREG,MMXREG,0}, "\2\x0F\x59\110", IF_PENT|IF_MMX|IF_CYRIX}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PMULHUW[] = { + {I_PMULHUW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE4\110", IF_KATMAI|IF_MMX}, + {I_PMULHUW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE4\110", IF_KATMAI|IF_MMX|IF_SM}, + {I_PMULHUW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE4\110", IF_WILLAMETTE|IF_SSE2}, + {I_PMULHUW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE4\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PMULHW[] = { + {I_PMULHW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE5\110", IF_PENT|IF_MMX|IF_SM}, + {I_PMULHW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE5\110", IF_PENT|IF_MMX}, + {I_PMULHW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE5\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PMULHW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE5\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PMULLW[] = { + {I_PMULLW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD5\110", IF_PENT|IF_MMX|IF_SM}, + {I_PMULLW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD5\110", IF_PENT|IF_MMX}, + {I_PMULLW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD5\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PMULLW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD5\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PMULUDQ[] = { + {I_PMULUDQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF4\110", IF_WILLAMETTE|IF_SSE2}, + {I_PMULUDQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF4\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PMULUDQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF4\110", IF_WILLAMETTE|IF_SSE2}, + {I_PMULUDQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF4\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PMVGEZB[] = { + {I_PMVGEZB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x5C\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PMVLZB[] = { + {I_PMVLZB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x5B\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PMVNZB[] = { + {I_PMVNZB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x5A\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PMVZB[] = { + {I_PMVZB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x58\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, + ITEMPLATE_END +}; + +static struct itemplate instrux_POP[] = { + {I_POP, 1, {REG16,0,0}, "\320\10\x58", IF_8086}, + {I_POP, 1, {REG32,0,0}, "\321\10\x58", IF_386}, + {I_POP, 1, {REGMEM|BITS16,0,0}, "\320\300\1\x8F\200", IF_8086}, + {I_POP, 1, {REGMEM|BITS32,0,0}, "\321\300\1\x8F\200", IF_386}, + {I_POP, 1, {REG_CS,0,0}, "\1\x0F", IF_8086|IF_UNDOC}, + {I_POP, 1, {REG_DESS,0,0}, "\4", IF_8086}, + {I_POP, 1, {REG_FSGS,0,0}, "\1\x0F\5", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_POPA[] = { + {I_POPA, 0, {0,0,0}, "\322\1\x61", IF_186}, + ITEMPLATE_END +}; + +static struct itemplate instrux_POPAD[] = { + {I_POPAD, 0, {0,0,0}, "\321\1\x61", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_POPAW[] = { + {I_POPAW, 0, {0,0,0}, "\320\1\x61", IF_186}, + ITEMPLATE_END +}; + +static struct itemplate instrux_POPF[] = { + {I_POPF, 0, {0,0,0}, "\322\1\x9D", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_POPFD[] = { + {I_POPFD, 0, {0,0,0}, "\321\1\x9D", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_POPFW[] = { + {I_POPFW, 0, {0,0,0}, "\320\1\x9D", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_POR[] = { + {I_POR, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xEB\110", IF_PENT|IF_MMX|IF_SM}, + {I_POR, 2, {MMXREG,MMXREG,0}, "\2\x0F\xEB\110", IF_PENT|IF_MMX}, + {I_POR, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xEB\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_POR, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xEB\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PREFETCH[] = { + {I_PREFETCH, 1, {MEMORY,0,0}, "\2\x0F\x0D\200", IF_PENT|IF_3DNOW|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PREFETCHNTA[] = { + {I_PREFETCHNTA, 1, {MEMORY,0,0}, "\300\2\x0F\x18\200", IF_KATMAI}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PREFETCHT0[] = { + {I_PREFETCHT0, 1, {MEMORY,0,0}, "\300\2\x0F\x18\201", IF_KATMAI}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PREFETCHT1[] = { + {I_PREFETCHT1, 1, {MEMORY,0,0}, "\300\2\x0F\x18\202", IF_KATMAI}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PREFETCHT2[] = { + {I_PREFETCHT2, 1, {MEMORY,0,0}, "\300\2\x0F\x18\203", IF_KATMAI}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PREFETCHW[] = { + {I_PREFETCHW, 1, {MEMORY,0,0}, "\2\x0F\x0D\201", IF_PENT|IF_3DNOW|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSADBW[] = { + {I_PSADBW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF6\110", IF_KATMAI|IF_MMX}, + {I_PSADBW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF6\110", IF_KATMAI|IF_MMX|IF_SM}, + {I_PSADBW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF6\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSADBW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF6\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSHUFD[] = { + {I_PSHUFD, 3, {XMMREG,XMMREG,IMMEDIATE}, "\3\x66\x0F\x70\110\22", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, + {I_PSHUFD, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\3\x66\x0F\x70\110\22", IF_WILLAMETTE|IF_SSE2|IF_SM2|IF_SB|IF_AR2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSHUFHW[] = { + {I_PSHUFHW, 3, {XMMREG,XMMREG,IMMEDIATE}, "\333\2\x0F\x70\110\22", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, + {I_PSHUFHW, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\333\2\x0F\x70\110\22", IF_WILLAMETTE|IF_SSE2|IF_SM2|IF_SB|IF_AR2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSHUFLW[] = { + {I_PSHUFLW, 3, {XMMREG,XMMREG,IMMEDIATE}, "\3\xF2\x0F\x70\110\22", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, + {I_PSHUFLW, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\3\xF2\x0F\x70\110\22", IF_WILLAMETTE|IF_SSE2|IF_SM2|IF_SB|IF_AR2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSHUFW[] = { + {I_PSHUFW, 3, {MMXREG,MMXREG,IMMEDIATE}, "\2\x0F\x70\110\22", IF_KATMAI|IF_MMX|IF_SB|IF_AR2}, + {I_PSHUFW, 3, {MMXREG,MEMORY,IMMEDIATE}, "\301\2\x0F\x70\110\22", IF_KATMAI|IF_MMX|IF_SM2|IF_SB|IF_AR2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSLLD[] = { + {I_PSLLD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF2\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSLLD, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF2\110", IF_PENT|IF_MMX}, + {I_PSLLD, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x72\206\25", IF_PENT|IF_MMX}, + {I_PSLLD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF2\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSLLD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF2\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSLLD, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x72\206\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSLLDQ[] = { + {I_PSLLDQ, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x73\207\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSLLQ[] = { + {I_PSLLQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF3\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSLLQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF3\110", IF_PENT|IF_MMX}, + {I_PSLLQ, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x73\206\25", IF_PENT|IF_MMX}, + {I_PSLLQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF3\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSLLQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF3\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSLLQ, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x73\206\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSLLW[] = { + {I_PSLLW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF1\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSLLW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF1\110", IF_PENT|IF_MMX}, + {I_PSLLW, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x71\206\25", IF_PENT|IF_MMX}, + {I_PSLLW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF1\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSLLW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF1\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSLLW, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x71\206\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSRAD[] = { + {I_PSRAD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE2\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSRAD, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE2\110", IF_PENT|IF_MMX}, + {I_PSRAD, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x72\204\25", IF_PENT|IF_MMX}, + {I_PSRAD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE2\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSRAD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE2\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSRAD, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x72\204\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSRAW[] = { + {I_PSRAW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE1\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSRAW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE1\110", IF_PENT|IF_MMX}, + {I_PSRAW, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x71\204\25", IF_PENT|IF_MMX}, + {I_PSRAW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE1\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSRAW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE1\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSRAW, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x71\204\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSRLD[] = { + {I_PSRLD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD2\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSRLD, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD2\110", IF_PENT|IF_MMX}, + {I_PSRLD, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x72\202\25", IF_PENT|IF_MMX}, + {I_PSRLD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD2\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSRLD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD2\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSRLD, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x72\202\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSRLDQ[] = { + {I_PSRLDQ, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x73\203\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSRLQ[] = { + {I_PSRLQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD3\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSRLQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD3\110", IF_PENT|IF_MMX}, + {I_PSRLQ, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x73\202\25", IF_PENT|IF_MMX}, + {I_PSRLQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD3\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSRLQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD3\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSRLQ, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x73\202\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSRLW[] = { + {I_PSRLW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD1\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSRLW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD1\110", IF_PENT|IF_MMX}, + {I_PSRLW, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x71\202\25", IF_PENT|IF_MMX}, + {I_PSRLW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD1\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSRLW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD1\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSRLW, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x71\202\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSUBB[] = { + {I_PSUBB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF8\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSUBB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF8\110", IF_PENT|IF_MMX}, + {I_PSUBB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF8\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSUBB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF8\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSUBD[] = { + {I_PSUBD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xFA\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSUBD, 2, {MMXREG,MMXREG,0}, "\2\x0F\xFA\110", IF_PENT|IF_MMX}, + {I_PSUBD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xFA\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSUBD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xFA\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSUBQ[] = { + {I_PSUBQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\xFB\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSUBQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xFB\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSUBQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xFB\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSUBQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xFB\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSUBSB[] = { + {I_PSUBSB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE8\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSUBSB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE8\110", IF_PENT|IF_MMX}, + {I_PSUBSB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE8\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSUBSB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE8\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSUBSIW[] = { + {I_PSUBSIW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x55\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, + {I_PSUBSIW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x55\110", IF_PENT|IF_MMX|IF_CYRIX}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSUBSW[] = { + {I_PSUBSW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE9\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSUBSW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE9\110", IF_PENT|IF_MMX}, + {I_PSUBSW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE9\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSUBSW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE9\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSUBUSB[] = { + {I_PSUBUSB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD8\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSUBUSB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD8\110", IF_PENT|IF_MMX}, + {I_PSUBUSB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD8\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSUBUSB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD8\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSUBUSW[] = { + {I_PSUBUSW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD9\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSUBUSW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD9\110", IF_PENT|IF_MMX}, + {I_PSUBUSW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD9\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSUBUSW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD9\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSUBW[] = { + {I_PSUBW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF9\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSUBW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF9\110", IF_PENT|IF_MMX}, + {I_PSUBW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF9\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSUBW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF9\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PSWAPD[] = { + {I_PSWAPD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xBB", IF_PENT|IF_3DNOW|IF_SM}, + {I_PSWAPD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xBB", IF_PENT|IF_3DNOW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PUNPCKHBW[] = { + {I_PUNPCKHBW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x68\110", IF_PENT|IF_MMX|IF_SM}, + {I_PUNPCKHBW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x68\110", IF_PENT|IF_MMX}, + {I_PUNPCKHBW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x68\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PUNPCKHBW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x68\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PUNPCKHDQ[] = { + {I_PUNPCKHDQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x6A\110", IF_PENT|IF_MMX|IF_SM}, + {I_PUNPCKHDQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\x6A\110", IF_PENT|IF_MMX}, + {I_PUNPCKHDQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x6A\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PUNPCKHDQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x6A\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PUNPCKHQDQ[] = { + {I_PUNPCKHQDQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x6D\110", IF_WILLAMETTE|IF_SSE2}, + {I_PUNPCKHQDQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x6D\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PUNPCKHWD[] = { + {I_PUNPCKHWD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x69\110", IF_PENT|IF_MMX|IF_SM}, + {I_PUNPCKHWD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x69\110", IF_PENT|IF_MMX}, + {I_PUNPCKHWD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x69\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PUNPCKHWD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x69\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PUNPCKLBW[] = { + {I_PUNPCKLBW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x60\110", IF_PENT|IF_MMX|IF_SM}, + {I_PUNPCKLBW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x60\110", IF_PENT|IF_MMX}, + {I_PUNPCKLBW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x60\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PUNPCKLBW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x60\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PUNPCKLDQ[] = { + {I_PUNPCKLDQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x62\110", IF_PENT|IF_MMX|IF_SM}, + {I_PUNPCKLDQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\x62\110", IF_PENT|IF_MMX}, + {I_PUNPCKLDQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x62\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PUNPCKLDQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x62\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PUNPCKLQDQ[] = { + {I_PUNPCKLQDQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x6C\110", IF_WILLAMETTE|IF_SSE2}, + {I_PUNPCKLQDQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x6C\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PUNPCKLWD[] = { + {I_PUNPCKLWD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x61\110", IF_PENT|IF_MMX|IF_SM}, + {I_PUNPCKLWD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x61\110", IF_PENT|IF_MMX}, + {I_PUNPCKLWD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x61\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PUNPCKLWD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x61\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PUSH[] = { + {I_PUSH, 1, {REG16,0,0}, "\320\10\x50", IF_8086}, + {I_PUSH, 1, {REG32,0,0}, "\321\10\x50", IF_386}, + {I_PUSH, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xFF\206", IF_8086}, + {I_PUSH, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xFF\206", IF_386}, + {I_PUSH, 1, {REG_CS,0,0}, "\6", IF_8086}, + {I_PUSH, 1, {REG_DESS,0,0}, "\6", IF_8086}, + {I_PUSH, 1, {REG_FSGS,0,0}, "\1\x0F\7", IF_386}, + {I_PUSH, 1, {IMMEDIATE|BITS8,0,0}, "\1\x6A\14", IF_186}, + {I_PUSH, 1, {SBYTE,0,0}, "\1\x6A\14", IF_186}, + {I_PUSH, 1, {IMMEDIATE|BITS16,0,0}, "\320\133\1\x68\130", IF_186}, + {I_PUSH, 1, {IMMEDIATE|BITS32,0,0}, "\321\143\1\x68\140", IF_386}, + {I_PUSH, 1, {IMMEDIATE,0,0}, "\1\x68\34", IF_186}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PUSHA[] = { + {I_PUSHA, 0, {0,0,0}, "\322\1\x60", IF_186}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PUSHAD[] = { + {I_PUSHAD, 0, {0,0,0}, "\321\1\x60", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PUSHAW[] = { + {I_PUSHAW, 0, {0,0,0}, "\320\1\x60", IF_186}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PUSHF[] = { + {I_PUSHF, 0, {0,0,0}, "\322\1\x9C", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PUSHFD[] = { + {I_PUSHFD, 0, {0,0,0}, "\321\1\x9C", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PUSHFW[] = { + {I_PUSHFW, 0, {0,0,0}, "\320\1\x9C", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_PXOR[] = { + {I_PXOR, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xEF\110", IF_PENT|IF_MMX|IF_SM}, + {I_PXOR, 2, {MMXREG,MMXREG,0}, "\2\x0F\xEF\110", IF_PENT|IF_MMX}, + {I_PXOR, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xEF\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PXOR, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xEF\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_RCL[] = { + {I_RCL, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\202", IF_8086}, + {I_RCL, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\202", IF_8086}, + {I_RCL, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\202\25", IF_186|IF_SB}, + {I_RCL, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\202", IF_8086}, + {I_RCL, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\202", IF_8086}, + {I_RCL, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\202\25", IF_186|IF_SB}, + {I_RCL, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\202", IF_386}, + {I_RCL, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\202", IF_386}, + {I_RCL, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\202\25", IF_386|IF_SB}, + ITEMPLATE_END +}; + +static struct itemplate instrux_RCPPS[] = { + {I_RCPPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x53\110", IF_KATMAI|IF_SSE}, + {I_RCPPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x53\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_RCPSS[] = { + {I_RCPSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x53\110", IF_KATMAI|IF_SSE}, + {I_RCPSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x53\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_RCR[] = { + {I_RCR, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\203", IF_8086}, + {I_RCR, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\203", IF_8086}, + {I_RCR, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\203\25", IF_186|IF_SB}, + {I_RCR, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\203", IF_8086}, + {I_RCR, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\203", IF_8086}, + {I_RCR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\203\25", IF_186|IF_SB}, + {I_RCR, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\203", IF_386}, + {I_RCR, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\203", IF_386}, + {I_RCR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\203\25", IF_386|IF_SB}, + ITEMPLATE_END +}; + +static struct itemplate instrux_RDMSR[] = { + {I_RDMSR, 0, {0,0,0}, "\2\x0F\x32", IF_PENT|IF_PRIV}, + ITEMPLATE_END +}; + +static struct itemplate instrux_RDPMC[] = { + {I_RDPMC, 0, {0,0,0}, "\2\x0F\x33", IF_P6}, + ITEMPLATE_END +}; + +static struct itemplate instrux_RDSHR[] = { + {I_RDSHR, 1, {REGMEM|BITS32,0,0}, "\321\300\2\x0F\x36\200", IF_P6|IF_CYRIX|IF_SMM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_RDTSC[] = { + {I_RDTSC, 0, {0,0,0}, "\2\x0F\x31", IF_PENT}, + ITEMPLATE_END +}; + +static struct itemplate instrux_RESB[] = { + {I_RESB, 1, {IMMEDIATE,0,0}, "\340", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_RESD[] = { + ITEMPLATE_END +}; + +static struct itemplate instrux_RESQ[] = { + ITEMPLATE_END +}; + +static struct itemplate instrux_REST[] = { + ITEMPLATE_END +}; + +static struct itemplate instrux_RESW[] = { + ITEMPLATE_END +}; + +static struct itemplate instrux_RET[] = { + {I_RET, 0, {0,0,0}, "\1\xC3", IF_8086}, + {I_RET, 1, {IMMEDIATE,0,0}, "\1\xC2\30", IF_8086|IF_SW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_RETF[] = { + {I_RETF, 0, {0,0,0}, "\1\xCB", IF_8086}, + {I_RETF, 1, {IMMEDIATE,0,0}, "\1\xCA\30", IF_8086|IF_SW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_RETN[] = { + {I_RETN, 0, {0,0,0}, "\1\xC3", IF_8086}, + {I_RETN, 1, {IMMEDIATE,0,0}, "\1\xC2\30", IF_8086|IF_SW}, + ITEMPLATE_END +}; + +static struct itemplate instrux_ROL[] = { + {I_ROL, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\200", IF_8086}, + {I_ROL, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\200", IF_8086}, + {I_ROL, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\200\25", IF_186|IF_SB}, + {I_ROL, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\200", IF_8086}, + {I_ROL, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\200", IF_8086}, + {I_ROL, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\200\25", IF_186|IF_SB}, + {I_ROL, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\200", IF_386}, + {I_ROL, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\200", IF_386}, + {I_ROL, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\200\25", IF_386|IF_SB}, + ITEMPLATE_END +}; + +static struct itemplate instrux_ROR[] = { + {I_ROR, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\201", IF_8086}, + {I_ROR, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\201", IF_8086}, + {I_ROR, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\201\25", IF_186|IF_SB}, + {I_ROR, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\201", IF_8086}, + {I_ROR, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\201", IF_8086}, + {I_ROR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\201\25", IF_186|IF_SB}, + {I_ROR, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\201", IF_386}, + {I_ROR, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\201", IF_386}, + {I_ROR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\201\25", IF_386|IF_SB}, + ITEMPLATE_END +}; + +static struct itemplate instrux_RSDC[] = { + {I_RSDC, 2, {REG_SREG,MEMORY|BITS80,0}, "\301\2\x0F\x79\110", IF_486|IF_CYRIX|IF_SMM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_RSLDT[] = { + {I_RSLDT, 1, {MEMORY|BITS80,0,0}, "\300\2\x0F\x7B\200", IF_486|IF_CYRIX|IF_SMM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_RSM[] = { + {I_RSM, 0, {0,0,0}, "\2\x0F\xAA", IF_PENT|IF_SMM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_RSQRTPS[] = { + {I_RSQRTPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x52\110", IF_KATMAI|IF_SSE}, + {I_RSQRTPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x52\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_RSQRTSS[] = { + {I_RSQRTSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x52\110", IF_KATMAI|IF_SSE}, + {I_RSQRTSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x52\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_RSTS[] = { + {I_RSTS, 1, {MEMORY|BITS80,0,0}, "\300\2\x0F\x7D\200", IF_486|IF_CYRIX|IF_SMM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SAHF[] = { + {I_SAHF, 0, {0,0,0}, "\1\x9E", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SAL[] = { + {I_SAL, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\204", IF_8086}, + {I_SAL, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\204", IF_8086}, + {I_SAL, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\204\25", IF_186|IF_SB}, + {I_SAL, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\204", IF_8086}, + {I_SAL, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\204", IF_8086}, + {I_SAL, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\204\25", IF_186|IF_SB}, + {I_SAL, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\204", IF_386}, + {I_SAL, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\204", IF_386}, + {I_SAL, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\204\25", IF_386|IF_SB}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SALC[] = { + {I_SALC, 0, {0,0,0}, "\1\xD6", IF_8086|IF_UNDOC}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SAR[] = { + {I_SAR, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\207", IF_8086}, + {I_SAR, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\207", IF_8086}, + {I_SAR, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\207\25", IF_186|IF_SB}, + {I_SAR, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\207", IF_8086}, + {I_SAR, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\207", IF_8086}, + {I_SAR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\207\25", IF_186|IF_SB}, + {I_SAR, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\207", IF_386}, + {I_SAR, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\207", IF_386}, + {I_SAR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\207\25", IF_386|IF_SB}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SBB[] = { + {I_SBB, 2, {MEMORY,REG8,0}, "\300\1\x18\101", IF_8086|IF_SM}, + {I_SBB, 2, {REG8,REG8,0}, "\1\x18\101", IF_8086}, + {I_SBB, 2, {MEMORY,REG16,0}, "\320\300\1\x19\101", IF_8086|IF_SM}, + {I_SBB, 2, {REG16,REG16,0}, "\320\1\x19\101", IF_8086}, + {I_SBB, 2, {MEMORY,REG32,0}, "\321\300\1\x19\101", IF_386|IF_SM}, + {I_SBB, 2, {REG32,REG32,0}, "\321\1\x19\101", IF_386}, + {I_SBB, 2, {REG8,MEMORY,0}, "\301\1\x1A\110", IF_8086|IF_SM}, + {I_SBB, 2, {REG8,REG8,0}, "\1\x1A\110", IF_8086}, + {I_SBB, 2, {REG16,MEMORY,0}, "\320\301\1\x1B\110", IF_8086|IF_SM}, + {I_SBB, 2, {REG16,REG16,0}, "\320\1\x1B\110", IF_8086}, + {I_SBB, 2, {REG32,MEMORY,0}, "\321\301\1\x1B\110", IF_386|IF_SM}, + {I_SBB, 2, {REG32,REG32,0}, "\321\1\x1B\110", IF_386}, + {I_SBB, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\203\15", IF_8086}, + {I_SBB, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\203\15", IF_386}, + {I_SBB, 2, {REG_AL,IMMEDIATE,0}, "\1\x1C\21", IF_8086|IF_SM}, + {I_SBB, 2, {REG_AX,SBYTE,0}, "\320\1\x83\203\15", IF_8086|IF_SM}, + {I_SBB, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x1D\31", IF_8086|IF_SM}, + {I_SBB, 2, {REG_EAX,SBYTE,0}, "\321\1\x83\203\15", IF_386|IF_SM}, + {I_SBB, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x1D\41", IF_386|IF_SM}, + {I_SBB, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\203\21", IF_8086|IF_SM}, + {I_SBB, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\203\131", IF_8086|IF_SM}, + {I_SBB, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\203\141", IF_386|IF_SM}, + {I_SBB, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\203\21", IF_8086|IF_SM}, + {I_SBB, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\203\131", IF_8086|IF_SM}, + {I_SBB, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\203\141", IF_386|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SCASB[] = { + {I_SCASB, 0, {0,0,0}, "\332\1\xAE", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SCASD[] = { + {I_SCASD, 0, {0,0,0}, "\332\321\1\xAF", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SCASW[] = { + {I_SCASW, 0, {0,0,0}, "\332\320\1\xAF", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SFENCE[] = { + {I_SFENCE, 0, {0,0,0}, "\3\x0F\xAE\xF8", IF_KATMAI}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SGDT[] = { + {I_SGDT, 1, {MEMORY,0,0}, "\300\2\x0F\x01\200", IF_286}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SHL[] = { + {I_SHL, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\204", IF_8086}, + {I_SHL, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\204", IF_8086}, + {I_SHL, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\204\25", IF_186|IF_SB}, + {I_SHL, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\204", IF_8086}, + {I_SHL, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\204", IF_8086}, + {I_SHL, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\204\25", IF_186|IF_SB}, + {I_SHL, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\204", IF_386}, + {I_SHL, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\204", IF_386}, + {I_SHL, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\204\25", IF_386|IF_SB}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SHLD[] = { + {I_SHLD, 3, {MEMORY,REG16,IMMEDIATE}, "\300\320\2\x0F\xA4\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, + {I_SHLD, 3, {REG16,REG16,IMMEDIATE}, "\320\2\x0F\xA4\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, + {I_SHLD, 3, {MEMORY,REG32,IMMEDIATE}, "\300\321\2\x0F\xA4\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, + {I_SHLD, 3, {REG32,REG32,IMMEDIATE}, "\321\2\x0F\xA4\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, + {I_SHLD, 3, {MEMORY,REG16,REG_CL}, "\300\320\2\x0F\xA5\101", IF_386|IF_SM}, + {I_SHLD, 3, {REG16,REG16,REG_CL}, "\320\2\x0F\xA5\101", IF_386}, + {I_SHLD, 3, {MEMORY,REG32,REG_CL}, "\300\321\2\x0F\xA5\101", IF_386|IF_SM}, + {I_SHLD, 3, {REG32,REG32,REG_CL}, "\321\2\x0F\xA5\101", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SHR[] = { + {I_SHR, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\205", IF_8086}, + {I_SHR, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\205", IF_8086}, + {I_SHR, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\205\25", IF_186|IF_SB}, + {I_SHR, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\205", IF_8086}, + {I_SHR, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\205", IF_8086}, + {I_SHR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\205\25", IF_186|IF_SB}, + {I_SHR, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\205", IF_386}, + {I_SHR, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\205", IF_386}, + {I_SHR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\205\25", IF_386|IF_SB}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SHRD[] = { + {I_SHRD, 3, {MEMORY,REG16,IMMEDIATE}, "\300\320\2\x0F\xAC\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, + {I_SHRD, 3, {REG16,REG16,IMMEDIATE}, "\320\2\x0F\xAC\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, + {I_SHRD, 3, {MEMORY,REG32,IMMEDIATE}, "\300\321\2\x0F\xAC\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, + {I_SHRD, 3, {REG32,REG32,IMMEDIATE}, "\321\2\x0F\xAC\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, + {I_SHRD, 3, {MEMORY,REG16,REG_CL}, "\300\320\2\x0F\xAD\101", IF_386|IF_SM}, + {I_SHRD, 3, {REG16,REG16,REG_CL}, "\320\2\x0F\xAD\101", IF_386}, + {I_SHRD, 3, {MEMORY,REG32,REG_CL}, "\300\321\2\x0F\xAD\101", IF_386|IF_SM}, + {I_SHRD, 3, {REG32,REG32,REG_CL}, "\321\2\x0F\xAD\101", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SHUFPD[] = { + {I_SHUFPD, 3, {XMMREG,XMMREG,IMMEDIATE}, "\3\x66\x0F\xC6\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, + {I_SHUFPD, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\3\x66\x0F\xC6\110\26", IF_WILLAMETTE|IF_SSE2|IF_SM|IF_SB|IF_AR2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SHUFPS[] = { + {I_SHUFPS, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\2\x0F\xC6\110\26", IF_KATMAI|IF_SSE|IF_SB|IF_AR2}, + {I_SHUFPS, 3, {XMMREG,XMMREG,IMMEDIATE}, "\2\x0F\xC6\110\26", IF_KATMAI|IF_SSE|IF_SB|IF_AR2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SIDT[] = { + {I_SIDT, 1, {MEMORY,0,0}, "\300\2\x0F\x01\201", IF_286}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SLDT[] = { + {I_SLDT, 1, {MEMORY,0,0}, "\300\1\x0F\17\200", IF_286}, + {I_SLDT, 1, {MEMORY|BITS16,0,0}, "\300\1\x0F\17\200", IF_286}, + {I_SLDT, 1, {REG16,0,0}, "\320\1\x0F\17\200", IF_286}, + {I_SLDT, 1, {REG32,0,0}, "\321\1\x0F\17\200", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SMI[] = { + {I_SMI, 0, {0,0,0}, "\1\xF1", IF_386|IF_UNDOC}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SMINT[] = { + {I_SMINT, 0, {0,0,0}, "\2\x0F\x38", IF_P6|IF_CYRIX}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SMINTOLD[] = { + {I_SMINTOLD, 0, {0,0,0}, "\2\x0F\x7E", IF_486|IF_CYRIX}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SMSW[] = { + {I_SMSW, 1, {MEMORY,0,0}, "\300\2\x0F\x01\204", IF_286}, + {I_SMSW, 1, {MEMORY|BITS16,0,0}, "\300\2\x0F\x01\204", IF_286}, + {I_SMSW, 1, {REG16,0,0}, "\320\2\x0F\x01\204", IF_286}, + {I_SMSW, 1, {REG32,0,0}, "\321\2\x0F\x01\204", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SQRTPD[] = { + {I_SQRTPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x51\110", IF_WILLAMETTE|IF_SSE2}, + {I_SQRTPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x51\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SQRTPS[] = { + {I_SQRTPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x51\110", IF_KATMAI|IF_SSE}, + {I_SQRTPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x51\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SQRTSD[] = { + {I_SQRTSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x51\110", IF_WILLAMETTE|IF_SSE2}, + {I_SQRTSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x51\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SQRTSS[] = { + {I_SQRTSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x51\110", IF_KATMAI|IF_SSE}, + {I_SQRTSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x51\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_STC[] = { + {I_STC, 0, {0,0,0}, "\1\xF9", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_STD[] = { + {I_STD, 0, {0,0,0}, "\1\xFD", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_STI[] = { + {I_STI, 0, {0,0,0}, "\1\xFB", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_STMXCSR[] = { + {I_STMXCSR, 1, {MEMORY,0,0}, "\300\2\x0F\xAE\203", IF_KATMAI|IF_SSE|IF_SD}, + ITEMPLATE_END +}; + +static struct itemplate instrux_STOSB[] = { + {I_STOSB, 0, {0,0,0}, "\1\xAA", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_STOSD[] = { + {I_STOSD, 0, {0,0,0}, "\321\1\xAB", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_STOSW[] = { + {I_STOSW, 0, {0,0,0}, "\320\1\xAB", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_STR[] = { + {I_STR, 1, {MEMORY,0,0}, "\300\1\x0F\17\201", IF_286|IF_PROT}, + {I_STR, 1, {MEMORY|BITS16,0,0}, "\300\1\x0F\17\201", IF_286|IF_PROT}, + {I_STR, 1, {REG16,0,0}, "\320\1\x0F\17\201", IF_286|IF_PROT}, + {I_STR, 1, {REG32,0,0}, "\321\1\x0F\17\201", IF_386|IF_PROT}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SUB[] = { + {I_SUB, 2, {MEMORY,REG8,0}, "\300\1\x28\101", IF_8086|IF_SM}, + {I_SUB, 2, {REG8,REG8,0}, "\1\x28\101", IF_8086}, + {I_SUB, 2, {MEMORY,REG16,0}, "\320\300\1\x29\101", IF_8086|IF_SM}, + {I_SUB, 2, {REG16,REG16,0}, "\320\1\x29\101", IF_8086}, + {I_SUB, 2, {MEMORY,REG32,0}, "\321\300\1\x29\101", IF_386|IF_SM}, + {I_SUB, 2, {REG32,REG32,0}, "\321\1\x29\101", IF_386}, + {I_SUB, 2, {REG8,MEMORY,0}, "\301\1\x2A\110", IF_8086|IF_SM}, + {I_SUB, 2, {REG8,REG8,0}, "\1\x2A\110", IF_8086}, + {I_SUB, 2, {REG16,MEMORY,0}, "\320\301\1\x2B\110", IF_8086|IF_SM}, + {I_SUB, 2, {REG16,REG16,0}, "\320\1\x2B\110", IF_8086}, + {I_SUB, 2, {REG32,MEMORY,0}, "\321\301\1\x2B\110", IF_386|IF_SM}, + {I_SUB, 2, {REG32,REG32,0}, "\321\1\x2B\110", IF_386}, + {I_SUB, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\205\15", IF_8086}, + {I_SUB, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\205\15", IF_386}, + {I_SUB, 2, {REG_AL,IMMEDIATE,0}, "\1\x2C\21", IF_8086|IF_SM}, + {I_SUB, 2, {REG_AX,SBYTE,0}, "\320\1\x83\205\15", IF_8086|IF_SM}, + {I_SUB, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x2D\31", IF_8086|IF_SM}, + {I_SUB, 2, {REG_EAX,SBYTE,0}, "\321\1\x83\205\15", IF_386|IF_SM}, + {I_SUB, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x2D\41", IF_386|IF_SM}, + {I_SUB, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\205\21", IF_8086|IF_SM}, + {I_SUB, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\205\131", IF_8086|IF_SM}, + {I_SUB, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\205\141", IF_386|IF_SM}, + {I_SUB, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\205\21", IF_8086|IF_SM}, + {I_SUB, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\205\131", IF_8086|IF_SM}, + {I_SUB, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\205\141", IF_386|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SUBPD[] = { + {I_SUBPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x5C\110", IF_WILLAMETTE|IF_SSE2}, + {I_SUBPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x5C\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SUBPS[] = { + {I_SUBPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x5C\110", IF_KATMAI|IF_SSE}, + {I_SUBPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x5C\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SUBSD[] = { + {I_SUBSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x5C\110", IF_WILLAMETTE|IF_SSE2}, + {I_SUBSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x5C\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SUBSS[] = { + {I_SUBSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x5C\110", IF_KATMAI|IF_SSE}, + {I_SUBSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x5C\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SVDC[] = { + {I_SVDC, 2, {MEMORY|BITS80,REG_SREG,0}, "\300\2\x0F\x78\101", IF_486|IF_CYRIX|IF_SMM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SVLDT[] = { + {I_SVLDT, 1, {MEMORY|BITS80,0,0}, "\300\2\x0F\x7A\200", IF_486|IF_CYRIX|IF_SMM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SVTS[] = { + {I_SVTS, 1, {MEMORY|BITS80,0,0}, "\300\2\x0F\x7C\200", IF_486|IF_CYRIX|IF_SMM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SYSCALL[] = { + {I_SYSCALL, 0, {0,0,0}, "\2\x0F\x05", IF_P6|IF_AMD}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SYSENTER[] = { + {I_SYSENTER, 0, {0,0,0}, "\2\x0F\x34", IF_P6}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SYSEXIT[] = { + {I_SYSEXIT, 0, {0,0,0}, "\2\x0F\x35", IF_P6|IF_PRIV}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SYSRET[] = { + {I_SYSRET, 0, {0,0,0}, "\2\x0F\x07", IF_P6|IF_PRIV|IF_AMD}, + ITEMPLATE_END +}; + +static struct itemplate instrux_TEST[] = { + {I_TEST, 2, {MEMORY,REG8,0}, "\300\1\x84\101", IF_8086|IF_SM}, + {I_TEST, 2, {REG8,REG8,0}, "\1\x84\101", IF_8086}, + {I_TEST, 2, {MEMORY,REG16,0}, "\320\300\1\x85\101", IF_8086|IF_SM}, + {I_TEST, 2, {REG16,REG16,0}, "\320\1\x85\101", IF_8086}, + {I_TEST, 2, {MEMORY,REG32,0}, "\321\300\1\x85\101", IF_386|IF_SM}, + {I_TEST, 2, {REG32,REG32,0}, "\321\1\x85\101", IF_386}, + {I_TEST, 2, {REG8,MEMORY,0}, "\301\1\x84\110", IF_8086|IF_SM}, + {I_TEST, 2, {REG16,MEMORY,0}, "\320\301\1\x85\110", IF_8086|IF_SM}, + {I_TEST, 2, {REG32,MEMORY,0}, "\321\301\1\x85\110", IF_386|IF_SM}, + {I_TEST, 2, {REG_AL,IMMEDIATE,0}, "\1\xA8\21", IF_8086|IF_SM}, + {I_TEST, 2, {REG_AX,IMMEDIATE,0}, "\320\1\xA9\31", IF_8086|IF_SM}, + {I_TEST, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\xA9\41", IF_386|IF_SM}, + {I_TEST, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xF6\200\21", IF_8086|IF_SM}, + {I_TEST, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xF7\200\31", IF_8086|IF_SM}, + {I_TEST, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xF7\200\41", IF_386|IF_SM}, + {I_TEST, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\xF6\200\21", IF_8086|IF_SM}, + {I_TEST, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\1\xF7\200\31", IF_8086|IF_SM}, + {I_TEST, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\1\xF7\200\41", IF_386|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_UCOMISD[] = { + {I_UCOMISD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x2E\110", IF_WILLAMETTE|IF_SSE2}, + {I_UCOMISD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x2E\110", IF_WILLAMETTE|IF_SSE2}, + ITEMPLATE_END +}; + +static struct itemplate instrux_UCOMISS[] = { + {I_UCOMISS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x2E\110", IF_KATMAI|IF_SSE}, + {I_UCOMISS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x2E\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_UD0[] = { + {I_UD0, 0, {0,0,0}, "\2\x0F\xFF", IF_286|IF_UNDOC}, + ITEMPLATE_END +}; + +static struct itemplate instrux_UD1[] = { + {I_UD1, 0, {0,0,0}, "\2\x0F\xB9", IF_286|IF_UNDOC}, + ITEMPLATE_END +}; + +static struct itemplate instrux_UD2[] = { + {I_UD2, 0, {0,0,0}, "\2\x0F\x0B", IF_286}, + ITEMPLATE_END +}; + +static struct itemplate instrux_UMOV[] = { + {I_UMOV, 2, {MEMORY,REG8,0}, "\300\2\x0F\x10\101", IF_386|IF_UNDOC|IF_SM}, + {I_UMOV, 2, {REG8,REG8,0}, "\2\x0F\x10\101", IF_386|IF_UNDOC}, + {I_UMOV, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\x11\101", IF_386|IF_UNDOC|IF_SM}, + {I_UMOV, 2, {REG16,REG16,0}, "\320\2\x0F\x11\101", IF_386|IF_UNDOC}, + {I_UMOV, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\x11\101", IF_386|IF_UNDOC|IF_SM}, + {I_UMOV, 2, {REG32,REG32,0}, "\321\2\x0F\x11\101", IF_386|IF_UNDOC}, + {I_UMOV, 2, {REG8,MEMORY,0}, "\301\2\x0F\x12\110", IF_386|IF_UNDOC|IF_SM}, + {I_UMOV, 2, {REG8,REG8,0}, "\2\x0F\x12\110", IF_386|IF_UNDOC}, + {I_UMOV, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\x13\110", IF_386|IF_UNDOC|IF_SM}, + {I_UMOV, 2, {REG16,REG16,0}, "\320\2\x0F\x13\110", IF_386|IF_UNDOC}, + {I_UMOV, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\x13\110", IF_386|IF_UNDOC|IF_SM}, + {I_UMOV, 2, {REG32,REG32,0}, "\321\2\x0F\x13\110", IF_386|IF_UNDOC}, + ITEMPLATE_END +}; + +static struct itemplate instrux_UNPCKHPD[] = { + {I_UNPCKHPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x15\110", IF_WILLAMETTE|IF_SSE2}, + {I_UNPCKHPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x15\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_UNPCKHPS[] = { + {I_UNPCKHPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x15\110", IF_KATMAI|IF_SSE}, + {I_UNPCKHPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x15\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_UNPCKLPD[] = { + {I_UNPCKLPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x14\110", IF_WILLAMETTE|IF_SSE2}, + {I_UNPCKLPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x14\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_UNPCKLPS[] = { + {I_UNPCKLPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x14\110", IF_KATMAI|IF_SSE}, + {I_UNPCKLPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x14\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_VERR[] = { + {I_VERR, 1, {MEMORY,0,0}, "\300\1\x0F\17\204", IF_286|IF_PROT}, + {I_VERR, 1, {MEMORY|BITS16,0,0}, "\300\1\x0F\17\204", IF_286|IF_PROT}, + {I_VERR, 1, {REG16,0,0}, "\1\x0F\17\204", IF_286|IF_PROT}, + ITEMPLATE_END +}; + +static struct itemplate instrux_VERW[] = { + {I_VERW, 1, {MEMORY,0,0}, "\300\1\x0F\17\205", IF_286|IF_PROT}, + {I_VERW, 1, {MEMORY|BITS16,0,0}, "\300\1\x0F\17\205", IF_286|IF_PROT}, + {I_VERW, 1, {REG16,0,0}, "\1\x0F\17\205", IF_286|IF_PROT}, + ITEMPLATE_END +}; + +static struct itemplate instrux_WAIT[] = { + {I_WAIT, 0, {0,0,0}, "\1\x9B", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_WBINVD[] = { + {I_WBINVD, 0, {0,0,0}, "\2\x0F\x09", IF_486|IF_PRIV}, + ITEMPLATE_END +}; + +static struct itemplate instrux_WRMSR[] = { + {I_WRMSR, 0, {0,0,0}, "\2\x0F\x30", IF_PENT|IF_PRIV}, + ITEMPLATE_END +}; + +static struct itemplate instrux_WRSHR[] = { + {I_WRSHR, 1, {REGMEM|BITS32,0,0}, "\321\300\2\x0F\x37\200", IF_P6|IF_CYRIX|IF_SMM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_XADD[] = { + {I_XADD, 2, {MEMORY,REG8,0}, "\300\2\x0F\xC0\101", IF_486|IF_SM}, + {I_XADD, 2, {REG8,REG8,0}, "\2\x0F\xC0\101", IF_486}, + {I_XADD, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xC1\101", IF_486|IF_SM}, + {I_XADD, 2, {REG16,REG16,0}, "\320\2\x0F\xC1\101", IF_486}, + {I_XADD, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xC1\101", IF_486|IF_SM}, + {I_XADD, 2, {REG32,REG32,0}, "\321\2\x0F\xC1\101", IF_486}, + ITEMPLATE_END +}; + +static struct itemplate instrux_XBTS[] = { + {I_XBTS, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xA6\110", IF_386|IF_SW|IF_UNDOC}, + {I_XBTS, 2, {REG16,REG16,0}, "\320\2\x0F\xA6\110", IF_386|IF_UNDOC}, + {I_XBTS, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xA6\110", IF_386|IF_SD|IF_UNDOC}, + {I_XBTS, 2, {REG32,REG32,0}, "\321\2\x0F\xA6\110", IF_386|IF_UNDOC}, + ITEMPLATE_END +}; + +static struct itemplate instrux_XCHG[] = { + {I_XCHG, 2, {REG_AX,REG16,0}, "\320\11\x90", IF_8086}, + {I_XCHG, 2, {REG_EAX,REG32,0}, "\321\11\x90", IF_386}, + {I_XCHG, 2, {REG16,REG_AX,0}, "\320\10\x90", IF_8086}, + {I_XCHG, 2, {REG32,REG_EAX,0}, "\321\10\x90", IF_386}, + {I_XCHG, 2, {REG8,MEMORY,0}, "\301\1\x86\110", IF_8086|IF_SM}, + {I_XCHG, 2, {REG8,REG8,0}, "\1\x86\110", IF_8086}, + {I_XCHG, 2, {REG16,MEMORY,0}, "\320\301\1\x87\110", IF_8086|IF_SM}, + {I_XCHG, 2, {REG16,REG16,0}, "\320\1\x87\110", IF_8086}, + {I_XCHG, 2, {REG32,MEMORY,0}, "\321\301\1\x87\110", IF_386|IF_SM}, + {I_XCHG, 2, {REG32,REG32,0}, "\321\1\x87\110", IF_386}, + {I_XCHG, 2, {MEMORY,REG8,0}, "\300\1\x86\101", IF_8086|IF_SM}, + {I_XCHG, 2, {REG8,REG8,0}, "\1\x86\101", IF_8086}, + {I_XCHG, 2, {MEMORY,REG16,0}, "\320\300\1\x87\101", IF_8086|IF_SM}, + {I_XCHG, 2, {REG16,REG16,0}, "\320\1\x87\101", IF_8086}, + {I_XCHG, 2, {MEMORY,REG32,0}, "\321\300\1\x87\101", IF_386|IF_SM}, + {I_XCHG, 2, {REG32,REG32,0}, "\321\1\x87\101", IF_386}, + ITEMPLATE_END +}; + +static struct itemplate instrux_XLAT[] = { + {I_XLAT, 0, {0,0,0}, "\1\xD7", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_XLATB[] = { + {I_XLATB, 0, {0,0,0}, "\1\xD7", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_XOR[] = { + {I_XOR, 2, {MEMORY,REG8,0}, "\300\1\x30\101", IF_8086|IF_SM}, + {I_XOR, 2, {REG8,REG8,0}, "\1\x30\101", IF_8086}, + {I_XOR, 2, {MEMORY,REG16,0}, "\320\300\1\x31\101", IF_8086|IF_SM}, + {I_XOR, 2, {REG16,REG16,0}, "\320\1\x31\101", IF_8086}, + {I_XOR, 2, {MEMORY,REG32,0}, "\321\300\1\x31\101", IF_386|IF_SM}, + {I_XOR, 2, {REG32,REG32,0}, "\321\1\x31\101", IF_386}, + {I_XOR, 2, {REG8,MEMORY,0}, "\301\1\x32\110", IF_8086|IF_SM}, + {I_XOR, 2, {REG8,REG8,0}, "\1\x32\110", IF_8086}, + {I_XOR, 2, {REG16,MEMORY,0}, "\320\301\1\x33\110", IF_8086|IF_SM}, + {I_XOR, 2, {REG16,REG16,0}, "\320\1\x33\110", IF_8086}, + {I_XOR, 2, {REG32,MEMORY,0}, "\321\301\1\x33\110", IF_386|IF_SM}, + {I_XOR, 2, {REG32,REG32,0}, "\321\1\x33\110", IF_386}, + {I_XOR, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\206\15", IF_8086}, + {I_XOR, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\206\15", IF_386}, + {I_XOR, 2, {REG_AL,IMMEDIATE,0}, "\1\x34\21", IF_8086|IF_SM}, + {I_XOR, 2, {REG_AX,SBYTE,0}, "\320\1\x83\206\15", IF_8086|IF_SM}, + {I_XOR, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x35\31", IF_8086|IF_SM}, + {I_XOR, 2, {REG_EAX,SBYTE,0}, "\321\1\x83\206\15", IF_386|IF_SM}, + {I_XOR, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x35\41", IF_386|IF_SM}, + {I_XOR, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\206\21", IF_8086|IF_SM}, + {I_XOR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\206\131", IF_8086|IF_SM}, + {I_XOR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\206\141", IF_386|IF_SM}, + {I_XOR, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\206\21", IF_8086|IF_SM}, + {I_XOR, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\206\131", IF_8086|IF_SM}, + {I_XOR, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\206\141", IF_386|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_XORPD[] = { + {I_XORPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x57\110", IF_WILLAMETTE|IF_SSE2}, + {I_XORPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x57\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + ITEMPLATE_END +}; + +static struct itemplate instrux_XORPS[] = { + {I_XORPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x57\110", IF_KATMAI|IF_SSE}, + {I_XORPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x57\110", IF_KATMAI|IF_SSE}, + ITEMPLATE_END +}; + +static struct itemplate instrux_XSTORE[] = { + {I_XSTORE, 0, {0,0,0}, "\3\x0F\xA7\xC0", IF_P6|IF_CYRIX}, + ITEMPLATE_END +}; + +static struct itemplate instrux_CMOVcc[] = { + {I_CMOVcc, 2, {REG16,MEMORY,0}, "\320\301\1\x0F\330\x40\110", IF_P6|IF_SM}, + {I_CMOVcc, 2, {REG16,REG16,0}, "\320\1\x0F\330\x40\110", IF_P6}, + {I_CMOVcc, 2, {REG32,MEMORY,0}, "\321\301\1\x0F\330\x40\110", IF_P6|IF_SM}, + {I_CMOVcc, 2, {REG32,REG32,0}, "\321\1\x0F\330\x40\110", IF_P6}, + ITEMPLATE_END +}; + +static struct itemplate instrux_Jcc[] = { + {I_Jcc, 1, {IMMEDIATE|NEAR,0,0}, "\322\1\x0F\330\x80\64", IF_386}, + {I_Jcc, 1, {IMMEDIATE|BITS16|NEAR,0,0}, "\320\1\x0F\330\x80\64", IF_386}, + {I_Jcc, 1, {IMMEDIATE|BITS32|NEAR,0,0}, "\321\1\x0F\330\x80\64", IF_386}, + {I_Jcc, 1, {IMMEDIATE|SHORT,0,0}, "\330\x70\50", IF_8086}, + {I_Jcc, 1, {IMMEDIATE,0,0}, "\370\330\x70\50", IF_8086}, + {I_Jcc, 1, {IMMEDIATE,0,0}, "\1\x0F\330\x80\64", IF_386}, + {I_Jcc, 1, {IMMEDIATE,0,0}, "\330\x71\373\1\xE9\64", IF_8086}, + {I_Jcc, 1, {IMMEDIATE,0,0}, "\330\x70\50", IF_8086}, + ITEMPLATE_END +}; + +static struct itemplate instrux_SETcc[] = { + {I_SETcc, 1, {MEMORY,0,0}, "\300\1\x0F\330\x90\200", IF_386|IF_SB}, + {I_SETcc, 1, {REG8,0,0}, "\300\1\x0F\330\x90\200", IF_386}, + ITEMPLATE_END +}; + +struct itemplate *nasm_instructions[] = { + instrux_AAA, + instrux_AAD, + instrux_AAM, + instrux_AAS, + instrux_ADC, + instrux_ADD, + instrux_ADDPD, + instrux_ADDPS, + instrux_ADDSD, + instrux_ADDSS, + instrux_ADDSUBPD, + instrux_ADDSUBPS, + instrux_AND, + instrux_ANDNPD, + instrux_ANDNPS, + instrux_ANDPD, + instrux_ANDPS, + instrux_ARPL, + instrux_BOUND, + instrux_BSF, + instrux_BSR, + instrux_BSWAP, + instrux_BT, + instrux_BTC, + instrux_BTR, + instrux_BTS, + instrux_CALL, + instrux_CBW, + instrux_CDQ, + instrux_CLC, + instrux_CLD, + instrux_CLFLUSH, + instrux_CLI, + instrux_CLTS, + instrux_CMC, + instrux_CMP, + instrux_CMPEQPD, + instrux_CMPEQPS, + instrux_CMPEQSD, + instrux_CMPEQSS, + instrux_CMPLEPD, + instrux_CMPLEPS, + instrux_CMPLESD, + instrux_CMPLESS, + instrux_CMPLTPD, + instrux_CMPLTPS, + instrux_CMPLTSD, + instrux_CMPLTSS, + instrux_CMPNEQPD, + instrux_CMPNEQPS, + instrux_CMPNEQSD, + instrux_CMPNEQSS, + instrux_CMPNLEPD, + instrux_CMPNLEPS, + instrux_CMPNLESD, + instrux_CMPNLESS, + instrux_CMPNLTPD, + instrux_CMPNLTPS, + instrux_CMPNLTSD, + instrux_CMPNLTSS, + instrux_CMPORDPD, + instrux_CMPORDPS, + instrux_CMPORDSD, + instrux_CMPORDSS, + instrux_CMPPD, + instrux_CMPPS, + instrux_CMPSB, + instrux_CMPSD, + instrux_CMPSS, + instrux_CMPSW, + instrux_CMPUNORDPD, + instrux_CMPUNORDPS, + instrux_CMPUNORDSD, + instrux_CMPUNORDSS, + instrux_CMPXCHG, + instrux_CMPXCHG486, + instrux_CMPXCHG8B, + instrux_COMISD, + instrux_COMISS, + instrux_CPUID, + instrux_CVTDQ2PD, + instrux_CVTDQ2PS, + instrux_CVTPD2DQ, + instrux_CVTPD2PI, + instrux_CVTPD2PS, + instrux_CVTPI2PD, + instrux_CVTPI2PS, + instrux_CVTPS2DQ, + instrux_CVTPS2PD, + instrux_CVTPS2PI, + instrux_CVTSD2SI, + instrux_CVTSD2SS, + instrux_CVTSI2SD, + instrux_CVTSI2SS, + instrux_CVTSS2SD, + instrux_CVTSS2SI, + instrux_CVTTPD2DQ, + instrux_CVTTPD2PI, + instrux_CVTTPS2DQ, + instrux_CVTTPS2PI, + instrux_CVTTSD2SI, + instrux_CVTTSS2SI, + instrux_CWD, + instrux_CWDE, + instrux_DAA, + instrux_DAS, + instrux_DB, + instrux_DD, + instrux_DEC, + instrux_DIV, + instrux_DIVPD, + instrux_DIVPS, + instrux_DIVSD, + instrux_DIVSS, + instrux_DQ, + instrux_DT, + instrux_DW, + instrux_EMMS, + instrux_ENTER, + instrux_EQU, + instrux_F2XM1, + instrux_FABS, + instrux_FADD, + instrux_FADDP, + instrux_FBLD, + instrux_FBSTP, + instrux_FCHS, + instrux_FCLEX, + instrux_FCMOVB, + instrux_FCMOVBE, + instrux_FCMOVE, + instrux_FCMOVNB, + instrux_FCMOVNBE, + instrux_FCMOVNE, + instrux_FCMOVNU, + instrux_FCMOVU, + instrux_FCOM, + instrux_FCOMI, + instrux_FCOMIP, + instrux_FCOMP, + instrux_FCOMPP, + instrux_FCOS, + instrux_FDECSTP, + instrux_FDISI, + instrux_FDIV, + instrux_FDIVP, + instrux_FDIVR, + instrux_FDIVRP, + instrux_FEMMS, + instrux_FENI, + instrux_FFREE, + instrux_FFREEP, + instrux_FIADD, + instrux_FICOM, + instrux_FICOMP, + instrux_FIDIV, + instrux_FIDIVR, + instrux_FILD, + instrux_FIMUL, + instrux_FINCSTP, + instrux_FINIT, + instrux_FIST, + instrux_FISTP, + instrux_FISTTP, + instrux_FISUB, + instrux_FISUBR, + instrux_FLD, + instrux_FLD1, + instrux_FLDCW, + instrux_FLDENV, + instrux_FLDL2E, + instrux_FLDL2T, + instrux_FLDLG2, + instrux_FLDLN2, + instrux_FLDPI, + instrux_FLDZ, + instrux_FMUL, + instrux_FMULP, + instrux_FNCLEX, + instrux_FNDISI, + instrux_FNENI, + instrux_FNINIT, + instrux_FNOP, + instrux_FNSAVE, + instrux_FNSTCW, + instrux_FNSTENV, + instrux_FNSTSW, + instrux_FPATAN, + instrux_FPREM, + instrux_FPREM1, + instrux_FPTAN, + instrux_FRNDINT, + instrux_FRSTOR, + instrux_FSAVE, + instrux_FSCALE, + instrux_FSETPM, + instrux_FSIN, + instrux_FSINCOS, + instrux_FSQRT, + instrux_FST, + instrux_FSTCW, + instrux_FSTENV, + instrux_FSTP, + instrux_FSTSW, + instrux_FSUB, + instrux_FSUBP, + instrux_FSUBR, + instrux_FSUBRP, + instrux_FTST, + instrux_FUCOM, + instrux_FUCOMI, + instrux_FUCOMIP, + instrux_FUCOMP, + instrux_FUCOMPP, + instrux_FWAIT, + instrux_FXAM, + instrux_FXCH, + instrux_FXRSTOR, + instrux_FXSAVE, + instrux_FXTRACT, + instrux_FYL2X, + instrux_FYL2XP1, + instrux_HADDPD, + instrux_HADDPS, + instrux_HLT, + instrux_HSUBPD, + instrux_HSUBPS, + instrux_IBTS, + instrux_ICEBP, + instrux_IDIV, + instrux_IMUL, + instrux_IN, + instrux_INC, + instrux_INCBIN, + instrux_INSB, + instrux_INSD, + instrux_INSW, + instrux_INT, + instrux_INT01, + instrux_INT03, + instrux_INT1, + instrux_INT3, + instrux_INTO, + instrux_INVD, + instrux_INVLPG, + instrux_IRET, + instrux_IRETD, + instrux_IRETW, + instrux_JCXZ, + instrux_JECXZ, + instrux_JMP, + instrux_JMPE, + instrux_LAHF, + instrux_LAR, + instrux_LDDQU, + instrux_LDMXCSR, + instrux_LDS, + instrux_LEA, + instrux_LEAVE, + instrux_LES, + instrux_LFENCE, + instrux_LFS, + instrux_LGDT, + instrux_LGS, + instrux_LIDT, + instrux_LLDT, + instrux_LMSW, + instrux_LOADALL, + instrux_LOADALL286, + instrux_LODSB, + instrux_LODSD, + instrux_LODSW, + instrux_LOOP, + instrux_LOOPE, + instrux_LOOPNE, + instrux_LOOPNZ, + instrux_LOOPZ, + instrux_LSL, + instrux_LSS, + instrux_LTR, + instrux_MASKMOVDQU, + instrux_MASKMOVQ, + instrux_MAXPD, + instrux_MAXPS, + instrux_MAXSD, + instrux_MAXSS, + instrux_MFENCE, + instrux_MINPD, + instrux_MINPS, + instrux_MINSD, + instrux_MINSS, + instrux_MONITOR, + instrux_MOV, + instrux_MOVAPD, + instrux_MOVAPS, + instrux_MOVD, + instrux_MOVDDUP, + instrux_MOVDQ2Q, + instrux_MOVDQA, + instrux_MOVDQU, + instrux_MOVHLPS, + instrux_MOVHPD, + instrux_MOVHPS, + instrux_MOVLHPS, + instrux_MOVLPD, + instrux_MOVLPS, + instrux_MOVMSKPD, + instrux_MOVMSKPS, + instrux_MOVNTDQ, + instrux_MOVNTI, + instrux_MOVNTPD, + instrux_MOVNTPS, + instrux_MOVNTQ, + instrux_MOVQ, + instrux_MOVQ2DQ, + instrux_MOVSB, + instrux_MOVSD, + instrux_MOVSHDUP, + instrux_MOVSLDUP, + instrux_MOVSS, + instrux_MOVSW, + instrux_MOVSX, + instrux_MOVUPD, + instrux_MOVUPS, + instrux_MOVZX, + instrux_MUL, + instrux_MULPD, + instrux_MULPS, + instrux_MULSD, + instrux_MULSS, + instrux_MWAIT, + instrux_NEG, + instrux_NOP, + instrux_NOT, + instrux_OR, + instrux_ORPD, + instrux_ORPS, + instrux_OUT, + instrux_OUTSB, + instrux_OUTSD, + instrux_OUTSW, + instrux_PACKSSDW, + instrux_PACKSSWB, + instrux_PACKUSWB, + instrux_PADDB, + instrux_PADDD, + instrux_PADDQ, + instrux_PADDSB, + instrux_PADDSIW, + instrux_PADDSW, + instrux_PADDUSB, + instrux_PADDUSW, + instrux_PADDW, + instrux_PAND, + instrux_PANDN, + instrux_PAUSE, + instrux_PAVEB, + instrux_PAVGB, + instrux_PAVGUSB, + instrux_PAVGW, + instrux_PCMPEQB, + instrux_PCMPEQD, + instrux_PCMPEQW, + instrux_PCMPGTB, + instrux_PCMPGTD, + instrux_PCMPGTW, + instrux_PDISTIB, + instrux_PEXTRW, + instrux_PF2ID, + instrux_PF2IW, + instrux_PFACC, + instrux_PFADD, + instrux_PFCMPEQ, + instrux_PFCMPGE, + instrux_PFCMPGT, + instrux_PFMAX, + instrux_PFMIN, + instrux_PFMUL, + instrux_PFNACC, + instrux_PFPNACC, + instrux_PFRCP, + instrux_PFRCPIT1, + instrux_PFRCPIT2, + instrux_PFRSQIT1, + instrux_PFRSQRT, + instrux_PFSUB, + instrux_PFSUBR, + instrux_PI2FD, + instrux_PI2FW, + instrux_PINSRW, + instrux_PMACHRIW, + instrux_PMADDWD, + instrux_PMAGW, + instrux_PMAXSW, + instrux_PMAXUB, + instrux_PMINSW, + instrux_PMINUB, + instrux_PMOVMSKB, + instrux_PMULHRIW, + instrux_PMULHRWA, + instrux_PMULHRWC, + instrux_PMULHUW, + instrux_PMULHW, + instrux_PMULLW, + instrux_PMULUDQ, + instrux_PMVGEZB, + instrux_PMVLZB, + instrux_PMVNZB, + instrux_PMVZB, + instrux_POP, + instrux_POPA, + instrux_POPAD, + instrux_POPAW, + instrux_POPF, + instrux_POPFD, + instrux_POPFW, + instrux_POR, + instrux_PREFETCH, + instrux_PREFETCHNTA, + instrux_PREFETCHT0, + instrux_PREFETCHT1, + instrux_PREFETCHT2, + instrux_PREFETCHW, + instrux_PSADBW, + instrux_PSHUFD, + instrux_PSHUFHW, + instrux_PSHUFLW, + instrux_PSHUFW, + instrux_PSLLD, + instrux_PSLLDQ, + instrux_PSLLQ, + instrux_PSLLW, + instrux_PSRAD, + instrux_PSRAW, + instrux_PSRLD, + instrux_PSRLDQ, + instrux_PSRLQ, + instrux_PSRLW, + instrux_PSUBB, + instrux_PSUBD, + instrux_PSUBQ, + instrux_PSUBSB, + instrux_PSUBSIW, + instrux_PSUBSW, + instrux_PSUBUSB, + instrux_PSUBUSW, + instrux_PSUBW, + instrux_PSWAPD, + instrux_PUNPCKHBW, + instrux_PUNPCKHDQ, + instrux_PUNPCKHQDQ, + instrux_PUNPCKHWD, + instrux_PUNPCKLBW, + instrux_PUNPCKLDQ, + instrux_PUNPCKLQDQ, + instrux_PUNPCKLWD, + instrux_PUSH, + instrux_PUSHA, + instrux_PUSHAD, + instrux_PUSHAW, + instrux_PUSHF, + instrux_PUSHFD, + instrux_PUSHFW, + instrux_PXOR, + instrux_RCL, + instrux_RCPPS, + instrux_RCPSS, + instrux_RCR, + instrux_RDMSR, + instrux_RDPMC, + instrux_RDSHR, + instrux_RDTSC, + instrux_RESB, + instrux_RESD, + instrux_RESQ, + instrux_REST, + instrux_RESW, + instrux_RET, + instrux_RETF, + instrux_RETN, + instrux_ROL, + instrux_ROR, + instrux_RSDC, + instrux_RSLDT, + instrux_RSM, + instrux_RSQRTPS, + instrux_RSQRTSS, + instrux_RSTS, + instrux_SAHF, + instrux_SAL, + instrux_SALC, + instrux_SAR, + instrux_SBB, + instrux_SCASB, + instrux_SCASD, + instrux_SCASW, + instrux_SFENCE, + instrux_SGDT, + instrux_SHL, + instrux_SHLD, + instrux_SHR, + instrux_SHRD, + instrux_SHUFPD, + instrux_SHUFPS, + instrux_SIDT, + instrux_SLDT, + instrux_SMI, + instrux_SMINT, + instrux_SMINTOLD, + instrux_SMSW, + instrux_SQRTPD, + instrux_SQRTPS, + instrux_SQRTSD, + instrux_SQRTSS, + instrux_STC, + instrux_STD, + instrux_STI, + instrux_STMXCSR, + instrux_STOSB, + instrux_STOSD, + instrux_STOSW, + instrux_STR, + instrux_SUB, + instrux_SUBPD, + instrux_SUBPS, + instrux_SUBSD, + instrux_SUBSS, + instrux_SVDC, + instrux_SVLDT, + instrux_SVTS, + instrux_SYSCALL, + instrux_SYSENTER, + instrux_SYSEXIT, + instrux_SYSRET, + instrux_TEST, + instrux_UCOMISD, + instrux_UCOMISS, + instrux_UD0, + instrux_UD1, + instrux_UD2, + instrux_UMOV, + instrux_UNPCKHPD, + instrux_UNPCKHPS, + instrux_UNPCKLPD, + instrux_UNPCKLPS, + instrux_VERR, + instrux_VERW, + instrux_WAIT, + instrux_WBINVD, + instrux_WRMSR, + instrux_WRSHR, + instrux_XADD, + instrux_XBTS, + instrux_XCHG, + instrux_XLAT, + instrux_XLATB, + instrux_XOR, + instrux_XORPD, + instrux_XORPS, + instrux_XSTORE, + instrux_CMOVcc, + instrux_Jcc, + instrux_SETcc, +}; diff --git a/AltairZ80/insnsd.c b/AltairZ80/insnsd.c new file mode 100644 index 00000000..0f10cdb5 --- /dev/null +++ b/AltairZ80/insnsd.c @@ -0,0 +1,4516 @@ +/* This file auto-generated from insns.dat by insns.pl - don't edit it */ + +#include "nasm.h" +#include "insns.h" + +static struct itemplate instrux[] = { + {I_AAA, 0, {0,0,0}, "\1\x37", IF_8086}, + {I_AAD, 0, {0,0,0}, "\2\xD5\x0A", IF_8086}, + {I_AAD, 1, {IMMEDIATE,0,0}, "\1\xD5\24", IF_8086|IF_SB}, + {I_AAM, 0, {0,0,0}, "\2\xD4\x0A", IF_8086}, + {I_AAM, 1, {IMMEDIATE,0,0}, "\1\xD4\24", IF_8086|IF_SB}, + {I_AAS, 0, {0,0,0}, "\1\x3F", IF_8086}, + {I_ADC, 2, {MEMORY,REG8,0}, "\300\1\x10\101", IF_8086|IF_SM}, + {I_ADC, 2, {REG8,REG8,0}, "\1\x10\101", IF_8086}, + {I_ADC, 2, {MEMORY,REG16,0}, "\320\300\1\x11\101", IF_8086|IF_SM}, + {I_ADC, 2, {REG16,REG16,0}, "\320\1\x11\101", IF_8086}, + {I_ADC, 2, {MEMORY,REG32,0}, "\321\300\1\x11\101", IF_386|IF_SM}, + {I_ADC, 2, {REG32,REG32,0}, "\321\1\x11\101", IF_386}, + {I_ADC, 2, {REG8,MEMORY,0}, "\301\1\x12\110", IF_8086|IF_SM}, + {I_ADC, 2, {REG8,REG8,0}, "\1\x12\110", IF_8086}, + {I_ADC, 2, {REG16,MEMORY,0}, "\320\301\1\x13\110", IF_8086|IF_SM}, + {I_ADC, 2, {REG16,REG16,0}, "\320\1\x13\110", IF_8086}, + {I_ADC, 2, {REG32,MEMORY,0}, "\321\301\1\x13\110", IF_386|IF_SM}, + {I_ADC, 2, {REG32,REG32,0}, "\321\1\x13\110", IF_386}, + {I_ADC, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\202\15", IF_8086}, + {I_ADC, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\202\15", IF_386}, + {I_ADC, 2, {REG_AL,IMMEDIATE,0}, "\1\x14\21", IF_8086|IF_SM}, + {I_ADC, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x15\31", IF_8086|IF_SM}, + {I_ADC, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x15\41", IF_386|IF_SM}, + {I_ADC, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\202\21", IF_8086|IF_SM}, + {I_ADC, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\202\131", IF_8086|IF_SM}, + {I_ADC, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\202\141", IF_386|IF_SM}, + {I_ADC, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\202\21", IF_8086|IF_SM}, + {I_ADC, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\202\131", IF_8086|IF_SM}, + {I_ADC, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\202\141", IF_386|IF_SM}, + {I_ADD, 2, {MEMORY,REG8,0}, "\300\17\101", IF_8086|IF_SM}, + {I_ADD, 2, {REG8,REG8,0}, "\17\101", IF_8086}, + {I_ADD, 2, {MEMORY,REG16,0}, "\320\300\1\x01\101", IF_8086|IF_SM}, + {I_ADD, 2, {REG16,REG16,0}, "\320\1\x01\101", IF_8086}, + {I_ADD, 2, {MEMORY,REG32,0}, "\321\300\1\x01\101", IF_386|IF_SM}, + {I_ADD, 2, {REG32,REG32,0}, "\321\1\x01\101", IF_386}, + {I_ADD, 2, {REG8,MEMORY,0}, "\301\1\x02\110", IF_8086|IF_SM}, + {I_ADD, 2, {REG8,REG8,0}, "\1\x02\110", IF_8086}, + {I_ADD, 2, {REG16,MEMORY,0}, "\320\301\1\x03\110", IF_8086|IF_SM}, + {I_ADD, 2, {REG16,REG16,0}, "\320\1\x03\110", IF_8086}, + {I_ADD, 2, {REG32,MEMORY,0}, "\321\301\1\x03\110", IF_386|IF_SM}, + {I_ADD, 2, {REG32,REG32,0}, "\321\1\x03\110", IF_386}, + {I_ADD, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\200\15", IF_8086}, + {I_ADD, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\200\15", IF_386}, + {I_ADD, 2, {REG_AL,IMMEDIATE,0}, "\1\x04\21", IF_8086|IF_SM}, + {I_ADD, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x05\31", IF_8086|IF_SM}, + {I_ADD, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x05\41", IF_386|IF_SM}, + {I_ADD, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\200\21", IF_8086|IF_SM}, + {I_ADD, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\200\131", IF_8086|IF_SM}, + {I_ADD, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\200\141", IF_386|IF_SM}, + {I_ADD, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\200\21", IF_8086|IF_SM}, + {I_ADD, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\200\131", IF_8086|IF_SM}, + {I_ADD, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\200\141", IF_386|IF_SM}, + {I_AND, 2, {MEMORY,REG8,0}, "\300\1\x20\101", IF_8086|IF_SM}, + {I_AND, 2, {REG8,REG8,0}, "\1\x20\101", IF_8086}, + {I_AND, 2, {MEMORY,REG16,0}, "\320\300\1\x21\101", IF_8086|IF_SM}, + {I_AND, 2, {REG16,REG16,0}, "\320\1\x21\101", IF_8086}, + {I_AND, 2, {MEMORY,REG32,0}, "\321\300\1\x21\101", IF_386|IF_SM}, + {I_AND, 2, {REG32,REG32,0}, "\321\1\x21\101", IF_386}, + {I_AND, 2, {REG8,MEMORY,0}, "\301\1\x22\110", IF_8086|IF_SM}, + {I_AND, 2, {REG8,REG8,0}, "\1\x22\110", IF_8086}, + {I_AND, 2, {REG16,MEMORY,0}, "\320\301\1\x23\110", IF_8086|IF_SM}, + {I_AND, 2, {REG16,REG16,0}, "\320\1\x23\110", IF_8086}, + {I_AND, 2, {REG32,MEMORY,0}, "\321\301\1\x23\110", IF_386|IF_SM}, + {I_AND, 2, {REG32,REG32,0}, "\321\1\x23\110", IF_386}, + {I_AND, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\204\15", IF_8086}, + {I_AND, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\204\15", IF_386}, + {I_AND, 2, {REG_AL,IMMEDIATE,0}, "\1\x24\21", IF_8086|IF_SM}, + {I_AND, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x25\31", IF_8086|IF_SM}, + {I_AND, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x25\41", IF_386|IF_SM}, + {I_AND, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\204\21", IF_8086|IF_SM}, + {I_AND, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\204\131", IF_8086|IF_SM}, + {I_AND, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\204\141", IF_386|IF_SM}, + {I_AND, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\204\21", IF_8086|IF_SM}, + {I_AND, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\204\131", IF_8086|IF_SM}, + {I_AND, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\204\141", IF_386|IF_SM}, + {I_ARPL, 2, {MEMORY,REG16,0}, "\300\1\x63\101", IF_286|IF_PROT|IF_SM}, + {I_ARPL, 2, {REG16,REG16,0}, "\1\x63\101", IF_286|IF_PROT}, + {I_BOUND, 2, {REG16,MEMORY,0}, "\320\301\1\x62\110", IF_186}, + {I_BOUND, 2, {REG32,MEMORY,0}, "\321\301\1\x62\110", IF_386}, + {I_BSF, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xBC\110", IF_386|IF_SM}, + {I_BSF, 2, {REG16,REG16,0}, "\320\2\x0F\xBC\110", IF_386}, + {I_BSF, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xBC\110", IF_386|IF_SM}, + {I_BSF, 2, {REG32,REG32,0}, "\321\2\x0F\xBC\110", IF_386}, + {I_BSR, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xBD\110", IF_386|IF_SM}, + {I_BSR, 2, {REG16,REG16,0}, "\320\2\x0F\xBD\110", IF_386}, + {I_BSR, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xBD\110", IF_386|IF_SM}, + {I_BSR, 2, {REG32,REG32,0}, "\321\2\x0F\xBD\110", IF_386}, + {I_BSWAP, 1, {REG32,0,0}, "\321\1\x0F\10\xC8", IF_486}, + {I_BT, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xA3\101", IF_386|IF_SM}, + {I_BT, 2, {REG16,REG16,0}, "\320\2\x0F\xA3\101", IF_386}, + {I_BT, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xA3\101", IF_386|IF_SM}, + {I_BT, 2, {REG32,REG32,0}, "\321\2\x0F\xA3\101", IF_386}, + {I_BT, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\2\x0F\xBA\204\25", IF_386|IF_SB}, + {I_BT, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\2\x0F\xBA\204\25", IF_386|IF_SB}, + {I_BTC, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xBB\101", IF_386|IF_SM}, + {I_BTC, 2, {REG16,REG16,0}, "\320\2\x0F\xBB\101", IF_386}, + {I_BTC, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xBB\101", IF_386|IF_SM}, + {I_BTC, 2, {REG32,REG32,0}, "\321\2\x0F\xBB\101", IF_386}, + {I_BTC, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\2\x0F\xBA\207\25", IF_386|IF_SB}, + {I_BTC, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\2\x0F\xBA\207\25", IF_386|IF_SB}, + {I_BTR, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xB3\101", IF_386|IF_SM}, + {I_BTR, 2, {REG16,REG16,0}, "\320\2\x0F\xB3\101", IF_386}, + {I_BTR, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xB3\101", IF_386|IF_SM}, + {I_BTR, 2, {REG32,REG32,0}, "\321\2\x0F\xB3\101", IF_386}, + {I_BTR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\2\x0F\xBA\206\25", IF_386|IF_SB}, + {I_BTR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\2\x0F\xBA\206\25", IF_386|IF_SB}, + {I_BTS, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xAB\101", IF_386|IF_SM}, + {I_BTS, 2, {REG16,REG16,0}, "\320\2\x0F\xAB\101", IF_386}, + {I_BTS, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xAB\101", IF_386|IF_SM}, + {I_BTS, 2, {REG32,REG32,0}, "\321\2\x0F\xAB\101", IF_386}, + {I_BTS, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\2\x0F\xBA\205\25", IF_386|IF_SB}, + {I_BTS, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\2\x0F\xBA\205\25", IF_386|IF_SB}, + {I_CALL, 1, {IMMEDIATE,0,0}, "\322\1\xE8\64", IF_8086}, + {I_CALL, 1, {IMMEDIATE|NEAR,0,0}, "\322\1\xE8\64", IF_8086}, + {I_CALL, 1, {IMMEDIATE|BITS16,0,0}, "\320\1\xE8\64", IF_8086}, + {I_CALL, 1, {IMMEDIATE|BITS16|NEAR,0,0}, "\320\1\xE8\64", IF_8086}, + {I_CALL, 1, {IMMEDIATE|BITS32,0,0}, "\321\1\xE8\64", IF_386}, + {I_CALL, 1, {IMMEDIATE|BITS32|NEAR,0,0}, "\321\1\xE8\64", IF_386}, + {I_CALL, 2, {IMMEDIATE|COLON,IMMEDIATE,0}, "\322\1\x9A\35\30", IF_8086}, + {I_CALL, 2, {IMMEDIATE|BITS16|COLON,IMMEDIATE,0}, "\320\1\x9A\31\30", IF_8086}, + {I_CALL, 2, {IMMEDIATE|COLON,IMMEDIATE|BITS16,0}, "\320\1\x9A\31\30", IF_8086}, + {I_CALL, 2, {IMMEDIATE|BITS32|COLON,IMMEDIATE,0}, "\321\1\x9A\41\30", IF_386}, + {I_CALL, 2, {IMMEDIATE|COLON,IMMEDIATE|BITS32,0}, "\321\1\x9A\41\30", IF_386}, + {I_CALL, 1, {MEMORY|FAR,0,0}, "\322\300\1\xFF\203", IF_8086}, + {I_CALL, 1, {MEMORY|BITS16|FAR,0,0}, "\320\300\1\xFF\203", IF_8086}, + {I_CALL, 1, {MEMORY|BITS32|FAR,0,0}, "\321\300\1\xFF\203", IF_386}, + {I_CALL, 1, {MEMORY|NEAR,0,0}, "\322\300\1\xFF\202", IF_8086}, + {I_CALL, 1, {MEMORY|BITS16|NEAR,0,0}, "\320\300\1\xFF\202", IF_8086}, + {I_CALL, 1, {MEMORY|BITS32|NEAR,0,0}, "\321\300\1\xFF\202", IF_386}, + {I_CALL, 1, {REG16,0,0}, "\320\300\1\xFF\202", IF_8086}, + {I_CALL, 1, {REG32,0,0}, "\321\300\1\xFF\202", IF_386}, + {I_CALL, 1, {MEMORY,0,0}, "\322\300\1\xFF\202", IF_8086}, + {I_CALL, 1, {MEMORY|BITS16,0,0}, "\320\300\1\xFF\202", IF_8086}, + {I_CALL, 1, {MEMORY|BITS32,0,0}, "\321\300\1\xFF\202", IF_386}, + {I_CBW, 0, {0,0,0}, "\320\1\x98", IF_8086}, + {I_CDQ, 0, {0,0,0}, "\321\1\x99", IF_386}, + {I_CLC, 0, {0,0,0}, "\1\xF8", IF_8086}, + {I_CLD, 0, {0,0,0}, "\1\xFC", IF_8086}, + {I_CLI, 0, {0,0,0}, "\1\xFA", IF_8086}, + {I_CLTS, 0, {0,0,0}, "\2\x0F\x06", IF_286|IF_PRIV}, + {I_CMC, 0, {0,0,0}, "\1\xF5", IF_8086}, + {I_CMP, 2, {MEMORY,REG8,0}, "\300\1\x38\101", IF_8086|IF_SM}, + {I_CMP, 2, {REG8,REG8,0}, "\1\x38\101", IF_8086}, + {I_CMP, 2, {MEMORY,REG16,0}, "\320\300\1\x39\101", IF_8086|IF_SM}, + {I_CMP, 2, {REG16,REG16,0}, "\320\1\x39\101", IF_8086}, + {I_CMP, 2, {MEMORY,REG32,0}, "\321\300\1\x39\101", IF_386|IF_SM}, + {I_CMP, 2, {REG32,REG32,0}, "\321\1\x39\101", IF_386}, + {I_CMP, 2, {REG8,MEMORY,0}, "\301\1\x3A\110", IF_8086|IF_SM}, + {I_CMP, 2, {REG8,REG8,0}, "\1\x3A\110", IF_8086}, + {I_CMP, 2, {REG16,MEMORY,0}, "\320\301\1\x3B\110", IF_8086|IF_SM}, + {I_CMP, 2, {REG16,REG16,0}, "\320\1\x3B\110", IF_8086}, + {I_CMP, 2, {REG32,MEMORY,0}, "\321\301\1\x3B\110", IF_386|IF_SM}, + {I_CMP, 2, {REG32,REG32,0}, "\321\1\x3B\110", IF_386}, + {I_CMP, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\207\15", IF_8086}, + {I_CMP, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\207\15", IF_386}, + {I_CMP, 2, {REG_AL,IMMEDIATE,0}, "\1\x3C\21", IF_8086|IF_SM}, + {I_CMP, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x3D\31", IF_8086|IF_SM}, + {I_CMP, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x3D\41", IF_386|IF_SM}, + {I_CMP, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\207\21", IF_8086|IF_SM}, + {I_CMP, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\207\131", IF_8086|IF_SM}, + {I_CMP, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\207\141", IF_386|IF_SM}, + {I_CMP, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\207\21", IF_8086|IF_SM}, + {I_CMP, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\207\131", IF_8086|IF_SM}, + {I_CMP, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\207\141", IF_386|IF_SM}, + {I_CMPSB, 0, {0,0,0}, "\332\1\xA6", IF_8086}, + {I_CMPSD, 0, {0,0,0}, "\332\321\1\xA7", IF_386}, + {I_CMPSW, 0, {0,0,0}, "\332\320\1\xA7", IF_8086}, + {I_CMPXCHG, 2, {MEMORY,REG8,0}, "\300\2\x0F\xB0\101", IF_PENT|IF_SM}, + {I_CMPXCHG, 2, {REG8,REG8,0}, "\2\x0F\xB0\101", IF_PENT}, + {I_CMPXCHG, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xB1\101", IF_PENT|IF_SM}, + {I_CMPXCHG, 2, {REG16,REG16,0}, "\320\2\x0F\xB1\101", IF_PENT}, + {I_CMPXCHG, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xB1\101", IF_PENT|IF_SM}, + {I_CMPXCHG, 2, {REG32,REG32,0}, "\321\2\x0F\xB1\101", IF_PENT}, + {I_CMPXCHG486, 2, {MEMORY,REG8,0}, "\300\2\x0F\xA6\101", IF_486|IF_SM|IF_UNDOC}, + {I_CMPXCHG486, 2, {REG8,REG8,0}, "\2\x0F\xA6\101", IF_486|IF_UNDOC}, + {I_CMPXCHG486, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xA7\101", IF_486|IF_SM|IF_UNDOC}, + {I_CMPXCHG486, 2, {REG16,REG16,0}, "\320\2\x0F\xA7\101", IF_486|IF_UNDOC}, + {I_CMPXCHG486, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xA7\101", IF_486|IF_SM|IF_UNDOC}, + {I_CMPXCHG486, 2, {REG32,REG32,0}, "\321\2\x0F\xA7\101", IF_486|IF_UNDOC}, + {I_CMPXCHG8B, 1, {MEMORY,0,0}, "\300\2\x0F\xC7\201", IF_PENT}, + {I_CPUID, 0, {0,0,0}, "\2\x0F\xA2", IF_PENT}, + {I_CWD, 0, {0,0,0}, "\320\1\x99", IF_8086}, + {I_CWDE, 0, {0,0,0}, "\321\1\x98", IF_386}, + {I_DAA, 0, {0,0,0}, "\1\x27", IF_8086}, + {I_DAS, 0, {0,0,0}, "\1\x2F", IF_8086}, + {I_DEC, 1, {REG16,0,0}, "\320\10\x48", IF_8086}, + {I_DEC, 1, {REG32,0,0}, "\321\10\x48", IF_386}, + {I_DEC, 1, {REGMEM|BITS8,0,0}, "\300\1\xFE\201", IF_8086}, + {I_DEC, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xFF\201", IF_8086}, + {I_DEC, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xFF\201", IF_386}, + {I_DIV, 1, {REGMEM|BITS8,0,0}, "\300\1\xF6\206", IF_8086}, + {I_DIV, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xF7\206", IF_8086}, + {I_DIV, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xF7\206", IF_386}, + {I_EMMS, 0, {0,0,0}, "\2\x0F\x77", IF_PENT|IF_MMX}, + {I_ENTER, 2, {IMMEDIATE,IMMEDIATE,0}, "\1\xC8\30\25", IF_186}, + {I_EQU, 1, {IMMEDIATE,0,0}, "\0", IF_8086}, + {I_EQU, 2, {IMMEDIATE|COLON,IMMEDIATE,0}, "\0", IF_8086}, + {I_F2XM1, 0, {0,0,0}, "\2\xD9\xF0", IF_8086|IF_FPU}, + {I_FABS, 0, {0,0,0}, "\2\xD9\xE1", IF_8086|IF_FPU}, + {I_FADD, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\200", IF_8086|IF_FPU}, + {I_FADD, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\200", IF_8086|IF_FPU}, + {I_FADD, 1, {FPUREG|TO,0,0}, "\1\xDC\10\xC0", IF_8086|IF_FPU}, + {I_FADD, 1, {FPUREG,0,0}, "\1\xD8\10\xC0", IF_8086|IF_FPU}, + {I_FADD, 2, {FPUREG,FPU0,0}, "\1\xDC\10\xC0", IF_8086|IF_FPU}, + {I_FADD, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xC0", IF_8086|IF_FPU}, + {I_FADDP, 1, {FPUREG,0,0}, "\1\xDE\10\xC0", IF_8086|IF_FPU}, + {I_FADDP, 2, {FPUREG,FPU0,0}, "\1\xDE\10\xC0", IF_8086|IF_FPU}, + {I_FBLD, 1, {MEMORY|BITS80,0,0}, "\300\1\xDF\204", IF_8086|IF_FPU}, + {I_FBLD, 1, {MEMORY,0,0}, "\300\1\xDF\204", IF_8086|IF_FPU}, + {I_FBSTP, 1, {MEMORY|BITS80,0,0}, "\300\1\xDF\206", IF_8086|IF_FPU}, + {I_FBSTP, 1, {MEMORY,0,0}, "\300\1\xDF\206", IF_8086|IF_FPU}, + {I_FCHS, 0, {0,0,0}, "\2\xD9\xE0", IF_8086|IF_FPU}, + {I_FCLEX, 0, {0,0,0}, "\3\x9B\xDB\xE2", IF_8086|IF_FPU}, + {I_FCMOVB, 1, {FPUREG,0,0}, "\1\xDA\10\xC0", IF_P6|IF_FPU}, + {I_FCMOVB, 2, {FPU0,FPUREG,0}, "\1\xDA\11\xC0", IF_P6|IF_FPU}, + {I_FCMOVBE, 1, {FPUREG,0,0}, "\1\xDA\10\xD0", IF_P6|IF_FPU}, + {I_FCMOVBE, 2, {FPU0,FPUREG,0}, "\1\xDA\11\xD0", IF_P6|IF_FPU}, + {I_FCMOVE, 1, {FPUREG,0,0}, "\1\xDA\10\xC8", IF_P6|IF_FPU}, + {I_FCMOVE, 2, {FPU0,FPUREG,0}, "\1\xDA\11\xC8", IF_P6|IF_FPU}, + {I_FCMOVNB, 1, {FPUREG,0,0}, "\1\xDB\10\xC0", IF_P6|IF_FPU}, + {I_FCMOVNB, 2, {FPU0,FPUREG,0}, "\1\xDB\11\xC0", IF_P6|IF_FPU}, + {I_FCMOVNBE, 1, {FPUREG,0,0}, "\1\xDB\10\xD0", IF_P6|IF_FPU}, + {I_FCMOVNBE, 2, {FPU0,FPUREG,0}, "\1\xDB\11\xD0", IF_P6|IF_FPU}, + {I_FCMOVNE, 1, {FPUREG,0,0}, "\1\xDB\10\xC8", IF_P6|IF_FPU}, + {I_FCMOVNE, 2, {FPU0,FPUREG,0}, "\1\xDB\11\xC8", IF_P6|IF_FPU}, + {I_FCMOVNU, 1, {FPUREG,0,0}, "\1\xDB\10\xD8", IF_P6|IF_FPU}, + {I_FCMOVNU, 2, {FPU0,FPUREG,0}, "\1\xDB\11\xD8", IF_P6|IF_FPU}, + {I_FCMOVU, 1, {FPUREG,0,0}, "\1\xDA\10\xD8", IF_P6|IF_FPU}, + {I_FCMOVU, 2, {FPU0,FPUREG,0}, "\1\xDA\11\xD8", IF_P6|IF_FPU}, + {I_FCOM, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\202", IF_8086|IF_FPU}, + {I_FCOM, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\202", IF_8086|IF_FPU}, + {I_FCOM, 1, {FPUREG,0,0}, "\1\xD8\10\xD0", IF_8086|IF_FPU}, + {I_FCOM, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xD0", IF_8086|IF_FPU}, + {I_FCOMI, 1, {FPUREG,0,0}, "\1\xDB\10\xF0", IF_P6|IF_FPU}, + {I_FCOMI, 2, {FPU0,FPUREG,0}, "\1\xDB\11\xF0", IF_P6|IF_FPU}, + {I_FCOMIP, 1, {FPUREG,0,0}, "\1\xDF\10\xF0", IF_P6|IF_FPU}, + {I_FCOMIP, 2, {FPU0,FPUREG,0}, "\1\xDF\11\xF0", IF_P6|IF_FPU}, + {I_FCOMP, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\203", IF_8086|IF_FPU}, + {I_FCOMP, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\203", IF_8086|IF_FPU}, + {I_FCOMP, 1, {FPUREG,0,0}, "\1\xD8\10\xD8", IF_8086|IF_FPU}, + {I_FCOMP, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xD8", IF_8086|IF_FPU}, + {I_FCOMPP, 0, {0,0,0}, "\2\xDE\xD9", IF_8086|IF_FPU}, + {I_FCOS, 0, {0,0,0}, "\2\xD9\xFF", IF_386|IF_FPU}, + {I_FDECSTP, 0, {0,0,0}, "\2\xD9\xF6", IF_8086|IF_FPU}, + {I_FDISI, 0, {0,0,0}, "\3\x9B\xDB\xE1", IF_8086|IF_FPU}, + {I_FDIV, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\206", IF_8086|IF_FPU}, + {I_FDIV, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\206", IF_8086|IF_FPU}, + {I_FDIV, 1, {FPUREG|TO,0,0}, "\1\xDC\10\xF8", IF_8086|IF_FPU}, + {I_FDIV, 2, {FPUREG,FPU0,0}, "\1\xDC\10\xF8", IF_8086|IF_FPU}, + {I_FDIV, 1, {FPUREG,0,0}, "\1\xD8\10\xF0", IF_8086|IF_FPU}, + {I_FDIV, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xF0", IF_8086|IF_FPU}, + {I_FDIVP, 2, {FPUREG,FPU0,0}, "\1\xDE\10\xF8", IF_8086|IF_FPU}, + {I_FDIVP, 1, {FPUREG,0,0}, "\1\xDE\10\xF8", IF_8086|IF_FPU}, + {I_FDIVR, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\207", IF_8086|IF_FPU}, + {I_FDIVR, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\207", IF_8086|IF_FPU}, + {I_FDIVR, 1, {FPUREG|TO,0,0}, "\1\xDC\10\xF0", IF_8086|IF_FPU}, + {I_FDIVR, 2, {FPUREG,FPU0,0}, "\1\xDC\10\xF0", IF_8086|IF_FPU}, + {I_FDIVR, 1, {FPUREG,0,0}, "\1\xD8\10\xF8", IF_8086|IF_FPU}, + {I_FDIVR, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xF8", IF_8086|IF_FPU}, + {I_FDIVRP, 1, {FPUREG,0,0}, "\1\xDE\10\xF0", IF_8086|IF_FPU}, + {I_FDIVRP, 2, {FPUREG,FPU0,0}, "\1\xDE\10\xF0", IF_8086|IF_FPU}, + {I_FEMMS, 0, {0,0,0}, "\2\x0F\x0E", IF_PENT|IF_3DNOW}, + {I_FENI, 0, {0,0,0}, "\3\x9B\xDB\xE0", IF_8086|IF_FPU}, + {I_FFREE, 1, {FPUREG,0,0}, "\1\xDD\10\xC0", IF_8086|IF_FPU}, + {I_FFREEP, 1, {FPUREG,0,0}, "\1\xDF\10\xC0", IF_286|IF_FPU|IF_UNDOC}, + {I_FIADD, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\200", IF_8086|IF_FPU}, + {I_FIADD, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\200", IF_8086|IF_FPU}, + {I_FICOM, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\202", IF_8086|IF_FPU}, + {I_FICOM, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\202", IF_8086|IF_FPU}, + {I_FICOMP, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\203", IF_8086|IF_FPU}, + {I_FICOMP, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\203", IF_8086|IF_FPU}, + {I_FIDIV, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\206", IF_8086|IF_FPU}, + {I_FIDIV, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\206", IF_8086|IF_FPU}, + {I_FIDIVR, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\207", IF_8086|IF_FPU}, + {I_FIDIVR, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\207", IF_8086|IF_FPU}, + {I_FILD, 1, {MEMORY|BITS32,0,0}, "\300\1\xDB\200", IF_8086|IF_FPU}, + {I_FILD, 1, {MEMORY|BITS16,0,0}, "\300\1\xDF\200", IF_8086|IF_FPU}, + {I_FILD, 1, {MEMORY|BITS64,0,0}, "\300\1\xDF\205", IF_8086|IF_FPU}, + {I_FIMUL, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\201", IF_8086|IF_FPU}, + {I_FIMUL, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\201", IF_8086|IF_FPU}, + {I_FINCSTP, 0, {0,0,0}, "\2\xD9\xF7", IF_8086|IF_FPU}, + {I_FINIT, 0, {0,0,0}, "\3\x9B\xDB\xE3", IF_8086|IF_FPU}, + {I_FIST, 1, {MEMORY|BITS32,0,0}, "\300\1\xDB\202", IF_8086|IF_FPU}, + {I_FIST, 1, {MEMORY|BITS16,0,0}, "\300\1\xDF\202", IF_8086|IF_FPU}, + {I_FISTP, 1, {MEMORY|BITS32,0,0}, "\300\1\xDB\203", IF_8086|IF_FPU}, + {I_FISTP, 1, {MEMORY|BITS16,0,0}, "\300\1\xDF\203", IF_8086|IF_FPU}, + {I_FISTP, 1, {MEMORY|BITS64,0,0}, "\300\1\xDF\207", IF_8086|IF_FPU}, + {I_FISTTP, 1, {MEMORY|BITS32,0,0}, "\300\1\xDD\201", IF_PRESCOTT|IF_FPU}, + {I_FISTTP, 1, {MEMORY|BITS16,0,0}, "\300\1\xDB\201", IF_PRESCOTT|IF_FPU}, + {I_FISTTP, 1, {MEMORY|BITS64,0,0}, "\300\1\xDF\201", IF_PRESCOTT|IF_FPU}, + {I_FISUB, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\204", IF_8086|IF_FPU}, + {I_FISUB, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\204", IF_8086|IF_FPU}, + {I_FISUBR, 1, {MEMORY|BITS32,0,0}, "\300\1\xDA\205", IF_8086|IF_FPU}, + {I_FISUBR, 1, {MEMORY|BITS16,0,0}, "\300\1\xDE\205", IF_8086|IF_FPU}, + {I_FLD, 1, {MEMORY|BITS32,0,0}, "\300\1\xD9\200", IF_8086|IF_FPU}, + {I_FLD, 1, {MEMORY|BITS64,0,0}, "\300\1\xDD\200", IF_8086|IF_FPU}, + {I_FLD, 1, {MEMORY|BITS80,0,0}, "\300\1\xDB\205", IF_8086|IF_FPU}, + {I_FLD, 1, {FPUREG,0,0}, "\1\xD9\10\xC0", IF_8086|IF_FPU}, + {I_FLD1, 0, {0,0,0}, "\2\xD9\xE8", IF_8086|IF_FPU}, + {I_FLDCW, 1, {MEMORY,0,0}, "\300\1\xD9\205", IF_8086|IF_FPU|IF_SW}, + {I_FLDENV, 1, {MEMORY,0,0}, "\300\1\xD9\204", IF_8086|IF_FPU}, + {I_FLDL2E, 0, {0,0,0}, "\2\xD9\xEA", IF_8086|IF_FPU}, + {I_FLDL2T, 0, {0,0,0}, "\2\xD9\xE9", IF_8086|IF_FPU}, + {I_FLDLG2, 0, {0,0,0}, "\2\xD9\xEC", IF_8086|IF_FPU}, + {I_FLDLN2, 0, {0,0,0}, "\2\xD9\xED", IF_8086|IF_FPU}, + {I_FLDPI, 0, {0,0,0}, "\2\xD9\xEB", IF_8086|IF_FPU}, + {I_FLDZ, 0, {0,0,0}, "\2\xD9\xEE", IF_8086|IF_FPU}, + {I_FMUL, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\201", IF_8086|IF_FPU}, + {I_FMUL, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\201", IF_8086|IF_FPU}, + {I_FMUL, 1, {FPUREG|TO,0,0}, "\1\xDC\10\xC8", IF_8086|IF_FPU}, + {I_FMUL, 2, {FPUREG,FPU0,0}, "\1\xDC\10\xC8", IF_8086|IF_FPU}, + {I_FMUL, 1, {FPUREG,0,0}, "\1\xD8\10\xC8", IF_8086|IF_FPU}, + {I_FMUL, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xC8", IF_8086|IF_FPU}, + {I_FMULP, 1, {FPUREG,0,0}, "\1\xDE\10\xC8", IF_8086|IF_FPU}, + {I_FMULP, 2, {FPUREG,FPU0,0}, "\1\xDE\10\xC8", IF_8086|IF_FPU}, + {I_FNCLEX, 0, {0,0,0}, "\2\xDB\xE2", IF_8086|IF_FPU}, + {I_FNDISI, 0, {0,0,0}, "\2\xDB\xE1", IF_8086|IF_FPU}, + {I_FNENI, 0, {0,0,0}, "\2\xDB\xE0", IF_8086|IF_FPU}, + {I_FNINIT, 0, {0,0,0}, "\2\xDB\xE3", IF_8086|IF_FPU}, + {I_FNOP, 0, {0,0,0}, "\2\xD9\xD0", IF_8086|IF_FPU}, + {I_FNSAVE, 1, {MEMORY,0,0}, "\300\1\xDD\206", IF_8086|IF_FPU}, + {I_FNSTCW, 1, {MEMORY,0,0}, "\300\1\xD9\207", IF_8086|IF_FPU|IF_SW}, + {I_FNSTENV, 1, {MEMORY,0,0}, "\300\1\xD9\206", IF_8086|IF_FPU}, + {I_FNSTSW, 1, {MEMORY,0,0}, "\300\1\xDD\207", IF_8086|IF_FPU|IF_SW}, + {I_FNSTSW, 1, {REG_AX,0,0}, "\2\xDF\xE0", IF_286|IF_FPU}, + {I_FPATAN, 0, {0,0,0}, "\2\xD9\xF3", IF_8086|IF_FPU}, + {I_FPREM, 0, {0,0,0}, "\2\xD9\xF8", IF_8086|IF_FPU}, + {I_FPREM1, 0, {0,0,0}, "\2\xD9\xF5", IF_386|IF_FPU}, + {I_FPTAN, 0, {0,0,0}, "\2\xD9\xF2", IF_8086|IF_FPU}, + {I_FRNDINT, 0, {0,0,0}, "\2\xD9\xFC", IF_8086|IF_FPU}, + {I_FRSTOR, 1, {MEMORY,0,0}, "\300\1\xDD\204", IF_8086|IF_FPU}, + {I_FSAVE, 1, {MEMORY,0,0}, "\300\2\x9B\xDD\206", IF_8086|IF_FPU}, + {I_FSCALE, 0, {0,0,0}, "\2\xD9\xFD", IF_8086|IF_FPU}, + {I_FSETPM, 0, {0,0,0}, "\2\xDB\xE4", IF_286|IF_FPU}, + {I_FSIN, 0, {0,0,0}, "\2\xD9\xFE", IF_386|IF_FPU}, + {I_FSINCOS, 0, {0,0,0}, "\2\xD9\xFB", IF_386|IF_FPU}, + {I_FSQRT, 0, {0,0,0}, "\2\xD9\xFA", IF_8086|IF_FPU}, + {I_FST, 1, {MEMORY|BITS32,0,0}, "\300\1\xD9\202", IF_8086|IF_FPU}, + {I_FST, 1, {MEMORY|BITS64,0,0}, "\300\1\xDD\202", IF_8086|IF_FPU}, + {I_FST, 1, {FPUREG,0,0}, "\1\xDD\10\xD0", IF_8086|IF_FPU}, + {I_FSTCW, 1, {MEMORY,0,0}, "\300\2\x9B\xD9\207", IF_8086|IF_FPU|IF_SW}, + {I_FSTENV, 1, {MEMORY,0,0}, "\300\2\x9B\xD9\206", IF_8086|IF_FPU}, + {I_FSTP, 1, {MEMORY|BITS32,0,0}, "\300\1\xD9\203", IF_8086|IF_FPU}, + {I_FSTP, 1, {MEMORY|BITS64,0,0}, "\300\1\xDD\203", IF_8086|IF_FPU}, + {I_FSTP, 1, {MEMORY|BITS80,0,0}, "\300\1\xDB\207", IF_8086|IF_FPU}, + {I_FSTP, 1, {FPUREG,0,0}, "\1\xDD\10\xD8", IF_8086|IF_FPU}, + {I_FSTSW, 1, {MEMORY,0,0}, "\300\2\x9B\xDD\207", IF_8086|IF_FPU|IF_SW}, + {I_FSTSW, 1, {REG_AX,0,0}, "\3\x9B\xDF\xE0", IF_286|IF_FPU}, + {I_FSUB, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\204", IF_8086|IF_FPU}, + {I_FSUB, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\204", IF_8086|IF_FPU}, + {I_FSUB, 1, {FPUREG|TO,0,0}, "\1\xDC\10\xE8", IF_8086|IF_FPU}, + {I_FSUB, 2, {FPUREG,FPU0,0}, "\1\xDC\10\xE8", IF_8086|IF_FPU}, + {I_FSUB, 1, {FPUREG,0,0}, "\1\xD8\10\xE0", IF_8086|IF_FPU}, + {I_FSUB, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xE0", IF_8086|IF_FPU}, + {I_FSUBP, 1, {FPUREG,0,0}, "\1\xDE\10\xE8", IF_8086|IF_FPU}, + {I_FSUBP, 2, {FPUREG,FPU0,0}, "\1\xDE\10\xE8", IF_8086|IF_FPU}, + {I_FSUBR, 1, {MEMORY|BITS32,0,0}, "\300\1\xD8\205", IF_8086|IF_FPU}, + {I_FSUBR, 1, {MEMORY|BITS64,0,0}, "\300\1\xDC\205", IF_8086|IF_FPU}, + {I_FSUBR, 1, {FPUREG|TO,0,0}, "\1\xDC\10\xE0", IF_8086|IF_FPU}, + {I_FSUBR, 2, {FPUREG,FPU0,0}, "\1\xDC\10\xE0", IF_8086|IF_FPU}, + {I_FSUBR, 1, {FPUREG,0,0}, "\1\xD8\10\xE8", IF_8086|IF_FPU}, + {I_FSUBR, 2, {FPU0,FPUREG,0}, "\1\xD8\11\xE8", IF_8086|IF_FPU}, + {I_FSUBRP, 1, {FPUREG,0,0}, "\1\xDE\10\xE0", IF_8086|IF_FPU}, + {I_FSUBRP, 2, {FPUREG,FPU0,0}, "\1\xDE\10\xE0", IF_8086|IF_FPU}, + {I_FTST, 0, {0,0,0}, "\2\xD9\xE4", IF_8086|IF_FPU}, + {I_FUCOM, 1, {FPUREG,0,0}, "\1\xDD\10\xE0", IF_386|IF_FPU}, + {I_FUCOM, 2, {FPU0,FPUREG,0}, "\1\xDD\11\xE0", IF_386|IF_FPU}, + {I_FUCOMI, 1, {FPUREG,0,0}, "\1\xDB\10\xE8", IF_P6|IF_FPU}, + {I_FUCOMI, 2, {FPU0,FPUREG,0}, "\1\xDB\11\xE8", IF_P6|IF_FPU}, + {I_FUCOMIP, 1, {FPUREG,0,0}, "\1\xDF\10\xE8", IF_P6|IF_FPU}, + {I_FUCOMIP, 2, {FPU0,FPUREG,0}, "\1\xDF\11\xE8", IF_P6|IF_FPU}, + {I_FUCOMP, 1, {FPUREG,0,0}, "\1\xDD\10\xE8", IF_386|IF_FPU}, + {I_FUCOMP, 2, {FPU0,FPUREG,0}, "\1\xDD\11\xE8", IF_386|IF_FPU}, + {I_FUCOMPP, 0, {0,0,0}, "\2\xDA\xE9", IF_386|IF_FPU}, + {I_FXAM, 0, {0,0,0}, "\2\xD9\xE5", IF_8086|IF_FPU}, + {I_FXCH, 0, {0,0,0}, "\2\xD9\xC9", IF_8086|IF_FPU}, + {I_FXCH, 1, {FPUREG,0,0}, "\1\xD9\10\xC8", IF_8086|IF_FPU}, + {I_FXCH, 2, {FPUREG,FPU0,0}, "\1\xD9\10\xC8", IF_8086|IF_FPU}, + {I_FXCH, 2, {FPU0,FPUREG,0}, "\1\xD9\11\xC8", IF_8086|IF_FPU}, + {I_FXTRACT, 0, {0,0,0}, "\2\xD9\xF4", IF_8086|IF_FPU}, + {I_FYL2X, 0, {0,0,0}, "\2\xD9\xF1", IF_8086|IF_FPU}, + {I_FYL2XP1, 0, {0,0,0}, "\2\xD9\xF9", IF_8086|IF_FPU}, + {I_HLT, 0, {0,0,0}, "\1\xF4", IF_8086|IF_PRIV}, + {I_IDIV, 1, {REGMEM|BITS8,0,0}, "\300\1\xF6\207", IF_8086}, + {I_IDIV, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xF7\207", IF_8086}, + {I_IDIV, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xF7\207", IF_386}, + {I_IMUL, 1, {REGMEM|BITS8,0,0}, "\300\1\xF6\205", IF_8086}, + {I_IMUL, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xF7\205", IF_8086}, + {I_IMUL, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xF7\205", IF_386}, + {I_IMUL, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xAF\110", IF_386|IF_SM}, + {I_IMUL, 2, {REG16,REG16,0}, "\320\2\x0F\xAF\110", IF_386}, + {I_IMUL, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xAF\110", IF_386|IF_SM}, + {I_IMUL, 2, {REG32,REG32,0}, "\321\2\x0F\xAF\110", IF_386}, + {I_IMUL, 3, {REG16,MEMORY,IMMEDIATE|BITS8}, "\320\301\1\x6B\110\16", IF_186|IF_SM}, + {I_IMUL, 3, {REG16,MEMORY,IMMEDIATE|BITS16}, "\320\301\1\x69\110\32", IF_186|IF_SM}, + {I_IMUL, 3, {REG16,REG16,IMMEDIATE|BITS8}, "\320\1\x6B\110\16", IF_186}, + {I_IMUL, 3, {REG16,REG16,IMMEDIATE|BITS16}, "\320\1\x69\110\32", IF_186}, + {I_IMUL, 3, {REG32,MEMORY,IMMEDIATE|BITS8}, "\321\301\1\x6B\110\16", IF_386|IF_SM}, + {I_IMUL, 3, {REG32,MEMORY,IMMEDIATE|BITS32}, "\321\301\1\x69\110\42", IF_386|IF_SM}, + {I_IMUL, 3, {REG32,REG32,IMMEDIATE|BITS8}, "\321\1\x6B\110\16", IF_386}, + {I_IMUL, 3, {REG32,REG32,IMMEDIATE|BITS32}, "\321\1\x69\110\42", IF_386}, + {I_IMUL, 2, {REG16,IMMEDIATE|BITS8,0}, "\320\1\x6B\100\15", IF_186}, + {I_IMUL, 2, {REG16,IMMEDIATE|BITS16,0}, "\320\1\x69\100\31", IF_186}, + {I_IMUL, 2, {REG32,IMMEDIATE|BITS8,0}, "\321\1\x6B\100\15", IF_386}, + {I_IMUL, 2, {REG32,IMMEDIATE|BITS32,0}, "\321\1\x69\100\41", IF_386}, + {I_IN, 2, {REG_AL,IMMEDIATE,0}, "\1\xE4\25", IF_8086|IF_SB}, + {I_IN, 2, {REG_AX,IMMEDIATE,0}, "\320\1\xE5\25", IF_8086|IF_SB}, + {I_IN, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\xE5\25", IF_386|IF_SB}, + {I_IN, 2, {REG_AL,REG_DX,0}, "\1\xEC", IF_8086}, + {I_IN, 2, {REG_AX,REG_DX,0}, "\320\1\xED", IF_8086}, + {I_IN, 2, {REG_EAX,REG_DX,0}, "\321\1\xED", IF_386}, + {I_INC, 1, {REG16,0,0}, "\320\10\x40", IF_8086}, + {I_INC, 1, {REG32,0,0}, "\321\10\x40", IF_386}, + {I_INC, 1, {REGMEM|BITS8,0,0}, "\300\1\xFE\200", IF_8086}, + {I_INC, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xFF\200", IF_8086}, + {I_INC, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xFF\200", IF_386}, + {I_INSB, 0, {0,0,0}, "\1\x6C", IF_186}, + {I_INSD, 0, {0,0,0}, "\321\1\x6D", IF_386}, + {I_INSW, 0, {0,0,0}, "\320\1\x6D", IF_186}, + {I_INT, 1, {IMMEDIATE,0,0}, "\1\xCD\24", IF_8086|IF_SB}, + {I_INT1, 0, {0,0,0}, "\1\xF1", IF_386}, + {I_INT3, 0, {0,0,0}, "\1\xCC", IF_8086}, + {I_INTO, 0, {0,0,0}, "\1\xCE", IF_8086}, + {I_INVD, 0, {0,0,0}, "\2\x0F\x08", IF_486|IF_PRIV}, + {I_INVLPG, 1, {MEMORY,0,0}, "\300\2\x0F\x01\207", IF_486|IF_PRIV}, + {I_IRET, 0, {0,0,0}, "\322\1\xCF", IF_8086}, + {I_IRETD, 0, {0,0,0}, "\321\1\xCF", IF_386}, + {I_IRETW, 0, {0,0,0}, "\320\1\xCF", IF_8086}, + {I_JCXZ, 1, {IMMEDIATE,0,0}, "\310\1\xE3\50", IF_8086}, + {I_JECXZ, 1, {IMMEDIATE,0,0}, "\311\1\xE3\50", IF_386}, + {I_JMP, 1, {IMMEDIATE|SHORT,0,0}, "\1\xEB\50", IF_8086}, + {I_JMP, 1, {IMMEDIATE,0,0}, "\322\1\xE9\64", IF_8086}, + {I_JMP, 1, {IMMEDIATE|BITS16,0,0}, "\320\1\xE9\64", IF_8086}, + {I_JMP, 1, {IMMEDIATE|BITS32,0,0}, "\321\1\xE9\64", IF_386}, + {I_JMP, 2, {IMMEDIATE|COLON,IMMEDIATE,0}, "\322\1\xEA\35\30", IF_8086}, + {I_JMP, 2, {IMMEDIATE|BITS16|COLON,IMMEDIATE,0}, "\320\1\xEA\31\30", IF_8086}, + {I_JMP, 2, {IMMEDIATE|COLON,IMMEDIATE|BITS16,0}, "\320\1\xEA\31\30", IF_8086}, + {I_JMP, 2, {IMMEDIATE|BITS32|COLON,IMMEDIATE,0}, "\321\1\xEA\41\30", IF_386}, + {I_JMP, 2, {IMMEDIATE|COLON,IMMEDIATE|BITS32,0}, "\321\1\xEA\41\30", IF_386}, + {I_JMP, 1, {MEMORY|FAR,0,0}, "\322\300\1\xFF\205", IF_8086}, + {I_JMP, 1, {MEMORY|BITS16|FAR,0,0}, "\320\300\1\xFF\205", IF_8086}, + {I_JMP, 1, {MEMORY|BITS32|FAR,0,0}, "\321\300\1\xFF\205", IF_386}, + {I_JMP, 1, {MEMORY|NEAR,0,0}, "\322\300\1\xFF\204", IF_8086}, + {I_JMP, 1, {MEMORY|BITS16|NEAR,0,0}, "\320\300\1\xFF\204", IF_8086}, + {I_JMP, 1, {MEMORY|BITS32|NEAR,0,0}, "\321\300\1\xFF\204", IF_386}, + {I_JMP, 1, {REG16,0,0}, "\320\300\1\xFF\204", IF_8086}, + {I_JMP, 1, {REG32,0,0}, "\321\300\1\xFF\204", IF_386}, + {I_JMP, 1, {MEMORY,0,0}, "\322\300\1\xFF\204", IF_8086}, + {I_JMP, 1, {MEMORY|BITS16,0,0}, "\320\300\1\xFF\204", IF_8086}, + {I_JMP, 1, {MEMORY|BITS32,0,0}, "\321\300\1\xFF\204", IF_386}, + {I_JMPE, 1, {IMMEDIATE,0,0}, "\322\2\x0F\xB8\64", IF_IA64}, + {I_JMPE, 1, {IMMEDIATE|BITS16,0,0}, "\320\2\x0F\xB8\64", IF_IA64}, + {I_JMPE, 1, {IMMEDIATE|BITS32,0,0}, "\321\2\x0F\xB8\64", IF_IA64}, + {I_JMPE, 1, {REGMEM|BITS16,0,0}, "\320\2\x0F\x00\206", IF_IA64}, + {I_JMPE, 1, {REGMEM|BITS32,0,0}, "\321\2\x0F\x00\206", IF_IA64}, + {I_LAHF, 0, {0,0,0}, "\1\x9F", IF_8086}, + {I_LAR, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\x02\110", IF_286|IF_PROT|IF_SM}, + {I_LAR, 2, {REG16,REG16,0}, "\320\2\x0F\x02\110", IF_286|IF_PROT}, + {I_LAR, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\x02\110", IF_386|IF_PROT|IF_SM}, + {I_LAR, 2, {REG32,REG32,0}, "\321\2\x0F\x02\110", IF_386|IF_PROT}, + {I_LDS, 2, {REG16,MEMORY,0}, "\320\301\1\xC5\110", IF_8086}, + {I_LDS, 2, {REG32,MEMORY,0}, "\321\301\1\xC5\110", IF_386}, + {I_LEA, 2, {REG16,MEMORY,0}, "\320\301\1\x8D\110", IF_8086}, + {I_LEA, 2, {REG32,MEMORY,0}, "\321\301\1\x8D\110", IF_386}, + {I_LEAVE, 0, {0,0,0}, "\1\xC9", IF_186}, + {I_LES, 2, {REG16,MEMORY,0}, "\320\301\1\xC4\110", IF_8086}, + {I_LES, 2, {REG32,MEMORY,0}, "\321\301\1\xC4\110", IF_386}, + {I_LFS, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xB4\110", IF_386}, + {I_LFS, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xB4\110", IF_386}, + {I_LGDT, 1, {MEMORY,0,0}, "\300\2\x0F\x01\202", IF_286|IF_PRIV}, + {I_LGS, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xB5\110", IF_386}, + {I_LGS, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xB5\110", IF_386}, + {I_LIDT, 1, {MEMORY,0,0}, "\300\2\x0F\x01\203", IF_286|IF_PRIV}, + {I_LLDT, 1, {MEMORY,0,0}, "\300\1\x0F\17\202", IF_286|IF_PROT|IF_PRIV}, + {I_LLDT, 1, {MEMORY|BITS16,0,0}, "\300\1\x0F\17\202", IF_286|IF_PROT|IF_PRIV}, + {I_LLDT, 1, {REG16,0,0}, "\1\x0F\17\202", IF_286|IF_PROT|IF_PRIV}, + {I_LMSW, 1, {MEMORY,0,0}, "\300\2\x0F\x01\206", IF_286|IF_PRIV}, + {I_LMSW, 1, {MEMORY|BITS16,0,0}, "\300\2\x0F\x01\206", IF_286|IF_PRIV}, + {I_LMSW, 1, {REG16,0,0}, "\2\x0F\x01\206", IF_286|IF_PRIV}, + {I_LOADALL, 0, {0,0,0}, "\2\x0F\x07", IF_386|IF_UNDOC}, + {I_LOADALL286, 0, {0,0,0}, "\2\x0F\x05", IF_286|IF_UNDOC}, + {I_LODSB, 0, {0,0,0}, "\1\xAC", IF_8086}, + {I_LODSD, 0, {0,0,0}, "\321\1\xAD", IF_386}, + {I_LODSW, 0, {0,0,0}, "\320\1\xAD", IF_8086}, + {I_LOOP, 1, {IMMEDIATE,0,0}, "\312\1\xE2\50", IF_8086}, + {I_LOOP, 2, {IMMEDIATE,REG_CX,0}, "\310\1\xE2\50", IF_8086}, + {I_LOOP, 2, {IMMEDIATE,REG_ECX,0}, "\311\1\xE2\50", IF_386}, + {I_LOOPE, 1, {IMMEDIATE,0,0}, "\312\1\xE1\50", IF_8086}, + {I_LOOPE, 2, {IMMEDIATE,REG_CX,0}, "\310\1\xE1\50", IF_8086}, + {I_LOOPE, 2, {IMMEDIATE,REG_ECX,0}, "\311\1\xE1\50", IF_386}, + {I_LOOPNE, 1, {IMMEDIATE,0,0}, "\312\1\xE0\50", IF_8086}, + {I_LOOPNE, 2, {IMMEDIATE,REG_CX,0}, "\310\1\xE0\50", IF_8086}, + {I_LOOPNE, 2, {IMMEDIATE,REG_ECX,0}, "\311\1\xE0\50", IF_386}, + {I_LOOPNZ, 1, {IMMEDIATE,0,0}, "\312\1\xE0\50", IF_8086}, + {I_LOOPNZ, 2, {IMMEDIATE,REG_CX,0}, "\310\1\xE0\50", IF_8086}, + {I_LOOPNZ, 2, {IMMEDIATE,REG_ECX,0}, "\311\1\xE0\50", IF_386}, + {I_LOOPZ, 1, {IMMEDIATE,0,0}, "\312\1\xE1\50", IF_8086}, + {I_LOOPZ, 2, {IMMEDIATE,REG_CX,0}, "\310\1\xE1\50", IF_8086}, + {I_LOOPZ, 2, {IMMEDIATE,REG_ECX,0}, "\311\1\xE1\50", IF_386}, + {I_LSL, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\x03\110", IF_286|IF_PROT|IF_SM}, + {I_LSL, 2, {REG16,REG16,0}, "\320\2\x0F\x03\110", IF_286|IF_PROT}, + {I_LSL, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\x03\110", IF_386|IF_PROT|IF_SM}, + {I_LSL, 2, {REG32,REG32,0}, "\321\2\x0F\x03\110", IF_386|IF_PROT}, + {I_LSS, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xB2\110", IF_386}, + {I_LSS, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\xB2\110", IF_386}, + {I_LTR, 1, {MEMORY,0,0}, "\300\1\x0F\17\203", IF_286|IF_PROT|IF_PRIV}, + {I_LTR, 1, {MEMORY|BITS16,0,0}, "\300\1\x0F\17\203", IF_286|IF_PROT|IF_PRIV}, + {I_LTR, 1, {REG16,0,0}, "\1\x0F\17\203", IF_286|IF_PROT|IF_PRIV}, + {I_MONITOR, 0, {0,0,0}, "\3\x0F\x01\xC8", IF_PRESCOTT}, + {I_MOV, 2, {MEMORY,REG_SREG,0}, "\300\1\x8C\101", IF_8086|IF_SM}, + {I_MOV, 2, {REG16,REG_SREG,0}, "\320\1\x8C\101", IF_8086}, + {I_MOV, 2, {REG32,REG_SREG,0}, "\321\1\x8C\101", IF_386}, + {I_MOV, 2, {REG_SREG,MEMORY,0}, "\301\1\x8E\110", IF_8086|IF_SM}, + {I_MOV, 2, {REG_SREG,REG16,0}, "\1\x8E\110", IF_8086}, + {I_MOV, 2, {REG_SREG,REG32,0}, "\1\x8E\110", IF_386}, + {I_MOV, 2, {REG_AL,MEM_OFFS,0}, "\301\1\xA0\45", IF_8086|IF_SM}, + {I_MOV, 2, {REG_AX,MEM_OFFS,0}, "\301\320\1\xA1\45", IF_8086|IF_SM}, + {I_MOV, 2, {REG_EAX,MEM_OFFS,0}, "\301\321\1\xA1\45", IF_386|IF_SM}, + {I_MOV, 2, {MEM_OFFS,REG_AL,0}, "\300\1\xA2\44", IF_8086|IF_SM}, + {I_MOV, 2, {MEM_OFFS,REG_AX,0}, "\300\320\1\xA3\44", IF_8086|IF_SM}, + {I_MOV, 2, {MEM_OFFS,REG_EAX,0}, "\300\321\1\xA3\44", IF_386|IF_SM}, + {I_MOV, 2, {REG32,REG_CREG,0}, "\2\x0F\x20\101", IF_386|IF_PRIV}, + {I_MOV, 2, {REG32,REG_DREG,0}, "\2\x0F\x21\101", IF_386|IF_PRIV}, + {I_MOV, 2, {REG32,REG_TREG,0}, "\2\x0F\x24\101", IF_386|IF_PRIV}, + {I_MOV, 2, {REG_CREG,REG32,0}, "\2\x0F\x22\110", IF_386|IF_PRIV}, + {I_MOV, 2, {REG_DREG,REG32,0}, "\2\x0F\x23\110", IF_386|IF_PRIV}, + {I_MOV, 2, {REG_TREG,REG32,0}, "\2\x0F\x26\110", IF_386|IF_PRIV}, + {I_MOV, 2, {MEMORY,REG8,0}, "\300\1\x88\101", IF_8086|IF_SM}, + {I_MOV, 2, {REG8,REG8,0}, "\1\x88\101", IF_8086}, + {I_MOV, 2, {MEMORY,REG16,0}, "\320\300\1\x89\101", IF_8086|IF_SM}, + {I_MOV, 2, {REG16,REG16,0}, "\320\1\x89\101", IF_8086}, + {I_MOV, 2, {MEMORY,REG32,0}, "\321\300\1\x89\101", IF_386|IF_SM}, + {I_MOV, 2, {REG32,REG32,0}, "\321\1\x89\101", IF_386}, + {I_MOV, 2, {REG8,MEMORY,0}, "\301\1\x8A\110", IF_8086|IF_SM}, + {I_MOV, 2, {REG8,REG8,0}, "\1\x8A\110", IF_8086}, + {I_MOV, 2, {REG16,MEMORY,0}, "\320\301\1\x8B\110", IF_8086|IF_SM}, + {I_MOV, 2, {REG16,REG16,0}, "\320\1\x8B\110", IF_8086}, + {I_MOV, 2, {REG32,MEMORY,0}, "\321\301\1\x8B\110", IF_386|IF_SM}, + {I_MOV, 2, {REG32,REG32,0}, "\321\1\x8B\110", IF_386}, + {I_MOV, 2, {REG8,IMMEDIATE,0}, "\10\xB0\21", IF_8086|IF_SM}, + {I_MOV, 2, {REG16,IMMEDIATE,0}, "\320\10\xB8\31", IF_8086|IF_SM}, + {I_MOV, 2, {REG32,IMMEDIATE,0}, "\321\10\xB8\41", IF_386|IF_SM}, + {I_MOV, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC6\200\21", IF_8086|IF_SM}, + {I_MOV, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC7\200\31", IF_8086|IF_SM}, + {I_MOV, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC7\200\41", IF_386|IF_SM}, + {I_MOV, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\xC6\200\21", IF_8086|IF_SM}, + {I_MOV, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\1\xC7\200\31", IF_8086|IF_SM}, + {I_MOV, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\1\xC7\200\41", IF_386|IF_SM}, + {I_MOVD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x6E\110", IF_PENT|IF_MMX|IF_SD}, + {I_MOVD, 2, {MMXREG,REG32,0}, "\2\x0F\x6E\110", IF_PENT|IF_MMX}, + {I_MOVD, 2, {MEMORY,MMXREG,0}, "\300\2\x0F\x7E\101", IF_PENT|IF_MMX|IF_SD}, + {I_MOVD, 2, {REG32,MMXREG,0}, "\2\x0F\x7E\101", IF_PENT|IF_MMX}, + {I_MOVQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x6F\110", IF_PENT|IF_MMX|IF_SM}, + {I_MOVQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\x6F\110", IF_PENT|IF_MMX}, + {I_MOVQ, 2, {MEMORY,MMXREG,0}, "\300\2\x0F\x7F\101", IF_PENT|IF_MMX|IF_SM}, + {I_MOVQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\x7F\101", IF_PENT|IF_MMX}, + {I_MOVSB, 0, {0,0,0}, "\1\xA4", IF_8086}, + {I_MOVSD, 0, {0,0,0}, "\321\1\xA5", IF_386}, + {I_MOVSW, 0, {0,0,0}, "\320\1\xA5", IF_8086}, + {I_MOVSX, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xBE\110", IF_386|IF_SB}, + {I_MOVSX, 2, {REG16,REG8,0}, "\320\2\x0F\xBE\110", IF_386}, + {I_MOVSX, 2, {REG32,REGMEM|BITS8,0}, "\321\301\2\x0F\xBE\110", IF_386}, + {I_MOVSX, 2, {REG32,REGMEM|BITS16,0}, "\321\301\2\x0F\xBF\110", IF_386}, + {I_MOVZX, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\xB6\110", IF_386|IF_SB}, + {I_MOVZX, 2, {REG16,REG8,0}, "\320\2\x0F\xB6\110", IF_386}, + {I_MOVZX, 2, {REG32,REGMEM|BITS8,0}, "\321\301\2\x0F\xB6\110", IF_386}, + {I_MOVZX, 2, {REG32,REGMEM|BITS16,0}, "\321\301\2\x0F\xB7\110", IF_386}, + {I_MUL, 1, {REGMEM|BITS8,0,0}, "\300\1\xF6\204", IF_8086}, + {I_MUL, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xF7\204", IF_8086}, + {I_MUL, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xF7\204", IF_386}, + {I_MWAIT, 0, {0,0,0}, "\3\x0F\x01\xC9", IF_PRESCOTT}, + {I_NEG, 1, {REGMEM|BITS8,0,0}, "\300\1\xF6\203", IF_8086}, + {I_NEG, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xF7\203", IF_8086}, + {I_NEG, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xF7\203", IF_386}, + {I_NOP, 0, {0,0,0}, "\1\x90", IF_8086}, + {I_NOT, 1, {REGMEM|BITS8,0,0}, "\300\1\xF6\202", IF_8086}, + {I_NOT, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xF7\202", IF_8086}, + {I_NOT, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xF7\202", IF_386}, + {I_OR, 2, {MEMORY,REG8,0}, "\300\1\x08\101", IF_8086|IF_SM}, + {I_OR, 2, {REG8,REG8,0}, "\1\x08\101", IF_8086}, + {I_OR, 2, {MEMORY,REG16,0}, "\320\300\1\x09\101", IF_8086|IF_SM}, + {I_OR, 2, {REG16,REG16,0}, "\320\1\x09\101", IF_8086}, + {I_OR, 2, {MEMORY,REG32,0}, "\321\300\1\x09\101", IF_386|IF_SM}, + {I_OR, 2, {REG32,REG32,0}, "\321\1\x09\101", IF_386}, + {I_OR, 2, {REG8,MEMORY,0}, "\301\1\x0A\110", IF_8086|IF_SM}, + {I_OR, 2, {REG8,REG8,0}, "\1\x0A\110", IF_8086}, + {I_OR, 2, {REG16,MEMORY,0}, "\320\301\1\x0B\110", IF_8086|IF_SM}, + {I_OR, 2, {REG16,REG16,0}, "\320\1\x0B\110", IF_8086}, + {I_OR, 2, {REG32,MEMORY,0}, "\321\301\1\x0B\110", IF_386|IF_SM}, + {I_OR, 2, {REG32,REG32,0}, "\321\1\x0B\110", IF_386}, + {I_OR, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\201\15", IF_8086}, + {I_OR, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\201\15", IF_386}, + {I_OR, 2, {REG_AL,IMMEDIATE,0}, "\1\x0C\21", IF_8086|IF_SM}, + {I_OR, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x0D\31", IF_8086|IF_SM}, + {I_OR, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x0D\41", IF_386|IF_SM}, + {I_OR, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\201\21", IF_8086|IF_SM}, + {I_OR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\201\131", IF_8086|IF_SM}, + {I_OR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\201\141", IF_386|IF_SM}, + {I_OR, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\201\21", IF_8086|IF_SM}, + {I_OR, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\201\131", IF_8086|IF_SM}, + {I_OR, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\201\141", IF_386|IF_SM}, + {I_OUT, 2, {IMMEDIATE,REG_AL,0}, "\1\xE6\24", IF_8086|IF_SB}, + {I_OUT, 2, {IMMEDIATE,REG_AX,0}, "\320\1\xE7\24", IF_8086|IF_SB}, + {I_OUT, 2, {IMMEDIATE,REG_EAX,0}, "\321\1\xE7\24", IF_386|IF_SB}, + {I_OUT, 2, {REG_DX,REG_AL,0}, "\1\xEE", IF_8086}, + {I_OUT, 2, {REG_DX,REG_AX,0}, "\320\1\xEF", IF_8086}, + {I_OUT, 2, {REG_DX,REG_EAX,0}, "\321\1\xEF", IF_386}, + {I_OUTSB, 0, {0,0,0}, "\1\x6E", IF_186}, + {I_OUTSD, 0, {0,0,0}, "\321\1\x6F", IF_386}, + {I_OUTSW, 0, {0,0,0}, "\320\1\x6F", IF_186}, + {I_PACKSSDW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x6B\110", IF_PENT|IF_MMX|IF_SM}, + {I_PACKSSDW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x6B\110", IF_PENT|IF_MMX}, + {I_PACKSSWB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x63\110", IF_PENT|IF_MMX|IF_SM}, + {I_PACKSSWB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x63\110", IF_PENT|IF_MMX}, + {I_PACKUSWB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x67\110", IF_PENT|IF_MMX|IF_SM}, + {I_PACKUSWB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x67\110", IF_PENT|IF_MMX}, + {I_PADDB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xFC\110", IF_PENT|IF_MMX|IF_SM}, + {I_PADDB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xFC\110", IF_PENT|IF_MMX}, + {I_PADDD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xFE\110", IF_PENT|IF_MMX|IF_SM}, + {I_PADDD, 2, {MMXREG,MMXREG,0}, "\2\x0F\xFE\110", IF_PENT|IF_MMX}, + {I_PADDSB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xEC\110", IF_PENT|IF_MMX|IF_SM}, + {I_PADDSB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xEC\110", IF_PENT|IF_MMX}, + {I_PADDSIW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x51\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, + {I_PADDSIW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x51\110", IF_PENT|IF_MMX|IF_CYRIX}, + {I_PADDSW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xED\110", IF_PENT|IF_MMX|IF_SM}, + {I_PADDSW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xED\110", IF_PENT|IF_MMX}, + {I_PADDUSB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xDC\110", IF_PENT|IF_MMX|IF_SM}, + {I_PADDUSB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xDC\110", IF_PENT|IF_MMX}, + {I_PADDUSW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xDD\110", IF_PENT|IF_MMX|IF_SM}, + {I_PADDUSW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xDD\110", IF_PENT|IF_MMX}, + {I_PADDW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xFD\110", IF_PENT|IF_MMX|IF_SM}, + {I_PADDW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xFD\110", IF_PENT|IF_MMX}, + {I_PAND, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xDB\110", IF_PENT|IF_MMX|IF_SM}, + {I_PAND, 2, {MMXREG,MMXREG,0}, "\2\x0F\xDB\110", IF_PENT|IF_MMX}, + {I_PANDN, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xDF\110", IF_PENT|IF_MMX|IF_SM}, + {I_PANDN, 2, {MMXREG,MMXREG,0}, "\2\x0F\xDF\110", IF_PENT|IF_MMX}, + {I_PAVEB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x50\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, + {I_PAVEB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x50\110", IF_PENT|IF_MMX|IF_CYRIX}, + {I_PAVGUSB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xBF", IF_PENT|IF_3DNOW|IF_SM}, + {I_PAVGUSB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xBF", IF_PENT|IF_3DNOW}, + {I_PCMPEQB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x74\110", IF_PENT|IF_MMX|IF_SM}, + {I_PCMPEQB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x74\110", IF_PENT|IF_MMX}, + {I_PCMPEQD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x76\110", IF_PENT|IF_MMX|IF_SM}, + {I_PCMPEQD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x76\110", IF_PENT|IF_MMX}, + {I_PCMPEQW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x75\110", IF_PENT|IF_MMX|IF_SM}, + {I_PCMPEQW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x75\110", IF_PENT|IF_MMX}, + {I_PCMPGTB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x64\110", IF_PENT|IF_MMX|IF_SM}, + {I_PCMPGTB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x64\110", IF_PENT|IF_MMX}, + {I_PCMPGTD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x66\110", IF_PENT|IF_MMX|IF_SM}, + {I_PCMPGTD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x66\110", IF_PENT|IF_MMX}, + {I_PCMPGTW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x65\110", IF_PENT|IF_MMX|IF_SM}, + {I_PCMPGTW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x65\110", IF_PENT|IF_MMX}, + {I_PDISTIB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x54\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, + {I_PF2ID, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x1D", IF_PENT|IF_3DNOW|IF_SM}, + {I_PF2ID, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x1D", IF_PENT|IF_3DNOW}, + {I_PFACC, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xAE", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFACC, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xAE", IF_PENT|IF_3DNOW}, + {I_PFADD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x9E", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFADD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x9E", IF_PENT|IF_3DNOW}, + {I_PFCMPEQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xB0", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFCMPEQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xB0", IF_PENT|IF_3DNOW}, + {I_PFCMPGE, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x90", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFCMPGE, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x90", IF_PENT|IF_3DNOW}, + {I_PFCMPGT, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xA0", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFCMPGT, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xA0", IF_PENT|IF_3DNOW}, + {I_PFMAX, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xA4", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFMAX, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xA4", IF_PENT|IF_3DNOW}, + {I_PFMIN, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x94", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFMIN, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x94", IF_PENT|IF_3DNOW}, + {I_PFMUL, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xB4", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFMUL, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xB4", IF_PENT|IF_3DNOW}, + {I_PFRCP, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x96", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFRCP, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x96", IF_PENT|IF_3DNOW}, + {I_PFRCPIT1, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xA6", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFRCPIT1, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xA6", IF_PENT|IF_3DNOW}, + {I_PFRCPIT2, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xB6", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFRCPIT2, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xB6", IF_PENT|IF_3DNOW}, + {I_PFRSQIT1, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xA7", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFRSQIT1, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xA7", IF_PENT|IF_3DNOW}, + {I_PFRSQRT, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x97", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFRSQRT, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x97", IF_PENT|IF_3DNOW}, + {I_PFSUB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x9A", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFSUB, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x9A", IF_PENT|IF_3DNOW}, + {I_PFSUBR, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xAA", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFSUBR, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xAA", IF_PENT|IF_3DNOW}, + {I_PI2FD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x0D", IF_PENT|IF_3DNOW|IF_SM}, + {I_PI2FD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x0D", IF_PENT|IF_3DNOW}, + {I_PMACHRIW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x5E\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, + {I_PMADDWD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF5\110", IF_PENT|IF_MMX|IF_SM}, + {I_PMADDWD, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF5\110", IF_PENT|IF_MMX}, + {I_PMAGW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x52\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, + {I_PMAGW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x52\110", IF_PENT|IF_MMX|IF_CYRIX}, + {I_PMULHRIW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x5D\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, + {I_PMULHRIW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x5D\110", IF_PENT|IF_MMX|IF_CYRIX}, + {I_PMULHRWA, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\1\xB7", IF_PENT|IF_3DNOW|IF_SM}, + {I_PMULHRWA, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\1\xB7", IF_PENT|IF_3DNOW}, + {I_PMULHRWC, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x59\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, + {I_PMULHRWC, 2, {MMXREG,MMXREG,0}, "\2\x0F\x59\110", IF_PENT|IF_MMX|IF_CYRIX}, + {I_PMULHW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE5\110", IF_PENT|IF_MMX|IF_SM}, + {I_PMULHW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE5\110", IF_PENT|IF_MMX}, + {I_PMULLW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD5\110", IF_PENT|IF_MMX|IF_SM}, + {I_PMULLW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD5\110", IF_PENT|IF_MMX}, + {I_PMVGEZB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x5C\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, + {I_PMVLZB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x5B\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, + {I_PMVNZB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x5A\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, + {I_PMVZB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x58\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, + {I_POP, 1, {REG16,0,0}, "\320\10\x58", IF_8086}, + {I_POP, 1, {REG32,0,0}, "\321\10\x58", IF_386}, + {I_POP, 1, {REGMEM|BITS16,0,0}, "\320\300\1\x8F\200", IF_8086}, + {I_POP, 1, {REGMEM|BITS32,0,0}, "\321\300\1\x8F\200", IF_386}, + {I_POP, 1, {REG_DESS,0,0}, "\4", IF_8086}, + {I_POP, 1, {REG_FSGS,0,0}, "\1\x0F\5", IF_386}, + {I_POPA, 0, {0,0,0}, "\322\1\x61", IF_186}, + {I_POPAD, 0, {0,0,0}, "\321\1\x61", IF_386}, + {I_POPAW, 0, {0,0,0}, "\320\1\x61", IF_186}, + {I_POPF, 0, {0,0,0}, "\322\1\x9D", IF_8086}, + {I_POPFD, 0, {0,0,0}, "\321\1\x9D", IF_386}, + {I_POPFW, 0, {0,0,0}, "\320\1\x9D", IF_8086}, + {I_POR, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xEB\110", IF_PENT|IF_MMX|IF_SM}, + {I_POR, 2, {MMXREG,MMXREG,0}, "\2\x0F\xEB\110", IF_PENT|IF_MMX}, + {I_PREFETCH, 1, {MEMORY,0,0}, "\2\x0F\x0D\200", IF_PENT|IF_3DNOW|IF_SM}, + {I_PREFETCHW, 1, {MEMORY,0,0}, "\2\x0F\x0D\201", IF_PENT|IF_3DNOW|IF_SM}, + {I_PSLLD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF2\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSLLD, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF2\110", IF_PENT|IF_MMX}, + {I_PSLLD, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x72\206\25", IF_PENT|IF_MMX}, + {I_PSLLQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF3\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSLLQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF3\110", IF_PENT|IF_MMX}, + {I_PSLLQ, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x73\206\25", IF_PENT|IF_MMX}, + {I_PSLLW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF1\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSLLW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF1\110", IF_PENT|IF_MMX}, + {I_PSLLW, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x71\206\25", IF_PENT|IF_MMX}, + {I_PSRAD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE2\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSRAD, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE2\110", IF_PENT|IF_MMX}, + {I_PSRAD, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x72\204\25", IF_PENT|IF_MMX}, + {I_PSRAW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE1\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSRAW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE1\110", IF_PENT|IF_MMX}, + {I_PSRAW, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x71\204\25", IF_PENT|IF_MMX}, + {I_PSRLD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD2\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSRLD, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD2\110", IF_PENT|IF_MMX}, + {I_PSRLD, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x72\202\25", IF_PENT|IF_MMX}, + {I_PSRLQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD3\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSRLQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD3\110", IF_PENT|IF_MMX}, + {I_PSRLQ, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x73\202\25", IF_PENT|IF_MMX}, + {I_PSRLW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD1\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSRLW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD1\110", IF_PENT|IF_MMX}, + {I_PSRLW, 2, {MMXREG,IMMEDIATE,0}, "\2\x0F\x71\202\25", IF_PENT|IF_MMX}, + {I_PSUBB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF8\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSUBB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF8\110", IF_PENT|IF_MMX}, + {I_PSUBD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xFA\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSUBD, 2, {MMXREG,MMXREG,0}, "\2\x0F\xFA\110", IF_PENT|IF_MMX}, + {I_PSUBSB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE8\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSUBSB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE8\110", IF_PENT|IF_MMX}, + {I_PSUBSIW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x55\110", IF_PENT|IF_MMX|IF_SM|IF_CYRIX}, + {I_PSUBSIW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x55\110", IF_PENT|IF_MMX|IF_CYRIX}, + {I_PSUBSW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE9\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSUBSW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE9\110", IF_PENT|IF_MMX}, + {I_PSUBUSB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD8\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSUBUSB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD8\110", IF_PENT|IF_MMX}, + {I_PSUBUSW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD9\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSUBUSW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD9\110", IF_PENT|IF_MMX}, + {I_PSUBW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF9\110", IF_PENT|IF_MMX|IF_SM}, + {I_PSUBW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF9\110", IF_PENT|IF_MMX}, + {I_PUNPCKHBW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x68\110", IF_PENT|IF_MMX|IF_SM}, + {I_PUNPCKHBW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x68\110", IF_PENT|IF_MMX}, + {I_PUNPCKHDQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x6A\110", IF_PENT|IF_MMX|IF_SM}, + {I_PUNPCKHDQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\x6A\110", IF_PENT|IF_MMX}, + {I_PUNPCKHWD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x69\110", IF_PENT|IF_MMX|IF_SM}, + {I_PUNPCKHWD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x69\110", IF_PENT|IF_MMX}, + {I_PUNPCKLBW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x60\110", IF_PENT|IF_MMX|IF_SM}, + {I_PUNPCKLBW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x60\110", IF_PENT|IF_MMX}, + {I_PUNPCKLDQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x62\110", IF_PENT|IF_MMX|IF_SM}, + {I_PUNPCKLDQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\x62\110", IF_PENT|IF_MMX}, + {I_PUNPCKLWD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x61\110", IF_PENT|IF_MMX|IF_SM}, + {I_PUNPCKLWD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x61\110", IF_PENT|IF_MMX}, + {I_PUSH, 1, {REG16,0,0}, "\320\10\x50", IF_8086}, + {I_PUSH, 1, {REG32,0,0}, "\321\10\x50", IF_386}, + {I_PUSH, 1, {REGMEM|BITS16,0,0}, "\320\300\1\xFF\206", IF_8086}, + {I_PUSH, 1, {REGMEM|BITS32,0,0}, "\321\300\1\xFF\206", IF_386}, + {I_PUSH, 1, {REG_CS,0,0}, "\6", IF_8086}, + {I_PUSH, 1, {REG_DESS,0,0}, "\6", IF_8086}, + {I_PUSH, 1, {REG_FSGS,0,0}, "\1\x0F\7", IF_386}, + {I_PUSH, 1, {IMMEDIATE|BITS8,0,0}, "\1\x6A\14", IF_186}, + {I_PUSH, 1, {IMMEDIATE|BITS16,0,0}, "\320\133\1\x68\130", IF_186}, + {I_PUSH, 1, {IMMEDIATE|BITS32,0,0}, "\321\143\1\x68\140", IF_386}, + {I_PUSH, 1, {IMMEDIATE,0,0}, "\1\x68\34", IF_186}, + {I_PUSHA, 0, {0,0,0}, "\322\1\x60", IF_186}, + {I_PUSHAD, 0, {0,0,0}, "\321\1\x60", IF_386}, + {I_PUSHAW, 0, {0,0,0}, "\320\1\x60", IF_186}, + {I_PUSHF, 0, {0,0,0}, "\322\1\x9C", IF_8086}, + {I_PUSHFD, 0, {0,0,0}, "\321\1\x9C", IF_386}, + {I_PUSHFW, 0, {0,0,0}, "\320\1\x9C", IF_8086}, + {I_PXOR, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xEF\110", IF_PENT|IF_MMX|IF_SM}, + {I_PXOR, 2, {MMXREG,MMXREG,0}, "\2\x0F\xEF\110", IF_PENT|IF_MMX}, + {I_RCL, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\202", IF_8086}, + {I_RCL, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\202", IF_8086}, + {I_RCL, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\202\25", IF_186|IF_SB}, + {I_RCL, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\202", IF_8086}, + {I_RCL, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\202", IF_8086}, + {I_RCL, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\202\25", IF_186|IF_SB}, + {I_RCL, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\202", IF_386}, + {I_RCL, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\202", IF_386}, + {I_RCL, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\202\25", IF_386|IF_SB}, + {I_RCR, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\203", IF_8086}, + {I_RCR, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\203", IF_8086}, + {I_RCR, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\203\25", IF_186|IF_SB}, + {I_RCR, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\203", IF_8086}, + {I_RCR, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\203", IF_8086}, + {I_RCR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\203\25", IF_186|IF_SB}, + {I_RCR, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\203", IF_386}, + {I_RCR, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\203", IF_386}, + {I_RCR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\203\25", IF_386|IF_SB}, + {I_RDSHR, 1, {REGMEM|BITS32,0,0}, "\321\300\2\x0F\x36\200", IF_P6|IF_CYRIX|IF_SMM}, + {I_RDMSR, 0, {0,0,0}, "\2\x0F\x32", IF_PENT|IF_PRIV}, + {I_RDPMC, 0, {0,0,0}, "\2\x0F\x33", IF_P6}, + {I_RDTSC, 0, {0,0,0}, "\2\x0F\x31", IF_PENT}, + {I_RESB, 1, {IMMEDIATE,0,0}, "\340", IF_8086}, + {I_RET, 0, {0,0,0}, "\1\xC3", IF_8086}, + {I_RET, 1, {IMMEDIATE,0,0}, "\1\xC2\30", IF_8086|IF_SW}, + {I_RETF, 0, {0,0,0}, "\1\xCB", IF_8086}, + {I_RETF, 1, {IMMEDIATE,0,0}, "\1\xCA\30", IF_8086|IF_SW}, + {I_RETN, 0, {0,0,0}, "\1\xC3", IF_8086}, + {I_RETN, 1, {IMMEDIATE,0,0}, "\1\xC2\30", IF_8086|IF_SW}, + {I_ROL, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\200", IF_8086}, + {I_ROL, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\200", IF_8086}, + {I_ROL, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\200\25", IF_186|IF_SB}, + {I_ROL, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\200", IF_8086}, + {I_ROL, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\200", IF_8086}, + {I_ROL, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\200\25", IF_186|IF_SB}, + {I_ROL, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\200", IF_386}, + {I_ROL, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\200", IF_386}, + {I_ROL, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\200\25", IF_386|IF_SB}, + {I_ROR, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\201", IF_8086}, + {I_ROR, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\201", IF_8086}, + {I_ROR, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\201\25", IF_186|IF_SB}, + {I_ROR, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\201", IF_8086}, + {I_ROR, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\201", IF_8086}, + {I_ROR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\201\25", IF_186|IF_SB}, + {I_ROR, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\201", IF_386}, + {I_ROR, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\201", IF_386}, + {I_ROR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\201\25", IF_386|IF_SB}, + {I_RSDC, 2, {REG_SREG,MEMORY|BITS80,0}, "\301\2\x0F\x79\110", IF_486|IF_CYRIX|IF_SMM}, + {I_RSLDT, 1, {MEMORY|BITS80,0,0}, "\300\2\x0F\x7B\200", IF_486|IF_CYRIX|IF_SMM}, + {I_RSM, 0, {0,0,0}, "\2\x0F\xAA", IF_PENT|IF_SMM}, + {I_RSTS, 1, {MEMORY|BITS80,0,0}, "\300\2\x0F\x7D\200", IF_486|IF_CYRIX|IF_SMM}, + {I_SAHF, 0, {0,0,0}, "\1\x9E", IF_8086}, + {I_SALC, 0, {0,0,0}, "\1\xD6", IF_8086|IF_UNDOC}, + {I_SAR, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\207", IF_8086}, + {I_SAR, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\207", IF_8086}, + {I_SAR, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\207\25", IF_186|IF_SB}, + {I_SAR, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\207", IF_8086}, + {I_SAR, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\207", IF_8086}, + {I_SAR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\207\25", IF_186|IF_SB}, + {I_SAR, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\207", IF_386}, + {I_SAR, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\207", IF_386}, + {I_SAR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\207\25", IF_386|IF_SB}, + {I_SBB, 2, {MEMORY,REG8,0}, "\300\1\x18\101", IF_8086|IF_SM}, + {I_SBB, 2, {REG8,REG8,0}, "\1\x18\101", IF_8086}, + {I_SBB, 2, {MEMORY,REG16,0}, "\320\300\1\x19\101", IF_8086|IF_SM}, + {I_SBB, 2, {REG16,REG16,0}, "\320\1\x19\101", IF_8086}, + {I_SBB, 2, {MEMORY,REG32,0}, "\321\300\1\x19\101", IF_386|IF_SM}, + {I_SBB, 2, {REG32,REG32,0}, "\321\1\x19\101", IF_386}, + {I_SBB, 2, {REG8,MEMORY,0}, "\301\1\x1A\110", IF_8086|IF_SM}, + {I_SBB, 2, {REG8,REG8,0}, "\1\x1A\110", IF_8086}, + {I_SBB, 2, {REG16,MEMORY,0}, "\320\301\1\x1B\110", IF_8086|IF_SM}, + {I_SBB, 2, {REG16,REG16,0}, "\320\1\x1B\110", IF_8086}, + {I_SBB, 2, {REG32,MEMORY,0}, "\321\301\1\x1B\110", IF_386|IF_SM}, + {I_SBB, 2, {REG32,REG32,0}, "\321\1\x1B\110", IF_386}, + {I_SBB, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\203\15", IF_8086}, + {I_SBB, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\203\15", IF_386}, + {I_SBB, 2, {REG_AL,IMMEDIATE,0}, "\1\x1C\21", IF_8086|IF_SM}, + {I_SBB, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x1D\31", IF_8086|IF_SM}, + {I_SBB, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x1D\41", IF_386|IF_SM}, + {I_SBB, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\203\21", IF_8086|IF_SM}, + {I_SBB, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\203\131", IF_8086|IF_SM}, + {I_SBB, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\203\141", IF_386|IF_SM}, + {I_SBB, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\203\21", IF_8086|IF_SM}, + {I_SBB, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\203\131", IF_8086|IF_SM}, + {I_SBB, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\203\141", IF_386|IF_SM}, + {I_SCASB, 0, {0,0,0}, "\332\1\xAE", IF_8086}, + {I_SCASD, 0, {0,0,0}, "\332\321\1\xAF", IF_386}, + {I_SCASW, 0, {0,0,0}, "\332\320\1\xAF", IF_8086}, + {I_SGDT, 1, {MEMORY,0,0}, "\300\2\x0F\x01\200", IF_286}, + {I_SHL, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\204", IF_8086}, + {I_SHL, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\204", IF_8086}, + {I_SHL, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\204\25", IF_186|IF_SB}, + {I_SHL, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\204", IF_8086}, + {I_SHL, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\204", IF_8086}, + {I_SHL, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\204\25", IF_186|IF_SB}, + {I_SHL, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\204", IF_386}, + {I_SHL, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\204", IF_386}, + {I_SHL, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\204\25", IF_386|IF_SB}, + {I_SHLD, 3, {MEMORY,REG16,IMMEDIATE}, "\300\320\2\x0F\xA4\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, + {I_SHLD, 3, {REG16,REG16,IMMEDIATE}, "\320\2\x0F\xA4\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, + {I_SHLD, 3, {MEMORY,REG32,IMMEDIATE}, "\300\321\2\x0F\xA4\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, + {I_SHLD, 3, {REG32,REG32,IMMEDIATE}, "\321\2\x0F\xA4\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, + {I_SHLD, 3, {MEMORY,REG16,REG_CL}, "\300\320\2\x0F\xA5\101", IF_386|IF_SM}, + {I_SHLD, 3, {REG16,REG16,REG_CL}, "\320\2\x0F\xA5\101", IF_386}, + {I_SHLD, 3, {MEMORY,REG32,REG_CL}, "\300\321\2\x0F\xA5\101", IF_386|IF_SM}, + {I_SHLD, 3, {REG32,REG32,REG_CL}, "\321\2\x0F\xA5\101", IF_386}, + {I_SHR, 2, {REGMEM|BITS8,UNITY,0}, "\300\1\xD0\205", IF_8086}, + {I_SHR, 2, {REGMEM|BITS8,REG_CL,0}, "\300\1\xD2\205", IF_8086}, + {I_SHR, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xC0\205\25", IF_186|IF_SB}, + {I_SHR, 2, {REGMEM|BITS16,UNITY,0}, "\320\300\1\xD1\205", IF_8086}, + {I_SHR, 2, {REGMEM|BITS16,REG_CL,0}, "\320\300\1\xD3\205", IF_8086}, + {I_SHR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xC1\205\25", IF_186|IF_SB}, + {I_SHR, 2, {REGMEM|BITS32,UNITY,0}, "\321\300\1\xD1\205", IF_386}, + {I_SHR, 2, {REGMEM|BITS32,REG_CL,0}, "\321\300\1\xD3\205", IF_386}, + {I_SHR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xC1\205\25", IF_386|IF_SB}, + {I_SHRD, 3, {MEMORY,REG16,IMMEDIATE}, "\300\320\2\x0F\xAC\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, + {I_SHRD, 3, {REG16,REG16,IMMEDIATE}, "\320\2\x0F\xAC\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, + {I_SHRD, 3, {MEMORY,REG32,IMMEDIATE}, "\300\321\2\x0F\xAC\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, + {I_SHRD, 3, {REG32,REG32,IMMEDIATE}, "\321\2\x0F\xAC\101\26", IF_386|IF_SM2|IF_SB|IF_AR2}, + {I_SHRD, 3, {MEMORY,REG16,REG_CL}, "\300\320\2\x0F\xAD\101", IF_386|IF_SM}, + {I_SHRD, 3, {REG16,REG16,REG_CL}, "\320\2\x0F\xAD\101", IF_386}, + {I_SHRD, 3, {MEMORY,REG32,REG_CL}, "\300\321\2\x0F\xAD\101", IF_386|IF_SM}, + {I_SHRD, 3, {REG32,REG32,REG_CL}, "\321\2\x0F\xAD\101", IF_386}, + {I_SIDT, 1, {MEMORY,0,0}, "\300\2\x0F\x01\201", IF_286}, + {I_SLDT, 1, {MEMORY,0,0}, "\300\1\x0F\17\200", IF_286}, + {I_SLDT, 1, {MEMORY|BITS16,0,0}, "\300\1\x0F\17\200", IF_286}, + {I_SLDT, 1, {REG16,0,0}, "\320\1\x0F\17\200", IF_286}, + {I_SLDT, 1, {REG32,0,0}, "\321\1\x0F\17\200", IF_386}, + {I_SMI, 0, {0,0,0}, "\1\xF1", IF_386|IF_UNDOC}, + {I_SMINT, 0, {0,0,0}, "\2\x0F\x38", IF_P6|IF_CYRIX}, + {I_SMSW, 1, {MEMORY,0,0}, "\300\2\x0F\x01\204", IF_286}, + {I_SMSW, 1, {MEMORY|BITS16,0,0}, "\300\2\x0F\x01\204", IF_286}, + {I_SMSW, 1, {REG16,0,0}, "\320\2\x0F\x01\204", IF_286}, + {I_SMSW, 1, {REG32,0,0}, "\321\2\x0F\x01\204", IF_386}, + {I_STC, 0, {0,0,0}, "\1\xF9", IF_8086}, + {I_STD, 0, {0,0,0}, "\1\xFD", IF_8086}, + {I_STI, 0, {0,0,0}, "\1\xFB", IF_8086}, + {I_STOSB, 0, {0,0,0}, "\1\xAA", IF_8086}, + {I_STOSD, 0, {0,0,0}, "\321\1\xAB", IF_386}, + {I_STOSW, 0, {0,0,0}, "\320\1\xAB", IF_8086}, + {I_STR, 1, {MEMORY,0,0}, "\300\1\x0F\17\201", IF_286|IF_PROT}, + {I_STR, 1, {MEMORY|BITS16,0,0}, "\300\1\x0F\17\201", IF_286|IF_PROT}, + {I_STR, 1, {REG16,0,0}, "\320\1\x0F\17\201", IF_286|IF_PROT}, + {I_STR, 1, {REG32,0,0}, "\321\1\x0F\17\201", IF_386|IF_PROT}, + {I_SUB, 2, {MEMORY,REG8,0}, "\300\1\x28\101", IF_8086|IF_SM}, + {I_SUB, 2, {REG8,REG8,0}, "\1\x28\101", IF_8086}, + {I_SUB, 2, {MEMORY,REG16,0}, "\320\300\1\x29\101", IF_8086|IF_SM}, + {I_SUB, 2, {REG16,REG16,0}, "\320\1\x29\101", IF_8086}, + {I_SUB, 2, {MEMORY,REG32,0}, "\321\300\1\x29\101", IF_386|IF_SM}, + {I_SUB, 2, {REG32,REG32,0}, "\321\1\x29\101", IF_386}, + {I_SUB, 2, {REG8,MEMORY,0}, "\301\1\x2A\110", IF_8086|IF_SM}, + {I_SUB, 2, {REG8,REG8,0}, "\1\x2A\110", IF_8086}, + {I_SUB, 2, {REG16,MEMORY,0}, "\320\301\1\x2B\110", IF_8086|IF_SM}, + {I_SUB, 2, {REG16,REG16,0}, "\320\1\x2B\110", IF_8086}, + {I_SUB, 2, {REG32,MEMORY,0}, "\321\301\1\x2B\110", IF_386|IF_SM}, + {I_SUB, 2, {REG32,REG32,0}, "\321\1\x2B\110", IF_386}, + {I_SUB, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\205\15", IF_8086}, + {I_SUB, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\205\15", IF_386}, + {I_SUB, 2, {REG_AL,IMMEDIATE,0}, "\1\x2C\21", IF_8086|IF_SM}, + {I_SUB, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x2D\31", IF_8086|IF_SM}, + {I_SUB, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x2D\41", IF_386|IF_SM}, + {I_SUB, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\205\21", IF_8086|IF_SM}, + {I_SUB, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\205\131", IF_8086|IF_SM}, + {I_SUB, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\205\141", IF_386|IF_SM}, + {I_SUB, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\205\21", IF_8086|IF_SM}, + {I_SUB, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\205\131", IF_8086|IF_SM}, + {I_SUB, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\205\141", IF_386|IF_SM}, + {I_SVDC, 2, {MEMORY|BITS80,REG_SREG,0}, "\300\2\x0F\x78\101", IF_486|IF_CYRIX|IF_SMM}, + {I_SVLDT, 1, {MEMORY|BITS80,0,0}, "\300\2\x0F\x7A\200", IF_486|IF_CYRIX|IF_SMM}, + {I_SVTS, 1, {MEMORY|BITS80,0,0}, "\300\2\x0F\x7C\200", IF_486|IF_CYRIX|IF_SMM}, + {I_SYSCALL, 0, {0,0,0}, "\2\x0F\x05", IF_P6|IF_AMD}, + {I_SYSENTER, 0, {0,0,0}, "\2\x0F\x34", IF_P6}, + {I_SYSEXIT, 0, {0,0,0}, "\2\x0F\x35", IF_P6|IF_PRIV}, + {I_SYSRET, 0, {0,0,0}, "\2\x0F\x07", IF_P6|IF_PRIV|IF_AMD}, + {I_TEST, 2, {MEMORY,REG8,0}, "\300\1\x84\101", IF_8086|IF_SM}, + {I_TEST, 2, {REG8,REG8,0}, "\1\x84\101", IF_8086}, + {I_TEST, 2, {MEMORY,REG16,0}, "\320\300\1\x85\101", IF_8086|IF_SM}, + {I_TEST, 2, {REG16,REG16,0}, "\320\1\x85\101", IF_8086}, + {I_TEST, 2, {MEMORY,REG32,0}, "\321\300\1\x85\101", IF_386|IF_SM}, + {I_TEST, 2, {REG32,REG32,0}, "\321\1\x85\101", IF_386}, + {I_TEST, 2, {REG8,MEMORY,0}, "\301\1\x84\110", IF_8086|IF_SM}, + {I_TEST, 2, {REG16,MEMORY,0}, "\320\301\1\x85\110", IF_8086|IF_SM}, + {I_TEST, 2, {REG32,MEMORY,0}, "\321\301\1\x85\110", IF_386|IF_SM}, + {I_TEST, 2, {REG_AL,IMMEDIATE,0}, "\1\xA8\21", IF_8086|IF_SM}, + {I_TEST, 2, {REG_AX,IMMEDIATE,0}, "\320\1\xA9\31", IF_8086|IF_SM}, + {I_TEST, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\xA9\41", IF_386|IF_SM}, + {I_TEST, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\xF6\200\21", IF_8086|IF_SM}, + {I_TEST, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\1\xF7\200\31", IF_8086|IF_SM}, + {I_TEST, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\1\xF7\200\41", IF_386|IF_SM}, + {I_TEST, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\xF6\200\21", IF_8086|IF_SM}, + {I_TEST, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\1\xF7\200\31", IF_8086|IF_SM}, + {I_TEST, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\1\xF7\200\41", IF_386|IF_SM}, + {I_UD0, 0, {0,0,0}, "\2\x0F\xFF", IF_286|IF_UNDOC}, + {I_UD1, 0, {0,0,0}, "\2\x0F\xB9", IF_286|IF_UNDOC}, + {I_UD2, 0, {0,0,0}, "\2\x0F\x0B", IF_286}, + {I_UMOV, 2, {MEMORY,REG8,0}, "\300\2\x0F\x10\101", IF_386|IF_UNDOC|IF_SM}, + {I_UMOV, 2, {REG8,REG8,0}, "\2\x0F\x10\101", IF_386|IF_UNDOC}, + {I_UMOV, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\x11\101", IF_386|IF_UNDOC|IF_SM}, + {I_UMOV, 2, {REG16,REG16,0}, "\320\2\x0F\x11\101", IF_386|IF_UNDOC}, + {I_UMOV, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\x11\101", IF_386|IF_UNDOC|IF_SM}, + {I_UMOV, 2, {REG32,REG32,0}, "\321\2\x0F\x11\101", IF_386|IF_UNDOC}, + {I_UMOV, 2, {REG8,MEMORY,0}, "\301\2\x0F\x12\110", IF_386|IF_UNDOC|IF_SM}, + {I_UMOV, 2, {REG8,REG8,0}, "\2\x0F\x12\110", IF_386|IF_UNDOC}, + {I_UMOV, 2, {REG16,MEMORY,0}, "\320\301\2\x0F\x13\110", IF_386|IF_UNDOC|IF_SM}, + {I_UMOV, 2, {REG16,REG16,0}, "\320\2\x0F\x13\110", IF_386|IF_UNDOC}, + {I_UMOV, 2, {REG32,MEMORY,0}, "\321\301\2\x0F\x13\110", IF_386|IF_UNDOC|IF_SM}, + {I_UMOV, 2, {REG32,REG32,0}, "\321\2\x0F\x13\110", IF_386|IF_UNDOC}, + {I_VERR, 1, {MEMORY,0,0}, "\300\1\x0F\17\204", IF_286|IF_PROT}, + {I_VERR, 1, {MEMORY|BITS16,0,0}, "\300\1\x0F\17\204", IF_286|IF_PROT}, + {I_VERR, 1, {REG16,0,0}, "\1\x0F\17\204", IF_286|IF_PROT}, + {I_VERW, 1, {MEMORY,0,0}, "\300\1\x0F\17\205", IF_286|IF_PROT}, + {I_VERW, 1, {MEMORY|BITS16,0,0}, "\300\1\x0F\17\205", IF_286|IF_PROT}, + {I_VERW, 1, {REG16,0,0}, "\1\x0F\17\205", IF_286|IF_PROT}, + {I_WAIT, 0, {0,0,0}, "\1\x9B", IF_8086}, + {I_FWAIT, 0, {0,0,0}, "\1\x9B", IF_8086}, + {I_WBINVD, 0, {0,0,0}, "\2\x0F\x09", IF_486|IF_PRIV}, + {I_WRSHR, 1, {REGMEM|BITS32,0,0}, "\321\300\2\x0F\x37\200", IF_P6|IF_CYRIX|IF_SMM}, + {I_WRMSR, 0, {0,0,0}, "\2\x0F\x30", IF_PENT|IF_PRIV}, + {I_XADD, 2, {MEMORY,REG8,0}, "\300\2\x0F\xC0\101", IF_486|IF_SM}, + {I_XADD, 2, {REG8,REG8,0}, "\2\x0F\xC0\101", IF_486}, + {I_XADD, 2, {MEMORY,REG16,0}, "\320\300\2\x0F\xC1\101", IF_486|IF_SM}, + {I_XADD, 2, {REG16,REG16,0}, "\320\2\x0F\xC1\101", IF_486}, + {I_XADD, 2, {MEMORY,REG32,0}, "\321\300\2\x0F\xC1\101", IF_486|IF_SM}, + {I_XADD, 2, {REG32,REG32,0}, "\321\2\x0F\xC1\101", IF_486}, + {I_XCHG, 2, {REG_AX,REG16,0}, "\320\11\x90", IF_8086}, + {I_XCHG, 2, {REG_EAX,REG32,0}, "\321\11\x90", IF_386}, + {I_XCHG, 2, {REG16,REG_AX,0}, "\320\10\x90", IF_8086}, + {I_XCHG, 2, {REG32,REG_EAX,0}, "\321\10\x90", IF_386}, + {I_XCHG, 2, {REG8,MEMORY,0}, "\301\1\x86\110", IF_8086|IF_SM}, + {I_XCHG, 2, {REG8,REG8,0}, "\1\x86\110", IF_8086}, + {I_XCHG, 2, {REG16,MEMORY,0}, "\320\301\1\x87\110", IF_8086|IF_SM}, + {I_XCHG, 2, {REG16,REG16,0}, "\320\1\x87\110", IF_8086}, + {I_XCHG, 2, {REG32,MEMORY,0}, "\321\301\1\x87\110", IF_386|IF_SM}, + {I_XCHG, 2, {REG32,REG32,0}, "\321\1\x87\110", IF_386}, + {I_XCHG, 2, {MEMORY,REG8,0}, "\300\1\x86\101", IF_8086|IF_SM}, + {I_XCHG, 2, {REG8,REG8,0}, "\1\x86\101", IF_8086}, + {I_XCHG, 2, {MEMORY,REG16,0}, "\320\300\1\x87\101", IF_8086|IF_SM}, + {I_XCHG, 2, {REG16,REG16,0}, "\320\1\x87\101", IF_8086}, + {I_XCHG, 2, {MEMORY,REG32,0}, "\321\300\1\x87\101", IF_386|IF_SM}, + {I_XCHG, 2, {REG32,REG32,0}, "\321\1\x87\101", IF_386}, + {I_XLATB, 0, {0,0,0}, "\1\xD7", IF_8086}, + {I_XLAT, 0, {0,0,0}, "\1\xD7", IF_8086}, + {I_XOR, 2, {MEMORY,REG8,0}, "\300\1\x30\101", IF_8086|IF_SM}, + {I_XOR, 2, {REG8,REG8,0}, "\1\x30\101", IF_8086}, + {I_XOR, 2, {MEMORY,REG16,0}, "\320\300\1\x31\101", IF_8086|IF_SM}, + {I_XOR, 2, {REG16,REG16,0}, "\320\1\x31\101", IF_8086}, + {I_XOR, 2, {MEMORY,REG32,0}, "\321\300\1\x31\101", IF_386|IF_SM}, + {I_XOR, 2, {REG32,REG32,0}, "\321\1\x31\101", IF_386}, + {I_XOR, 2, {REG8,MEMORY,0}, "\301\1\x32\110", IF_8086|IF_SM}, + {I_XOR, 2, {REG8,REG8,0}, "\1\x32\110", IF_8086}, + {I_XOR, 2, {REG16,MEMORY,0}, "\320\301\1\x33\110", IF_8086|IF_SM}, + {I_XOR, 2, {REG16,REG16,0}, "\320\1\x33\110", IF_8086}, + {I_XOR, 2, {REG32,MEMORY,0}, "\321\301\1\x33\110", IF_386|IF_SM}, + {I_XOR, 2, {REG32,REG32,0}, "\321\1\x33\110", IF_386}, + {I_XOR, 2, {REGMEM|BITS16,IMMEDIATE|BITS8,0}, "\320\300\1\x83\206\15", IF_8086}, + {I_XOR, 2, {REGMEM|BITS32,IMMEDIATE|BITS8,0}, "\321\300\1\x83\206\15", IF_386}, + {I_XOR, 2, {REG_AL,IMMEDIATE,0}, "\1\x34\21", IF_8086|IF_SM}, + {I_XOR, 2, {REG_AX,IMMEDIATE,0}, "\320\1\x35\31", IF_8086|IF_SM}, + {I_XOR, 2, {REG_EAX,IMMEDIATE,0}, "\321\1\x35\41", IF_386|IF_SM}, + {I_XOR, 2, {REGMEM|BITS8,IMMEDIATE,0}, "\300\1\x80\206\21", IF_8086|IF_SM}, + {I_XOR, 2, {REGMEM|BITS16,IMMEDIATE,0}, "\320\300\134\1\x81\206\131", IF_8086|IF_SM}, + {I_XOR, 2, {REGMEM|BITS32,IMMEDIATE,0}, "\321\300\144\1\x81\206\141", IF_386|IF_SM}, + {I_XOR, 2, {MEMORY,IMMEDIATE|BITS8,0}, "\300\1\x80\206\21", IF_8086|IF_SM}, + {I_XOR, 2, {MEMORY,IMMEDIATE|BITS16,0}, "\320\300\134\1\x81\206\131", IF_8086|IF_SM}, + {I_XOR, 2, {MEMORY,IMMEDIATE|BITS32,0}, "\321\300\144\1\x81\206\141", IF_386|IF_SM}, + {I_XSTORE, 0, {0,0,0}, "\3\x0F\xA7\xC0", IF_P6|IF_CYRIX}, + {I_CMOVcc, 2, {REG16,MEMORY,0}, "\320\301\1\x0F\330\x40\110", IF_P6|IF_SM}, + {I_CMOVcc, 2, {REG16,REG16,0}, "\320\1\x0F\330\x40\110", IF_P6}, + {I_CMOVcc, 2, {REG32,MEMORY,0}, "\321\301\1\x0F\330\x40\110", IF_P6|IF_SM}, + {I_CMOVcc, 2, {REG32,REG32,0}, "\321\1\x0F\330\x40\110", IF_P6}, + {I_Jcc, 1, {IMMEDIATE|NEAR,0,0}, "\322\1\x0F\330\x80\64", IF_386}, + {I_Jcc, 1, {IMMEDIATE|BITS16|NEAR,0,0}, "\320\1\x0F\330\x80\64", IF_386}, + {I_Jcc, 1, {IMMEDIATE|BITS32|NEAR,0,0}, "\321\1\x0F\330\x80\64", IF_386}, + {I_Jcc, 1, {IMMEDIATE,0,0}, "\330\x70\50", IF_8086}, + {I_SETcc, 1, {MEMORY,0,0}, "\300\1\x0F\330\x90\200", IF_386|IF_SB}, + {I_SETcc, 1, {REG8,0,0}, "\300\1\x0F\330\x90\200", IF_386}, + {I_ADDPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x58\110", IF_KATMAI|IF_SSE}, + {I_ADDPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x58\110", IF_KATMAI|IF_SSE}, + {I_ADDSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x58\110", IF_KATMAI|IF_SSE}, + {I_ADDSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x58\110", IF_KATMAI|IF_SSE}, + {I_ANDNPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x55\110", IF_KATMAI|IF_SSE}, + {I_ANDNPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x55\110", IF_KATMAI|IF_SSE}, + {I_ANDPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x54\110", IF_KATMAI|IF_SSE}, + {I_ANDPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x54\110", IF_KATMAI|IF_SSE}, + {I_CMPEQPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x00", IF_KATMAI|IF_SSE}, + {I_CMPEQPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x00", IF_KATMAI|IF_SSE}, + {I_CMPEQSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x00", IF_KATMAI|IF_SSE}, + {I_CMPEQSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x00", IF_KATMAI|IF_SSE}, + {I_CMPLEPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x02", IF_KATMAI|IF_SSE}, + {I_CMPLEPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x02", IF_KATMAI|IF_SSE}, + {I_CMPLESS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x02", IF_KATMAI|IF_SSE}, + {I_CMPLESS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x02", IF_KATMAI|IF_SSE}, + {I_CMPLTPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x01", IF_KATMAI|IF_SSE}, + {I_CMPLTPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x01", IF_KATMAI|IF_SSE}, + {I_CMPLTSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x01", IF_KATMAI|IF_SSE}, + {I_CMPLTSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x01", IF_KATMAI|IF_SSE}, + {I_CMPNEQPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x04", IF_KATMAI|IF_SSE}, + {I_CMPNEQPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x04", IF_KATMAI|IF_SSE}, + {I_CMPNEQSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x04", IF_KATMAI|IF_SSE}, + {I_CMPNEQSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x04", IF_KATMAI|IF_SSE}, + {I_CMPNLEPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x06", IF_KATMAI|IF_SSE}, + {I_CMPNLEPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x06", IF_KATMAI|IF_SSE}, + {I_CMPNLESS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x06", IF_KATMAI|IF_SSE}, + {I_CMPNLESS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x06", IF_KATMAI|IF_SSE}, + {I_CMPNLTPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x05", IF_KATMAI|IF_SSE}, + {I_CMPNLTPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x05", IF_KATMAI|IF_SSE}, + {I_CMPNLTSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x05", IF_KATMAI|IF_SSE}, + {I_CMPNLTSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x05", IF_KATMAI|IF_SSE}, + {I_CMPORDPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x07", IF_KATMAI|IF_SSE}, + {I_CMPORDPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x07", IF_KATMAI|IF_SSE}, + {I_CMPORDSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x07", IF_KATMAI|IF_SSE}, + {I_CMPORDSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x07", IF_KATMAI|IF_SSE}, + {I_CMPUNORDPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\xC2\110\1\x03", IF_KATMAI|IF_SSE}, + {I_CMPUNORDPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\xC2\110\1\x03", IF_KATMAI|IF_SSE}, + {I_CMPUNORDSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xC2\110\1\x03", IF_KATMAI|IF_SSE}, + {I_CMPUNORDSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xC2\110\1\x03", IF_KATMAI|IF_SSE}, + {I_CMPPS, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\331\2\x0F\xC2\110\26", IF_KATMAI|IF_SSE|IF_SB|IF_AR2}, + {I_CMPPS, 3, {XMMREG,XMMREG,IMMEDIATE}, "\331\2\x0F\xC2\110\26", IF_KATMAI|IF_SSE|IF_SB|IF_AR2}, + {I_CMPSS, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\333\2\x0F\xC2\110\26", IF_KATMAI|IF_SSE|IF_SB|IF_AR2}, + {I_CMPSS, 3, {XMMREG,XMMREG,IMMEDIATE}, "\333\2\x0F\xC2\110\26", IF_KATMAI|IF_SSE|IF_SB|IF_AR2}, + {I_COMISS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x2F\110", IF_KATMAI|IF_SSE}, + {I_COMISS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x2F\110", IF_KATMAI|IF_SSE}, + {I_CVTPI2PS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x2A\110", IF_KATMAI|IF_SSE|IF_MMX}, + {I_CVTPI2PS, 2, {XMMREG,MMXREG,0}, "\331\2\x0F\x2A\110", IF_KATMAI|IF_SSE|IF_MMX}, + {I_CVTPS2PI, 2, {MMXREG,MEMORY,0}, "\301\331\2\x0F\x2D\110", IF_KATMAI|IF_SSE|IF_MMX}, + {I_CVTPS2PI, 2, {MMXREG,XMMREG,0}, "\331\2\x0F\x2D\110", IF_KATMAI|IF_SSE|IF_MMX}, + {I_CVTSI2SS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x2A\110", IF_KATMAI|IF_SSE|IF_SD|IF_AR1}, + {I_CVTSI2SS, 2, {XMMREG,REG32,0}, "\333\2\x0F\x2A\110", IF_KATMAI|IF_SSE}, + {I_CVTSS2SI, 2, {REG32,MEMORY,0}, "\301\333\2\x0F\x2D\110", IF_KATMAI|IF_SSE}, + {I_CVTSS2SI, 2, {REG32,XMMREG,0}, "\333\2\x0F\x2D\110", IF_KATMAI|IF_SSE}, + {I_CVTTPS2PI, 2, {MMXREG,MEMORY,0}, "\301\331\2\x0F\x2C\110", IF_KATMAI|IF_SSE|IF_MMX}, + {I_CVTTPS2PI, 2, {MMXREG,XMMREG,0}, "\331\2\x0F\x2C\110", IF_KATMAI|IF_SSE|IF_MMX}, + {I_CVTTSS2SI, 2, {REG32,MEMORY,0}, "\301\333\2\x0F\x2C\110", IF_KATMAI|IF_SSE}, + {I_CVTTSS2SI, 2, {REG32,XMMREG,0}, "\333\2\x0F\x2C\110", IF_KATMAI|IF_SSE}, + {I_DIVPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x5E\110", IF_KATMAI|IF_SSE}, + {I_DIVPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x5E\110", IF_KATMAI|IF_SSE}, + {I_DIVSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x5E\110", IF_KATMAI|IF_SSE}, + {I_DIVSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x5E\110", IF_KATMAI|IF_SSE}, + {I_LDMXCSR, 1, {MEMORY,0,0}, "\300\2\x0F\xAE\202", IF_KATMAI|IF_SSE|IF_SD}, + {I_MAXPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x5F\110", IF_KATMAI|IF_SSE}, + {I_MAXPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x5F\110", IF_KATMAI|IF_SSE}, + {I_MAXSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x5F\110", IF_KATMAI|IF_SSE}, + {I_MAXSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x5F\110", IF_KATMAI|IF_SSE}, + {I_MINPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x5D\110", IF_KATMAI|IF_SSE}, + {I_MINPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x5D\110", IF_KATMAI|IF_SSE}, + {I_MINSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x5D\110", IF_KATMAI|IF_SSE}, + {I_MINSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x5D\110", IF_KATMAI|IF_SSE}, + {I_MOVAPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x28\110", IF_KATMAI|IF_SSE}, + {I_MOVAPS, 2, {MEMORY,XMMREG,0}, "\300\2\x0F\x29\101", IF_KATMAI|IF_SSE}, + {I_MOVAPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x28\110", IF_KATMAI|IF_SSE}, + {I_MOVAPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x29\101", IF_KATMAI|IF_SSE}, + {I_MOVHPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x16\110", IF_KATMAI|IF_SSE}, + {I_MOVHPS, 2, {MEMORY,XMMREG,0}, "\300\2\x0F\x17\101", IF_KATMAI|IF_SSE}, + {I_MOVLHPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x16\110", IF_KATMAI|IF_SSE}, + {I_MOVLPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x12\110", IF_KATMAI|IF_SSE}, + {I_MOVLPS, 2, {MEMORY,XMMREG,0}, "\300\2\x0F\x13\101", IF_KATMAI|IF_SSE}, + {I_MOVHLPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x12\110", IF_KATMAI|IF_SSE}, + {I_MOVMSKPS, 2, {REG32,XMMREG,0}, "\2\x0F\x50\110", IF_KATMAI|IF_SSE}, + {I_MOVNTPS, 2, {MEMORY,XMMREG,0}, "\300\2\x0F\x2B\101", IF_KATMAI|IF_SSE}, + {I_MOVSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x10\110", IF_KATMAI|IF_SSE}, + {I_MOVSS, 2, {MEMORY,XMMREG,0}, "\300\333\2\x0F\x11\101", IF_KATMAI|IF_SSE}, + {I_MOVSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x10\110", IF_KATMAI|IF_SSE}, + {I_MOVSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x11\101", IF_KATMAI|IF_SSE}, + {I_MOVUPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x10\110", IF_KATMAI|IF_SSE}, + {I_MOVUPS, 2, {MEMORY,XMMREG,0}, "\300\331\2\x0F\x11\101", IF_KATMAI|IF_SSE}, + {I_MOVUPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x10\110", IF_KATMAI|IF_SSE}, + {I_MOVUPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x11\101", IF_KATMAI|IF_SSE}, + {I_MULPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x59\110", IF_KATMAI|IF_SSE}, + {I_MULPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x59\110", IF_KATMAI|IF_SSE}, + {I_MULSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x59\110", IF_KATMAI|IF_SSE}, + {I_MULSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x59\110", IF_KATMAI|IF_SSE}, + {I_ORPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x56\110", IF_KATMAI|IF_SSE}, + {I_ORPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x56\110", IF_KATMAI|IF_SSE}, + {I_RCPPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x53\110", IF_KATMAI|IF_SSE}, + {I_RCPPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x53\110", IF_KATMAI|IF_SSE}, + {I_RCPSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x53\110", IF_KATMAI|IF_SSE}, + {I_RCPSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x53\110", IF_KATMAI|IF_SSE}, + {I_RSQRTPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x52\110", IF_KATMAI|IF_SSE}, + {I_RSQRTPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x52\110", IF_KATMAI|IF_SSE}, + {I_RSQRTSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x52\110", IF_KATMAI|IF_SSE}, + {I_RSQRTSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x52\110", IF_KATMAI|IF_SSE}, + {I_SHUFPS, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\2\x0F\xC6\110\26", IF_KATMAI|IF_SSE|IF_SB|IF_AR2}, + {I_SHUFPS, 3, {XMMREG,XMMREG,IMMEDIATE}, "\2\x0F\xC6\110\26", IF_KATMAI|IF_SSE|IF_SB|IF_AR2}, + {I_SQRTPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x51\110", IF_KATMAI|IF_SSE}, + {I_SQRTPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x51\110", IF_KATMAI|IF_SSE}, + {I_SQRTSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x51\110", IF_KATMAI|IF_SSE}, + {I_SQRTSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x51\110", IF_KATMAI|IF_SSE}, + {I_STMXCSR, 1, {MEMORY,0,0}, "\300\2\x0F\xAE\203", IF_KATMAI|IF_SSE|IF_SD}, + {I_SUBPS, 2, {XMMREG,MEMORY,0}, "\301\331\2\x0F\x5C\110", IF_KATMAI|IF_SSE}, + {I_SUBPS, 2, {XMMREG,XMMREG,0}, "\331\2\x0F\x5C\110", IF_KATMAI|IF_SSE}, + {I_SUBSS, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x5C\110", IF_KATMAI|IF_SSE}, + {I_SUBSS, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x5C\110", IF_KATMAI|IF_SSE}, + {I_UCOMISS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x2E\110", IF_KATMAI|IF_SSE}, + {I_UCOMISS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x2E\110", IF_KATMAI|IF_SSE}, + {I_UNPCKHPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x15\110", IF_KATMAI|IF_SSE}, + {I_UNPCKHPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x15\110", IF_KATMAI|IF_SSE}, + {I_UNPCKLPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x14\110", IF_KATMAI|IF_SSE}, + {I_UNPCKLPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x14\110", IF_KATMAI|IF_SSE}, + {I_XORPS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x57\110", IF_KATMAI|IF_SSE}, + {I_XORPS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x57\110", IF_KATMAI|IF_SSE}, + {I_FXRSTOR, 1, {MEMORY,0,0}, "\300\2\x0F\xAE\201", IF_P6|IF_SSE|IF_FPU}, + {I_FXSAVE, 1, {MEMORY,0,0}, "\300\2\x0F\xAE\200", IF_P6|IF_SSE|IF_FPU}, + {I_PREFETCHNTA, 1, {MEMORY,0,0}, "\300\2\x0F\x18\200", IF_KATMAI}, + {I_PREFETCHT0, 1, {MEMORY,0,0}, "\300\2\x0F\x18\201", IF_KATMAI}, + {I_PREFETCHT1, 1, {MEMORY,0,0}, "\300\2\x0F\x18\202", IF_KATMAI}, + {I_PREFETCHT2, 1, {MEMORY,0,0}, "\300\2\x0F\x18\203", IF_KATMAI}, + {I_SFENCE, 0, {0,0,0}, "\3\x0F\xAE\xF8", IF_KATMAI}, + {I_MASKMOVQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF7\110", IF_KATMAI|IF_MMX}, + {I_MOVNTQ, 2, {MEMORY,MMXREG,0}, "\300\2\x0F\xE7\101", IF_KATMAI|IF_MMX|IF_SM}, + {I_PAVGB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE0\110", IF_KATMAI|IF_MMX}, + {I_PAVGB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE0\110", IF_KATMAI|IF_MMX|IF_SM}, + {I_PAVGW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE3\110", IF_KATMAI|IF_MMX}, + {I_PAVGW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE3\110", IF_KATMAI|IF_MMX|IF_SM}, + {I_PEXTRW, 3, {REG32,MMXREG,IMMEDIATE}, "\2\x0F\xC5\110\26", IF_KATMAI|IF_MMX|IF_SB|IF_AR2}, + {I_PINSRW, 3, {MMXREG,REG16,IMMEDIATE}, "\2\x0F\xC4\110\26", IF_KATMAI|IF_MMX|IF_SB|IF_AR2}, + {I_PINSRW, 3, {MMXREG,MEMORY,IMMEDIATE}, "\301\2\x0F\xC4\110\26", IF_KATMAI|IF_MMX|IF_SB|IF_AR2}, + {I_PMAXSW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xEE\110", IF_KATMAI|IF_MMX}, + {I_PMAXSW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xEE\110", IF_KATMAI|IF_MMX|IF_SM}, + {I_PMAXUB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xDE\110", IF_KATMAI|IF_MMX}, + {I_PMAXUB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xDE\110", IF_KATMAI|IF_MMX|IF_SM}, + {I_PMINSW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xEA\110", IF_KATMAI|IF_MMX}, + {I_PMINSW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xEA\110", IF_KATMAI|IF_MMX|IF_SM}, + {I_PMINUB, 2, {MMXREG,MMXREG,0}, "\2\x0F\xDA\110", IF_KATMAI|IF_MMX}, + {I_PMINUB, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xDA\110", IF_KATMAI|IF_MMX|IF_SM}, + {I_PMOVMSKB, 2, {REG32,MMXREG,0}, "\2\x0F\xD7\110", IF_KATMAI|IF_MMX}, + {I_PMULHUW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xE4\110", IF_KATMAI|IF_MMX}, + {I_PMULHUW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xE4\110", IF_KATMAI|IF_MMX|IF_SM}, + {I_PSADBW, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF6\110", IF_KATMAI|IF_MMX}, + {I_PSADBW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF6\110", IF_KATMAI|IF_MMX|IF_SM}, + {I_PSHUFW, 3, {MMXREG,MMXREG,IMMEDIATE}, "\2\x0F\x70\110\22", IF_KATMAI|IF_MMX|IF_SB|IF_AR2}, + {I_PSHUFW, 3, {MMXREG,MEMORY,IMMEDIATE}, "\301\2\x0F\x70\110\22", IF_KATMAI|IF_MMX|IF_SM2|IF_SB|IF_AR2}, + {I_PF2IW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x1C", IF_PENT|IF_3DNOW|IF_SM}, + {I_PF2IW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x1C", IF_PENT|IF_3DNOW}, + {I_PFNACC, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x8A", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFNACC, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x8A", IF_PENT|IF_3DNOW}, + {I_PFPNACC, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x8E", IF_PENT|IF_3DNOW|IF_SM}, + {I_PFPNACC, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x8E", IF_PENT|IF_3DNOW}, + {I_PI2FW, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\x0C", IF_PENT|IF_3DNOW|IF_SM}, + {I_PI2FW, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\x0C", IF_PENT|IF_3DNOW}, + {I_PSWAPD, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\x0F\110\01\xBB", IF_PENT|IF_3DNOW|IF_SM}, + {I_PSWAPD, 2, {MMXREG,MMXREG,0}, "\2\x0F\x0F\110\01\xBB", IF_PENT|IF_3DNOW}, + {I_MASKMOVDQU, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF7\110", IF_WILLAMETTE|IF_SSE2}, + {I_CLFLUSH, 1, {MEMORY,0,0}, "\300\2\x0F\xAE\207", IF_WILLAMETTE|IF_SSE2}, + {I_MOVNTDQ, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\xE7\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_MOVNTI, 2, {MEMORY,REG32,0}, "\300\2\x0F\xC3\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_MOVNTPD, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x2B\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PAUSE, 0, {0,0,0}, "\333\1\x90", IF_WILLAMETTE|IF_SSE2}, + {I_LFENCE, 0, {0,0,0}, "\3\x0F\xAE\xE8", IF_WILLAMETTE|IF_SSE2}, + {I_MFENCE, 0, {0,0,0}, "\3\x0F\xAE\xF0", IF_WILLAMETTE|IF_SSE2}, + {I_MOVD, 2, {XMMREG,REG32,0}, "\3\x66\x0F\x6E\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVD, 2, {REG32,XMMREG,0}, "\3\x66\x0F\x7E\101", IF_WILLAMETTE|IF_SSE2}, + {I_MOVD, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x7E\101", IF_WILLAMETTE|IF_SSE2}, + {I_MOVD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x6E\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVDQA, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x6F\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVDQA, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x7F\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_MOVDQA, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x6F\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_MOVDQA, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x7F\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVDQU, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x6F\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVDQU, 2, {MEMORY,XMMREG,0}, "\333\300\2\x0F\x7F\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_MOVDQU, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x6F\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_MOVDQU, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x7F\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVDQ2Q, 2, {MMXREG,XMMREG,0}, "\3\xF2\x0F\xD6\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVQ, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x7E\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD6\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVQ, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\xD6\101", IF_WILLAMETTE|IF_SSE2}, + {I_MOVQ, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x7E\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVQ2DQ, 2, {XMMREG,MMXREG,0}, "\333\2\x0F\xD6\110", IF_WILLAMETTE|IF_SSE2}, + {I_PACKSSWB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x63\110", IF_WILLAMETTE|IF_SSE2}, + {I_PACKSSWB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x63\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PACKSSDW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x6B\110", IF_WILLAMETTE|IF_SSE2}, + {I_PACKSSDW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x6B\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PACKUSWB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x67\110", IF_WILLAMETTE|IF_SSE2}, + {I_PACKUSWB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x67\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PADDB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xFC\110", IF_WILLAMETTE|IF_SSE2}, + {I_PADDB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xFC\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PADDW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xFD\110", IF_WILLAMETTE|IF_SSE2}, + {I_PADDW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xFD\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PADDD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xFE\110", IF_WILLAMETTE|IF_SSE2}, + {I_PADDD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xFE\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PADDQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\xD4\110", IF_WILLAMETTE|IF_SSE2}, + {I_PADDQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xD4\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PADDQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD4\110", IF_WILLAMETTE|IF_SSE2}, + {I_PADDQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD4\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PADDSB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xEC\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PADDSB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xEC\110", IF_WILLAMETTE|IF_SSE2}, + {I_PADDSW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xED\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PADDSW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xED\110", IF_WILLAMETTE|IF_SSE2}, + {I_PADDUSB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xDC\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PADDUSB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xDC\110", IF_WILLAMETTE|IF_SSE2}, + {I_PADDUSW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xDD\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PADDUSW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xDD\110", IF_WILLAMETTE|IF_SSE2}, + {I_PAND, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xDB\110", IF_WILLAMETTE|IF_SSE2}, + {I_PAND, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xDB\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PANDN, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xDF\110", IF_WILLAMETTE|IF_SSE2}, + {I_PANDN, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xDF\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PAVGB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE0\110", IF_WILLAMETTE|IF_SSE2}, + {I_PAVGB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE0\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PAVGW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE3\110", IF_WILLAMETTE|IF_SSE2}, + {I_PAVGW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE3\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PCMPEQB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x74\110", IF_WILLAMETTE|IF_SSE2}, + {I_PCMPEQB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x74\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PCMPEQW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x75\110", IF_WILLAMETTE|IF_SSE2}, + {I_PCMPEQW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x75\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PCMPEQD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x76\110", IF_WILLAMETTE|IF_SSE2}, + {I_PCMPEQD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x76\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PCMPGTB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x64\110", IF_WILLAMETTE|IF_SSE2}, + {I_PCMPGTB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x64\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PCMPGTW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x65\110", IF_WILLAMETTE|IF_SSE2}, + {I_PCMPGTW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x65\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PCMPGTD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x66\110", IF_WILLAMETTE|IF_SSE2}, + {I_PCMPGTD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x66\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PEXTRW, 3, {REG32,XMMREG,IMMEDIATE}, "\3\x66\x0F\xC5\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, + {I_PINSRW, 3, {XMMREG,REG16,IMMEDIATE}, "\3\x66\x0F\xC4\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, + {I_PINSRW, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\3\x66\x0F\xC4\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, + {I_PMADDWD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF5\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PMADDWD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF5\110", IF_WILLAMETTE|IF_SSE2}, + {I_PMAXSW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xEE\110", IF_WILLAMETTE|IF_SSE2}, + {I_PMAXSW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xEE\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PMAXUB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xDE\110", IF_WILLAMETTE|IF_SSE2}, + {I_PMAXUB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xDE\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PMINSW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xEA\110", IF_WILLAMETTE|IF_SSE2}, + {I_PMINSW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xEA\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PMINUB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xDA\110", IF_WILLAMETTE|IF_SSE2}, + {I_PMINUB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xDA\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PMOVMSKB, 2, {REG32,XMMREG,0}, "\3\x66\x0F\xD7\110", IF_WILLAMETTE|IF_SSE2}, + {I_PMULHUW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE4\110", IF_WILLAMETTE|IF_SSE2}, + {I_PMULHUW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE4\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PMULHW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE5\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PMULHW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE5\110", IF_WILLAMETTE|IF_SSE2}, + {I_PMULLW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD5\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PMULLW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD5\110", IF_WILLAMETTE|IF_SSE2}, + {I_PMULUDQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\xF4\110", IF_WILLAMETTE|IF_SSE2}, + {I_PMULUDQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xF4\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PMULUDQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF4\110", IF_WILLAMETTE|IF_SSE2}, + {I_PMULUDQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF4\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_POR, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xEB\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_POR, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xEB\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSADBW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF6\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSADBW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF6\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSHUFD, 3, {XMMREG,XMMREG,IMMEDIATE}, "\3\x66\x0F\x70\110\22", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, + {I_PSHUFD, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\3\x66\x0F\x70\110\22", IF_WILLAMETTE|IF_SSE2|IF_SM2|IF_SB|IF_AR2}, + {I_PSHUFHW, 3, {XMMREG,XMMREG,IMMEDIATE}, "\333\2\x0F\x70\110\22", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, + {I_PSHUFHW, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\333\2\x0F\x70\110\22", IF_WILLAMETTE|IF_SSE2|IF_SM2|IF_SB|IF_AR2}, + {I_PSHUFLW, 3, {XMMREG,XMMREG,IMMEDIATE}, "\3\xF2\x0F\x70\110\22", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, + {I_PSHUFLW, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\3\xF2\x0F\x70\110\22", IF_WILLAMETTE|IF_SSE2|IF_SM2|IF_SB|IF_AR2}, + {I_PSLLDQ, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x73\207\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, + {I_PSLLW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF1\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSLLW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF1\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSLLW, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x71\206\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, + {I_PSLLD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF2\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSLLD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF2\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSLLD, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x72\206\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, + {I_PSLLQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF3\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSLLQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF3\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSLLQ, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x73\206\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, + {I_PSRAW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE1\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSRAW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE1\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSRAW, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x71\204\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, + {I_PSRAD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE2\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSRAD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE2\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSRAD, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x72\204\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, + {I_PSRLDQ, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x73\203\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, + {I_PSRLW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD1\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSRLW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD1\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSRLW, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x71\202\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, + {I_PSRLD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD2\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSRLD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD2\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSRLD, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x72\202\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, + {I_PSRLQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD3\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSRLQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD3\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSRLQ, 2, {XMMREG,IMMEDIATE,0}, "\3\x66\x0F\x73\202\25", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR1}, + {I_PSUBB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF8\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSUBB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF8\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSUBW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xF9\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSUBW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xF9\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSUBD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xFA\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSUBD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xFA\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSUBQ, 2, {MMXREG,MMXREG,0}, "\2\x0F\xFB\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSUBQ, 2, {MMXREG,MEMORY,0}, "\301\2\x0F\xFB\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSUBQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xFB\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSUBQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xFB\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSUBSB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE8\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSUBSB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE8\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSUBSW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE9\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSUBSW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE9\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSUBUSB, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD8\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSUBUSB, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD8\110", IF_WILLAMETTE|IF_SSE2}, + {I_PSUBUSW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD9\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PSUBUSW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD9\110", IF_WILLAMETTE|IF_SSE2}, + {I_PUNPCKHBW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x68\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PUNPCKHBW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x68\110", IF_WILLAMETTE|IF_SSE2}, + {I_PUNPCKHWD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x69\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PUNPCKHWD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x69\110", IF_WILLAMETTE|IF_SSE2}, + {I_PUNPCKHDQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x6A\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PUNPCKHDQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x6A\110", IF_WILLAMETTE|IF_SSE2}, + {I_PUNPCKHQDQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x6D\110", IF_WILLAMETTE|IF_SSE2}, + {I_PUNPCKHQDQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x6D\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PUNPCKLBW, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x60\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PUNPCKLBW, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x60\110", IF_WILLAMETTE|IF_SSE2}, + {I_PUNPCKLWD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x61\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PUNPCKLWD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x61\110", IF_WILLAMETTE|IF_SSE2}, + {I_PUNPCKLDQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x62\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PUNPCKLDQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x62\110", IF_WILLAMETTE|IF_SSE2}, + {I_PUNPCKLQDQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x6C\110", IF_WILLAMETTE|IF_SSE2}, + {I_PUNPCKLQDQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x6C\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PXOR, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xEF\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_PXOR, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xEF\110", IF_WILLAMETTE|IF_SSE2}, + {I_ADDPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\x58\110", IF_WILLAMETTE|IF_SSE2}, + {I_ADDPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\x58\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_ADDSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\x58\110", IF_WILLAMETTE|IF_SSE2}, + {I_ADDSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\x58\110", IF_WILLAMETTE|IF_SSE2}, + {I_ANDNPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\x55\110", IF_WILLAMETTE|IF_SSE2}, + {I_ANDNPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\x55\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_ANDPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\x54\110", IF_WILLAMETTE|IF_SSE2}, + {I_ANDPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\x54\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_CMPEQPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x00", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_CMPEQPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x00", IF_WILLAMETTE|IF_SSE2}, + {I_CMPEQSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x00", IF_WILLAMETTE|IF_SSE2}, + {I_CMPEQSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x00", IF_WILLAMETTE|IF_SSE2}, + {I_CMPLEPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x02", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_CMPLEPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x02", IF_WILLAMETTE|IF_SSE2}, + {I_CMPLESD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x02", IF_WILLAMETTE|IF_SSE2}, + {I_CMPLESD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x02", IF_WILLAMETTE|IF_SSE2}, + {I_CMPLTPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x01", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_CMPLTPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x01", IF_WILLAMETTE|IF_SSE2}, + {I_CMPLTSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x01", IF_WILLAMETTE|IF_SSE2}, + {I_CMPLTSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x01", IF_WILLAMETTE|IF_SSE2}, + {I_CMPNEQPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x04", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_CMPNEQPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x04", IF_WILLAMETTE|IF_SSE2}, + {I_CMPNEQSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x04", IF_WILLAMETTE|IF_SSE2}, + {I_CMPNEQSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x04", IF_WILLAMETTE|IF_SSE2}, + {I_CMPNLEPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x06", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_CMPNLEPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x06", IF_WILLAMETTE|IF_SSE2}, + {I_CMPNLESD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x06", IF_WILLAMETTE|IF_SSE2}, + {I_CMPNLESD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x06", IF_WILLAMETTE|IF_SSE2}, + {I_CMPNLTPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x05", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_CMPNLTPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x05", IF_WILLAMETTE|IF_SSE2}, + {I_CMPNLTSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x05", IF_WILLAMETTE|IF_SSE2}, + {I_CMPNLTSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x05", IF_WILLAMETTE|IF_SSE2}, + {I_CMPORDPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x07", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_CMPORDPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x07", IF_WILLAMETTE|IF_SSE2}, + {I_CMPORDSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x07", IF_WILLAMETTE|IF_SSE2}, + {I_CMPORDSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x07", IF_WILLAMETTE|IF_SSE2}, + {I_CMPUNORDPD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\xC2\110\1\x03", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_CMPUNORDPD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\xC2\110\1\x03", IF_WILLAMETTE|IF_SSE2}, + {I_CMPUNORDSD, 2, {XMMREG,MEMORY,0}, "\301\331\3\xF2\x0F\xC2\110\1\x03", IF_WILLAMETTE|IF_SSE2}, + {I_CMPUNORDSD, 2, {XMMREG,XMMREG,0}, "\331\3\xF2\x0F\xC2\110\1\x03", IF_WILLAMETTE|IF_SSE2}, + {I_CMPPD, 3, {XMMREG,XMMREG,IMMEDIATE}, "\331\3\x66\x0F\xC2\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, + {I_CMPPD, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\331\3\x66\x0F\xC2\110\26", IF_WILLAMETTE|IF_SSE2|IF_SM2|IF_SB|IF_AR2}, + {I_CMPSD, 3, {XMMREG,XMMREG,IMMEDIATE}, "\331\3\xF2\x0F\xC2\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, + {I_CMPSD, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\331\3\xF2\x0F\xC2\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, + {I_COMISD, 2, {XMMREG,XMMREG,0}, "\331\3\x66\x0F\x2F\110", IF_WILLAMETTE|IF_SSE2}, + {I_COMISD, 2, {XMMREG,MEMORY,0}, "\301\331\3\x66\x0F\x2F\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTDQ2PD, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\xE6\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTDQ2PD, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\xE6\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTDQ2PS, 2, {XMMREG,XMMREG,0}, "\2\x0F\x5B\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTDQ2PS, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x5B\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_CVTPD2DQ, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\xE6\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTPD2DQ, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\xE6\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_CVTPD2PI, 2, {MMXREG,XMMREG,0}, "\3\x66\x0F\x2D\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTPD2PI, 2, {MMXREG,MEMORY,0}, "\301\3\x66\x0F\x2D\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTPD2PS, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTPD2PS, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_CVTPI2PD, 2, {XMMREG,MMXREG,0}, "\3\x66\x0F\x2A\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTPI2PD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x2A\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTPS2DQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x5B\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTPS2DQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x5B\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_CVTPS2PD, 2, {XMMREG,XMMREG,0}, "\2\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTPS2PD, 2, {XMMREG,MEMORY,0}, "\301\2\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTSD2SI, 2, {REG32,XMMREG,0}, "\3\xF2\x0F\x2D\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTSD2SI, 2, {REG32,MEMORY,0}, "\301\3\xF2\x0F\x2D\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTSD2SS, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTSD2SS, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTSI2SD, 2, {XMMREG,REG32,0}, "\3\xF2\x0F\x2A\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTSI2SD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x2A\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTSS2SD, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTSS2SD, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x5A\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTTPD2PI, 2, {MMXREG,XMMREG,0}, "\3\x66\x0F\x2C\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTTPD2PI, 2, {MMXREG,MEMORY,0}, "\301\3\x66\x0F\x2C\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTTPD2DQ, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xE6\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTTPD2DQ, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xE6\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_CVTTPS2DQ, 2, {XMMREG,XMMREG,0}, "\333\2\x0F\x5B\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTTPS2DQ, 2, {XMMREG,MEMORY,0}, "\301\333\2\x0F\x5B\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_CVTTSD2SI, 2, {REG32,XMMREG,0}, "\3\xF2\x0F\x2C\110", IF_WILLAMETTE|IF_SSE2}, + {I_CVTTSD2SI, 2, {REG32,MEMORY,0}, "\301\3\xF2\x0F\x2C\110", IF_WILLAMETTE|IF_SSE2}, + {I_DIVPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x5E\110", IF_WILLAMETTE|IF_SSE2}, + {I_DIVPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x5E\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_DIVSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x5E\110", IF_WILLAMETTE|IF_SSE2}, + {I_DIVSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x5E\110", IF_WILLAMETTE|IF_SSE2}, + {I_MAXPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x5F\110", IF_WILLAMETTE|IF_SSE2}, + {I_MAXPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x5F\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_MAXSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x5F\110", IF_WILLAMETTE|IF_SSE2}, + {I_MAXSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x5F\110", IF_WILLAMETTE|IF_SSE2}, + {I_MINPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x5D\110", IF_WILLAMETTE|IF_SSE2}, + {I_MINPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x5D\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_MINSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x5D\110", IF_WILLAMETTE|IF_SSE2}, + {I_MINSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x5D\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVAPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x28\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVAPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x29\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVAPD, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x29\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_MOVAPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x28\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_MOVHPD, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x17\101", IF_WILLAMETTE|IF_SSE2}, + {I_MOVHPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x16\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVLPD, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x13\101", IF_WILLAMETTE|IF_SSE2}, + {I_MOVLPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x12\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVMSKPD, 2, {REG32,XMMREG,0}, "\3\x66\x0F\x50\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x10\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x11\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVSD, 2, {MEMORY,XMMREG,0}, "\300\3\xF2\x0F\x11\101", IF_WILLAMETTE|IF_SSE2}, + {I_MOVSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x10\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVUPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x10\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVUPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x11\110", IF_WILLAMETTE|IF_SSE2}, + {I_MOVUPD, 2, {MEMORY,XMMREG,0}, "\300\3\x66\x0F\x11\101", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_MOVUPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x10\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_MULPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x59\110", IF_WILLAMETTE|IF_SSE2}, + {I_MULPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x59\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_MULSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x59\110", IF_WILLAMETTE|IF_SSE2}, + {I_MULSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x59\110", IF_WILLAMETTE|IF_SSE2}, + {I_ORPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x56\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_ORPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x56\110", IF_WILLAMETTE|IF_SSE2}, + {I_SHUFPD, 3, {XMMREG,XMMREG,IMMEDIATE}, "\3\x66\x0F\xC6\110\26", IF_WILLAMETTE|IF_SSE2|IF_SB|IF_AR2}, + {I_SHUFPD, 3, {XMMREG,MEMORY,IMMEDIATE}, "\301\3\x66\x0F\xC6\110\26", IF_WILLAMETTE|IF_SSE2|IF_SM|IF_SB|IF_AR2}, + {I_SQRTPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x51\110", IF_WILLAMETTE|IF_SSE2}, + {I_SQRTPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x51\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_SQRTSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x51\110", IF_WILLAMETTE|IF_SSE2}, + {I_SQRTSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x51\110", IF_WILLAMETTE|IF_SSE2}, + {I_SUBPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x5C\110", IF_WILLAMETTE|IF_SSE2}, + {I_SUBPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x5C\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_SUBSD, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x5C\110", IF_WILLAMETTE|IF_SSE2}, + {I_SUBSD, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x5C\110", IF_WILLAMETTE|IF_SSE2}, + {I_UCOMISD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x2E\110", IF_WILLAMETTE|IF_SSE2}, + {I_UCOMISD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x2E\110", IF_WILLAMETTE|IF_SSE2}, + {I_UNPCKHPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x15\110", IF_WILLAMETTE|IF_SSE2}, + {I_UNPCKHPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x15\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_UNPCKLPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x14\110", IF_WILLAMETTE|IF_SSE2}, + {I_UNPCKLPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x14\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_XORPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x57\110", IF_WILLAMETTE|IF_SSE2}, + {I_XORPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x57\110", IF_WILLAMETTE|IF_SSE2|IF_SM}, + {I_ADDSUBPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\xD0\110", IF_PRESCOTT|IF_SSE3|IF_SM}, + {I_ADDSUBPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\xD0\110", IF_PRESCOTT|IF_SSE3}, + {I_ADDSUBPS, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\xD0\110", IF_PRESCOTT|IF_SSE3|IF_SM}, + {I_ADDSUBPS, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\xD0\110", IF_PRESCOTT|IF_SSE3}, + {I_HADDPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x7C\110", IF_PRESCOTT|IF_SSE3|IF_SM}, + {I_HADDPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x7C\110", IF_PRESCOTT|IF_SSE3}, + {I_HADDPS, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x7C\110", IF_PRESCOTT|IF_SSE3|IF_SM}, + {I_HADDPS, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x7C\110", IF_PRESCOTT|IF_SSE3}, + {I_HSUBPD, 2, {XMMREG,MEMORY,0}, "\301\3\x66\x0F\x7D\110", IF_PRESCOTT|IF_SSE3|IF_SM}, + {I_HSUBPD, 2, {XMMREG,XMMREG,0}, "\3\x66\x0F\x7D\110", IF_PRESCOTT|IF_SSE3}, + {I_HSUBPS, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x7D\110", IF_PRESCOTT|IF_SSE3|IF_SM}, + {I_HSUBPS, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x7D\110", IF_PRESCOTT|IF_SSE3}, + {I_LDDQU, 2, {XMMREG,MEMORY,0}, "\3\xF2\x0F\xF0\110", IF_PRESCOTT|IF_SSE3}, + {I_MOVDDUP, 2, {XMMREG,MEMORY,0}, "\301\3\xF2\x0F\x12\110", IF_PRESCOTT|IF_SSE3}, + {I_MOVDDUP, 2, {XMMREG,XMMREG,0}, "\3\xF2\x0F\x12\110", IF_PRESCOTT|IF_SSE3}, + {I_MOVSHDUP, 2, {XMMREG,MEMORY,0}, "\301\3\xF3\x0F\x16\110", IF_PRESCOTT|IF_SSE3}, + {I_MOVSHDUP, 2, {XMMREG,XMMREG,0}, "\3\xF3\x0F\x16\110", IF_PRESCOTT|IF_SSE3}, + {I_MOVSLDUP, 2, {XMMREG,MEMORY,0}, "\301\3\xF3\x0F\x12\110", IF_PRESCOTT|IF_SSE3}, + {I_MOVSLDUP, 2, {XMMREG,XMMREG,0}, "\3\xF3\x0F\x12\110", IF_PRESCOTT|IF_SSE3}, + ITEMPLATE_END +}; + +static struct itemplate *itable_00[] = { + instrux + 29, + instrux + 30, + NULL +}; + +static struct itemplate *itable_01[] = { + instrux + 31, + instrux + 32, + instrux + 33, + instrux + 34, + NULL +}; + +static struct itemplate *itable_02[] = { + instrux + 35, + instrux + 36, + NULL +}; + +static struct itemplate *itable_03[] = { + instrux + 37, + instrux + 38, + instrux + 39, + instrux + 40, + NULL +}; + +static struct itemplate *itable_04[] = { + instrux + 43, + NULL +}; + +static struct itemplate *itable_05[] = { + instrux + 44, + instrux + 45, + NULL +}; + +static struct itemplate *itable_06[] = { + instrux + 778, + instrux + 779, + NULL +}; + +static struct itemplate *itable_07[] = { + instrux + 710, + NULL +}; + +static struct itemplate *itable_08[] = { + instrux + 578, + instrux + 579, + NULL +}; + +static struct itemplate *itable_09[] = { + instrux + 580, + instrux + 581, + instrux + 582, + instrux + 583, + NULL +}; + +static struct itemplate *itable_0A[] = { + instrux + 584, + instrux + 585, + NULL +}; + +static struct itemplate *itable_0B[] = { + instrux + 586, + instrux + 587, + instrux + 588, + instrux + 589, + NULL +}; + +static struct itemplate *itable_0C[] = { + instrux + 592, + NULL +}; + +static struct itemplate *itable_0D[] = { + instrux + 593, + instrux + 594, + NULL +}; + +static struct itemplate *itable_0E[] = { + instrux + 778, + instrux + 779, + NULL +}; + +static struct itemplate *itable_0F[] = { + instrux + 79, + instrux + 80, + instrux + 81, + instrux + 82, + instrux + 83, + instrux + 84, + instrux + 85, + instrux + 86, + instrux + 87, + instrux + 88, + instrux + 89, + instrux + 90, + instrux + 91, + instrux + 92, + instrux + 93, + instrux + 94, + instrux + 95, + instrux + 96, + instrux + 97, + instrux + 98, + instrux + 99, + instrux + 100, + instrux + 101, + instrux + 102, + instrux + 103, + instrux + 104, + instrux + 105, + instrux + 106, + instrux + 107, + instrux + 108, + instrux + 109, + instrux + 110, + instrux + 111, + instrux + 139, + instrux + 167, + instrux + 168, + instrux + 169, + instrux + 170, + instrux + 171, + instrux + 172, + instrux + 173, + instrux + 174, + instrux + 175, + instrux + 176, + instrux + 177, + instrux + 178, + instrux + 179, + instrux + 180, + instrux + 193, + instrux + 261, + instrux + 389, + instrux + 390, + instrux + 391, + instrux + 392, + instrux + 423, + instrux + 424, + instrux + 450, + instrux + 451, + instrux + 452, + instrux + 453, + instrux + 454, + instrux + 456, + instrux + 457, + instrux + 458, + instrux + 459, + instrux + 467, + instrux + 468, + instrux + 469, + instrux + 470, + instrux + 471, + instrux + 472, + instrux + 473, + instrux + 474, + instrux + 475, + instrux + 476, + instrux + 477, + instrux + 478, + instrux + 479, + instrux + 480, + instrux + 499, + instrux + 500, + instrux + 501, + instrux + 502, + instrux + 503, + instrux + 504, + instrux + 505, + instrux + 506, + instrux + 507, + instrux + 508, + instrux + 521, + instrux + 522, + instrux + 523, + instrux + 524, + instrux + 525, + instrux + 526, + instrux + 548, + instrux + 549, + instrux + 550, + instrux + 551, + instrux + 552, + instrux + 553, + instrux + 554, + instrux + 555, + instrux + 559, + instrux + 560, + instrux + 561, + instrux + 562, + instrux + 563, + instrux + 564, + instrux + 565, + instrux + 566, + instrux + 570, + instrux + 610, + instrux + 611, + instrux + 612, + instrux + 613, + instrux + 614, + instrux + 615, + instrux + 616, + instrux + 617, + instrux + 618, + instrux + 619, + instrux + 620, + instrux + 621, + instrux + 622, + instrux + 623, + instrux + 624, + instrux + 625, + instrux + 626, + instrux + 627, + instrux + 628, + instrux + 629, + instrux + 630, + instrux + 631, + instrux + 632, + instrux + 633, + instrux + 634, + instrux + 635, + instrux + 636, + instrux + 637, + instrux + 638, + instrux + 639, + instrux + 640, + instrux + 641, + instrux + 642, + instrux + 643, + instrux + 644, + instrux + 645, + instrux + 646, + instrux + 647, + instrux + 648, + instrux + 649, + instrux + 650, + instrux + 651, + instrux + 652, + instrux + 653, + instrux + 654, + instrux + 655, + instrux + 656, + instrux + 657, + instrux + 658, + instrux + 659, + instrux + 660, + instrux + 661, + instrux + 662, + instrux + 663, + instrux + 664, + instrux + 665, + instrux + 666, + instrux + 667, + instrux + 668, + instrux + 669, + instrux + 670, + instrux + 671, + instrux + 672, + instrux + 673, + instrux + 674, + instrux + 675, + instrux + 676, + instrux + 677, + instrux + 678, + instrux + 679, + instrux + 680, + instrux + 681, + instrux + 682, + instrux + 683, + instrux + 684, + instrux + 685, + instrux + 686, + instrux + 687, + instrux + 688, + instrux + 689, + instrux + 690, + instrux + 691, + instrux + 692, + instrux + 693, + instrux + 694, + instrux + 695, + instrux + 696, + instrux + 697, + instrux + 698, + instrux + 699, + instrux + 700, + instrux + 701, + instrux + 702, + instrux + 703, + instrux + 704, + instrux + 705, + instrux + 711, + instrux + 718, + instrux + 719, + instrux + 720, + instrux + 721, + instrux + 722, + instrux + 723, + instrux + 724, + instrux + 725, + instrux + 726, + instrux + 727, + instrux + 728, + instrux + 729, + instrux + 730, + instrux + 731, + instrux + 732, + instrux + 733, + instrux + 734, + instrux + 735, + instrux + 736, + instrux + 737, + instrux + 738, + instrux + 739, + instrux + 740, + instrux + 741, + instrux + 742, + instrux + 743, + instrux + 744, + instrux + 745, + instrux + 746, + instrux + 747, + instrux + 748, + instrux + 749, + instrux + 750, + instrux + 751, + instrux + 752, + instrux + 753, + instrux + 754, + instrux + 755, + instrux + 756, + instrux + 757, + instrux + 758, + instrux + 759, + instrux + 760, + instrux + 761, + instrux + 762, + instrux + 763, + instrux + 764, + instrux + 765, + instrux + 766, + instrux + 767, + instrux + 768, + instrux + 769, + instrux + 770, + instrux + 771, + instrux + 772, + instrux + 773, + instrux + 780, + instrux + 791, + instrux + 792, + instrux + 811, + instrux + 812, + instrux + 813, + instrux + 814, + instrux + 840, + instrux + 841, + instrux + 842, + instrux + 843, + instrux + 881, + instrux + 891, + instrux + 892, + instrux + 893, + instrux + 894, + instrux + 895, + instrux + 896, + instrux + 897, + instrux + 898, + instrux + 908, + instrux + 909, + instrux + 910, + instrux + 911, + instrux + 912, + instrux + 913, + instrux + 914, + instrux + 915, + instrux + 916, + instrux + 917, + instrux + 918, + instrux + 919, + instrux + 920, + instrux + 922, + instrux + 923, + instrux + 924, + instrux + 925, + instrux + 926, + instrux + 933, + instrux + 934, + instrux + 935, + instrux + 936, + instrux + 960, + instrux + 961, + instrux + 962, + instrux + 963, + instrux + 964, + instrux + 965, + instrux + 966, + instrux + 985, + instrux + 986, + instrux + 987, + instrux + 988, + instrux + 989, + instrux + 990, + instrux + 991, + instrux + 992, + instrux + 993, + instrux + 994, + instrux + 995, + instrux + 996, + instrux + 997, + instrux + 998, + instrux + 999, + instrux + 1000, + instrux + 1001, + instrux + 1002, + instrux + 1003, + instrux + 1004, + instrux + 1005, + instrux + 1008, + instrux + 1009, + instrux + 1010, + instrux + 1011, + instrux + 1012, + instrux + 1013, + instrux + 1014, + instrux + 1015, + instrux + 1016, + instrux + 1058, + instrux + 1059, + instrux + 1060, + instrux + 1061, + instrux + 1062, + instrux + 1063, + instrux + 1064, + instrux + 1065, + instrux + 1067, + instrux + 1068, + instrux + 1069, + instrux + 1070, + instrux + 1071, + instrux + 1072, + instrux + 1073, + instrux + 1074, + instrux + 1075, + instrux + 1076, + instrux + 1077, + instrux + 1078, + instrux + 1079, + instrux + 1080, + instrux + 1081, + instrux + 1082, + instrux + 1083, + instrux + 1084, + instrux + 1085, + instrux + 1086, + instrux + 1087, + instrux + 1088, + instrux + 1089, + instrux + 1090, + instrux + 1091, + instrux + 1092, + instrux + 1093, + instrux + 1094, + instrux + 1095, + instrux + 1096, + instrux + 1097, + instrux + 1098, + instrux + 1099, + instrux + 1100, + instrux + 1101, + instrux + 1102, + instrux + 1103, + instrux + 1104, + instrux + 1105, + instrux + 1106, + instrux + 1107, + instrux + 1108, + instrux + 1109, + instrux + 1110, + instrux + 1111, + instrux + 1112, + instrux + 1113, + instrux + 1114, + instrux + 1115, + instrux + 1116, + instrux + 1117, + instrux + 1118, + instrux + 1119, + instrux + 1120, + instrux + 1121, + instrux + 1122, + instrux + 1123, + instrux + 1124, + instrux + 1125, + instrux + 1126, + instrux + 1127, + instrux + 1128, + instrux + 1129, + instrux + 1130, + instrux + 1131, + instrux + 1132, + instrux + 1133, + instrux + 1134, + instrux + 1135, + instrux + 1136, + instrux + 1137, + instrux + 1138, + instrux + 1139, + instrux + 1140, + instrux + 1141, + instrux + 1142, + instrux + 1143, + instrux + 1144, + instrux + 1145, + instrux + 1146, + instrux + 1147, + instrux + 1148, + instrux + 1149, + instrux + 1150, + instrux + 1151, + instrux + 1152, + instrux + 1153, + instrux + 1154, + instrux + 1155, + instrux + 1156, + instrux + 1157, + instrux + 1158, + instrux + 1159, + instrux + 1160, + instrux + 1161, + instrux + 1162, + instrux + 1163, + instrux + 1164, + instrux + 1165, + instrux + 1166, + instrux + 1167, + instrux + 1168, + instrux + 1169, + instrux + 1170, + instrux + 1171, + instrux + 1172, + instrux + 1173, + instrux + 1174, + instrux + 1175, + instrux + 1176, + instrux + 1177, + instrux + 1178, + instrux + 1179, + instrux + 1180, + instrux + 1181, + instrux + 1182, + instrux + 1183, + instrux + 1184, + instrux + 1185, + instrux + 1186, + instrux + 1187, + instrux + 1188, + instrux + 1189, + instrux + 1190, + instrux + 1191, + instrux + 1192, + instrux + 1193, + instrux + 1194, + instrux + 1195, + instrux + 1196, + instrux + 1197, + instrux + 1198, + instrux + 1199, + instrux + 1200, + instrux + 1201, + instrux + 1202, + instrux + 1203, + instrux + 1204, + instrux + 1205, + instrux + 1206, + instrux + 1207, + instrux + 1208, + instrux + 1209, + instrux + 1210, + instrux + 1211, + instrux + 1212, + instrux + 1213, + instrux + 1214, + instrux + 1215, + instrux + 1216, + instrux + 1217, + instrux + 1218, + instrux + 1219, + instrux + 1220, + instrux + 1221, + instrux + 1222, + instrux + 1223, + instrux + 1224, + instrux + 1225, + instrux + 1226, + instrux + 1227, + instrux + 1228, + instrux + 1229, + instrux + 1230, + instrux + 1231, + instrux + 1232, + instrux + 1233, + instrux + 1235, + instrux + 1237, + instrux + 1240, + instrux + 1241, + instrux + 1250, + instrux + 1251, + instrux + 1252, + instrux + 1253, + instrux + 1255, + instrux + 1258, + instrux + 1259, + instrux + 1272, + instrux + 1273, + instrux + 1324, + instrux + 1325, + instrux + 1334, + instrux + 1335, + instrux + 1370, + instrux + 1371, + instrux + 1446, + instrux + 1447, + instrux + 1448, + instrux + 1449, + instrux + 1460, + instrux + 1461, + instrux + 1468, + instrux + 1469, + instrux + 1474, + instrux + 1475, + NULL +}; + +static struct itemplate *itable_10[] = { + instrux + 6, + instrux + 7, + NULL +}; + +static struct itemplate *itable_11[] = { + instrux + 8, + instrux + 9, + instrux + 10, + instrux + 11, + NULL +}; + +static struct itemplate *itable_12[] = { + instrux + 12, + instrux + 13, + NULL +}; + +static struct itemplate *itable_13[] = { + instrux + 14, + instrux + 15, + instrux + 16, + instrux + 17, + NULL +}; + +static struct itemplate *itable_14[] = { + instrux + 20, + NULL +}; + +static struct itemplate *itable_15[] = { + instrux + 21, + instrux + 22, + NULL +}; + +static struct itemplate *itable_16[] = { + instrux + 778, + instrux + 779, + NULL +}; + +static struct itemplate *itable_17[] = { + instrux + 710, + NULL +}; + +static struct itemplate *itable_18[] = { + instrux + 855, + instrux + 856, + NULL +}; + +static struct itemplate *itable_19[] = { + instrux + 857, + instrux + 858, + instrux + 859, + instrux + 860, + NULL +}; + +static struct itemplate *itable_1A[] = { + instrux + 861, + instrux + 862, + NULL +}; + +static struct itemplate *itable_1B[] = { + instrux + 863, + instrux + 864, + instrux + 865, + instrux + 866, + NULL +}; + +static struct itemplate *itable_1C[] = { + instrux + 869, + NULL +}; + +static struct itemplate *itable_1D[] = { + instrux + 870, + instrux + 871, + NULL +}; + +static struct itemplate *itable_1E[] = { + instrux + 778, + instrux + 779, + NULL +}; + +static struct itemplate *itable_1F[] = { + instrux + 710, + NULL +}; + +static struct itemplate *itable_20[] = { + instrux + 52, + instrux + 53, + NULL +}; + +static struct itemplate *itable_21[] = { + instrux + 54, + instrux + 55, + instrux + 56, + instrux + 57, + NULL +}; + +static struct itemplate *itable_22[] = { + instrux + 58, + instrux + 59, + NULL +}; + +static struct itemplate *itable_23[] = { + instrux + 60, + instrux + 61, + instrux + 62, + instrux + 63, + NULL +}; + +static struct itemplate *itable_24[] = { + instrux + 66, + NULL +}; + +static struct itemplate *itable_25[] = { + instrux + 67, + instrux + 68, + NULL +}; + +static struct itemplate *itable_26[] = { + NULL +}; + +static struct itemplate *itable_27[] = { + instrux + 183, + NULL +}; + +static struct itemplate *itable_28[] = { + instrux + 937, + instrux + 938, + NULL +}; + +static struct itemplate *itable_29[] = { + instrux + 939, + instrux + 940, + instrux + 941, + instrux + 942, + NULL +}; + +static struct itemplate *itable_2A[] = { + instrux + 943, + instrux + 944, + NULL +}; + +static struct itemplate *itable_2B[] = { + instrux + 945, + instrux + 946, + instrux + 947, + instrux + 948, + NULL +}; + +static struct itemplate *itable_2C[] = { + instrux + 951, + NULL +}; + +static struct itemplate *itable_2D[] = { + instrux + 952, + instrux + 953, + NULL +}; + +static struct itemplate *itable_2E[] = { + NULL +}; + +static struct itemplate *itable_2F[] = { + instrux + 184, + NULL +}; + +static struct itemplate *itable_30[] = { + instrux + 1035, + instrux + 1036, + NULL +}; + +static struct itemplate *itable_31[] = { + instrux + 1037, + instrux + 1038, + instrux + 1039, + instrux + 1040, + NULL +}; + +static struct itemplate *itable_32[] = { + instrux + 1041, + instrux + 1042, + NULL +}; + +static struct itemplate *itable_33[] = { + instrux + 1043, + instrux + 1044, + instrux + 1045, + instrux + 1046, + NULL +}; + +static struct itemplate *itable_34[] = { + instrux + 1049, + NULL +}; + +static struct itemplate *itable_35[] = { + instrux + 1050, + instrux + 1051, + NULL +}; + +static struct itemplate *itable_36[] = { + NULL +}; + +static struct itemplate *itable_37[] = { + instrux + 0, + NULL +}; + +static struct itemplate *itable_38[] = { + instrux + 141, + instrux + 142, + NULL +}; + +static struct itemplate *itable_39[] = { + instrux + 143, + instrux + 144, + instrux + 145, + instrux + 146, + NULL +}; + +static struct itemplate *itable_3A[] = { + instrux + 147, + instrux + 148, + NULL +}; + +static struct itemplate *itable_3B[] = { + instrux + 149, + instrux + 150, + instrux + 151, + instrux + 152, + NULL +}; + +static struct itemplate *itable_3C[] = { + instrux + 155, + NULL +}; + +static struct itemplate *itable_3D[] = { + instrux + 156, + instrux + 157, + NULL +}; + +static struct itemplate *itable_3E[] = { + NULL +}; + +static struct itemplate *itable_3F[] = { + instrux + 5, + NULL +}; + +static struct itemplate *itable_40[] = { + instrux + 411, + instrux + 412, + NULL +}; + +static struct itemplate *itable_41[] = { + instrux + 411, + instrux + 412, + NULL +}; + +static struct itemplate *itable_42[] = { + instrux + 411, + instrux + 412, + NULL +}; + +static struct itemplate *itable_43[] = { + instrux + 411, + instrux + 412, + NULL +}; + +static struct itemplate *itable_44[] = { + instrux + 411, + instrux + 412, + NULL +}; + +static struct itemplate *itable_45[] = { + instrux + 411, + instrux + 412, + NULL +}; + +static struct itemplate *itable_46[] = { + instrux + 411, + instrux + 412, + NULL +}; + +static struct itemplate *itable_47[] = { + instrux + 411, + instrux + 412, + NULL +}; + +static struct itemplate *itable_48[] = { + instrux + 185, + instrux + 186, + NULL +}; + +static struct itemplate *itable_49[] = { + instrux + 185, + instrux + 186, + NULL +}; + +static struct itemplate *itable_4A[] = { + instrux + 185, + instrux + 186, + NULL +}; + +static struct itemplate *itable_4B[] = { + instrux + 185, + instrux + 186, + NULL +}; + +static struct itemplate *itable_4C[] = { + instrux + 185, + instrux + 186, + NULL +}; + +static struct itemplate *itable_4D[] = { + instrux + 185, + instrux + 186, + NULL +}; + +static struct itemplate *itable_4E[] = { + instrux + 185, + instrux + 186, + NULL +}; + +static struct itemplate *itable_4F[] = { + instrux + 185, + instrux + 186, + NULL +}; + +static struct itemplate *itable_50[] = { + instrux + 774, + instrux + 775, + NULL +}; + +static struct itemplate *itable_51[] = { + instrux + 774, + instrux + 775, + NULL +}; + +static struct itemplate *itable_52[] = { + instrux + 774, + instrux + 775, + NULL +}; + +static struct itemplate *itable_53[] = { + instrux + 774, + instrux + 775, + NULL +}; + +static struct itemplate *itable_54[] = { + instrux + 774, + instrux + 775, + NULL +}; + +static struct itemplate *itable_55[] = { + instrux + 774, + instrux + 775, + NULL +}; + +static struct itemplate *itable_56[] = { + instrux + 774, + instrux + 775, + NULL +}; + +static struct itemplate *itable_57[] = { + instrux + 774, + instrux + 775, + NULL +}; + +static struct itemplate *itable_58[] = { + instrux + 706, + instrux + 707, + NULL +}; + +static struct itemplate *itable_59[] = { + instrux + 706, + instrux + 707, + NULL +}; + +static struct itemplate *itable_5A[] = { + instrux + 706, + instrux + 707, + NULL +}; + +static struct itemplate *itable_5B[] = { + instrux + 706, + instrux + 707, + NULL +}; + +static struct itemplate *itable_5C[] = { + instrux + 706, + instrux + 707, + NULL +}; + +static struct itemplate *itable_5D[] = { + instrux + 706, + instrux + 707, + NULL +}; + +static struct itemplate *itable_5E[] = { + instrux + 706, + instrux + 707, + NULL +}; + +static struct itemplate *itable_5F[] = { + instrux + 706, + instrux + 707, + NULL +}; + +static struct itemplate *itable_60[] = { + instrux + 785, + instrux + 786, + instrux + 787, + NULL +}; + +static struct itemplate *itable_61[] = { + instrux + 712, + instrux + 713, + instrux + 714, + NULL +}; + +static struct itemplate *itable_62[] = { + instrux + 77, + instrux + 78, + NULL +}; + +static struct itemplate *itable_63[] = { + instrux + 75, + instrux + 76, + NULL +}; + +static struct itemplate *itable_64[] = { + NULL +}; + +static struct itemplate *itable_65[] = { + NULL +}; + +static struct itemplate *itable_66[] = { + instrux + 1234, + instrux + 1236, + instrux + 1238, + instrux + 1242, + instrux + 1243, + instrux + 1244, + instrux + 1245, + instrux + 1246, + instrux + 1247, + instrux + 1248, + instrux + 1249, + instrux + 1256, + instrux + 1257, + instrux + 1260, + instrux + 1261, + instrux + 1262, + instrux + 1263, + instrux + 1264, + instrux + 1265, + instrux + 1266, + instrux + 1267, + instrux + 1268, + instrux + 1269, + instrux + 1270, + instrux + 1271, + instrux + 1274, + instrux + 1275, + instrux + 1276, + instrux + 1277, + instrux + 1278, + instrux + 1279, + instrux + 1280, + instrux + 1281, + instrux + 1282, + instrux + 1283, + instrux + 1284, + instrux + 1285, + instrux + 1286, + instrux + 1287, + instrux + 1288, + instrux + 1289, + instrux + 1290, + instrux + 1291, + instrux + 1292, + instrux + 1293, + instrux + 1294, + instrux + 1295, + instrux + 1296, + instrux + 1297, + instrux + 1298, + instrux + 1299, + instrux + 1300, + instrux + 1301, + instrux + 1302, + instrux + 1303, + instrux + 1304, + instrux + 1305, + instrux + 1306, + instrux + 1307, + instrux + 1308, + instrux + 1309, + instrux + 1310, + instrux + 1311, + instrux + 1312, + instrux + 1313, + instrux + 1314, + instrux + 1315, + instrux + 1316, + instrux + 1317, + instrux + 1318, + instrux + 1319, + instrux + 1320, + instrux + 1321, + instrux + 1322, + instrux + 1323, + instrux + 1326, + instrux + 1327, + instrux + 1328, + instrux + 1329, + instrux + 1330, + instrux + 1331, + instrux + 1332, + instrux + 1333, + instrux + 1338, + instrux + 1339, + instrux + 1340, + instrux + 1341, + instrux + 1342, + instrux + 1343, + instrux + 1344, + instrux + 1345, + instrux + 1346, + instrux + 1347, + instrux + 1348, + instrux + 1349, + instrux + 1350, + instrux + 1351, + instrux + 1352, + instrux + 1353, + instrux + 1354, + instrux + 1355, + instrux + 1356, + instrux + 1357, + instrux + 1358, + instrux + 1359, + instrux + 1360, + instrux + 1361, + instrux + 1362, + instrux + 1363, + instrux + 1364, + instrux + 1365, + instrux + 1366, + instrux + 1367, + instrux + 1368, + instrux + 1369, + instrux + 1372, + instrux + 1373, + instrux + 1374, + instrux + 1375, + instrux + 1376, + instrux + 1377, + instrux + 1378, + instrux + 1379, + instrux + 1380, + instrux + 1381, + instrux + 1382, + instrux + 1383, + instrux + 1384, + instrux + 1385, + instrux + 1386, + instrux + 1387, + instrux + 1388, + instrux + 1389, + instrux + 1390, + instrux + 1391, + instrux + 1392, + instrux + 1393, + instrux + 1394, + instrux + 1395, + instrux + 1396, + instrux + 1397, + instrux + 1398, + instrux + 1399, + instrux + 1400, + instrux + 1401, + instrux + 1404, + instrux + 1405, + instrux + 1406, + instrux + 1407, + instrux + 1408, + instrux + 1409, + instrux + 1412, + instrux + 1413, + instrux + 1416, + instrux + 1417, + instrux + 1420, + instrux + 1421, + instrux + 1424, + instrux + 1425, + instrux + 1428, + instrux + 1429, + instrux + 1432, + instrux + 1433, + instrux + 1436, + instrux + 1437, + instrux + 1440, + instrux + 1441, + instrux + 1444, + instrux + 1445, + instrux + 1452, + instrux + 1453, + instrux + 1454, + instrux + 1455, + instrux + 1456, + instrux + 1457, + instrux + 1458, + instrux + 1459, + instrux + 1470, + instrux + 1471, + instrux + 1472, + instrux + 1473, + instrux + 1478, + instrux + 1479, + instrux + 1482, + instrux + 1483, + instrux + 1486, + instrux + 1487, + instrux + 1490, + instrux + 1491, + instrux + 1492, + instrux + 1493, + instrux + 1494, + instrux + 1495, + instrux + 1496, + instrux + 1497, + instrux + 1498, + instrux + 1503, + instrux + 1504, + instrux + 1505, + instrux + 1506, + instrux + 1507, + instrux + 1508, + instrux + 1511, + instrux + 1512, + instrux + 1513, + instrux + 1514, + instrux + 1515, + instrux + 1516, + instrux + 1519, + instrux + 1520, + instrux + 1523, + instrux + 1524, + instrux + 1525, + instrux + 1526, + instrux + 1527, + instrux + 1528, + instrux + 1529, + instrux + 1530, + instrux + 1531, + instrux + 1532, + instrux + 1535, + instrux + 1536, + instrux + 1539, + instrux + 1540, + NULL +}; + +static struct itemplate *itable_67[] = { + NULL +}; + +static struct itemplate *itable_68[] = { + instrux + 782, + instrux + 783, + instrux + 784, + NULL +}; + +static struct itemplate *itable_69[] = { + instrux + 394, + instrux + 396, + instrux + 398, + instrux + 400, + instrux + 402, + instrux + 404, + NULL +}; + +static struct itemplate *itable_6A[] = { + instrux + 781, + NULL +}; + +static struct itemplate *itable_6B[] = { + instrux + 393, + instrux + 395, + instrux + 397, + instrux + 399, + instrux + 401, + instrux + 403, + NULL +}; + +static struct itemplate *itable_6C[] = { + instrux + 416, + NULL +}; + +static struct itemplate *itable_6D[] = { + instrux + 417, + instrux + 418, + NULL +}; + +static struct itemplate *itable_6E[] = { + instrux + 607, + NULL +}; + +static struct itemplate *itable_6F[] = { + instrux + 608, + instrux + 609, + NULL +}; + +static struct itemplate *itable_70[] = { + instrux + 1066, + NULL +}; + +static struct itemplate *itable_71[] = { + instrux + 1066, + NULL +}; + +static struct itemplate *itable_72[] = { + instrux + 1066, + NULL +}; + +static struct itemplate *itable_73[] = { + instrux + 1066, + NULL +}; + +static struct itemplate *itable_74[] = { + instrux + 1066, + NULL +}; + +static struct itemplate *itable_75[] = { + instrux + 1066, + NULL +}; + +static struct itemplate *itable_76[] = { + instrux + 1066, + NULL +}; + +static struct itemplate *itable_77[] = { + instrux + 1066, + NULL +}; + +static struct itemplate *itable_78[] = { + instrux + 1066, + NULL +}; + +static struct itemplate *itable_79[] = { + instrux + 1066, + NULL +}; + +static struct itemplate *itable_7A[] = { + instrux + 1066, + NULL +}; + +static struct itemplate *itable_7B[] = { + instrux + 1066, + NULL +}; + +static struct itemplate *itable_7C[] = { + instrux + 1066, + NULL +}; + +static struct itemplate *itable_7D[] = { + instrux + 1066, + NULL +}; + +static struct itemplate *itable_7E[] = { + instrux + 1066, + NULL +}; + +static struct itemplate *itable_7F[] = { + instrux + 1066, + NULL +}; + +static struct itemplate *itable_80[] = { + instrux + 23, + instrux + 26, + instrux + 46, + instrux + 49, + instrux + 69, + instrux + 72, + instrux + 158, + instrux + 161, + instrux + 595, + instrux + 598, + instrux + 872, + instrux + 875, + instrux + 954, + instrux + 957, + instrux + 1052, + instrux + 1055, + NULL +}; + +static struct itemplate *itable_81[] = { + instrux + 24, + instrux + 25, + instrux + 27, + instrux + 28, + instrux + 47, + instrux + 48, + instrux + 50, + instrux + 51, + instrux + 70, + instrux + 71, + instrux + 73, + instrux + 74, + instrux + 159, + instrux + 160, + instrux + 162, + instrux + 163, + instrux + 596, + instrux + 597, + instrux + 599, + instrux + 600, + instrux + 873, + instrux + 874, + instrux + 876, + instrux + 877, + instrux + 955, + instrux + 956, + instrux + 958, + instrux + 959, + instrux + 1053, + instrux + 1054, + instrux + 1056, + instrux + 1057, + NULL +}; + +static struct itemplate *itable_82[] = { + NULL +}; + +static struct itemplate *itable_83[] = { + instrux + 18, + instrux + 19, + instrux + 41, + instrux + 42, + instrux + 64, + instrux + 65, + instrux + 153, + instrux + 154, + instrux + 590, + instrux + 591, + instrux + 867, + instrux + 868, + instrux + 949, + instrux + 950, + instrux + 1047, + instrux + 1048, + NULL +}; + +static struct itemplate *itable_84[] = { + instrux + 967, + instrux + 968, + instrux + 973, + NULL +}; + +static struct itemplate *itable_85[] = { + instrux + 969, + instrux + 970, + instrux + 971, + instrux + 972, + instrux + 974, + instrux + 975, + NULL +}; + +static struct itemplate *itable_86[] = { + instrux + 1021, + instrux + 1022, + instrux + 1027, + instrux + 1028, + NULL +}; + +static struct itemplate *itable_87[] = { + instrux + 1023, + instrux + 1024, + instrux + 1025, + instrux + 1026, + instrux + 1029, + instrux + 1030, + instrux + 1031, + instrux + 1032, + NULL +}; + +static struct itemplate *itable_88[] = { + instrux + 527, + instrux + 528, + NULL +}; + +static struct itemplate *itable_89[] = { + instrux + 529, + instrux + 530, + instrux + 531, + instrux + 532, + NULL +}; + +static struct itemplate *itable_8A[] = { + instrux + 533, + instrux + 534, + NULL +}; + +static struct itemplate *itable_8B[] = { + instrux + 535, + instrux + 536, + instrux + 537, + instrux + 538, + NULL +}; + +static struct itemplate *itable_8C[] = { + instrux + 509, + instrux + 510, + instrux + 511, + NULL +}; + +static struct itemplate *itable_8D[] = { + instrux + 462, + instrux + 463, + NULL +}; + +static struct itemplate *itable_8E[] = { + instrux + 512, + instrux + 513, + instrux + 514, + NULL +}; + +static struct itemplate *itable_8F[] = { + instrux + 708, + instrux + 709, + NULL +}; + +static struct itemplate *itable_90[] = { + instrux + 574, + instrux + 1017, + instrux + 1018, + instrux + 1019, + instrux + 1020, + instrux + 1239, + NULL +}; + +static struct itemplate *itable_91[] = { + instrux + 1017, + instrux + 1018, + instrux + 1019, + instrux + 1020, + NULL +}; + +static struct itemplate *itable_92[] = { + instrux + 1017, + instrux + 1018, + instrux + 1019, + instrux + 1020, + NULL +}; + +static struct itemplate *itable_93[] = { + instrux + 1017, + instrux + 1018, + instrux + 1019, + instrux + 1020, + NULL +}; + +static struct itemplate *itable_94[] = { + instrux + 1017, + instrux + 1018, + instrux + 1019, + instrux + 1020, + NULL +}; + +static struct itemplate *itable_95[] = { + instrux + 1017, + instrux + 1018, + instrux + 1019, + instrux + 1020, + NULL +}; + +static struct itemplate *itable_96[] = { + instrux + 1017, + instrux + 1018, + instrux + 1019, + instrux + 1020, + NULL +}; + +static struct itemplate *itable_97[] = { + instrux + 1017, + instrux + 1018, + instrux + 1019, + instrux + 1020, + NULL +}; + +static struct itemplate *itable_98[] = { + instrux + 134, + instrux + 182, + NULL +}; + +static struct itemplate *itable_99[] = { + instrux + 135, + instrux + 181, + NULL +}; + +static struct itemplate *itable_9A[] = { + instrux + 118, + instrux + 119, + instrux + 120, + instrux + 121, + instrux + 122, + NULL +}; + +static struct itemplate *itable_9B[] = { + instrux + 212, + instrux + 244, + instrux + 262, + instrux + 281, + instrux + 331, + instrux + 340, + instrux + 341, + instrux + 346, + instrux + 347, + instrux + 1006, + instrux + 1007, + NULL +}; + +static struct itemplate *itable_9C[] = { + instrux + 788, + instrux + 789, + instrux + 790, + NULL +}; + +static struct itemplate *itable_9D[] = { + instrux + 715, + instrux + 716, + instrux + 717, + NULL +}; + +static struct itemplate *itable_9E[] = { + instrux + 844, + NULL +}; + +static struct itemplate *itable_9F[] = { + instrux + 455, + NULL +}; + +static struct itemplate *itable_A0[] = { + instrux + 515, + NULL +}; + +static struct itemplate *itable_A1[] = { + instrux + 516, + instrux + 517, + NULL +}; + +static struct itemplate *itable_A2[] = { + instrux + 518, + NULL +}; + +static struct itemplate *itable_A3[] = { + instrux + 519, + instrux + 520, + NULL +}; + +static struct itemplate *itable_A4[] = { + instrux + 556, + NULL +}; + +static struct itemplate *itable_A5[] = { + instrux + 557, + instrux + 558, + NULL +}; + +static struct itemplate *itable_A6[] = { + instrux + 164, + NULL +}; + +static struct itemplate *itable_A7[] = { + instrux + 165, + instrux + 166, + NULL +}; + +static struct itemplate *itable_A8[] = { + instrux + 976, + NULL +}; + +static struct itemplate *itable_A9[] = { + instrux + 977, + instrux + 978, + NULL +}; + +static struct itemplate *itable_AA[] = { + instrux + 930, + NULL +}; + +static struct itemplate *itable_AB[] = { + instrux + 931, + instrux + 932, + NULL +}; + +static struct itemplate *itable_AC[] = { + instrux + 481, + NULL +}; + +static struct itemplate *itable_AD[] = { + instrux + 482, + instrux + 483, + NULL +}; + +static struct itemplate *itable_AE[] = { + instrux + 878, + NULL +}; + +static struct itemplate *itable_AF[] = { + instrux + 879, + instrux + 880, + NULL +}; + +static struct itemplate *itable_B0[] = { + instrux + 539, + NULL +}; + +static struct itemplate *itable_B1[] = { + instrux + 539, + NULL +}; + +static struct itemplate *itable_B2[] = { + instrux + 539, + NULL +}; + +static struct itemplate *itable_B3[] = { + instrux + 539, + NULL +}; + +static struct itemplate *itable_B4[] = { + instrux + 539, + NULL +}; + +static struct itemplate *itable_B5[] = { + instrux + 539, + NULL +}; + +static struct itemplate *itable_B6[] = { + instrux + 539, + NULL +}; + +static struct itemplate *itable_B7[] = { + instrux + 539, + NULL +}; + +static struct itemplate *itable_B8[] = { + instrux + 540, + instrux + 541, + NULL +}; + +static struct itemplate *itable_B9[] = { + instrux + 540, + instrux + 541, + NULL +}; + +static struct itemplate *itable_BA[] = { + instrux + 540, + instrux + 541, + NULL +}; + +static struct itemplate *itable_BB[] = { + instrux + 540, + instrux + 541, + NULL +}; + +static struct itemplate *itable_BC[] = { + instrux + 540, + instrux + 541, + NULL +}; + +static struct itemplate *itable_BD[] = { + instrux + 540, + instrux + 541, + NULL +}; + +static struct itemplate *itable_BE[] = { + instrux + 540, + instrux + 541, + NULL +}; + +static struct itemplate *itable_BF[] = { + instrux + 540, + instrux + 541, + NULL +}; + +static struct itemplate *itable_C0[] = { + instrux + 795, + instrux + 804, + instrux + 824, + instrux + 833, + instrux + 848, + instrux + 884, + instrux + 901, + NULL +}; + +static struct itemplate *itable_C1[] = { + instrux + 798, + instrux + 801, + instrux + 807, + instrux + 810, + instrux + 827, + instrux + 830, + instrux + 836, + instrux + 839, + instrux + 851, + instrux + 854, + instrux + 887, + instrux + 890, + instrux + 904, + instrux + 907, + NULL +}; + +static struct itemplate *itable_C2[] = { + instrux + 817, + instrux + 821, + NULL +}; + +static struct itemplate *itable_C3[] = { + instrux + 816, + instrux + 820, + NULL +}; + +static struct itemplate *itable_C4[] = { + instrux + 465, + instrux + 466, + NULL +}; + +static struct itemplate *itable_C5[] = { + instrux + 460, + instrux + 461, + NULL +}; + +static struct itemplate *itable_C6[] = { + instrux + 542, + instrux + 545, + NULL +}; + +static struct itemplate *itable_C7[] = { + instrux + 543, + instrux + 544, + instrux + 546, + instrux + 547, + NULL +}; + +static struct itemplate *itable_C8[] = { + instrux + 194, + NULL +}; + +static struct itemplate *itable_C9[] = { + instrux + 464, + NULL +}; + +static struct itemplate *itable_CA[] = { + instrux + 819, + NULL +}; + +static struct itemplate *itable_CB[] = { + instrux + 818, + NULL +}; + +static struct itemplate *itable_CC[] = { + instrux + 421, + NULL +}; + +static struct itemplate *itable_CD[] = { + instrux + 419, + NULL +}; + +static struct itemplate *itable_CE[] = { + instrux + 422, + NULL +}; + +static struct itemplate *itable_CF[] = { + instrux + 425, + instrux + 426, + instrux + 427, + NULL +}; + +static struct itemplate *itable_D0[] = { + instrux + 793, + instrux + 802, + instrux + 822, + instrux + 831, + instrux + 846, + instrux + 882, + instrux + 899, + NULL +}; + +static struct itemplate *itable_D1[] = { + instrux + 796, + instrux + 799, + instrux + 805, + instrux + 808, + instrux + 825, + instrux + 828, + instrux + 834, + instrux + 837, + instrux + 849, + instrux + 852, + instrux + 885, + instrux + 888, + instrux + 902, + instrux + 905, + NULL +}; + +static struct itemplate *itable_D2[] = { + instrux + 794, + instrux + 803, + instrux + 823, + instrux + 832, + instrux + 847, + instrux + 883, + instrux + 900, + NULL +}; + +static struct itemplate *itable_D3[] = { + instrux + 797, + instrux + 800, + instrux + 806, + instrux + 809, + instrux + 826, + instrux + 829, + instrux + 835, + instrux + 838, + instrux + 850, + instrux + 853, + instrux + 886, + instrux + 889, + instrux + 903, + instrux + 906, + NULL +}; + +static struct itemplate *itable_D4[] = { + instrux + 3, + instrux + 4, + NULL +}; + +static struct itemplate *itable_D5[] = { + instrux + 1, + instrux + 2, + NULL +}; + +static struct itemplate *itable_D6[] = { + instrux + 845, + NULL +}; + +static struct itemplate *itable_D7[] = { + instrux + 1033, + instrux + 1034, + NULL +}; + +static struct itemplate *itable_D8[] = { + instrux + 199, + instrux + 202, + instrux + 204, + instrux + 229, + instrux + 231, + instrux + 232, + instrux + 237, + instrux + 239, + instrux + 240, + instrux + 245, + instrux + 249, + instrux + 250, + instrux + 253, + instrux + 257, + instrux + 258, + instrux + 307, + instrux + 311, + instrux + 312, + instrux + 348, + instrux + 352, + instrux + 353, + instrux + 356, + instrux + 360, + instrux + 361, + NULL +}; + +static struct itemplate *itable_D9[] = { + instrux + 197, + instrux + 198, + instrux + 211, + instrux + 242, + instrux + 243, + instrux + 280, + instrux + 294, + instrux + 297, + instrux + 298, + instrux + 299, + instrux + 300, + instrux + 301, + instrux + 302, + instrux + 303, + instrux + 304, + instrux + 305, + instrux + 306, + instrux + 319, + instrux + 321, + instrux + 322, + instrux + 325, + instrux + 326, + instrux + 327, + instrux + 328, + instrux + 329, + instrux + 332, + instrux + 334, + instrux + 335, + instrux + 336, + instrux + 337, + instrux + 342, + instrux + 364, + instrux + 374, + instrux + 375, + instrux + 376, + instrux + 377, + instrux + 378, + instrux + 379, + instrux + 380, + instrux + 381, + NULL +}; + +static struct itemplate *itable_DA[] = { + instrux + 213, + instrux + 214, + instrux + 215, + instrux + 216, + instrux + 217, + instrux + 218, + instrux + 227, + instrux + 228, + instrux + 265, + instrux + 267, + instrux + 269, + instrux + 271, + instrux + 273, + instrux + 278, + instrux + 290, + instrux + 292, + instrux + 373, + NULL +}; + +static struct itemplate *itable_DB[] = { + instrux + 219, + instrux + 220, + instrux + 221, + instrux + 222, + instrux + 223, + instrux + 224, + instrux + 225, + instrux + 226, + instrux + 233, + instrux + 234, + instrux + 275, + instrux + 282, + instrux + 284, + instrux + 288, + instrux + 296, + instrux + 315, + instrux + 316, + instrux + 317, + instrux + 318, + instrux + 333, + instrux + 344, + instrux + 367, + instrux + 368, + NULL +}; + +static struct itemplate *itable_DC[] = { + instrux + 200, + instrux + 201, + instrux + 203, + instrux + 230, + instrux + 238, + instrux + 246, + instrux + 247, + instrux + 248, + instrux + 254, + instrux + 255, + instrux + 256, + instrux + 308, + instrux + 309, + instrux + 310, + instrux + 349, + instrux + 350, + instrux + 351, + instrux + 357, + instrux + 358, + instrux + 359, + NULL +}; + +static struct itemplate *itable_DD[] = { + instrux + 263, + instrux + 287, + instrux + 295, + instrux + 320, + instrux + 323, + instrux + 330, + instrux + 338, + instrux + 339, + instrux + 343, + instrux + 345, + instrux + 365, + instrux + 366, + instrux + 371, + instrux + 372, + NULL +}; + +static struct itemplate *itable_DE[] = { + instrux + 205, + instrux + 206, + instrux + 241, + instrux + 251, + instrux + 252, + instrux + 259, + instrux + 260, + instrux + 266, + instrux + 268, + instrux + 270, + instrux + 272, + instrux + 274, + instrux + 279, + instrux + 291, + instrux + 293, + instrux + 313, + instrux + 314, + instrux + 354, + instrux + 355, + instrux + 362, + instrux + 363, + NULL +}; + +static struct itemplate *itable_DF[] = { + instrux + 207, + instrux + 208, + instrux + 209, + instrux + 210, + instrux + 235, + instrux + 236, + instrux + 264, + instrux + 276, + instrux + 277, + instrux + 283, + instrux + 285, + instrux + 286, + instrux + 289, + instrux + 324, + instrux + 369, + instrux + 370, + NULL +}; + +static struct itemplate *itable_E0[] = { + instrux + 490, + instrux + 491, + instrux + 492, + instrux + 493, + instrux + 494, + instrux + 495, + NULL +}; + +static struct itemplate *itable_E1[] = { + instrux + 487, + instrux + 488, + instrux + 489, + instrux + 496, + instrux + 497, + instrux + 498, + NULL +}; + +static struct itemplate *itable_E2[] = { + instrux + 484, + instrux + 485, + instrux + 486, + NULL +}; + +static struct itemplate *itable_E3[] = { + instrux + 428, + instrux + 429, + NULL +}; + +static struct itemplate *itable_E4[] = { + instrux + 405, + NULL +}; + +static struct itemplate *itable_E5[] = { + instrux + 406, + instrux + 407, + NULL +}; + +static struct itemplate *itable_E6[] = { + instrux + 601, + NULL +}; + +static struct itemplate *itable_E7[] = { + instrux + 602, + instrux + 603, + NULL +}; + +static struct itemplate *itable_E8[] = { + instrux + 112, + instrux + 113, + instrux + 114, + instrux + 115, + instrux + 116, + instrux + 117, + NULL +}; + +static struct itemplate *itable_E9[] = { + instrux + 431, + instrux + 432, + instrux + 433, + NULL +}; + +static struct itemplate *itable_EA[] = { + instrux + 434, + instrux + 435, + instrux + 436, + instrux + 437, + instrux + 438, + NULL +}; + +static struct itemplate *itable_EB[] = { + instrux + 430, + NULL +}; + +static struct itemplate *itable_EC[] = { + instrux + 408, + NULL +}; + +static struct itemplate *itable_ED[] = { + instrux + 409, + instrux + 410, + NULL +}; + +static struct itemplate *itable_EE[] = { + instrux + 604, + NULL +}; + +static struct itemplate *itable_EF[] = { + instrux + 605, + instrux + 606, + NULL +}; + +static struct itemplate *itable_F0[] = { + NULL +}; + +static struct itemplate *itable_F1[] = { + instrux + 420, + instrux + 921, + NULL +}; + +static struct itemplate *itable_F2[] = { + instrux + 1254, + instrux + 1336, + instrux + 1337, + instrux + 1402, + instrux + 1403, + instrux + 1410, + instrux + 1411, + instrux + 1414, + instrux + 1415, + instrux + 1418, + instrux + 1419, + instrux + 1422, + instrux + 1423, + instrux + 1426, + instrux + 1427, + instrux + 1430, + instrux + 1431, + instrux + 1434, + instrux + 1435, + instrux + 1438, + instrux + 1439, + instrux + 1442, + instrux + 1443, + instrux + 1450, + instrux + 1451, + instrux + 1462, + instrux + 1463, + instrux + 1464, + instrux + 1465, + instrux + 1466, + instrux + 1467, + instrux + 1476, + instrux + 1477, + instrux + 1480, + instrux + 1481, + instrux + 1484, + instrux + 1485, + instrux + 1488, + instrux + 1489, + instrux + 1499, + instrux + 1500, + instrux + 1501, + instrux + 1502, + instrux + 1509, + instrux + 1510, + instrux + 1517, + instrux + 1518, + instrux + 1521, + instrux + 1522, + instrux + 1533, + instrux + 1534, + instrux + 1537, + instrux + 1538, + instrux + 1541, + instrux + 1542, + instrux + 1543, + instrux + 1544, + instrux + 1545, + NULL +}; + +static struct itemplate *itable_F3[] = { + instrux + 1546, + instrux + 1547, + instrux + 1548, + instrux + 1549, + NULL +}; + +static struct itemplate *itable_F4[] = { + instrux + 382, + NULL +}; + +static struct itemplate *itable_F5[] = { + instrux + 140, + NULL +}; + +static struct itemplate *itable_F6[] = { + instrux + 190, + instrux + 383, + instrux + 386, + instrux + 567, + instrux + 571, + instrux + 575, + instrux + 979, + instrux + 982, + NULL +}; + +static struct itemplate *itable_F7[] = { + instrux + 191, + instrux + 192, + instrux + 384, + instrux + 385, + instrux + 387, + instrux + 388, + instrux + 568, + instrux + 569, + instrux + 572, + instrux + 573, + instrux + 576, + instrux + 577, + instrux + 980, + instrux + 981, + instrux + 983, + instrux + 984, + NULL +}; + +static struct itemplate *itable_F8[] = { + instrux + 136, + NULL +}; + +static struct itemplate *itable_F9[] = { + instrux + 927, + NULL +}; + +static struct itemplate *itable_FA[] = { + instrux + 138, + NULL +}; + +static struct itemplate *itable_FB[] = { + instrux + 929, + NULL +}; + +static struct itemplate *itable_FC[] = { + instrux + 137, + NULL +}; + +static struct itemplate *itable_FD[] = { + instrux + 928, + NULL +}; + +static struct itemplate *itable_FE[] = { + instrux + 187, + instrux + 413, + NULL +}; + +static struct itemplate *itable_FF[] = { + instrux + 123, + instrux + 124, + instrux + 125, + instrux + 126, + instrux + 127, + instrux + 128, + instrux + 129, + instrux + 130, + instrux + 131, + instrux + 132, + instrux + 133, + instrux + 188, + instrux + 189, + instrux + 414, + instrux + 415, + instrux + 439, + instrux + 440, + instrux + 441, + instrux + 442, + instrux + 443, + instrux + 444, + instrux + 445, + instrux + 446, + instrux + 447, + instrux + 448, + instrux + 449, + instrux + 776, + instrux + 777, + NULL +}; + +struct itemplate **itable[] = { + itable_00, + itable_01, + itable_02, + itable_03, + itable_04, + itable_05, + itable_06, + itable_07, + itable_08, + itable_09, + itable_0A, + itable_0B, + itable_0C, + itable_0D, + itable_0E, + itable_0F, + itable_10, + itable_11, + itable_12, + itable_13, + itable_14, + itable_15, + itable_16, + itable_17, + itable_18, + itable_19, + itable_1A, + itable_1B, + itable_1C, + itable_1D, + itable_1E, + itable_1F, + itable_20, + itable_21, + itable_22, + itable_23, + itable_24, + itable_25, + itable_26, + itable_27, + itable_28, + itable_29, + itable_2A, + itable_2B, + itable_2C, + itable_2D, + itable_2E, + itable_2F, + itable_30, + itable_31, + itable_32, + itable_33, + itable_34, + itable_35, + itable_36, + itable_37, + itable_38, + itable_39, + itable_3A, + itable_3B, + itable_3C, + itable_3D, + itable_3E, + itable_3F, + itable_40, + itable_41, + itable_42, + itable_43, + itable_44, + itable_45, + itable_46, + itable_47, + itable_48, + itable_49, + itable_4A, + itable_4B, + itable_4C, + itable_4D, + itable_4E, + itable_4F, + itable_50, + itable_51, + itable_52, + itable_53, + itable_54, + itable_55, + itable_56, + itable_57, + itable_58, + itable_59, + itable_5A, + itable_5B, + itable_5C, + itable_5D, + itable_5E, + itable_5F, + itable_60, + itable_61, + itable_62, + itable_63, + itable_64, + itable_65, + itable_66, + itable_67, + itable_68, + itable_69, + itable_6A, + itable_6B, + itable_6C, + itable_6D, + itable_6E, + itable_6F, + itable_70, + itable_71, + itable_72, + itable_73, + itable_74, + itable_75, + itable_76, + itable_77, + itable_78, + itable_79, + itable_7A, + itable_7B, + itable_7C, + itable_7D, + itable_7E, + itable_7F, + itable_80, + itable_81, + itable_82, + itable_83, + itable_84, + itable_85, + itable_86, + itable_87, + itable_88, + itable_89, + itable_8A, + itable_8B, + itable_8C, + itable_8D, + itable_8E, + itable_8F, + itable_90, + itable_91, + itable_92, + itable_93, + itable_94, + itable_95, + itable_96, + itable_97, + itable_98, + itable_99, + itable_9A, + itable_9B, + itable_9C, + itable_9D, + itable_9E, + itable_9F, + itable_A0, + itable_A1, + itable_A2, + itable_A3, + itable_A4, + itable_A5, + itable_A6, + itable_A7, + itable_A8, + itable_A9, + itable_AA, + itable_AB, + itable_AC, + itable_AD, + itable_AE, + itable_AF, + itable_B0, + itable_B1, + itable_B2, + itable_B3, + itable_B4, + itable_B5, + itable_B6, + itable_B7, + itable_B8, + itable_B9, + itable_BA, + itable_BB, + itable_BC, + itable_BD, + itable_BE, + itable_BF, + itable_C0, + itable_C1, + itable_C2, + itable_C3, + itable_C4, + itable_C5, + itable_C6, + itable_C7, + itable_C8, + itable_C9, + itable_CA, + itable_CB, + itable_CC, + itable_CD, + itable_CE, + itable_CF, + itable_D0, + itable_D1, + itable_D2, + itable_D3, + itable_D4, + itable_D5, + itable_D6, + itable_D7, + itable_D8, + itable_D9, + itable_DA, + itable_DB, + itable_DC, + itable_DD, + itable_DE, + itable_DF, + itable_E0, + itable_E1, + itable_E2, + itable_E3, + itable_E4, + itable_E5, + itable_E6, + itable_E7, + itable_E8, + itable_E9, + itable_EA, + itable_EB, + itable_EC, + itable_ED, + itable_EE, + itable_EF, + itable_F0, + itable_F1, + itable_F2, + itable_F3, + itable_F4, + itable_F5, + itable_F6, + itable_F7, + itable_F8, + itable_F9, + itable_FA, + itable_FB, + itable_FC, + itable_FD, + itable_FE, + itable_FF, +}; diff --git a/AltairZ80/mfdc.c b/AltairZ80/mfdc.c new file mode 100644 index 00000000..6d2379fc --- /dev/null +++ b/AltairZ80/mfdc.c @@ -0,0 +1,682 @@ +/************************************************************************* + * * + * $Id: mfdc.c 1773 2008-01-11 05:46:19Z hharte $ * + * * + * Copyright (c) 2007-2008 Howard M. Harte. * + * http://www.hartetec.com * + * * + * 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 HOWARD M. HARTE 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 Howard M. Harte shall * + * not be used in advertising or otherwise to promote the sale, use or * + * other dealings in this Software without prior written authorization * + * Howard M. Harte. * + * * + * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. * + * * + * Module Description: * + * Micropolis FD Control module for SIMH. * + * See the "Vector Using MDOS Revision 8.4" manual at: * + * www.hartetechnologies.com/manuals in the Vector Graphic section * + * for details of the on-disk sector format and programming information. * + * * + * Environment: * + * User mode only * + * * + *************************************************************************/ + +/*#define DBG_MSG */ +#define USE_VGI /* Use 275-byte VGI-format sectors (includes all metadata) */ + +#include "altairz80_defs.h" +#include "sim_imd.h" + +#if defined (_WIN32) +#include +#endif + +#ifdef DBG_MSG +#define DBG_PRINT(args) printf args +#else +#define DBG_PRINT(args) +#endif + +#define SEEK_MSG 0x01 +#define ORDERS_MSG 0x02 +#define CMD_MSG 0x04 +#define RD_DATA_MSG 0x08 +#define WR_DATA_MSG 0x10 +#define STATUS_MSG 0x20 + +extern uint32 PCX; +extern t_stat set_membase(UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat show_membase(FILE *st, UNIT *uptr, int32 val, void *desc); +extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, + int32 (*routine)(const int32, const int32, const int32), uint8 unmap); +extern int32 find_unit_index(UNIT *uptr); + +static void MFDC_Command(uint8 cData); + +#define MFDC_MAX_DRIVES 4 +#define JUMPER_W9 1 /* Not Installed (0) = 2MHz, Installed (1) = 4MHz. */ +#define JUMPER_W10 0 + +#define MFDC_SECTOR_LEN 275 + +typedef union { + struct { + uint8 sync; + uint8 header[2]; + uint8 unused[10]; + uint8 data[256]; + uint8 checksum; + uint8 ecc[4]; + uint8 ecc_valid; /* Not used for Micropolis FDC, but is used by FDHD. */ + } u; + uint8 raw[MFDC_SECTOR_LEN]; + +} SECTOR_FORMAT; + +typedef struct { + UNIT *uptr; + DISK_INFO *imd; + uint8 track; + uint8 wp; /* Disk write protected */ + uint8 ready; /* Drive is ready */ + uint8 sector; /* Current Sector number */ + uint32 sector_wait_count; +} MFDC_DRIVE_INFO; + +typedef struct { + PNP_INFO pnp; /* Plug and Play */ + uint8 xfr_flag; /* Indicates controller is ready to send/receive data */ + uint8 sel_drive; /* Currently selected drive */ + uint8 selected; /* 1 if drive is selected */ + uint8 track0; /* Set it selected drive is on track 0 */ + uint8 head; /* Currently selected head */ + uint8 wr_latch; /* Write enable latch */ + uint8 int_enable; /* Interrupt Enable */ + uint32 datacount; /* Number of data bytes transferred from controller for current sector */ + uint8 read_in_progress; /* TRUE if a read is in progress */ + MFDC_DRIVE_INFO drive[MFDC_MAX_DRIVES]; +} MFDC_INFO; + +static MFDC_INFO mfdc_info_data = { { 0xF800, 1024, 0, 0 } }; +static MFDC_INFO *mfdc_info = &mfdc_info_data; + +static SECTOR_FORMAT sdata; + +#define UNIT_V_MFDC_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_MFDC_WLK (1 << UNIT_V_MFDC_WLK) +#define UNIT_V_MFDC_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ +#define UNIT_MFDC_VERBOSE (1 << UNIT_V_MFDC_VERBOSE) +#define MFDC_CAPACITY (77*16*MFDC_SECTOR_LEN) /* Default Micropolis Disk Capacity */ +#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */ +#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */ +#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */ + +static t_stat mfdc_reset(DEVICE *mfdc_dev); +static t_stat mfdc_attach(UNIT *uptr, char *cptr); +static t_stat mfdc_detach(UNIT *uptr); +static uint8 MFDC_Read(const uint32 Addr); +static uint8 MFDC_Write(const uint32 Addr, uint8 cData); + +static int32 mdskdev(const int32 Addr, const int32 rw, const int32 data); + +static int32 trace_level = 0; + +static UNIT mfdc_unit[] = { + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MFDC_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MFDC_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MFDC_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MFDC_CAPACITY) } +}; + +static REG mfdc_reg[] = { + { HRDATA (TRACELEVEL, trace_level, 16), }, + { NULL } +}; + +static MTAB mfdc_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE", &set_membase, &show_membase, NULL }, + { UNIT_MFDC_WLK, 0, "WRTENB", "WRTENB", NULL }, + { UNIT_MFDC_WLK, UNIT_MFDC_WLK, "WRTLCK", "WRTLCK", NULL }, + /* quiet, no warning messages */ + { UNIT_MFDC_VERBOSE, 0, "QUIET", "QUIET", NULL }, + /* verbose, show warning messages */ + { UNIT_MFDC_VERBOSE, UNIT_MFDC_VERBOSE, "VERBOSE", "VERBOSE", NULL }, + { 0 } +}; + +DEVICE mfdc_dev = { + "MDSK", mfdc_unit, mfdc_reg, mfdc_mod, + MFDC_MAX_DRIVES, 10, 31, 1, MFDC_MAX_DRIVES, MFDC_MAX_DRIVES, + NULL, NULL, &mfdc_reset, + NULL, &mfdc_attach, &mfdc_detach, + &mfdc_info_data, (DEV_DISABLE | DEV_DIS), 0, + NULL, NULL, NULL +}; + +/* Micropolis FD Control Boot ROM + * This ROM code is runtime-relocatable. See Appendix F of the "Vector Using MDOS Revision 8.4" + * manual at www.hartetechnologies.com/manuals in the Vector Graphic section. + */ +static uint8 mfdc_rom[256] = { + 0xF3, 0x21, 0xA2, 0x00, 0xF9, 0x36, 0xC9, 0xCD, 0xA2, 0x00, 0xEB, 0x2A, 0xA0, 0x00, 0x2E, 0x00, /* 0x00 */ + 0xE5, 0x01, 0x1D, 0x00, 0x09, 0xE5, 0xE1, 0x0E, 0x1A, 0x09, 0x06, 0xBD, 0xEB, 0x3B, 0x3B, 0x1A, /* 0x10 */ + 0x77, 0xBE, 0xC0, 0x23, 0x13, 0x05, 0xC0, 0xE1, 0x2A, 0xA0, 0x00, 0x11, 0x00, 0x02, 0x19, 0x22, /* 0x20 */ + 0xA2, 0x00, 0x36, 0xA0, 0xC3, 0xD4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0xA2, 0x00, 0x7E, 0xE6, /* 0x30 */ + 0x80, 0xCA, 0xA9, 0x00, 0x7E, 0xE6, 0x0F, 0xA8, 0xC2, 0xA9, 0x00, 0x23, 0xB6, 0xF2, 0xB7, 0x00, /* 0x40 */ + 0x23, 0x7E, 0xAF, 0xEB, 0x06, 0x00, 0x00, 0x00, 0x1A, 0x77, 0x23, 0x88, 0x47, 0x1A, 0x77, 0x23, /* 0x50 */ + 0x88, 0x47, 0x0D, 0xC2, 0xC3, 0x00, 0x1A, 0xB8, 0xC9, 0x2A, 0xA2, 0x00, 0x36, 0x20, 0x23, 0x7E, /* 0x60 */ + 0x2B, 0xE6, 0x24, 0xEE, 0x20, 0xC2, 0xD4, 0x00, 0x0E, 0x5E, 0xCD, 0x49, 0x01, 0x23, 0x7E, 0x2B, /* 0x70 */ + 0xE6, 0x24, 0xEE, 0x20, 0xC2, 0xD4, 0x00, 0x23, 0x7E, 0xE6, 0x08, 0x2B, 0xCA, 0x07, 0x01, 0x06, /* 0x80 */ + 0x08, 0x36, 0x61, 0x0E, 0x0F, 0xCD, 0x49, 0x01, 0x05, 0xC2, 0xFC, 0x00, 0x23, 0x7E, 0xE6, 0x08, /* 0x90 */ + 0x2B, 0xC2, 0x19, 0x01, 0x36, 0x60, 0x0E, 0x0F, 0xCD, 0x49, 0x01, 0xC3, 0x07, 0x01, 0x21, 0x5F, /* 0xA0 */ + 0x01, 0xCD, 0x37, 0x01, 0xC2, 0xD4, 0x00, 0x2A, 0x69, 0x02, 0x22, 0xA4, 0x00, 0xCD, 0x37, 0x01, /* 0xB0 */ + 0xC2, 0xD4, 0x00, 0x2A, 0xA4, 0x00, 0x11, 0x0C, 0x00, 0x19, 0xD1, 0xE9, 0xE5, 0xEB, 0x01, 0x86, /* 0xC0 */ + 0x00, 0xCD, 0xA6, 0x00, 0xE1, 0xC2, 0x37, 0x01, 0xE5, 0x7E, 0x23, 0xB6, 0xE1, 0xC9, 0x7E, 0xE6, /* 0xD0 */ + 0x20, 0x79, 0xC2, 0x51, 0x01, 0x07, 0x4F, 0x3E, 0xFF, 0xD6, 0x01, 0xB7, 0xC2, 0x54, 0x01, 0x0D, /* 0xE0 */ + 0xC2, 0x52, 0x01, 0xC9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0xA6, 0x00 /* 0xF0 */ +}; + +/* Reset routine */ +t_stat mfdc_reset(DEVICE *dptr) +{ + uint8 i; + PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; + + if(dptr->flags & DEV_DIS) { + sim_map_resource(pnp->mem_base, pnp->mem_size, RESOURCE_TYPE_MEMORY, &mdskdev, TRUE); + } else { + /* Connect MFDC at base address */ + for(i = 0; i < MFDC_MAX_DRIVES; i++) { + mfdc_info->drive[i].uptr = &mfdc_dev.units[i]; + } + if(sim_map_resource(pnp->mem_base, pnp->mem_size, RESOURCE_TYPE_MEMORY, &mdskdev, FALSE) != 0) { + printf("%s: error mapping resource at 0x%04x\n", __FUNCTION__, pnp->mem_base); + dptr->flags |= DEV_DIS; + return SCPE_ARG; + } + } + return SCPE_OK; +} + +/* Attach routine */ +t_stat mfdc_attach(UNIT *uptr, char *cptr) +{ + char header[4]; + t_stat r; + unsigned int i = 0; + + r = attach_unit(uptr, cptr); /* attach unit */ + if ( r != SCPE_OK) /* error? */ + return r; + + /* Determine length of this disk */ + if(sim_fsize(uptr->fileref) != 0) { + uptr->capac = sim_fsize(uptr->fileref); + } else { + uptr->capac = MFDC_CAPACITY; + } + + i = find_unit_index(uptr); + + /* Default for new file is DSK */ + uptr->u3 = IMAGE_TYPE_DSK; + + if(uptr->capac > 0) { + fgets(header, 4, uptr->fileref); + if(!strcmp(header, "IMD")) { + uptr->u3 = IMAGE_TYPE_IMD; + } else if(!strcmp(header, "CPT")) { + printf("CPT images not yet supported\n"); + uptr->u3 = IMAGE_TYPE_CPT; + mfdc_detach(uptr); + return SCPE_OPENERR; + } else { + uptr->u3 = IMAGE_TYPE_DSK; + } + } + + if (uptr->flags & UNIT_MFDC_VERBOSE) + printf("MDSK%d, attached to '%s', type=%s, len=%d\n", i, cptr, + uptr->u3 == IMAGE_TYPE_IMD ? "IMD" : uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK", + uptr->capac); + + if(uptr->u3 == IMAGE_TYPE_IMD) { + if(uptr->capac < 318000) { + printf("Cannot create IMD files with SIMH.\nCopy an existing file and format it with CP/M.\n"); + mfdc_detach(uptr); + return SCPE_OPENERR; + } + + if (uptr->flags & UNIT_MFDC_VERBOSE) + printf("--------------------------------------------------------\n"); + mfdc_info->drive[i].imd = diskOpen((uptr->fileref), (uptr->flags & UNIT_MFDC_VERBOSE)); + if (uptr->flags & UNIT_MFDC_VERBOSE) + printf("\n"); + } else { + mfdc_info->drive[i].imd = NULL; + } + + return SCPE_OK; +} + + +/* Detach routine */ +t_stat mfdc_detach(UNIT *uptr) +{ + t_stat r; + int8 i; + + for(i = 0; i < MFDC_MAX_DRIVES; i++) { + if(mfdc_dev.units[i].fileref == uptr->fileref) { + break; + } + } + + if (i >= MFDC_MAX_DRIVES) return SCPE_ARG; + + DBG_PRINT(("Detach MFDC%d\n", i)); + diskClose(mfdc_info->drive[i].imd); + + r = detach_unit(uptr); /* detach unit */ + if ( r != SCPE_OK) + return r; + + return SCPE_OK; +} + + + +static uint8 cy; +static uint8 adc(uint8 sum, uint8 a1) +{ + uint32 total; + + total = sum + a1 + cy; + + if(total > 0xFF) { + cy = 1; + } else { + cy = 0; + } + + return(total & 0xFF); +} + +/* Main Entry Point for Memory-Mapped I/O to the Micropolis FD Control Board + * + * The controller is typically located at 0xF800 in the Memory Map, and occupies + * 1K of address space. Accesses are broken down as follows: + * + * 0xF800-0xF8FF: Bootstrap ROM + * 0xF900-0xF9FF: Nothing (reads 0xFF) + * 0xFA00-0xFBFF: Controller registers: there are four registers, which are shadowed + * throughout this 512-byte range. + * + * The controller can be relocated on any 1K boundary in the memory map, and since the + * boot ROM code is runtime relocatable, it moves with the controller registers. + */ +static int32 mdskdev(const int32 Addr, const int32 rw, const int32 data) +{ + switch(Addr & 0x300) { + case 0x000: /* Boot ROM */ + if(rw == 0) { /* Read boot ROM */ + return(mfdc_rom[Addr & 0xFF]); + } else { + printf("MFDC: Attempt to write to boot ROM." NLP); + return (-1); + } + break; + case 0x100: /* Nothing */ + return(0xFF); + break; + case 0x200: + case 0x300: /* Controller Registers */ + if(rw == 0) { /* Read Register */ + return(MFDC_Read(Addr)); + } else { /* Write Register */ + return(MFDC_Write(Addr, data)); + } + break; + } + + return(-1); +} + + +static uint8 MFDC_Read(const uint32 Addr) +{ + uint8 cData; + MFDC_DRIVE_INFO *pDrive; + + cData = 0x00; + + pDrive = &mfdc_info->drive[mfdc_info->sel_drive]; + + switch(Addr & 0x3) { + case 0: + if(mfdc_info->read_in_progress == FALSE) { + pDrive->sector_wait_count++; + if(pDrive->sector_wait_count > 10) { + pDrive->sector++; + pDrive->sector &= 0x0F; /* Max of 16 sectors */ + mfdc_info->wr_latch = 0; /* on new sector, disable the write latch */ + DBG_PRINT(("Head over sector %d" NLP, pDrive->sector)); + pDrive->sector_wait_count = 0; + } + } + + cData = (pDrive->sector) & 0xF; /* [3:0] current sector */ + cData |= (JUMPER_W10 << 4); + cData |= ((~JUMPER_W9) & 1) << 5; + cData |= (0 << 6); /* Sector Interrupt Flag, reset by RESET command or Interrupt Disable */ + cData |= (1 << 7); /* Sector Flag */ + mfdc_info->xfr_flag = 1; /* Drive has data */ + mfdc_info->datacount = 0; + TRACE_PRINT(STATUS_MSG, ("MFDC: " ADDRESS_FORMAT " RD Sector Register = 0x%02x" NLP, PCX, cData)); + break; + case 1: + cData = (mfdc_info->sel_drive & 0x3); /* [1:0] selected drive */ + cData |= (!mfdc_info->selected << 2); /* [2] drive is selected */ + cData |= (pDrive->track == 0) ? 0x08 : 0; /* [3] TK0 */ + pDrive->wp = ((pDrive->uptr)->flags & UNIT_MFDC_WLK) ? 1 : 0; + cData |= (pDrive->wp << 4); /* [4] Write Protect */ + cData |= (pDrive->ready << 5); /* [5] Drive Ready */ + cData |= (0 << 6); /* [6] PINTE from S-100 Bus */ + cData |= (mfdc_info->xfr_flag << 7); /* [7] Transfer Flag */ + + TRACE_PRINT(STATUS_MSG, ("MFDC: " ADDRESS_FORMAT " RD Status = 0x%02x" NLP, PCX, cData)); + break; + case 2: + case 3: + if(mfdc_info->datacount == 0) { + unsigned int i, checksum; + unsigned long sec_offset; + unsigned int flags; + unsigned int readlen; + + /* Clear out unused portion of sector. */ + memset(&sdata.u.unused[0], 0x00, 10); + + sdata.u.sync = 0xFF; + sdata.u.header[0] = pDrive->track; + sdata.u.header[1] = pDrive->sector; + + TRACE_PRINT(RD_DATA_MSG, ("MFDC: " ADDRESS_FORMAT " RD Data T:%d S:[%d]" NLP, + PCX, + pDrive->track, + pDrive->sector)); + +#ifdef USE_VGI + sec_offset = (pDrive->track * MFDC_SECTOR_LEN * 16) + \ + (pDrive->sector * MFDC_SECTOR_LEN); +#else + sec_offset = (pDrive->track * 4096) + \ + (pDrive->sector * 256); +#endif /* USE_VGI */ + + if (!(pDrive->uptr->flags & UNIT_ATT)) { + if (pDrive->uptr->flags & UNIT_MFDC_VERBOSE) + printf("MFDC: " ADDRESS_FORMAT " MDSK%i not attached." NLP, PCX, + mfdc_info->sel_drive); + return 0x00; + } + + switch((pDrive->uptr)->u3) + { + case IMAGE_TYPE_IMD: + if(pDrive->imd == NULL) { + printf(".imd is NULL!" NLP); + } +/* printf("%s: Read: imd=%p" NLP, __FUNCTION__, pDrive->imd); */ + sectRead(pDrive->imd, + pDrive->track, + mfdc_info->head, + pDrive->sector, + sdata.u.data, + 256, + &flags, + &readlen); + break; + case IMAGE_TYPE_DSK: + if(pDrive->uptr->fileref == NULL) { + printf(".fileref is NULL!" NLP); + } else { + fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET); +#ifdef USE_VGI + fread(sdata.raw, MFDC_SECTOR_LEN, 1, (pDrive->uptr)->fileref); +#else + fread(sdata.u.data, 256, 1, (pDrive->uptr)->fileref); +#endif /* USE_VGI */ + } + break; + case IMAGE_TYPE_CPT: + printf("%s: CPT Format not supported" NLP, __FUNCTION__); + break; + default: + printf("%s: Unknown image Format" NLP, __FUNCTION__); + break; + } + +/* printf("%d/%d @%04x Len=%04x" NLP, sdata.u.header[0], sdata.u.header[1], sdata.u.header[9]<<8|sdata.u.header[8], sdata.u.header[11]<<8|sdata.u.header[10]); */ + + adc(0,0); /* clear Carry bit */ + checksum = 0; + + /* Checksum everything except the sync byte */ + for(i=1;i<269;i++) { + checksum = adc(checksum, sdata.raw[i]); + } + + sdata.u.checksum = checksum & 0xFF; +/* DBG_PRINT(("Checksum=%x" NLP, sdata.u.checksum)); */ + mfdc_info->read_in_progress = TRUE; + } + + cData = sdata.raw[mfdc_info->datacount]; + + mfdc_info->datacount++; + if(mfdc_info->datacount == 270) { + TRACE_PRINT(RD_DATA_MSG, ("MFDC: " ADDRESS_FORMAT " Read sector [%d] complete" NLP, + PCX, pDrive->sector)); + mfdc_info->read_in_progress = FALSE; + } + +/* DBG_PRINT(("MFDC: " ADDRESS_FORMAT " RD Data Sector %d[%03d]: 0x%02x" NLP, PCX, pDrive->sector, mfdc_info->datacount, cData)); */ + break; + } + + return (cData); +} + +static uint8 MFDC_Write(const uint32 Addr, uint8 cData) +{ + unsigned int sec_offset; + unsigned int flags = 0; + unsigned int writelen; + MFDC_DRIVE_INFO *pDrive; + + pDrive = &mfdc_info->drive[mfdc_info->sel_drive]; + + switch(Addr & 0x3) { + case 0: + case 1: + MFDC_Command(cData); + break; + case 2: + case 3: +/* DBG_PRINT(("MFDC: " ADDRESS_FORMAT " WR Data" NLP, PCX)); */ + if(mfdc_info->wr_latch == 0) { + printf("MFDC: " ADDRESS_FORMAT " Error, attempt to write data when write latch is not set." NLP, PCX); + } else { +#ifdef USE_VGI + sec_offset = (pDrive->track * MFDC_SECTOR_LEN * 16) + \ + (pDrive->sector * MFDC_SECTOR_LEN); + + sdata.raw[mfdc_info->datacount] = cData; +#else + int data_index = mfdc_info->datacount - 13; + + sec_offset = (pDrive->track * 4096) + \ + (pDrive->sector * 256); + + if((data_index >= 0) && (data_index < 256)) { + DBG_PRINT(("writing data [%03d]=%02x" NLP, data_index, cData)); + + sdata.u.data[data_index] = cData; + + } + +#endif /* USE_VGI */ + + mfdc_info->datacount ++; + + if(mfdc_info->datacount == 270) { + TRACE_PRINT(WR_DATA_MSG, ("MFDC: " ADDRESS_FORMAT " WR Data T:%d S:[%d]" NLP, + PCX, + pDrive->track, + pDrive->sector)); + + if (!(pDrive->uptr->flags & UNIT_ATT)) { + if (pDrive->uptr->flags & UNIT_MFDC_VERBOSE) + printf("MFDC: " ADDRESS_FORMAT " MDSK%i not attached." NLP, PCX, + mfdc_info->sel_drive); + return 0x00; + } + + switch((pDrive->uptr)->u3) + { + case IMAGE_TYPE_IMD: + if(pDrive->imd == NULL) { + printf(".imd is NULL!" NLP); + } + sectWrite(pDrive->imd, + pDrive->track, + mfdc_info->head, + pDrive->sector, + sdata.u.data, + 256, + &flags, + &writelen); + break; + case IMAGE_TYPE_DSK: + if(pDrive->uptr->fileref == NULL) { + printf(".fileref is NULL!" NLP); + } else { + fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET); +#ifdef USE_VGI + fwrite(sdata.raw, MFDC_SECTOR_LEN, 1, (pDrive->uptr)->fileref); +#else + fwrite(sdata.u.data, 256, 1, (pDrive->uptr)->fileref); +#endif /* USE_VGI */ + } + break; + case IMAGE_TYPE_CPT: + printf("%s: CPT Format not supported" NLP, __FUNCTION__); + break; + default: + printf("%s: Unknown image Format" NLP, __FUNCTION__); + break; + } + } + } + break; + } + + cData = 0x00; + + return (cData); +} + +#define MFDC_CMD_NOP 0 +#define MFDC_CMD_SELECT 1 +#define MFDC_CMD_INTR 2 +#define MFDC_CMD_STEP 3 +#define MFDC_CMD_SET_WRITE 4 +#define MFDC_CMD_RESET 5 + +static void MFDC_Command(uint8 cData) +{ + uint8 cCommand; + uint8 cModifier; + MFDC_DRIVE_INFO *pDrive; + + pDrive = &mfdc_info->drive[mfdc_info->sel_drive]; + + + cCommand = cData >> 5; + cModifier = cData & 0x1F; + + switch(cCommand) { + case MFDC_CMD_NOP: + TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " No Op." NLP, PCX)); + break; + case MFDC_CMD_SELECT: + mfdc_info->sel_drive = cModifier & 3; + mfdc_info->head = (cModifier & 0x10) >> 4; + mfdc_info->selected = TRUE; + + if(pDrive->uptr->fileref != NULL) { + pDrive->ready = 1; + } else { + pDrive->ready = 0; + } + + TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Select Drive: %d, Head: %s" NLP, + PCX, mfdc_info->sel_drive, (mfdc_info->head) ? "Upper" : "Lower")); + break; + case MFDC_CMD_INTR: + mfdc_info->int_enable = cModifier & 1; /* 0=int disable, 1=enable */ + TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Interrupts %s." NLP, + PCX, mfdc_info->int_enable ? "Enabled" : "Disabled")); + break; + case MFDC_CMD_STEP: + if(cModifier & 1) { /* Step IN */ + pDrive->track++; + } + else { /* Step OUT */ + if(pDrive->track != 0) { + pDrive->track--; + } + } + + TRACE_PRINT(SEEK_MSG, ("MFDC: " ADDRESS_FORMAT " Step %s, Track=%d." NLP, + PCX, (cModifier & 1) ? "IN" : "OUT", pDrive->track)); + + break; + case MFDC_CMD_SET_WRITE: + TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Set WRITE." NLP, PCX)); + mfdc_info->wr_latch = 1; /* Allow writes for the current sector */ + mfdc_info->datacount = 0; /* reset the byte counter */ + break; + case MFDC_CMD_RESET: + TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Reset Controller." NLP, PCX)); + mfdc_info->selected = 0; /* de-select the drive */ + mfdc_info->wr_latch = 0; /* Disable the write latch */ + mfdc_info->datacount = 0; /* reset the byte counter */ + break; + default: + TRACE_PRINT(CMD_MSG, ("MFDC: " ADDRESS_FORMAT " Unsupported command." NLP, PCX)); + break; + } +} diff --git a/AltairZ80/mfdc.h b/AltairZ80/mfdc.h new file mode 100644 index 00000000..991e1c8a --- /dev/null +++ b/AltairZ80/mfdc.h @@ -0,0 +1,46 @@ +/************************************************************************* + * * + * $Id: mfdc.h 1694 2007-12-14 05:23:11Z hharte $ * + * * + * Copyright (c) 2007-2008 Howard M. Harte. * + * http://www.hartetec.com * + * * + * 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 HOWARD M. HARTE 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 Howard M. Harte shall * + * not be used in advertising or otherwise to promote the sale, use or * + * other dealings in this Software without prior written authorization * + * Howard M. Harte. * + * * + * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. * + * * + * Module Description: * + * Micropolis FDC module for SIMH definitions * + * * + * Environment: * + * User mode only * + * * + *************************************************************************/ + +extern uint8 MFDC_Read(const uint32 Addr); +extern uint8 MFDC_Write(const uint32 Addr, uint8 cData); + + + diff --git a/AltairZ80/n8vem.c b/AltairZ80/n8vem.c new file mode 100644 index 00000000..f9cdf077 --- /dev/null +++ b/AltairZ80/n8vem.c @@ -0,0 +1,486 @@ +/************************************************************************* + * * + * $Id: n8vem.c 1902 2008-05-11 02:40:41Z hharte $ * + * * + * Copyright (c) 2007-2008 Howard M. Harte. * + * http://www.hartetec.com * + * * + * 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 HOWARD M. HARTE 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 Howard M. Harte shall * + * not be used in advertising or otherwise to promote the sale, use or * + * other dealings in this Software without prior written authorization * + * Howard M. Harte. * + * * + * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. * + * * + * Module Description: * + * N8VEM Single-Board Computer I/O module for SIMH. * + * http://groups.google.com/group/n8vem/web/n8vem-single-board-computer-home-page * + * * + * Environment: * + * User mode only * + * * + *************************************************************************/ + +/* #define DBG_MSG */ + +#include "altairz80_defs.h" + +#if defined (_WIN32) +#include +#endif + +#ifdef DBG_MSG +#define DBG_PRINT(args) printf args +#else +#define DBG_PRINT(args) +#endif + +#define PIO_MSG 0x01 +#define UART_MSG 0x02 +#define RTC_MSG 0x04 +#define MPCL_MSG 0x08 +#define ROM_MSG 0x10 +#define TRACE_MSG 0x80 + +#define N8VEM_MAX_DRIVES 2 + +#define UNIT_V_N8VEM_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ +#define UNIT_N8VEM_VERBOSE (1 << UNIT_V_N8VEM_VERBOSE) + +typedef struct { + PNP_INFO pnp; /* Plug and Play */ + uint8 *ram; + uint8 *rom; + uint8 rom_attached; + uint8 uart_scr; + uint8 uart_lcr; + uint8 mpcl_ram; + uint8 mpcl_rom; +} N8VEM_INFO; + +static N8VEM_INFO n8vem_info_data = { { 0x0, 0x8000, 0x60, 32 } }; +static N8VEM_INFO *n8vem_info = &n8vem_info_data; + +extern t_stat set_membase(UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat show_membase(FILE *st, UNIT *uptr, int32 val, void *desc); +extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc); +extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, + int32 (*routine)(const int32, const int32, const int32), uint8 unmap); +extern uint32 PCX; +extern REG *sim_PC; +extern int32 find_unit_index (UNIT *uptr); + +static t_stat n8vem_reset(DEVICE *n8vem_dev); +static t_stat n8vem_boot(int32 unitno, DEVICE *dptr); +static t_stat n8vem_attach(UNIT *uptr, char *cptr); +static t_stat n8vem_detach(UNIT *uptr); + +static uint8 N8VEM_Read(const uint32 Addr); +static uint8 N8VEM_Write(const uint32 Addr, uint8 cData); + +static int32 n8vemdev(const int32 port, const int32 io, const int32 data); +static int32 n8vem_mem(const int32 port, const int32 io, const int32 data); + +static int32 trace_level = 0x00; /* Disable all tracing by default */ +static int32 save_rom = 0x00; /* When set to 1, saves ROM back to file on disk at detach time */ +static int32 save_ram = 0x00; /* When set to 1, saves RAM back to file on disk at detach time */ +static int32 n8vem_pio1a = 0x00; /* 8255 PIO1A IN Port */ +static int32 n8vem_pio1b = 0x00; /* 8255 PIO1B OUT Port */ +static int32 n8vem_pio1c = 0x00; /* 8255 PIO1C IN Port */ +static int32 n8vem_pio1ctrl = 0x00; /* 8255 PIO1 Control Port */ + +#define N8VEM_ROM_SIZE (1024 * 1024) +#define N8VEM_RAM_SIZE (512 * 1024) + +#define N8VEM_RAM_SELECT (1 << 7) +#define N8VEM_RAM_MASK 0x0F +#define N8VEM_ROM_MASK 0x1F +#define N8VEM_ADDR_MASK 0x7FFF + +static UNIT n8vem_unit[] = { + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, N8VEM_ROM_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, N8VEM_RAM_SIZE) } +}; + +static REG n8vem_reg[] = { + { HRDATA (TRACELEVEL, trace_level, 16), }, + { HRDATA (SAVEROM, save_rom, 1), }, + { HRDATA (SAVERAM, save_ram, 1), }, + { HRDATA (PIO1A, n8vem_pio1a, 8), }, + { HRDATA (PIO1B, n8vem_pio1b, 8), }, + { HRDATA (PIO1C, n8vem_pio1c, 8), }, + { HRDATA (PIO1CTRL, n8vem_pio1ctrl, 8), }, + { NULL } +}; + +static MTAB n8vem_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE", &set_membase, &show_membase, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL }, + /* quiet, no warning messages */ + { UNIT_N8VEM_VERBOSE, 0, "QUIET", "QUIET", NULL }, + /* verbose, show warning messages */ + { UNIT_N8VEM_VERBOSE, UNIT_N8VEM_VERBOSE, "VERBOSE", "VERBOSE", NULL }, + { 0 } +}; + +DEVICE n8vem_dev = { + "N8VEM", n8vem_unit, n8vem_reg, n8vem_mod, + N8VEM_MAX_DRIVES, 10, 31, 1, N8VEM_MAX_DRIVES, N8VEM_MAX_DRIVES, + NULL, NULL, &n8vem_reset, + &n8vem_boot, &n8vem_attach, &n8vem_detach, + &n8vem_info_data, (DEV_DISABLE | DEV_DIS), 0, + NULL, NULL, NULL +}; + +/* Reset routine */ +static t_stat n8vem_reset(DEVICE *dptr) +{ + PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; + + TRACE_PRINT(TRACE_MSG, ("N8VEM: Reset." NLP)); + + if(dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */ + sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &n8vemdev, TRUE); + sim_map_resource(pnp->mem_base, pnp->mem_size, RESOURCE_TYPE_MEMORY, &n8vem_mem, TRUE); + free(n8vem_info->ram); + free(n8vem_info->rom); + } else { + /* Connect N8VEM at base address */ + if(sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &n8vemdev, FALSE) != 0) { + printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->io_base); + return SCPE_ARG; + } + /* Connect N8VEM Memory (512K RAM, 1MB FLASH) */ + if(sim_map_resource(pnp->mem_base, pnp->mem_size, RESOURCE_TYPE_MEMORY, &n8vem_mem, FALSE) != 0) { + printf("%s: error mapping MEM resource at 0x%04x\n", __FUNCTION__, pnp->mem_base); + return SCPE_ARG; + } + + n8vem_info->ram = calloc(1, (N8VEM_RAM_SIZE)); + n8vem_info->rom = calloc(1, (N8VEM_ROM_SIZE)); + + /* Clear the RAM and ROM mapping registers */ + n8vem_info->mpcl_ram = 0; + n8vem_info->mpcl_rom = 0; + } + return SCPE_OK; +} + +static t_stat n8vem_boot(int32 unitno, DEVICE *dptr) +{ + TRACE_PRINT(TRACE_MSG, ("N8VEM: Boot." NLP)); + + /* Clear the RAM and ROM mapping registers */ + n8vem_info->mpcl_ram = 0; + n8vem_info->mpcl_rom = 0; + + /* Set the PC to 0, and go. */ + *((int32 *) sim_PC->loc) = 0; + return SCPE_OK; +} + +/* Attach routine */ +static t_stat n8vem_attach(UNIT *uptr, char *cptr) +{ + t_stat r; + int32 i = 0; + + i = find_unit_index(uptr); + + if (i == -1) { + return (SCPE_IERR); + } + + r = attach_unit(uptr, cptr); /* attach unit */ + if ( r != SCPE_OK) /* error? */ + return r; + + /* Determine length of this disk */ + uptr->capac = sim_fsize(uptr->fileref); + + TRACE_PRINT(TRACE_MSG, ("N8VEM: Attach %s." NLP, i == 0 ? "ROM" : "RAM")); + + if(i == 0) { /* Attaching ROM */ + n8vem_info->rom_attached = TRUE; + + /* Erase ROM */ + memset(n8vem_info->rom, 0xFF, N8VEM_ROM_SIZE); + + if(uptr->capac > 0) { + /* Only read in enough of the file to fill the ROM. */ + if(uptr->capac > N8VEM_ROM_SIZE) uptr->capac = N8VEM_ROM_SIZE; + + printf("Reading %d bytes into ROM.\n", uptr->capac); + fread((void *)(n8vem_info->rom), uptr->capac, 1, uptr->fileref); + } + } else { /* attaching RAM */ + /* Erase RAM */ + memset(n8vem_info->ram, 0x00, N8VEM_RAM_SIZE); + + if(uptr->capac > 0) { + /* Only read in enough of the file to fill the RAM. */ + if(uptr->capac > N8VEM_RAM_SIZE) uptr->capac = N8VEM_RAM_SIZE; + + printf("Reading %d bytes into RAM.\n", uptr->capac); + fread((void *)(n8vem_info->ram), uptr->capac, 1, uptr->fileref); + } + } + return r; +} + +/* Detach routine */ +static t_stat n8vem_detach(UNIT *uptr) +{ + t_stat r; + int32 i = 0; + + i = find_unit_index(uptr); + + if (i == -1) { + return (SCPE_IERR); + } + + TRACE_PRINT(TRACE_MSG, ("N8VEM: Detach %s." NLP, i == 0 ? "ROM" : "RAM")); + + /* rewind to the beginning of the file. */ + fseek(uptr->fileref, 0, SEEK_SET); + + if(i == 0) { /* ROM */ + /* Save the ROM back to disk if SAVEROM is set. */ + if(save_rom == 1) { + printf("Writing %d bytes into ROM image.\n", N8VEM_ROM_SIZE); + fwrite((void *)(n8vem_info->rom), N8VEM_ROM_SIZE, 1, uptr->fileref); + } + } else { /* RAM */ + /* Save the RAM back to disk if SAVERAM is set. */ + if(save_ram == 1) { + printf("Writing %d bytes into RAM image.\n", N8VEM_RAM_SIZE); + fwrite((void *)(n8vem_info->ram), N8VEM_RAM_SIZE, 1, uptr->fileref); + } + } + r = detach_unit(uptr); /* detach unit */ + + return r; +} + +/* RAM MEMORY PAGE CONFIGURATION LATCH CONTROL PORT ( IO_Y3 ) INFORMATION + * + * 7 6 5 4 3 2 1 0 ONLY APPLICABLE TO THE LOWER MEMORY PAGE $0000-$7FFF + * ^ ^ ^ ^ ^ ^ ^ ^ + * : : : : : : : :--0 = A15 RAM ADDRESS LINE DEFAULT IS 0 + * : : : : : : :----0 = A16 RAM ADDRESS LINE DEFAULT IS 0 + * : : : : : :------0 = A17 RAM ADDRESS LINE DEFAULT IS 0 + * : : : : :--------0 = A18 RAM ADDRESS LINE DEFAULT IS 0 + * : : : :-----------0 = + * : : :-------------0 = + * : :---------------0 = + * :-----------------0 = + * + * ROM MEMORY PAGE CONFIGURATION LATCH CONTROL PORT ( IO_Y3+$04 ) INFORMATION + * + * 7 6 5 4 3 2 1 0 ONLY APPLICABLE TO THE LOWER MEMORY PAGE $0000-$7FFF + * ^ ^ ^ ^ ^ ^ ^ ^ + * : : : : : : : :--0 = A15 ROM ADDRESS LINE DEFAULT IS 0 + * : : : : : : :----0 = A16 ROM ADDRESS LINE DEFAULT IS 0 + * : : : : : :------0 = A17 ROM ADDRESS LINE DEFAULT IS 0 + * : : : : :--------0 = A18 ROM ADDRESS LINE DEFAULT IS 0 + * : : : :-----------0 = A19 ROM ONLY ADDRESS LINE DEFAULT IS 0 + * : : :-------------0 = + * : :---------------0 = + * :-----------------0 = ROM SELECT (0=ROM, 1=RAM) DEFAULT IS 0 + */ + static int32 n8vem_mem(const int32 Addr, const int32 write, const int32 data) +{ +/* DBG_PRINT(("N8VEM: ROM %s, Addr %04x" NLP, write ? "WR" : "RD", Addr)); */ + if(write) { + if(n8vem_info->mpcl_rom & N8VEM_RAM_SELECT) + { + n8vem_info->ram[((n8vem_info->mpcl_ram & N8VEM_RAM_MASK) << 15) | (Addr & N8VEM_ADDR_MASK)] = data; + } else { + if(save_rom == 1) { + n8vem_info->rom[((n8vem_info->mpcl_rom & N8VEM_ROM_MASK) << 15) | (Addr & N8VEM_ADDR_MASK)] = data; + } else { + TRACE_PRINT(ROM_MSG, ("N8VEM: " ADDRESS_FORMAT " WR ROM[0x%05x]: Cannot write to ROM." NLP, PCX, ((n8vem_info->mpcl_rom & N8VEM_ROM_MASK) << 15) | (Addr & N8VEM_ADDR_MASK))); + } + } + return 0; + } else { + if(n8vem_info->mpcl_rom & N8VEM_RAM_SELECT) + { + return n8vem_info->ram[((n8vem_info->mpcl_ram & N8VEM_RAM_MASK) << 15) | (Addr & N8VEM_ADDR_MASK)]; + } else { + return n8vem_info->rom[((n8vem_info->mpcl_rom & N8VEM_ROM_MASK) << 15) | (Addr & N8VEM_ADDR_MASK)]; + } + } +} + +static int32 n8vemdev(const int32 port, const int32 io, const int32 data) +{ +/* DBG_PRINT(("N8VEM: IO %s, Port %02x\n", io ? "WR" : "RD", port)); */ + if(io) { + N8VEM_Write(port, data); + return 0; + } else { + return(N8VEM_Read(port)); + } +} + +#define N8VEM_PIO1A 0x00 /* (INPUT) IN 1-8 */ +#define N8VEM_PIO1B 0x01 /* (OUTPUT) OUT TO LEDS */ +#define N8VEM_PIO1C 0x02 /* (INPUT) */ +#define N8VEM_PIO1CONT 0x03 /* CONTROL BYTE PIO 82C55 */ + +#define N8VEM_UART_DATA 0x08 +#define N8VEM_UART_RSR 0x09 +#define N8VEM_UART_INTR 0x0A +#define N8VEM_UART_LCR 0x0B +#define N8VEM_UART_MCR 0x0C +#define N8VEM_UART_LSR 0x0D +#define N8VEM_UART_MSR 0x0E +#define N8VEM_UART_SCR 0x0F + +#define N8VEM_MPCL_RAM 0x18 /* RAM Address control port */ +#define N8VEM_MPCL_RAM1 0x19 /* RAM Address control port */ +#define N8VEM_MPCL_RAM2 0x1A /* RAM Address control port */ +#define N8VEM_MPCL_RAM3 0x1B /* RAM Address control port */ +#define N8VEM_MPCL_ROM 0x1C /* ROM Address control port */ +#define N8VEM_MPCL_ROM1 0x1D /* ROM Address control port */ +#define N8VEM_MPCL_ROM2 0x1E /* ROM Address control port */ +#define N8VEM_MPCL_ROM3 0x1F /* ROM Address control port */ + +extern int32 sio0d(const int32 port, const int32 io, const int32 data); +extern int32 sio0s(const int32 port, const int32 io, const int32 data); + +static uint8 N8VEM_Read(const uint32 Addr) +{ + uint8 cData = 0xFF; + + switch(Addr & 0x1F) { + case N8VEM_PIO1A: + TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " RD: PIO1A" NLP, PCX)); + cData = n8vem_pio1a; + break; + case N8VEM_PIO1B: + TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " RD: PIO1B" NLP, PCX)); + cData = n8vem_pio1b; + break; + case N8VEM_PIO1C: + TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " RD: PIO1C" NLP, PCX)); + cData = n8vem_pio1c; + break; + case N8VEM_PIO1CONT: + TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " RD: PIO1CTRL" NLP, PCX)); + cData = n8vem_pio1ctrl; + break; + case N8VEM_UART_LCR: + cData = n8vem_info->uart_lcr; + break; + case N8VEM_UART_DATA: + case N8VEM_UART_RSR: + case N8VEM_UART_LSR: + case N8VEM_UART_INTR: + case N8VEM_UART_MCR: + case N8VEM_UART_MSR: + TRACE_PRINT(UART_MSG, ("N8VEM: " ADDRESS_FORMAT " RD[%02x]: UART not Implemented." NLP, PCX, Addr)); + break; + case N8VEM_UART_SCR: /* 16550 Scratchpad, implemented so software can detect UART is present */ + cData = n8vem_info->uart_scr; + break; + case N8VEM_MPCL_RAM: + case N8VEM_MPCL_RAM1: + case N8VEM_MPCL_RAM2: + case N8VEM_MPCL_RAM3: + TRACE_PRINT(MPCL_MSG, ("N8VEM: " ADDRESS_FORMAT " RD: MPCL_RAM not Implemented." NLP, PCX)); + break; + case N8VEM_MPCL_ROM: + case N8VEM_MPCL_ROM1: + case N8VEM_MPCL_ROM2: + case N8VEM_MPCL_ROM3: + TRACE_PRINT(MPCL_MSG, ("N8VEM: " ADDRESS_FORMAT " RD: MPCL_ROM not Implemented." NLP, PCX)); + break; + default: + TRACE_PRINT(TRACE_MSG, ("N8VEM: " ADDRESS_FORMAT " RD[%02x]: not Implemented." NLP, PCX, Addr)); + break; + } + + return (cData); + +} + +static uint8 N8VEM_Write(const uint32 Addr, uint8 cData) +{ + + switch(Addr & 0x1F) { + case N8VEM_PIO1A: + TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: PIO1A=0x%02x" NLP, PCX, cData)); + n8vem_pio1a = cData; + break; + case N8VEM_PIO1B: + TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: PIO1B=0x%02x" NLP, PCX, cData)); + n8vem_pio1b = cData; + break; + case N8VEM_PIO1C: + TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: PIO1C=0x%02x" NLP, PCX, cData)); + n8vem_pio1c = cData; + break; + case N8VEM_PIO1CONT: + TRACE_PRINT(PIO_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: PIO1_CTRL=0x%02x" NLP, PCX, cData)); + n8vem_pio1ctrl = cData; + break; + case N8VEM_UART_LCR: + TRACE_PRINT(UART_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: UART LCR=%02x." NLP, PCX, cData)); + n8vem_info->uart_lcr = cData; + break; + case N8VEM_UART_DATA: + case N8VEM_UART_RSR: + case N8VEM_UART_INTR: + case N8VEM_UART_MCR: + case N8VEM_UART_LSR: + case N8VEM_UART_MSR: + TRACE_PRINT(UART_MSG, ("N8VEM: " ADDRESS_FORMAT " WR[%02x]: UART not Implemented." NLP, PCX, Addr)); + break; + case N8VEM_UART_SCR: /* 16550 Scratchpad, implemented so software can detect UART is present */ + n8vem_info->uart_scr = cData; + break; + case N8VEM_MPCL_RAM: + case N8VEM_MPCL_RAM1: + case N8VEM_MPCL_RAM2: + case N8VEM_MPCL_RAM3: + TRACE_PRINT(MPCL_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: MPCL_RAM=0x%02x" NLP, PCX, cData)); + n8vem_info->mpcl_ram = cData; + break; + case N8VEM_MPCL_ROM: + case N8VEM_MPCL_ROM1: + case N8VEM_MPCL_ROM2: + case N8VEM_MPCL_ROM3: + TRACE_PRINT(MPCL_MSG, ("N8VEM: " ADDRESS_FORMAT " WR: MPCL_ROM=0x%02x" NLP, PCX, cData)); + n8vem_info->mpcl_rom = cData; + break; + default: + TRACE_PRINT(TRACE_MSG, ("N8VEM: " ADDRESS_FORMAT " WR[0x%02x]=0x%02x: not Implemented." NLP, PCX, Addr, cData)); + break; + } + + return(0); +} + diff --git a/AltairZ80/nasm.h b/AltairZ80/nasm.h new file mode 100644 index 00000000..87c2b387 --- /dev/null +++ b/AltairZ80/nasm.h @@ -0,0 +1,941 @@ +/* nasm.h main header file for the Netwide Assembler: inter-module interface + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + * + * initial version: 27/iii/95 by Simon Tatham + */ + +#ifndef NASM_NASM_H +#define NASM_NASM_H + +#include +#define NASM_VERSION_H +#define NASM_MAJOR_VER 0 +#define NASM_MINOR_VER 98 +#define NASM_SUBMINOR_VER 38 +#define NASM_PATCHLEVEL_VER 0 +#define NASM_VERSION_ID 0x00622600 +#define NASM_VER "0.98.38" + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef FALSE +#define FALSE 0 /* comes in handy */ +#endif +#ifndef TRUE +#define TRUE 1 +#endif + +#define NO_SEG -1L /* null segment value */ +#define SEG_ABS 0x40000000L /* mask for far-absolute segments */ + +#ifndef FILENAME_MAX +#define FILENAME_MAX 256 +#endif + +#ifndef PREFIX_MAX +#define PREFIX_MAX 10 +#endif + +#ifndef POSTFIX_MAX +#define POSTFIX_MAX 10 +#endif + +#define IDLEN_MAX 4096 + +/* + * Name pollution problems: on Digital UNIX pulls in some + * strange hardware header file which sees fit to define R_SP. We + * undefine it here so as not to break the enum below. + */ +#ifdef R_SP +#undef R_SP +#endif + +/* + * We must declare the existence of this structure type up here, + * since we have to reference it before we define it... + */ +struct ofmt; + +/* + * ------------------------- + * Error reporting functions + * ------------------------- + */ + +/* + * An error reporting function should look like this. + */ +typedef void (*efunc) (int severity, const char *fmt, ...); + +/* + * These are the error severity codes which get passed as the first + * argument to an efunc. + */ + +#define ERR_DEBUG 0x00000008 /* put out debugging message */ +#define ERR_WARNING 0x00000000 /* warn only: no further action */ +#define ERR_NONFATAL 0x00000001 /* terminate assembly after phase */ +#define ERR_FATAL 0x00000002 /* instantly fatal: exit with error */ +#define ERR_PANIC 0x00000003 /* internal error: panic instantly + * and dump core for reference */ +#define ERR_MASK 0x0000000F /* mask off the above codes */ +#define ERR_NOFILE 0x00000010 /* don't give source file name/line */ +#define ERR_USAGE 0x00000020 /* print a usage message */ +#define ERR_PASS1 0x00000040 /* only print this error on pass one */ + +/* + * These codes define specific types of suppressible warning. + */ + +#define ERR_WARN_MASK 0x0000FF00 /* the mask for this feature */ +#define ERR_WARN_SHR 8 /* how far to shift right */ + +#define ERR_WARN_MNP 0x00000100 /* macro-num-parameters warning */ +#define ERR_WARN_MSR 0x00000200 /* macro self-reference */ +#define ERR_WARN_OL 0x00000300 /* orphan label (no colon, and + * alone on line) */ +#define ERR_WARN_NOV 0x00000400 /* numeric overflow */ +#define ERR_WARN_GNUELF 0x00000500 /* using GNU ELF extensions */ +#define ERR_WARN_MAX 5 /* the highest numbered one */ + +/* + * ----------------------- + * Other function typedefs + * ----------------------- + */ + +/* + * A label-lookup function should look like this. + */ +typedef int (*lfunc) (char *label, long *segment, long *offset); + +/* + * And a label-definition function like this. The boolean parameter + * `is_norm' states whether the label is a `normal' label (which + * should affect the local-label system), or something odder like + * an EQU or a segment-base symbol, which shouldn't. + */ +typedef void (*ldfunc) (char *label, long segment, long offset, char *special, + int is_norm, int isextrn, struct ofmt *ofmt, + efunc error); + +/* + * List-file generators should look like this: + */ +typedef struct { + /* + * Called to initialise the listing file generator. Before this + * is called, the other routines will silently do nothing when + * called. The `char *' parameter is the file name to write the + * listing to. + */ + void (*init) (char *, efunc); + + /* + * Called to clear stuff up and close the listing file. + */ + void (*cleanup) (void); + + /* + * Called to output binary data. Parameters are: the offset; + * the data; the data type. Data types are similar to the + * output-format interface, only OUT_ADDRESS will _always_ be + * displayed as if it's relocatable, so ensure that any non- + * relocatable address has been converted to OUT_RAWDATA by + * then. Note that OUT_RAWDATA+0 is a valid data type, and is a + * dummy call used to give the listing generator an offset to + * work with when doing things like uplevel(LIST_TIMES) or + * uplevel(LIST_INCBIN). + */ + void (*output) (long, const void *, unsigned long); + + /* + * Called to send a text line to the listing generator. The + * `int' parameter is LIST_READ or LIST_MACRO depending on + * whether the line came directly from an input file or is the + * result of a multi-line macro expansion. + */ + void (*line) (int, char *); + + /* + * Called to change one of the various levelled mechanisms in + * the listing generator. LIST_INCLUDE and LIST_MACRO can be + * used to increase the nesting level of include files and + * macro expansions; LIST_TIMES and LIST_INCBIN switch on the + * two binary-output-suppression mechanisms for large-scale + * pseudo-instructions. + * + * LIST_MACRO_NOLIST is synonymous with LIST_MACRO except that + * it indicates the beginning of the expansion of a `nolist' + * macro, so anything under that level won't be expanded unless + * it includes another file. + */ + void (*uplevel) (int); + + /* + * Reverse the effects of uplevel. + */ + void (*downlevel) (int); +} ListGen; + +/* + * The expression evaluator must be passed a scanner function; a + * standard scanner is provided as part of nasmlib.c. The + * preprocessor will use a different one. Scanners, and the + * token-value structures they return, look like this. + * + * The return value from the scanner is always a copy of the + * `t_type' field in the structure. + */ +struct tokenval { + int t_type; + long t_integer, t_inttwo; + char *t_charptr; +}; +typedef int (*scanner) (void *private_data, struct tokenval *tv); + +/* + * Token types returned by the scanner, in addition to ordinary + * ASCII character values, and zero for end-of-string. + */ +enum { /* token types, other than chars */ + TOKEN_INVALID = -1, /* a placeholder value */ + TOKEN_EOS = 0, /* end of string */ + TOKEN_EQ = '=', TOKEN_GT = '>', TOKEN_LT = '<', /* aliases */ + TOKEN_ID = 256, TOKEN_NUM, TOKEN_REG, TOKEN_INSN, /* major token types */ + TOKEN_ERRNUM, /* numeric constant with error in */ + TOKEN_HERE, TOKEN_BASE, /* $ and $$ */ + TOKEN_SPECIAL, /* BYTE, WORD, DWORD, FAR, NEAR, etc */ + TOKEN_PREFIX, /* A32, O16, LOCK, REPNZ, TIMES, etc */ + TOKEN_SHL, TOKEN_SHR, /* << and >> */ + TOKEN_SDIV, TOKEN_SMOD, /* // and %% */ + TOKEN_GE, TOKEN_LE, TOKEN_NE, /* >=, <= and <> (!= is same as <>) */ + TOKEN_DBL_AND, TOKEN_DBL_OR, TOKEN_DBL_XOR, /* &&, || and ^^ */ + TOKEN_SEG, TOKEN_WRT, /* SEG and WRT */ + TOKEN_FLOAT /* floating-point constant */ +}; + +typedef struct { + long segment; + long offset; + int known; +} loc_t; + +/* + * Expression-evaluator datatype. Expressions, within the + * evaluator, are stored as an array of these beasts, terminated by + * a record with type==0. Mostly, it's a vector type: each type + * denotes some kind of a component, and the value denotes the + * multiple of that component present in the expression. The + * exception is the WRT type, whose `value' field denotes the + * segment to which the expression is relative. These segments will + * be segment-base types, i.e. either odd segment values or SEG_ABS + * types. So it is still valid to assume that anything with a + * `value' field of zero is insignificant. + */ +typedef struct { + long type; /* a register, or EXPR_xxx */ + long value; /* must be >= 32 bits */ +} expr; + +/* + * The evaluator can also return hints about which of two registers + * used in an expression should be the base register. See also the + * `operand' structure. + */ +struct eval_hints { + int base; + int type; +}; + +/* + * The actual expression evaluator function looks like this. When + * called, it expects the first token of its expression to already + * be in `*tv'; if it is not, set tv->t_type to TOKEN_INVALID and + * it will start by calling the scanner. + * + * If a forward reference happens during evaluation, the evaluator + * must set `*fwref' to TRUE if `fwref' is non-NULL. + * + * `critical' is non-zero if the expression may not contain forward + * references. The evaluator will report its own error if this + * occurs; if `critical' is 1, the error will be "symbol not + * defined before use", whereas if `critical' is 2, the error will + * be "symbol undefined". + * + * If `critical' has bit 8 set (in addition to its main value: 0x101 + * and 0x102 correspond to 1 and 2) then an extended expression + * syntax is recognised, in which relational operators such as =, < + * and >= are accepted, as well as low-precedence logical operators + * &&, ^^ and ||. + * + * If `hints' is non-NULL, it gets filled in with some hints as to + * the base register in complex effective addresses. + */ +#define CRITICAL 0x100 +typedef expr *(*evalfunc) (scanner sc, void *scprivate, struct tokenval *tv, + int *fwref, int critical, efunc error, + struct eval_hints *hints); + +/* + * Special values for expr->type. ASSUMPTION MADE HERE: the number + * of distinct register names (i.e. possible "type" fields for an + * expr structure) does not exceed 124 (EXPR_REG_START through + * EXPR_REG_END). + */ +#define EXPR_REG_START 1 +#define EXPR_REG_END 124 +#define EXPR_UNKNOWN 125L /* for forward references */ +#define EXPR_SIMPLE 126L +#define EXPR_WRT 127L +#define EXPR_SEGBASE 128L + +/* + * Preprocessors ought to look like this: + */ +typedef struct { + /* + * Called at the start of a pass; given a file name, the number + * of the pass, an error reporting function, an evaluator + * function, and a listing generator to talk to. + */ + void (*reset) (char *, int, efunc, evalfunc, ListGen *); + + /* + * Called to fetch a line of preprocessed source. The line + * returned has been malloc'ed, and so should be freed after + * use. + */ + char *(*getline) (void); + + /* + * Called at the end of a pass. + */ + void (*cleanup) (int); +} Preproc; + +/* + * ---------------------------------------------------------------- + * Some lexical properties of the NASM source language, included + * here because they are shared between the parser and preprocessor + * ---------------------------------------------------------------- + */ + +/* + * isidstart matches any character that may start an identifier, and isidchar + * matches any character that may appear at places other than the start of an + * identifier. E.g. a period may only appear at the start of an identifier + * (for local labels), whereas a number may appear anywhere *but* at the + * start. + */ + +#define isidstart(c) ( isalpha(c) || (c)=='_' || (c)=='.' || (c)=='?' \ + || (c)=='@' ) +#define isidchar(c) ( isidstart(c) || isdigit(c) || (c)=='$' || (c)=='#' \ + || (c)=='~' ) + +/* Ditto for numeric constants. */ + +#define isnumstart(c) ( isdigit(c) || (c)=='$' ) +#define isnumchar(c) ( isalnum(c) ) + +/* This returns the numeric value of a given 'digit'. */ + +#define numvalue(c) ((c)>='a' ? (c)-'a'+10 : (c)>='A' ? (c)-'A'+10 : (c)-'0') + +/* + * Data-type flags that get passed to listing-file routines. + */ +enum { + LIST_READ, LIST_MACRO, LIST_MACRO_NOLIST, LIST_INCLUDE, + LIST_INCBIN, LIST_TIMES +}; + +/* + * ----------------------------------------------------------- + * Format of the `insn' structure returned from `parser.c' and + * passed into `assemble.c' + * ----------------------------------------------------------- + */ + +/* + * Here we define the operand types. These are implemented as bit + * masks, since some are subsets of others; e.g. AX in a MOV + * instruction is a special operand type, whereas AX in other + * contexts is just another 16-bit register. (Also, consider CL in + * shift instructions, DX in OUT, etc.) + */ + +/* size, and other attributes, of the operand */ +#define BITS8 0x00000001L +#define BITS16 0x00000002L +#define BITS32 0x00000004L +#define BITS64 0x00000008L /* FPU only */ +#define BITS80 0x00000010L /* FPU only */ +#define FAR 0x00000020L /* grotty: this means 16:16 or */ + /* 16:32, like in CALL/JMP */ +#define NEAR 0x00000040L +#define SHORT 0x00000080L /* and this means what it says :) */ + +#define SIZE_MASK 0x000000FFL /* all the size attributes */ +#define NON_SIZE (~SIZE_MASK) + +#define TO 0x00000100L /* reverse effect in FADD, FSUB &c */ +#define COLON 0x00000200L /* operand is followed by a colon */ +#define STRICT 0x00000400L /* do not optimize this operand */ + +/* type of operand: memory reference, register, etc. */ +#define MEMORY 0x00204000L +#define REGISTER 0x00001000L /* register number in 'basereg' */ +#define IMMEDIATE 0x00002000L + +#define REGMEM 0x00200000L /* for r/m, ie EA, operands */ +#define REGNORM 0x00201000L /* 'normal' reg, qualifies as EA */ +#define REG8 0x00201001L +#define REG16 0x00201002L +#define REG32 0x00201004L +#define MMXREG 0x00201008L /* MMX registers */ +#define XMMREG 0x00201010L /* XMM Katmai reg */ +#define FPUREG 0x01000000L /* floating point stack registers */ +#define FPU0 0x01000800L /* FPU stack register zero */ + +/* special register operands: these may be treated differently */ +#define REG_SMASK 0x00070000L /* a mask for the following */ +#define REG_ACCUM 0x00211000L /* accumulator: AL, AX or EAX */ +#define REG_AL 0x00211001L /* REG_ACCUM | BITSxx */ +#define REG_AX 0x00211002L /* ditto */ +#define REG_EAX 0x00211004L /* and again */ +#define REG_COUNT 0x00221000L /* counter: CL, CX or ECX */ +#define REG_CL 0x00221001L /* REG_COUNT | BITSxx */ +#define REG_CX 0x00221002L /* ditto */ +#define REG_ECX 0x00221004L /* another one */ +#define REG_DL 0x00241001L +#define REG_DX 0x00241002L +#define REG_EDX 0x00241004L +#define REG_SREG 0x00081002L /* any segment register */ +#define REG_CS 0x01081002L /* CS */ +#define REG_DESS 0x02081002L /* DS, ES, SS (non-CS 86 registers) */ +#define REG_FSGS 0x04081002L /* FS, GS (386 extended registers) */ +#define REG_SEG67 0x08081002L /* Non-implemented segment registers */ +#define REG_CDT 0x00101004L /* CRn, DRn and TRn */ +#define REG_CREG 0x08101004L /* CRn */ +#define REG_DREG 0x10101004L /* DRn */ +#define REG_TREG 0x20101004L /* TRn */ + +/* special type of EA */ +#define MEM_OFFS 0x00604000L /* simple [address] offset */ + +/* special type of immediate operand */ +#define ONENESS 0x00800000L /* so UNITY == IMMEDIATE | ONENESS */ +#define UNITY 0x00802000L /* for shift/rotate instructions */ +#define BYTENESS 0x40000000L /* so SBYTE == IMMEDIATE | BYTENESS */ +#define SBYTE 0x40002000L /* for op r16/32,immediate instrs. */ + +/* Register names automatically generated from regs.dat */ +/* automatically generated from ./regs.dat - do not edit */ +enum reg_enum { + R_AH = EXPR_REG_START, + R_AL, + R_AX, + R_BH, + R_BL, + R_BP, + R_BX, + R_CH, + R_CL, + R_CR0, + R_CR1, + R_CR2, + R_CR3, + R_CR4, + R_CR5, + R_CR6, + R_CR7, + R_CS, + R_CX, + R_DH, + R_DI, + R_DL, + R_DR0, + R_DR1, + R_DR2, + R_DR3, + R_DR4, + R_DR5, + R_DR6, + R_DR7, + R_DS, + R_DX, + R_EAX, + R_EBP, + R_EBX, + R_ECX, + R_EDI, + R_EDX, + R_ES, + R_ESI, + R_ESP, + R_FS, + R_GS, + R_MM0, + R_MM1, + R_MM2, + R_MM3, + R_MM4, + R_MM5, + R_MM6, + R_MM7, + R_SEGR6, + R_SEGR7, + R_SI, + R_SP, + R_SS, + R_ST0, + R_ST1, + R_ST2, + R_ST3, + R_ST4, + R_ST5, + R_ST6, + R_ST7, + R_TR0, + R_TR1, + R_TR2, + R_TR3, + R_TR4, + R_TR5, + R_TR6, + R_TR7, + R_XMM0, + R_XMM1, + R_XMM2, + R_XMM3, + R_XMM4, + R_XMM5, + R_XMM6, + R_XMM7, + REG_ENUM_LIMIT +}; + +enum { /* condition code names */ + C_A, C_AE, C_B, C_BE, C_C, C_E, C_G, C_GE, C_L, C_LE, C_NA, C_NAE, + C_NB, C_NBE, C_NC, C_NE, C_NG, C_NGE, C_NL, C_NLE, C_NO, C_NP, + C_NS, C_NZ, C_O, C_P, C_PE, C_PO, C_S, C_Z +}; + +/* + * Note that because segment registers may be used as instruction + * prefixes, we must ensure the enumerations for prefixes and + * register names do not overlap. + */ +enum { /* instruction prefixes */ + PREFIX_ENUM_START = REG_ENUM_LIMIT, + P_A16 = PREFIX_ENUM_START, P_A32, P_LOCK, P_O16, P_O32, P_REP, P_REPE, + P_REPNE, P_REPNZ, P_REPZ, P_TIMES +}; + +enum { /* extended operand types */ + EOT_NOTHING, EOT_DB_STRING, EOT_DB_NUMBER +}; + +enum { /* special EA flags */ + EAF_BYTEOFFS = 1, /* force offset part to byte size */ + EAF_WORDOFFS = 2, /* force offset part to [d]word size */ + EAF_TIMESTWO = 4 /* really do EAX*2 not EAX+EAX */ +}; + +enum { /* values for `hinttype' */ + EAH_NOHINT = 0, /* no hint at all - our discretion */ + EAH_MAKEBASE = 1, /* try to make given reg the base */ + EAH_NOTBASE = 2 /* try _not_ to make reg the base */ +}; + +typedef struct { /* operand to an instruction */ + long type; /* type of operand */ + int addr_size; /* 0 means default; 16; 32 */ + int basereg, indexreg, scale; /* registers and scale involved */ + int hintbase, hinttype; /* hint as to real base register */ + long segment; /* immediate segment, if needed */ + long offset; /* any immediate number */ + long wrt; /* segment base it's relative to */ + int eaflags; /* special EA flags */ + int opflags; /* see OPFLAG_* defines below */ +} operand; + +#define OPFLAG_FORWARD 1 /* operand is a forward reference */ +#define OPFLAG_EXTERN 2 /* operand is an external reference */ + +typedef struct extop { /* extended operand */ + struct extop *next; /* linked list */ + long type; /* defined above */ + char *stringval; /* if it's a string, then here it is */ + int stringlen; /* ... and here's how long it is */ + long segment; /* if it's a number/address, then... */ + long offset; /* ... it's given here ... */ + long wrt; /* ... and here */ +} extop; + +#define MAXPREFIX 4 + +typedef struct { /* an instruction itself */ + char *label; /* the label defined, or NULL */ + int prefixes[MAXPREFIX]; /* instruction prefixes, if any */ + int nprefix; /* number of entries in above */ + int opcode; /* the opcode - not just the string */ + int condition; /* the condition code, if Jcc/SETcc */ + int operands; /* how many operands? 0-3 + * (more if db et al) */ + operand oprs[3]; /* the operands, defined as above */ + extop *eops; /* extended operands */ + int eops_float; /* true if DD and floating */ + long times; /* repeat count (TIMES prefix) */ + int forw_ref; /* is there a forward reference? */ +} insn; + +enum geninfo { GI_SWITCH }; +/* + * ------------------------------------------------------------ + * The data structure defining an output format driver, and the + * interfaces to the functions therein. + * ------------------------------------------------------------ + */ + +struct ofmt { + /* + * This is a short (one-liner) description of the type of + * output generated by the driver. + */ + const char *fullname; + + /* + * This is a single keyword used to select the driver. + */ + const char *shortname; + + /* + * this is reserved for out module specific help. + * It is set to NULL in all the out modules but is not implemented + * in the main program + */ + const char *helpstring; + + /* + * this is a pointer to the first element of the debug information + */ + struct dfmt **debug_formats; + + /* + * and a pointer to the element that is being used + * note: this is set to the default at compile time and changed if the + * -F option is selected. If developing a set of new debug formats for + * an output format, be sure to set this to whatever default you want + * + */ + struct dfmt *current_dfmt; + + /* + * This, if non-NULL, is a NULL-terminated list of `char *'s + * pointing to extra standard macros supplied by the object + * format (e.g. a sensible initial default value of __SECT__, + * and user-level equivalents for any format-specific + * directives). + */ + const char **stdmac; + + /* + * This procedure is called at the start of an output session. + * It tells the output format what file it will be writing to, + * what routine to report errors through, and how to interface + * to the label manager and expression evaluator if necessary. + * It also gives it a chance to do other initialisation. + */ + void (*init) (FILE *fp, efunc error, ldfunc ldef, evalfunc eval); + + /* + * This procedure is called to pass generic information to the + * object file. The first parameter gives the information type + * (currently only command line switches) + * and the second parameter gives the value. This function returns + * 1 if recognized, 0 if unrecognized + */ + int (*setinfo)(enum geninfo type, char **string); + + /* + * This procedure is called by assemble() to write actual + * generated code or data to the object file. Typically it + * doesn't have to actually _write_ it, just store it for + * later. + * + * The `type' argument specifies the type of output data, and + * usually the size as well: its contents are described below. + */ + void (*output) (long segto, const void *data, unsigned long type, + long segment, long wrt); + + /* + * This procedure is called once for every symbol defined in + * the module being assembled. It gives the name and value of + * the symbol, in NASM's terms, and indicates whether it has + * been declared to be global. Note that the parameter "name", + * when passed, will point to a piece of static storage + * allocated inside the label manager - it's safe to keep using + * that pointer, because the label manager doesn't clean up + * until after the output driver has. + * + * Values of `is_global' are: 0 means the symbol is local; 1 + * means the symbol is global; 2 means the symbol is common (in + * which case `offset' holds the _size_ of the variable). + * Anything else is available for the output driver to use + * internally. + * + * This routine explicitly _is_ allowed to call the label + * manager to define further symbols, if it wants to, even + * though it's been called _from_ the label manager. That much + * re-entrancy is guaranteed in the label manager. However, the + * label manager will in turn call this routine, so it should + * be prepared to be re-entrant itself. + * + * The `special' parameter contains special information passed + * through from the command that defined the label: it may have + * been an EXTERN, a COMMON or a GLOBAL. The distinction should + * be obvious to the output format from the other parameters. + */ + void (*symdef) (char *name, long segment, long offset, int is_global, + char *special); + + /* + * This procedure is called when the source code requests a + * segment change. It should return the corresponding segment + * _number_ for the name, or NO_SEG if the name is not a valid + * segment name. + * + * It may also be called with NULL, in which case it is to + * return the _default_ section number for starting assembly in. + * + * It is allowed to modify the string it is given a pointer to. + * + * It is also allowed to specify a default instruction size for + * the segment, by setting `*bits' to 16 or 32. Or, if it + * doesn't wish to define a default, it can leave `bits' alone. + */ + long (*section) (char *name, int pass, int *bits); + + /* + * This procedure is called to modify the segment base values + * returned from the SEG operator. It is given a segment base + * value (i.e. a segment value with the low bit set), and is + * required to produce in return a segment value which may be + * different. It can map segment bases to absolute numbers by + * means of returning SEG_ABS types. + * + * It should return NO_SEG if the segment base cannot be + * determined; the evaluator (which calls this routine) is + * responsible for throwing an error condition if that occurs + * in pass two or in a critical expression. + */ + long (*segbase) (long segment); + + /* + * This procedure is called to allow the output driver to + * process its own specific directives. When called, it has the + * directive word in `directive' and the parameter string in + * `value'. It is called in both assembly passes, and `pass' + * will be either 1 or 2. + * + * This procedure should return zero if it does not _recognise_ + * the directive, so that the main program can report an error. + * If it recognises the directive but then has its own errors, + * it should report them itself and then return non-zero. It + * should also return non-zero if it correctly processes the + * directive. + */ + int (*directive) (char *directive, char *value, int pass); + + /* + * This procedure is called before anything else - even before + * the "init" routine - and is passed the name of the input + * file from which this output file is being generated. It + * should return its preferred name for the output file in + * `outname', if outname[0] is not '\0', and do nothing to + * `outname' otherwise. Since it is called before the driver is + * properly initialised, it has to be passed its error handler + * separately. + * + * This procedure may also take its own copy of the input file + * name for use in writing the output file: it is _guaranteed_ + * that it will be called before the "init" routine. + * + * The parameter `outname' points to an area of storage + * guaranteed to be at least FILENAME_MAX in size. + */ + void (*filename) (char *inname, char *outname, efunc error); + + /* + * This procedure is called after assembly finishes, to allow + * the output driver to clean itself up and free its memory. + * Typically, it will also be the point at which the object + * file actually gets _written_. + * + * One thing the cleanup routine should always do is to close + * the output file pointer. + */ + void (*cleanup) (int debuginfo); +}; + +/* + * values for the `type' parameter to an output function. Each one + * must have the actual number of _bytes_ added to it. + * + * Exceptions are OUT_RELxADR, which denote an x-byte relocation + * which will be a relative jump. For this we need to know the + * distance in bytes from the start of the relocated record until + * the end of the containing instruction. _This_ is what is stored + * in the size part of the parameter, in this case. + * + * Also OUT_RESERVE denotes reservation of N bytes of BSS space, + * and the contents of the "data" parameter is irrelevant. + * + * The "data" parameter for the output function points to a "long", + * containing the address in question, unless the type is + * OUT_RAWDATA, in which case it points to an "unsigned char" + * array. + */ +#define OUT_RAWDATA 0x00000000UL +#define OUT_ADDRESS 0x10000000UL +#define OUT_REL2ADR 0x20000000UL +#define OUT_REL4ADR 0x30000000UL +#define OUT_RESERVE 0x40000000UL +#define OUT_TYPMASK 0xF0000000UL +#define OUT_SIZMASK 0x0FFFFFFFUL + +/* + * ------------------------------------------------------------ + * The data structure defining a debug format driver, and the + * interfaces to the functions therein. + * ------------------------------------------------------------ + */ + +struct dfmt { + + /* + * This is a short (one-liner) description of the type of + * output generated by the driver. + */ + const char *fullname; + + /* + * This is a single keyword used to select the driver. + */ + const char *shortname; + + + /* + * init - called initially to set up local pointer to object format, + * void pointer to implementation defined data, file pointer (which + * probably won't be used, but who knows?), and error function. + */ + void (*init) (struct ofmt * of, void * id, FILE * fp, efunc error); + + /* + * linenum - called any time there is output with a change of + * line number or file. + */ + void (*linenum) (const char * filename, long linenumber, long segto); + + /* + * debug_deflabel - called whenever a label is defined. Parameters + * are the same as to 'symdef()' in the output format. This function + * would be called before the output format version. + */ + + void (*debug_deflabel) (char * name, long segment, long offset, + int is_global, char * special); + /* + * debug_directive - called whenever a DEBUG directive other than 'LINE' + * is encountered. 'directive' contains the first parameter to the + * DEBUG directive, and params contains the rest. For example, + * 'DEBUG VAR _somevar:int' would translate to a call to this + * function with 'directive' equal to "VAR" and 'params' equal to + * "_somevar:int". + */ + void (*debug_directive) (const char * directive, const char * params); + + /* + * typevalue - called whenever the assembler wishes to register a type + * for the last defined label. This routine MUST detect if a type was + * already registered and not re-register it. + */ + void (*debug_typevalue) (long type); + + /* + * debug_output - called whenever output is required + * 'type' is the type of info required, and this is format-specific + */ + void (*debug_output) (int type, void *param); + + /* + * cleanup - called after processing of file is complete + */ + void (*cleanup) (void); + +}; +/* + * The type definition macros + * for debugging + * + * low 3 bits: reserved + * next 5 bits: type + * next 24 bits: number of elements for arrays (0 for labels) + */ + +#define TY_UNKNOWN 0x00 +#define TY_LABEL 0x08 +#define TY_BYTE 0x10 +#define TY_WORD 0x18 +#define TY_DWORD 0x20 +#define TY_FLOAT 0x28 +#define TY_QWORD 0x30 +#define TY_TBYTE 0x38 +#define TY_COMMON 0xE0 +#define TY_SEG 0xE8 +#define TY_EXTERN 0xF0 +#define TY_EQU 0xF8 + +#define TYM_TYPE(x) ((x) & 0xF8) +#define TYM_ELEMENTS(x) (((x) & 0xFFFFFF00) >> 8) + +#define TYS_ELEMENTS(x) ((x) << 8) +/* + * ----- + * Other + * ----- + */ + +/* + * This is a useful #define which I keep meaning to use more often: + * the number of elements of a statically defined array. + */ + +#define elements(x) ( sizeof(x) / sizeof(*(x)) ) + +extern int tasm_compatible_mode; + +/* + * This declaration passes the "pass" number to all other modules + * "pass0" assumes the values: 0, 0, ..., 0, 1, 2 + * where 0 = optimizing pass + * 1 = pass 1 + * 2 = pass 2 + */ + +extern int pass0; /* this is globally known */ +extern int optimizing; + +#endif diff --git a/AltairZ80/s100_64fdc.c b/AltairZ80/s100_64fdc.c new file mode 100644 index 00000000..c9d1104f --- /dev/null +++ b/AltairZ80/s100_64fdc.c @@ -0,0 +1,1541 @@ +/************************************************************************* + * * + * $Id: s100_64fdc.c 1907 2008-05-21 07:04:17Z hharte $ * + * * + * Copyright (c) 2007-2008 Howard M. Harte. * + * http://www.hartetec.com * + * * + * 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 HOWARD M. HARTE 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 Howard M. Harte shall * + * not be used in advertising or otherwise to promote the sale, use or * + * other dealings in this Software without prior written authorization * + * Howard M. Harte. * + * * + * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. * + * * + * Module Description: * + * Cromemco 4FDC/16FDC/64FDC Floppy Controller module for SIMH. * + * This module is a wrapper around the wd179x FDC module, and adds the * + * Cromemco-specific registers as well as the Cromemco RDOS Boot ROM. * + * * + * Environment: * + * User mode only * + * * + *************************************************************************/ + +/*#define DBG_MSG */ +#define DBG_MSG +#include "altairz80_defs.h" + +#if defined (_WIN32) +#include +#endif + +#include "sim_defs.h" /* simulator definitions */ +#include "wd179x.h" + +#ifdef DBG_MSG +#define DBG_PRINT(args) printf args +#else +#define DBG_PRINT(args) +#endif + +#define SEEK_MSG 0x01 +#define CMD_MSG 0x04 +#define RD_DATA_MSG 0x08 +#define WR_DATA_MSG 0x10 +#define STATUS_MSG 0x20 +#define DRIVE_MSG 0x40 +#define VERBOSE_MSG 0x80 + +#define CROMFDC_MAX_DRIVES 4 +#define CROMFDC_ROM_SIZE (8 * 1024) +#define CROMFDC_ADDR_MASK (CROMFDC_ROM_SIZE - 1) + +typedef struct { + PNP_INFO pnp; /* Plug and Play */ + uint32 dma_addr; /* DMA Transfer Address */ + uint8 rom_disabled; /* TRUE if ROM has been disabled */ + uint8 motor_on; + uint8 autowait; + uint8 rtc; +} CROMFDC_INFO; + +extern WD179X_INFO_PUB *wd179x_info; + +static CROMFDC_INFO cromfdc_info_data = { { 0xC000, CROMFDC_ROM_SIZE, 0x3, 2 } }; +static CROMFDC_INFO *cromfdc_info = &cromfdc_info_data; + +extern t_stat set_membase(UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat show_membase(FILE *st, UNIT *uptr, int32 val, void *desc); +extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc); +extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, + int32 (*routine)(const int32, const int32, const int32), uint8 unmap); + +t_stat cromfdc_svc (UNIT *uptr); + +extern REG *sim_PC; +extern uint32 PCX; /* external view of PC */ + +#define UNIT_V_CROMFDC_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_CROMFDC_WLK (1 << UNIT_V_CROMFDC_WLK) +#define UNIT_V_CROMFDC_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ +#define UNIT_CROMFDC_VERBOSE (1 << UNIT_V_CROMFDC_VERBOSE) +#define UNIT_V_CROMFDC_ROM (UNIT_V_UF + 2) /* boot ROM enabled */ +#define UNIT_CROMFDC_ROM (1 << UNIT_V_CROMFDC_ROM) +#define CROMFDC_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */ + +#define MOTOR_TO_LIMIT 128 + +static t_stat cromfdc_reset(DEVICE *cromfdc_dev); +static t_stat cromfdc_boot(int32 unitno, DEVICE *dptr); +static t_stat cromfdc_attach(UNIT *uptr, char *cptr); +static t_stat cromfdc_detach(UNIT *uptr); + +static int32 cromfdc_ext(const int32 port, const int32 io, const int32 data); +static int32 cromfdc_timer(const int32 port, const int32 io, const int32 data); +static int32 cromfdc_control(const int32 port, const int32 io, const int32 data); +static int32 cromfdc_banksel(const int32 port, const int32 io, const int32 data); +static int32 cromfdcrom(const int32 port, const int32 io, const int32 data); + +static int32 dipswitch = 0; /* 5-position DIP switch on 64FDC card */ +static int32 trace_level = 0; /* Disable all tracing by default */ +static int32 bootstrap = 0; /* 0 for RDOS 2.52, 1 for RDOS 3.12. */ +static int32 crofdc_type = 64; /* controller type, either 4, 16, or 64. */ +static int32 crofdc_boot = 1; /* BOOT jumper setting, default is auto-boot */ +static int32 crofdc_inh_init = 0; /* Inhibit Init (Format) switch, default is not inhibited */ + +/* Disk Control/Flags Register, 0x34 (IN) */ +#define CROMFDC_FLAG_DRQ (1 << 7) /* DRQ (All controllers) */ +#define CROMFDC_FLAG_BOOT (1 << 6) /* boot# jumper (active low) (All controllers) */ +#define CROMFDC_FLAG_SEL_REQ (1 << 5) /* Head Load (4FDC, 16FDC) / Select Request (64FDC) */ +#define CROMFDC_FLAG_INH_INIT (1 << 4) /* Unassigned (4FDC) / Inhibit_Init# (16FDC, 64FDC) */ +#define CROMFDC_FLAG_MTRON (1 << 3) /* Unassigned (4FDC) / Motor On (16FDC, 64FDC) */ +#define CROMFDC_FLAG_MTO (1 << 2) /* Unassigned (4FDC) / Motor Timeout (16FDC, 64FDC) */ +#define CROMFDC_FLAG_ATO (1 << 1) /* Unassigned (4FDC) / Autowait Timeout (16FDC, 64FDC) */ +#define CROMFDC_FLAG_EOJ (1 << 0) /* End of Job (INTRQ) (All Controllers) (16FDC, 64FDC) */ + +/* Disk Control/Flags Register, 0x34 (OUT) */ +#define CROMFDC_CTRL_AUTOWAIT (1 << 7) /* Auto Wait Enable (All controllers) */ +#define CROMFDC_CTRL_DDENS (1 << 6) /* Unassigned (4FDC) / Double Density (16FDC, 64FDC) */ +#define CROMFDC_CTRL_MTRON (1 << 5) /* Motor On (All controllers) */ +#define CROMFDC_CTRL_MAXI (1 << 4) /* Maxi (8") (All controllers) */ +#define CROMFDC_CTRL_DS4 (1 << 3) /* Drive Select 4 (All controllers) */ +#define CROMFDC_CTRL_DS3 (1 << 2) /* Drive Select 3 (All controllers) */ +#define CROMFDC_CTRL_DS2 (1 << 1) /* Drive Select 2 (All controllers) */ +#define CROMFDC_CTRL_DS1 (1 << 0) /* Drive Select 1 (All controllers) */ + +/* 64FDC Auxiliary Disk Command, 0x04 (OUT) */ +#define CROMFDC_AUX_RESERVED0 (1 << 0) /* Unused (All Controllers) */ +#define CROMFDC_AUX_CMD_SIDE (1 << 1) /* 16FDC, 64FDC: Side Select* Low=Side 1, High=Side 0. */ +#define CROMFDC_AUX_CTRL_OUT (1 << 2) /* Control Out* (All Controllers) */ +#define CROMFDC_AUX_RESTORE (1 << 3) /* 4FDC, 16FDC Restore* / 64FDC Unused */ +#define CROMFDC_AUX_FAST_SEEK (1 << 4) /* 4FDC, 16FDC Fast Seek* / 64FDC Unused */ +#define CROMFDC_AUX_SEL_OVERRIDE (1 << 5) /* 4FDC Eject Right* / 16FDC, 64FDC Drive Select Override */ +#define CROMFDC_AUX_EJECT (1 << 6) /* 4FDC Eject Left* / 16FDC Eject*, 64FDC Unused */ +#define CROMFDC_AUX_RESERVED7 (1 << 7) /* Unused (All Controllers) */ + + + +/* The CROMFDC does not really have RAM associated with it, but for ease of integration with the + * SIMH/AltairZ80 Resource Mapping Scheme, rather than Map and Unmap the ROM, simply implement our + * own RAM that can be swapped in when the CROMFDC Boot ROM is disabled. + */ +static uint8 cromfdcram[CROMFDC_ROM_SIZE]; + +static UNIT cromfdc_unit[] = { + { UDATA (&cromfdc_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE + UNIT_CROMFDC_ROM, CROMFDC_CAPACITY), 1024 }, + { UDATA (&cromfdc_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, CROMFDC_CAPACITY) }, + { UDATA (&cromfdc_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, CROMFDC_CAPACITY) }, + { UDATA (&cromfdc_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, CROMFDC_CAPACITY) } +}; + +static REG cromfdc_reg[] = { + { HRDATA (DIPSW, dipswitch, 16), }, + { HRDATA (TRACELEVEL, trace_level, 16), }, + { DRDATA (BOOTSTRAP, bootstrap, 10), }, + { DRDATA (FDCTYPE, crofdc_type, 10), }, + { DRDATA (BOOT, crofdc_boot, 10), }, + { DRDATA (INHINIT, crofdc_inh_init, 10), }, + { NULL } +}; + +static MTAB cromfdc_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE", &set_membase, &show_membase, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL }, + { UNIT_CROMFDC_WLK, 0, "WRTENB", "WRTENB", NULL }, + { UNIT_CROMFDC_WLK, UNIT_CROMFDC_WLK, "WRTLCK", "WRTLCK", NULL }, + /* quiet, no warning messages */ + { UNIT_CROMFDC_VERBOSE, 0, "QUIET", "QUIET", NULL }, + /* verbose, show warning messages */ + { UNIT_CROMFDC_VERBOSE, UNIT_CROMFDC_VERBOSE, "VERBOSE", "VERBOSE", NULL }, + { UNIT_CROMFDC_ROM, 0, "NOROM", "NOROM", NULL }, + { UNIT_CROMFDC_ROM, UNIT_CROMFDC_ROM, "ROM", "ROM", NULL }, + { 0 } +}; + +DEVICE cromfdc_dev = { + "CROMFDC", cromfdc_unit, cromfdc_reg, cromfdc_mod, + CROMFDC_MAX_DRIVES, 10, 31, 1, CROMFDC_MAX_DRIVES, CROMFDC_MAX_DRIVES, + NULL, NULL, &cromfdc_reset, + &cromfdc_boot, &cromfdc_attach, &cromfdc_detach, + &cromfdc_info_data, (DEV_DISABLE | DEV_DIS), 0, + NULL, NULL, NULL +}; + +/* This is the CROMFDC RDOS-II ROM. + * The CROMFDC has a single 8K ROM; however ths simulation includes + * two different versions of RDOS: + * RDOS 2.52 and RDOS 3.12 + * RDOS 2.52 is the default, but RDOS 3.12 can be + * selected with 'd cromfdc bootstrap ' at the SIMH SCP Prompt. + */ +static uint8 cromfdc_rom[2][CROMFDC_ROM_SIZE] = { +{ /* RDOS 2.52 */ + 0xF3, 0x18, 0x3C, 0xC3, 0x30, 0xC0, 0xC3, 0x04, 0xC5, 0xC3, 0x37, 0xC0, 0xC3, 0x3B, 0xC0, 0xC3, + 0x9E, 0xCB, 0xC3, 0x37, 0xCD, 0xC3, 0xD4, 0xC4, 0xC3, 0x52, 0xCD, 0xC3, 0xAB, 0xC5, 0xC3, 0x4B, + 0xC2, 0xC3, 0x6C, 0xCC, 0xC3, 0x76, 0xCC, 0xC3, 0xEA, 0xCB, 0xC3, 0xFE, 0xC7, 0xC3, 0x97, 0xCC, + 0x32, 0x77, 0x00, 0x78, 0xC3, 0x87, 0xC3, 0x32, 0x75, 0x00, 0xC9, 0x32, 0x76, 0x00, 0xC9, 0xAF, + 0xD3, 0x03, 0x47, 0xD9, 0x2F, 0xD3, 0x04, 0x3E, 0xD0, 0xD3, 0x30, 0x21, 0x2E, 0x00, 0xF9, 0x25, + 0x20, 0xFD, 0x74, 0x2C, 0x20, 0xFC, 0x24, 0x22, 0x62, 0x00, 0x22, 0x64, 0x00, 0xCD, 0x4B, 0xC2, + 0xDB, 0x34, 0xE6, 0x40, 0xC2, 0x39, 0xC1, 0xDB, 0x04, 0x2F, 0xE6, 0x03, 0x32, 0x77, 0x00, 0xCD, + 0x06, 0xC8, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x62, + 0x6F, 0x6F, 0x74, 0x2C, 0x20, 0x45, 0x53, 0x43, 0x20, 0x74, 0x6F, 0x20, 0x61, 0x62, 0x6F, 0x72, + 0x74, 0x8D, 0xCD, 0xA8, 0xCF, 0x57, 0xD3, 0x34, 0x06, 0x64, 0xCD, 0x28, 0xC1, 0x21, 0x64, 0x00, + 0xCD, 0xF1, 0xCF, 0x10, 0xF5, 0x32, 0x75, 0x00, 0x32, 0x7D, 0x00, 0x32, 0x78, 0x00, 0x3C, 0x32, + 0x76, 0x00, 0xCD, 0xF7, 0xC1, 0x32, 0x7E, 0x00, 0x21, 0x80, 0x00, 0x22, 0x7B, 0x00, 0x22, 0x79, + 0x00, 0x3E, 0x42, 0x32, 0x70, 0x00, 0x06, 0x02, 0xC5, 0xCD, 0x37, 0xCD, 0xD4, 0xCB, 0xCD, 0xD4, + 0x52, 0xCD, 0xC1, 0x30, 0x13, 0xCD, 0x28, 0xC1, 0x10, 0xEE, 0xCD, 0x06, 0xC8, 0x0D, 0x55, 0x6E, + 0x61, 0x62, 0x6C, 0x65, 0x20, 0xF4, 0x18, 0x2D, 0x3A, 0x80, 0x00, 0xFE, 0x40, 0x28, 0x04, 0xFE, + 0xE5, 0x20, 0x07, 0xCD, 0x06, 0xC8, 0x0D, 0xCE, 0x18, 0x1B, 0xCD, 0x28, 0xC1, 0xCD, 0xA8, 0xCF, + 0x57, 0x3A, 0x77, 0x00, 0x08, 0xCD, 0x06, 0xC8, 0x0D, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x62, 0x79, + 0x8D, 0x37, 0xC3, 0x80, 0x00, 0xCD, 0x06, 0xC8, 0x6F, 0x20, 0x62, 0x6F, 0x6F, 0x74, 0x8D, 0x3A, + 0x71, 0x00, 0xB7, 0xC4, 0x59, 0xC3, 0x18, 0x09, 0xCD, 0x76, 0xCC, 0xC4, 0x6C, 0xCC, 0xFE, 0x1B, + 0xC0, 0x3E, 0xD0, 0xD3, 0x30, 0x3E, 0x7C, 0xD3, 0x04, 0xCD, 0x06, 0xC8, 0x0D, 0x43, 0x72, 0x6F, + 0x6D, 0x65, 0x6D, 0x63, 0x6F, 0x20, 0x52, 0x44, 0x4F, 0x53, 0x20, 0x30, 0x32, 0x2E, 0x35, 0x32, + 0x8D, 0xAF, 0x32, 0x6C, 0x00, 0x3A, 0x7E, 0x00, 0x47, 0xCD, 0xE2, 0xC1, 0x31, 0x2E, 0x00, 0xCD, + 0x06, 0xC8, 0xBB, 0xCD, 0xA3, 0xC7, 0xCD, 0x14, 0xC8, 0xA7, 0x28, 0xE5, 0xCD, 0xC1, 0xC2, 0x28, + 0xE4, 0x78, 0xFE, 0x17, 0x30, 0x47, 0x87, 0x21, 0x8B, 0xC1, 0xCD, 0x86, 0xC1, 0x7E, 0x23, 0x66, + 0x6F, 0xCD, 0xC7, 0xC1, 0x18, 0xCF, 0x85, 0x6F, 0xD0, 0x24, 0xC9, 0xFD, 0xCC, 0xC8, 0xC1, 0xBD, + 0xC1, 0x2B, 0xC7, 0x2A, 0xC6, 0xBD, 0xC1, 0xC4, 0xC1, 0xBD, 0xC1, 0x45, 0xC2, 0xBD, 0xC1, 0xBD, + 0xC1, 0x39, 0xC4, 0x45, 0xC6, 0xBD, 0xC1, 0x36, 0xC6, 0xBD, 0xC1, 0xC2, 0xC6, 0x16, 0xC5, 0x7A, + 0xC6, 0x41, 0xC9, 0xBD, 0xC1, 0x52, 0xC6, 0x1A, 0xC5, 0xAF, 0x32, 0x6C, 0x00, 0xCD, 0x06, 0xC8, + 0x3F, 0x8D, 0x18, 0x91, 0xCD, 0x53, 0xC8, 0xE9, 0xCD, 0x14, 0xC8, 0xB7, 0xCA, 0x67, 0xC0, 0xFE, + 0x45, 0xD2, 0x2A, 0xC4, 0xD6, 0x41, 0xDA, 0x2A, 0xC4, 0xF5, 0x13, 0xCD, 0x27, 0xC8, 0xF1, 0xC3, + 0x6C, 0xC0, 0x3A, 0x6C, 0x00, 0xB7, 0xC8, 0xCD, 0xFE, 0xC7, 0xCB, 0x58, 0xC0, 0xCB, 0x78, 0x3E, + 0x3B, 0xC4, 0xFE, 0xC7, 0xC3, 0xFE, 0xC7, 0x7A, 0xD3, 0x34, 0x3E, 0xDF, 0xD3, 0x04, 0x3E, 0xD4, + 0xD3, 0x30, 0xDB, 0x34, 0x0F, 0x30, 0xFB, 0xDB, 0x30, 0x01, 0x00, 0x02, 0xCD, 0x3B, 0xC2, 0x3E, + 0xD4, 0xD3, 0x30, 0xCD, 0x34, 0xC2, 0x28, 0xDF, 0xDB, 0x34, 0x0F, 0x30, 0xF6, 0xDB, 0x30, 0x10, + 0xEE, 0xAF, 0xD3, 0x03, 0x79, 0xFE, 0x5A, 0x30, 0x03, 0x87, 0x87, 0x87, 0xFE, 0xB7, 0x3E, 0x80, + 0xD0, 0x3E, 0x04, 0xC9, 0xDB, 0x03, 0xFE, 0xC7, 0xC0, 0x0C, 0xC8, 0x3E, 0x01, 0xD3, 0x03, 0x3E, + 0xFA, 0xD3, 0x05, 0x18, 0xEF, 0xCD, 0x27, 0xC8, 0xCD, 0x97, 0xCC, 0xDB, 0x04, 0xE6, 0x08, 0x28, + 0x5D, 0x3E, 0x0A, 0xD3, 0x02, 0x21, 0xD0, 0x07, 0xCD, 0xF1, 0xCF, 0x3E, 0x08, 0xD3, 0x02, 0x16, + 0x64, 0x15, 0x28, 0xED, 0x21, 0xB9, 0xC2, 0x0E, 0x00, 0x3E, 0x19, 0x06, 0x09, 0xD3, 0x02, 0xED, + 0xA3, 0x28, 0xEE, 0xCD, 0x98, 0xC2, 0xCD, 0x98, 0xC2, 0x38, 0xE9, 0xFE, 0x0D, 0x3E, 0x09, 0x20, + 0xEC, 0x3E, 0x0D, 0xD3, 0x01, 0x21, 0xA0, 0x0F, 0xCD, 0xF1, 0xCF, 0xCD, 0x76, 0xCC, 0xC4, 0x6C, + 0xCC, 0xFE, 0x0D, 0x28, 0xEC, 0xC3, 0x97, 0xCC, 0xD5, 0x11, 0xA0, 0x8C, 0xCD, 0x76, 0xCC, 0x28, + 0x05, 0xCD, 0x6C, 0xCC, 0x18, 0x06, 0x1B, 0x7A, 0xB3, 0x20, 0xF1, 0x37, 0xD1, 0xC9, 0x3E, 0x09, + 0xD3, 0x02, 0x3E, 0x84, 0xD3, 0x00, 0xC3, 0x97, 0xCC, 0x90, 0xC0, 0xA0, 0x90, 0x88, 0x84, 0x82, + 0x01, 0xD6, 0x41, 0xDA, 0xBD, 0xC1, 0x47, 0x13, 0x1A, 0xFE, 0x3B, 0xC0, 0x78, 0xFE, 0x04, 0xD2, + 0x2A, 0xC4, 0xC6, 0x41, 0x32, 0x6C, 0x00, 0xCD, 0xF6, 0xC3, 0x13, 0x1A, 0xFE, 0x3B, 0x06, 0x0C, + 0x20, 0x0B, 0x13, 0x1A, 0xFE, 0x3B, 0x06, 0x04, 0x20, 0x03, 0x06, 0x80, 0x13, 0xC5, 0xCD, 0xB7, + 0xC3, 0xC1, 0x70, 0x30, 0x06, 0x3A, 0x6D, 0x00, 0xB0, 0x77, 0x37, 0xF5, 0xCD, 0x84, 0xC3, 0x32, + 0x78, 0x00, 0x32, 0x7D, 0x00, 0x3C, 0x32, 0x76, 0x00, 0xCD, 0x04, 0xC6, 0x3E, 0x48, 0x32, 0x70, + 0x00, 0xCD, 0x37, 0xCD, 0xF5, 0xCD, 0x1E, 0xC6, 0xF1, 0xDA, 0x0D, 0xC4, 0xF1, 0xDA, 0xB5, 0xC3, + 0xCD, 0x04, 0xC6, 0x21, 0x00, 0x01, 0x22, 0x7B, 0x00, 0xCD, 0xCB, 0xCD, 0xCD, 0x52, 0xCD, 0xF5, + 0xCD, 0x1E, 0xC6, 0xF1, 0x30, 0x2D, 0x3A, 0x71, 0x00, 0xB7, 0xF2, 0x45, 0xC3, 0x21, 0x64, 0x00, + 0xCD, 0xF1, 0xCF, 0x18, 0xDB, 0xCD, 0x06, 0xC8, 0x43, 0x61, 0x6E, 0x27, 0x74, 0x20, 0x72, 0x65, + 0x61, 0x64, 0x20, 0x4C, 0x61, 0x62, 0x65, 0x6C, 0x8D, 0x1E, 0x01, 0xCD, 0xF2, 0xC5, 0xCD, 0x13, + 0xC4, 0xAF, 0xC9, 0x01, 0x10, 0x00, 0x11, 0x7A, 0x01, 0xCD, 0xEE, 0xC3, 0x0E, 0x01, 0xCD, 0xEE, + 0xC3, 0x3A, 0x78, 0x01, 0xFE, 0x43, 0x20, 0x02, 0xCB, 0xC8, 0x3A, 0x7E, 0x00, 0xE6, 0xCC, 0xB0, + 0x2A, 0x6A, 0x00, 0x77, 0xCD, 0xF6, 0xC3, 0x32, 0x7E, 0x00, 0xCB, 0x47, 0x11, 0x0A, 0x10, 0x21, + 0x00, 0x02, 0x20, 0x0D, 0xCB, 0x4F, 0x11, 0x05, 0x08, 0x20, 0x06, 0x11, 0x12, 0x1A, 0x21, 0x80, + 0x00, 0x22, 0x79, 0x00, 0xCB, 0x7F, 0x3E, 0x4C, 0x42, 0x28, 0x03, 0x3E, 0x27, 0x43, 0x32, 0x6F, + 0x00, 0x78, 0x32, 0x6E, 0x00, 0xAF, 0xC9, 0xCD, 0x14, 0xC8, 0xB7, 0xC8, 0x01, 0x10, 0x00, 0xCD, + 0xDE, 0xC3, 0x0E, 0x01, 0xCD, 0xDE, 0xC3, 0xCD, 0x14, 0xC8, 0xFE, 0x43, 0x20, 0x06, 0xCB, 0xC8, + 0x13, 0xCD, 0x14, 0xC8, 0xB7, 0xC2, 0xB9, 0xC1, 0x78, 0x32, 0x6D, 0x00, 0x37, 0xC9, 0xCD, 0x14, + 0xC8, 0x13, 0xFE, 0x53, 0xC8, 0xFE, 0x44, 0xC2, 0xB9, 0xC1, 0x78, 0xB1, 0x47, 0xC9, 0x1A, 0x13, + 0x13, 0xFE, 0x44, 0xC0, 0x18, 0xF4, 0x3A, 0x6C, 0x00, 0xD6, 0x41, 0x32, 0x77, 0x00, 0x21, 0x66, + 0x00, 0xCD, 0x86, 0xC1, 0x22, 0x6A, 0x00, 0x7E, 0xB7, 0xC9, 0xCD, 0xF2, 0xC5, 0xCD, 0x13, 0xC4, + 0xC3, 0x55, 0xC1, 0xCD, 0x06, 0xC8, 0x20, 0x45, 0x72, 0x72, 0xAD, 0x3A, 0x70, 0x00, 0xCD, 0xFE, + 0xC7, 0x3A, 0x71, 0x00, 0xCD, 0xDB, 0xC7, 0xC3, 0x97, 0xCC, 0xCD, 0x06, 0xC8, 0x41, 0x2D, 0x44, + 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x8D, 0xC3, 0x55, 0xC1, 0xCD, 0x27, 0xC8, 0x3A, 0x77, 0x00, 0xF5, + 0x3A, 0x6C, 0x00, 0xF5, 0x3E, 0x41, 0xF5, 0x32, 0x6C, 0x00, 0xCD, 0xF6, 0xC3, 0x2A, 0x6A, 0x00, + 0x46, 0xC4, 0x63, 0xC4, 0xF1, 0x3C, 0xFE, 0x45, 0x38, 0xEC, 0xF1, 0x32, 0x6C, 0x00, 0xF1, 0x32, + 0x77, 0x00, 0xC9, 0xCD, 0x06, 0xC8, 0x20, 0xA0, 0xCD, 0xE2, 0xC1, 0xCD, 0x06, 0xC8, 0x3B, 0xA0, + 0xCB, 0x58, 0xC4, 0xFC, 0xC7, 0xCB, 0x78, 0xCC, 0xFC, 0xC7, 0xCB, 0x60, 0xCD, 0x98, 0xC4, 0xCD, + 0xFC, 0xC7, 0xCB, 0x40, 0xCD, 0x98, 0xC4, 0xCB, 0x48, 0x28, 0x0A, 0xCD, 0x06, 0xC8, 0x20, 0x43, + 0x72, 0x6F, 0x6D, 0x69, 0xF8, 0xC3, 0x97, 0xCC, 0x3E, 0x44, 0x20, 0x02, 0x3E, 0x53, 0xC3, 0xFE, + 0xC7, 0x47, 0x3A, 0x6C, 0x00, 0xB7, 0xCA, 0xBD, 0xC1, 0x78, 0xFE, 0x53, 0x28, 0x2C, 0xCD, 0xB0, + 0xC8, 0xDA, 0xBD, 0xC1, 0xE5, 0xCD, 0xE1, 0xC4, 0x3E, 0x53, 0x32, 0x70, 0x00, 0xE1, 0xAF, 0xB4, + 0xC2, 0xBD, 0xC1, 0x3A, 0x6F, 0x00, 0xBD, 0x38, 0xE8, 0x7D, 0x32, 0x75, 0x00, 0xCD, 0xD4, 0xC4, + 0xD0, 0xC3, 0x0D, 0xC4, 0xCD, 0xF8, 0xC5, 0xC3, 0xCB, 0xCD, 0x13, 0xCD, 0xE1, 0xC4, 0xC3, 0xCB, + 0xCD, 0x3A, 0x75, 0x00, 0x32, 0x7D, 0x00, 0xCD, 0xAD, 0xC8, 0xD8, 0xAF, 0xB4, 0xC2, 0xBD, 0xC1, + 0x7D, 0xB7, 0x20, 0x04, 0x32, 0x78, 0x00, 0xC9, 0x3D, 0x20, 0xF2, 0xCD, 0xF6, 0xC3, 0xCB, 0x67, + 0x28, 0x06, 0x3E, 0x01, 0x32, 0x78, 0x00, 0xC9, 0xCD, 0x06, 0xC8, 0x53, 0x2E, 0x53, 0x69, 0x64, + 0x65, 0x64, 0x8D, 0xC3, 0x55, 0xC1, 0x06, 0x52, 0x18, 0x02, 0x06, 0x57, 0x1A, 0xFE, 0x44, 0xC2, + 0xBD, 0xC1, 0x78, 0x32, 0x70, 0x00, 0xCD, 0xBB, 0xC5, 0xE5, 0xFD, 0xE1, 0x60, 0x69, 0xD5, 0xE5, + 0x7B, 0x32, 0x76, 0x00, 0xFD, 0x22, 0x7B, 0x00, 0xCD, 0xD4, 0xC4, 0x3A, 0x70, 0x00, 0xFE, 0x57, + 0x37, 0x3F, 0xCC, 0xAB, 0xC5, 0x38, 0x08, 0x3A, 0x70, 0x00, 0xFE, 0x52, 0xCC, 0x52, 0xCD, 0xE1, + 0xD1, 0xDA, 0x0A, 0xC4, 0xED, 0x4B, 0x79, 0x00, 0xFD, 0x09, 0x03, 0xED, 0x42, 0x23, 0xDA, 0xF2, + 0xC5, 0x1C, 0x3A, 0x6E, 0x00, 0xBB, 0x30, 0xC6, 0x3A, 0x75, 0x00, 0x32, 0x7D, 0x00, 0x3C, 0x47, + 0x3A, 0x6F, 0x00, 0xB8, 0x38, 0x08, 0x78, 0x32, 0x75, 0x00, 0x1E, 0x01, 0x18, 0xB0, 0x1D, 0xCD, + 0xF2, 0xC5, 0xCD, 0x06, 0xC8, 0x4E, 0x65, 0x78, 0x74, 0x20, 0x6D, 0x65, 0x6D, 0x6F, 0x72, 0x79, + 0x3A, 0xA0, 0xFD, 0xE5, 0xE1, 0xCD, 0xE2, 0xC7, 0xCD, 0x06, 0xC8, 0x0D, 0x45, 0x6E, 0x64, 0x20, + 0x6F, 0x66, 0x20, 0x44, 0x69, 0x73, 0x6B, 0x8D, 0xC3, 0x55, 0xC1, 0x21, 0x7E, 0x00, 0x46, 0xC5, + 0xCB, 0xCE, 0xCD, 0x5F, 0xCD, 0xC1, 0x78, 0x32, 0x7E, 0x00, 0xC9, 0x3A, 0x6C, 0x00, 0xB7, 0xCA, + 0xBD, 0xC1, 0x13, 0xCD, 0x2F, 0xC8, 0xAF, 0xB2, 0xC2, 0xBD, 0xC1, 0xB3, 0xCA, 0xBD, 0xC1, 0xC5, + 0xD5, 0xE5, 0xCD, 0xF8, 0xC5, 0xE1, 0xD1, 0xC1, 0x3A, 0x6E, 0x00, 0xBB, 0x38, 0xEA, 0xDB, 0x31, + 0x57, 0xEB, 0xCD, 0xFC, 0xC7, 0xCD, 0xE2, 0xC7, 0xEB, 0xCD, 0xFC, 0xC7, 0x3A, 0x78, 0x00, 0xC3, + 0xF0, 0xC7, 0xCD, 0xDE, 0xC5, 0xC3, 0x97, 0xCC, 0x3A, 0x75, 0x00, 0xB7, 0x20, 0x20, 0x3A, 0x78, + 0x00, 0xB7, 0x20, 0x1A, 0x3A, 0x7E, 0x00, 0xCB, 0x6F, 0xC0, 0xCB, 0x4F, 0x20, 0x03, 0xCB, 0x47, + 0xC8, 0x32, 0x7F, 0x00, 0xCB, 0xEF, 0xCB, 0x87, 0x32, 0x7E, 0x00, 0xC3, 0x9B, 0xC3, 0x3A, 0x7E, + 0x00, 0xCB, 0x6F, 0xC8, 0x3A, 0x7F, 0x00, 0xC3, 0x87, 0xC3, 0xCD, 0x53, 0xC8, 0x4D, 0xED, 0x78, + 0xCD, 0xE7, 0xC7, 0xC3, 0x97, 0xCC, 0xCD, 0xAD, 0xC8, 0xE5, 0xCD, 0x1B, 0xC8, 0xCD, 0x53, 0xC8, + 0xD1, 0x4D, 0xED, 0x59, 0xC9, 0xCD, 0x2F, 0xC8, 0xC5, 0xD5, 0xE5, 0xED, 0xB0, 0xE1, 0xD1, 0xC1, + 0x18, 0x03, 0xCD, 0x2F, 0xC8, 0x1A, 0xBE, 0x28, 0x19, 0xCD, 0xE2, 0xC7, 0x7E, 0xCD, 0xDB, 0xC7, + 0xCD, 0xFC, 0xC7, 0x1A, 0xCD, 0xDB, 0xC7, 0xCD, 0xFC, 0xC7, 0xEB, 0xCD, 0xE2, 0xC7, 0xEB, 0xCD, + 0x97, 0xCC, 0x13, 0x23, 0x0B, 0x78, 0xB1, 0x20, 0xDC, 0xC9, 0xCD, 0x14, 0xC8, 0xFE, 0x4D, 0xC2, + 0xA1, 0xC4, 0x13, 0x2A, 0x64, 0x00, 0xCD, 0x5B, 0xC8, 0xCD, 0xE2, 0xC7, 0x7E, 0xCD, 0xDB, 0xC7, + 0xCD, 0xFC, 0xC7, 0xCD, 0xA3, 0xC7, 0xCD, 0x14, 0xC8, 0xFE, 0x2E, 0xC8, 0xFE, 0x2D, 0x20, 0x03, + 0x2B, 0x18, 0x1A, 0xCD, 0xF1, 0xC6, 0x30, 0x07, 0xCD, 0x06, 0xC8, 0x3F, 0x8D, 0x18, 0xDA, 0xAF, + 0x80, 0x20, 0x03, 0x23, 0x18, 0x07, 0x48, 0x06, 0x00, 0xEB, 0xED, 0xB0, 0xEB, 0x22, 0x64, 0x00, + 0x18, 0xC7, 0xCD, 0x65, 0xC8, 0xC5, 0xCD, 0xF1, 0xC6, 0xD1, 0xDA, 0xBD, 0xC1, 0xAF, 0x80, 0xCA, + 0xBD, 0xC1, 0xC5, 0xD5, 0xE5, 0x11, 0x2E, 0x00, 0x1A, 0xBE, 0x20, 0x04, 0x13, 0x23, 0x10, 0xF8, + 0xE1, 0xE5, 0x06, 0x10, 0xCC, 0x60, 0xC7, 0xE1, 0xD1, 0xC1, 0x23, 0x1B, 0x7A, 0xB3, 0x20, 0xE2, + 0xC9, 0xE5, 0x06, 0x00, 0x21, 0x2E, 0x00, 0xCD, 0x14, 0xC8, 0xB7, 0x28, 0x29, 0xFE, 0x2C, 0x13, + 0x28, 0xF5, 0x4F, 0xFE, 0x27, 0x28, 0x12, 0xFE, 0x22, 0x28, 0x0E, 0x1B, 0xE5, 0xCD, 0xAD, 0xC8, + 0x7D, 0xE1, 0x38, 0x12, 0x77, 0x23, 0x04, 0x18, 0xDE, 0x1A, 0x13, 0xB7, 0x28, 0x08, 0xB9, 0x28, + 0xD6, 0x77, 0x23, 0x04, 0x18, 0xF3, 0x11, 0x2E, 0x00, 0xE1, 0xC9, 0xCD, 0x14, 0xC8, 0xFE, 0x4D, + 0x20, 0x01, 0x13, 0x01, 0x80, 0x00, 0x2A, 0x62, 0x00, 0xCD, 0x4E, 0xC8, 0x1E, 0x10, 0xAF, 0xB0, + 0x20, 0x0A, 0x3E, 0x0F, 0xB9, 0x38, 0x05, 0xAF, 0xB1, 0x28, 0x01, 0x59, 0xC5, 0x43, 0xCD, 0x60, + 0xC7, 0x22, 0x62, 0x00, 0xC1, 0x79, 0x93, 0x4F, 0x30, 0x01, 0x05, 0x78, 0xB1, 0x20, 0xDD, 0xC9, + 0xCD, 0xE2, 0xC7, 0xC5, 0xE5, 0xD5, 0x0E, 0x00, 0x1E, 0x04, 0x3E, 0x03, 0xA1, 0xCC, 0xA0, 0xC7, + 0xCD, 0xA0, 0xC7, 0x7E, 0xCD, 0xE7, 0xC7, 0x1C, 0x1C, 0x23, 0x0C, 0x10, 0xED, 0xCD, 0xA0, 0xC7, + 0x3E, 0x3A, 0xBB, 0x20, 0xF8, 0xD1, 0xE1, 0xC1, 0x7E, 0x23, 0xCD, 0x92, 0xC7, 0x10, 0xF9, 0xC3, + 0x97, 0xCC, 0xE6, 0x7F, 0xFE, 0x7F, 0x28, 0x04, 0xFE, 0x20, 0x30, 0x62, 0x3E, 0x2E, 0x18, 0x5E, + 0x1C, 0x18, 0x59, 0x3E, 0x31, 0x11, 0x2E, 0x00, 0x12, 0xD5, 0xCD, 0xEA, 0xCB, 0xE3, 0x23, 0x46, + 0x04, 0x23, 0xE5, 0x05, 0x28, 0x17, 0x7E, 0xCD, 0xD2, 0xC7, 0x77, 0x23, 0xFE, 0x22, 0x28, 0x04, + 0xFE, 0x27, 0x20, 0xEF, 0x05, 0x28, 0x06, 0xBE, 0x23, 0x20, 0xF9, 0x18, 0xE6, 0x36, 0x00, 0xD1, + 0xE1, 0xC9, 0xFE, 0x61, 0xD8, 0xFE, 0x7B, 0xD0, 0xD6, 0x20, 0xC9, 0xF5, 0xCD, 0xFC, 0xC7, 0xF1, + 0x18, 0x05, 0x7C, 0xCD, 0xE7, 0xC7, 0x7D, 0xF5, 0x1F, 0x1F, 0x1F, 0x1F, 0xCD, 0xF0, 0xC7, 0xF1, + 0xE6, 0x0F, 0xFE, 0x0A, 0x38, 0x02, 0xC6, 0x07, 0xC6, 0x30, 0x18, 0x02, 0x3E, 0x20, 0xF5, 0xE6, + 0x7F, 0xCD, 0x99, 0xCC, 0xF1, 0xC9, 0xE3, 0x7E, 0x23, 0xB7, 0x28, 0x06, 0xCD, 0xFE, 0xC7, 0xF2, + 0x07, 0xC8, 0xE3, 0xC9, 0x1A, 0xFE, 0x20, 0xC0, 0x13, 0x18, 0xF9, 0xCD, 0x14, 0xC8, 0xFE, 0x2C, + 0xC0, 0x13, 0xCD, 0x14, 0xC8, 0xAF, 0xC9, 0xCD, 0x14, 0xC8, 0xB7, 0xC8, 0xC3, 0xBD, 0xC1, 0x21, + 0x80, 0x00, 0x44, 0x4D, 0xCD, 0x68, 0xC8, 0xE5, 0xC5, 0xCD, 0x1B, 0xC8, 0xCD, 0xAD, 0xC8, 0xDA, + 0xBD, 0xC1, 0xCD, 0x27, 0xC8, 0xEB, 0xC1, 0xE1, 0xC9, 0xCD, 0x65, 0xC8, 0x18, 0xD9, 0xCD, 0x68, + 0xC8, 0x18, 0xD4, 0xCD, 0xAD, 0xC8, 0xDA, 0xBD, 0xC1, 0x18, 0xCC, 0xE5, 0xCD, 0xAD, 0xC8, 0x38, + 0x01, 0xE3, 0xE1, 0x18, 0xC2, 0x37, 0x18, 0x01, 0xB7, 0x08, 0xC5, 0xE5, 0xCD, 0xAD, 0xC8, 0x30, + 0x08, 0x08, 0xDA, 0xBD, 0xC1, 0x08, 0xE1, 0x18, 0x01, 0xF1, 0xCD, 0x87, 0xC8, 0x30, 0x06, 0x08, + 0xC1, 0xD0, 0xC3, 0xBD, 0xC1, 0xF1, 0xC9, 0xCD, 0x1B, 0xC8, 0x1A, 0xFE, 0x53, 0x20, 0x01, 0x13, + 0xE5, 0xF5, 0xCD, 0xAD, 0xC8, 0x38, 0x0F, 0x44, 0x4D, 0xF1, 0xE1, 0x28, 0x07, 0x79, 0x95, 0x4F, + 0x78, 0x9C, 0x47, 0x03, 0xB7, 0xC9, 0xF1, 0xE1, 0xCA, 0xBD, 0xC1, 0x37, 0xC9, 0xCD, 0x14, 0xC8, + 0xCD, 0xE0, 0xC8, 0xD8, 0xD5, 0x13, 0xCD, 0xE0, 0xC8, 0x30, 0xFA, 0xD1, 0xFE, 0x2E, 0x28, 0x05, + 0xCD, 0xCA, 0xC8, 0xA7, 0xC9, 0xCD, 0xF4, 0xC8, 0xA7, 0xC9, 0x21, 0x00, 0x00, 0xCD, 0xE0, 0xC8, + 0x38, 0x09, 0x29, 0x29, 0x29, 0x29, 0x85, 0x6F, 0x13, 0x18, 0xF2, 0xFE, 0x48, 0xC0, 0x13, 0xC9, + 0x1A, 0xFE, 0x30, 0xD8, 0xFE, 0x3A, 0x38, 0x09, 0xFE, 0x41, 0xD8, 0xFE, 0x47, 0x3F, 0xD8, 0xD6, + 0x07, 0xD6, 0x30, 0xC9, 0x21, 0x00, 0x00, 0xCD, 0x10, 0xC9, 0x13, 0x38, 0x0D, 0xC5, 0x29, 0x44, + 0x4D, 0x29, 0x29, 0x09, 0xC1, 0xCD, 0x86, 0xC1, 0x18, 0xED, 0xFE, 0x2E, 0xC8, 0xC3, 0xBD, 0xC1, + 0x1A, 0xFE, 0x30, 0xD8, 0xFE, 0x3A, 0x3F, 0xD8, 0xD6, 0x30, 0xC9, 0x01, 0x18, 0x00, 0x11, 0x00, + 0x01, 0x21, 0x29, 0xC9, 0xED, 0xB0, 0xC3, 0x00, 0x01, 0x01, 0x00, 0x10, 0x11, 0x00, 0x10, 0x21, + 0x00, 0xC0, 0xC5, 0xD5, 0xE5, 0xED, 0xB0, 0x3E, 0x01, 0xD3, 0x40, 0xD1, 0xE1, 0xC1, 0xED, 0xB0, + 0xC9, 0xCD, 0x14, 0xC8, 0xFE, 0x5A, 0xF5, 0x20, 0x01, 0x13, 0xCD, 0x27, 0xC8, 0xF1, 0xC4, 0x1B, + 0xC9, 0xCD, 0x06, 0xC8, 0x0D, 0x4D, 0x65, 0x6D, 0x6F, 0x72, 0x79, 0xBA, 0x01, 0x00, 0x10, 0xCD, + 0xFC, 0xC7, 0x79, 0xCD, 0xF0, 0xC7, 0x0C, 0x10, 0xF6, 0xCD, 0x97, 0xCC, 0x06, 0x07, 0xCD, 0xFC, + 0xC7, 0x10, 0xFB, 0x60, 0x68, 0xCD, 0xFC, 0xC7, 0xE5, 0x11, 0x00, 0x10, 0x7C, 0xFE, 0xC9, 0x20, + 0x09, 0x7D, 0xFE, 0x8D, 0x38, 0x04, 0xFE, 0x9C, 0x38, 0x12, 0x46, 0x3E, 0x55, 0x77, 0xBE, 0x20, + 0x05, 0x2F, 0x77, 0xBE, 0x28, 0x05, 0x70, 0x3E, 0x58, 0x18, 0x09, 0x70, 0x23, 0x1B, 0x7A, 0xB3, + 0x20, 0xDA, 0x3E, 0x5E, 0xCD, 0xFE, 0xC7, 0xE1, 0x3E, 0x10, 0x84, 0x67, 0x20, 0xC7, 0xCD, 0x06, + 0xC8, 0x0D, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x79, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x20, 0x28, + 0x65, 0x67, 0x2C, 0x20, 0x41, 0x3B, 0x20, 0x6F, 0x72, 0x20, 0x41, 0x3B, 0x3B, 0x20, 0x6F, 0x72, + 0x20, 0x41, 0x3B, 0x3B, 0x3B, 0x29, 0xA0, 0xCD, 0xA3, 0xC7, 0xCD, 0x14, 0xC8, 0xB7, 0xCA, 0x97, + 0xCC, 0xCD, 0xC1, 0xC2, 0xC2, 0xB9, 0xC1, 0xCD, 0x06, 0xC8, 0x53, 0x65, 0x65, 0x6B, 0x20, 0x74, + 0x65, 0x73, 0x74, 0x73, 0x3A, 0x8D, 0x06, 0x15, 0x21, 0x20, 0xCA, 0xDB, 0x31, 0x32, 0x7D, 0x00, + 0x7E, 0xC5, 0xE5, 0xFE, 0xFF, 0x20, 0x2E, 0xCD, 0x06, 0xC8, 0x20, 0x52, 0x65, 0x73, 0x74, 0x6F, + 0x72, 0x65, 0xBA, 0xCD, 0x04, 0xC6, 0xCD, 0x37, 0xCD, 0x08, 0xCD, 0x1E, 0xC6, 0x08, 0x18, 0x2C, + 0x01, 0x02, 0x03, 0x04, 0x05, 0xFE, 0x06, 0x07, 0x08, 0x09, 0x00, 0xFE, 0x27, 0x00, 0x15, 0x00, + 0x01, 0xFE, 0xFF, 0xFE, 0x27, 0xFE, 0xFE, 0x20, 0x06, 0xCD, 0x97, 0xCC, 0xB7, 0x18, 0x12, 0x32, + 0x75, 0x00, 0xCD, 0xDB, 0xC7, 0xCD, 0x06, 0xC8, 0xBA, 0xCD, 0xD4, 0xC4, 0xF5, 0xCD, 0x7A, 0xCB, + 0xF1, 0xE1, 0xC1, 0xDA, 0x97, 0xCC, 0x23, 0x10, 0xA2, 0xCD, 0x06, 0xC8, 0x0D, 0x52, 0x65, 0x61, + 0x64, 0x2F, 0x57, 0x72, 0x69, 0x74, 0x65, 0x20, 0x74, 0x65, 0x73, 0x74, 0x73, 0x8D, 0xCD, 0x94, + 0xCB, 0xCD, 0xB0, 0xCB, 0xDA, 0x97, 0xCC, 0xCD, 0x06, 0xC8, 0x57, 0x72, 0x69, 0x74, 0x65, 0x20, + 0x74, 0x65, 0x73, 0x74, 0x20, 0x4D, 0x41, 0x59, 0x20, 0x44, 0x45, 0x53, 0x54, 0x52, 0x4F, 0x59, + 0x20, 0x64, 0x61, 0x74, 0x61, 0x0D, 0x45, 0x53, 0x43, 0x3D, 0x61, 0x62, 0x6F, 0x72, 0x74, 0x20, + 0x52, 0x45, 0x54, 0x55, 0x52, 0x4E, 0x3D, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x65, 0x64, 0xA0, 0xCD, + 0xA3, 0xC7, 0x21, 0x00, 0x09, 0xCD, 0xA2, 0xCB, 0x01, 0x00, 0x02, 0x75, 0x23, 0x0B, 0x78, 0xB1, + 0x20, 0xF9, 0xCD, 0xC1, 0xCB, 0x30, 0x6E, 0xCD, 0x06, 0xC8, 0x54, 0x65, 0x73, 0x74, 0x20, 0x66, + 0x61, 0x69, 0x6C, 0x65, 0x64, 0x21, 0x0D, 0x44, 0x69, 0x73, 0x6B, 0x20, 0x64, 0x61, 0x74, 0x61, + 0x20, 0x61, 0xF4, 0x1E, 0x01, 0xCD, 0xDE, 0xC5, 0xCD, 0x06, 0xC8, 0x20, 0x6D, 0x61, 0x79, 0x20, + 0x68, 0x61, 0x76, 0x65, 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, 0x64, 0x65, 0x73, 0x74, 0x72, 0x6F, + 0x79, 0x65, 0x64, 0x0D, 0x4F, 0x72, 0x69, 0x67, 0x69, 0x6E, 0x61, 0x6C, 0x20, 0x69, 0x73, 0x20, + 0x6C, 0x6F, 0x63, 0x61, 0x74, 0x65, 0x64, 0x20, 0x61, 0x74, 0x20, 0x30, 0x44, 0x30, 0x30, 0xF3, + 0x2A, 0x79, 0x00, 0xCD, 0xE2, 0xC7, 0xCD, 0x06, 0xC8, 0x20, 0x69, 0x6E, 0x20, 0x6D, 0x65, 0x6D, + 0x6F, 0x72, 0x79, 0x8D, 0xC9, 0x21, 0x00, 0x0B, 0xCD, 0xA2, 0xCB, 0xCD, 0xB0, 0xCB, 0x38, 0x87, + 0xCD, 0x06, 0xC8, 0x50, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6E, 0x20, 0x63, 0x6F, 0x6D, 0x70, 0x61, + 0x72, 0x65, 0xA0, 0xED, 0x4B, 0x79, 0x00, 0x11, 0x00, 0x09, 0x21, 0x00, 0x0B, 0x1A, 0xBE, 0x20, + 0x09, 0x13, 0x23, 0x0B, 0x78, 0xB1, 0x20, 0xF5, 0x18, 0x01, 0x37, 0xCD, 0xD1, 0xCB, 0xCD, 0x94, + 0xCB, 0xCD, 0xC1, 0xCB, 0xDA, 0xC7, 0xCA, 0xC3, 0x97, 0xCC, 0x38, 0x06, 0xCD, 0x06, 0xC8, 0x4F, + 0xCB, 0xC9, 0xCD, 0x06, 0xC8, 0x65, 0x72, 0x72, 0x6F, 0x72, 0xA0, 0x3A, 0x71, 0x00, 0xCD, 0xE7, + 0xC7, 0xC3, 0x97, 0xCC, 0xCD, 0x06, 0xC8, 0x44, 0x61, 0x74, 0xE1, 0x21, 0x00, 0x0D, 0x22, 0x7B, + 0x00, 0xC9, 0x22, 0x7B, 0x00, 0xCD, 0x06, 0xC8, 0x50, 0x61, 0x74, 0x74, 0x65, 0x72, 0xEE, 0xC9, + 0xCD, 0xDA, 0xCB, 0xCD, 0x06, 0xC8, 0x20, 0x72, 0x65, 0x61, 0x64, 0xA0, 0xCD, 0x52, 0xCD, 0x18, + 0x10, 0xCD, 0xDA, 0xCB, 0xCD, 0x06, 0xC8, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0xA0, 0xCD, 0xAB, + 0xC5, 0xF5, 0xCD, 0x7A, 0xCB, 0xCD, 0x97, 0xCC, 0xF1, 0xC9, 0x3E, 0x27, 0x32, 0x75, 0x00, 0x32, + 0x7D, 0x00, 0x3E, 0x01, 0x32, 0x76, 0x00, 0xC3, 0xCB, 0xCD, 0xC5, 0xE5, 0x06, 0x00, 0x21, 0x02, + 0x00, 0x19, 0xCD, 0x64, 0xCC, 0xFE, 0x10, 0xCC, 0xBB, 0xCC, 0x28, 0xF6, 0xFE, 0x1B, 0xCA, 0x8E, + 0xCC, 0xFE, 0x08, 0x28, 0x04, 0xFE, 0x7F, 0x20, 0x11, 0xAF, 0xB0, 0x28, 0xE5, 0x2B, 0x05, 0xCD, + 0x4B, 0xCC, 0x7E, 0xFE, 0x20, 0xDC, 0x4B, 0xCC, 0x18, 0xD8, 0xFE, 0x0D, 0xCC, 0x45, 0xCC, 0x28, + 0x1B, 0xFE, 0x15, 0x20, 0x08, 0xCD, 0x45, 0xCC, 0xCD, 0x97, 0xCC, 0x18, 0xBF, 0x4F, 0x1A, 0x3D, + 0xB8, 0x28, 0xBF, 0x79, 0xCD, 0x45, 0xCC, 0x77, 0x23, 0x04, 0x18, 0xB6, 0x36, 0x00, 0x78, 0x13, + 0x12, 0x1B, 0xE1, 0xC1, 0xC9, 0xF5, 0xCD, 0x52, 0xCC, 0xF1, 0xC9, 0xCD, 0x06, 0xC8, 0x08, 0x20, + 0x88, 0xC9, 0xFE, 0x20, 0x30, 0x43, 0xFE, 0x0D, 0x28, 0x3F, 0xF5, 0xCD, 0x06, 0xC8, 0xDE, 0xF1, + 0xC6, 0x40, 0x18, 0x35, 0xCD, 0x23, 0xCD, 0xCD, 0x76, 0xCC, 0x28, 0xF8, 0xCD, 0x76, 0xCC, 0x28, + 0xFB, 0xDB, 0x01, 0xE6, 0x7F, 0xC9, 0xDB, 0x00, 0xE6, 0x40, 0xC9, 0xCD, 0x76, 0xCC, 0xC8, 0xCD, + 0x6C, 0xCC, 0xFE, 0x13, 0xCC, 0x6C, 0xCC, 0xFE, 0x0D, 0x28, 0x03, 0xFE, 0x1B, 0xC0, 0x31, 0x2E, + 0x00, 0xCD, 0x97, 0xCC, 0xC3, 0x55, 0xC1, 0x3E, 0x0D, 0xF5, 0xD9, 0xCB, 0x78, 0xD9, 0xC4, 0xCB, + 0xCC, 0xCD, 0x23, 0xCD, 0xDB, 0x00, 0xE6, 0x80, 0x28, 0xFA, 0xF1, 0xD3, 0x01, 0xFE, 0x0D, 0xC0, + 0x3E, 0x0A, 0xCD, 0x99, 0xCC, 0xCD, 0x7B, 0xCC, 0xFE, 0x10, 0xC0, 0xF5, 0xD9, 0x3E, 0x80, 0xA8, + 0x47, 0xCB, 0x78, 0xD9, 0xC4, 0xC9, 0xCC, 0xF1, 0xC9, 0x3E, 0x11, 0xF5, 0xE5, 0x21, 0x08, 0x00, + 0xCD, 0xF1, 0xCF, 0xE1, 0xF1, 0xF5, 0xFE, 0x11, 0x28, 0x13, 0xCD, 0x7B, 0xCC, 0xFE, 0x10, 0x20, + 0x05, 0xCD, 0xBB, 0xCC, 0xF1, 0xC9, 0xDB, 0x54, 0x2F, 0xE6, 0x20, 0x28, 0xED, 0xF1, 0xCB, 0xFF, + 0xD3, 0x54, 0xCB, 0xBF, 0xD3, 0x54, 0xCB, 0xFF, 0xD3, 0x54, 0xCB, 0xBF, 0xC9, 0xCD, 0x14, 0xC8, + 0xFE, 0x4F, 0xC2, 0xBD, 0xC1, 0x13, 0x1A, 0xFE, 0x4E, 0x28, 0x0E, 0xFE, 0x46, 0xC2, 0xBD, 0xC1, + 0xD9, 0xCB, 0xA8, 0xD9, 0x3E, 0xFF, 0xD3, 0x04, 0xC9, 0xD9, 0xCB, 0xE8, 0xD9, 0x3E, 0x01, 0x32, + 0x72, 0x00, 0xC9, 0xD9, 0xCB, 0x68, 0xD9, 0xC8, 0xC5, 0xCD, 0xA8, 0xCF, 0xC1, 0xD3, 0x34, 0xCD, + 0xD6, 0xCF, 0xEE, 0xA0, 0xD3, 0x04, 0xC9, 0x16, 0x02, 0xD5, 0xCD, 0x70, 0xCD, 0xD1, 0xD0, 0xD5, + 0x3E, 0x0A, 0x32, 0x75, 0x00, 0xCD, 0xCB, 0xCD, 0xCD, 0x70, 0xCD, 0xD1, 0xD0, 0x15, 0x20, 0xE9, + 0x18, 0x18, 0x16, 0x0A, 0xD5, 0xCD, 0x58, 0xCE, 0xD1, 0xD0, 0x15, 0x20, 0xF7, 0x18, 0x0B, 0x16, + 0x04, 0xD5, 0xCD, 0x9F, 0xCE, 0xD1, 0xD0, 0x15, 0x20, 0xF7, 0x3A, 0x71, 0x00, 0x4F, 0x37, 0xC9, + 0x97, 0x32, 0x75, 0x00, 0x32, 0x78, 0x00, 0xCD, 0x55, 0xCF, 0xD3, 0x34, 0xCD, 0x25, 0xCE, 0x38, + 0x0E, 0xD3, 0x30, 0xDB, 0x34, 0xCB, 0x57, 0x20, 0x3B, 0x1F, 0x30, 0xF7, 0xC3, 0x3E, 0xCE, 0x3E, + 0xC4, 0xD3, 0x30, 0xCD, 0xD6, 0xCF, 0xE6, 0x57, 0xD3, 0x04, 0xCD, 0xE4, 0xCF, 0xDB, 0x04, 0xE6, + 0x40, 0x20, 0x16, 0xCD, 0xCF, 0xCF, 0xDB, 0x34, 0xCB, 0x57, 0x20, 0x18, 0x1F, 0x30, 0xF7, 0x3E, + 0xD0, 0xD3, 0x30, 0x97, 0xD3, 0x31, 0xC3, 0x50, 0xCE, 0xDB, 0x34, 0xCB, 0x57, 0x20, 0x05, 0x1F, + 0x30, 0xDB, 0x18, 0xCB, 0x3E, 0x80, 0x32, 0x71, 0x00, 0x37, 0xC9, 0x97, 0xCD, 0x55, 0xCF, 0xD3, + 0x34, 0x3A, 0x75, 0x00, 0xD3, 0x33, 0x4F, 0x3A, 0x76, 0x00, 0xD3, 0x32, 0x3A, 0x7D, 0x00, 0xD3, + 0x31, 0x91, 0xCA, 0xCF, 0xCF, 0xCD, 0x25, 0xCE, 0x38, 0x0F, 0xF6, 0x10, 0xD3, 0x30, 0xDB, 0x34, + 0xCB, 0x57, 0x20, 0xD0, 0x1F, 0x30, 0xF7, 0x18, 0x45, 0xCD, 0xD6, 0xCF, 0xE6, 0x4F, 0xD3, 0x04, + 0x3E, 0x18, 0xD3, 0x30, 0xDB, 0x34, 0xCB, 0x57, 0x20, 0xBA, 0x1F, 0x30, 0xF7, 0xDB, 0x30, 0x2E, + 0x32, 0xDB, 0x04, 0xE6, 0x40, 0x20, 0xFA, 0x2D, 0x20, 0xF7, 0xDB, 0x04, 0xE6, 0x40, 0x20, 0xFA, + 0xCD, 0xCF, 0xCF, 0x18, 0x2B, 0x3A, 0x7E, 0x00, 0xCB, 0x57, 0x20, 0x0A, 0xCB, 0x5F, 0x3E, 0x0E, + 0x28, 0x02, 0x3E, 0x0C, 0xA7, 0xC9, 0xCB, 0x5F, 0x3E, 0x0F, 0x28, 0xF8, 0x37, 0xC9, 0xCD, 0xCF, + 0xCF, 0x21, 0x64, 0x00, 0xCD, 0xF1, 0xCF, 0xDB, 0x30, 0x32, 0x71, 0x00, 0xE6, 0x98, 0x37, 0xC0, + 0x3A, 0x75, 0x00, 0x32, 0x7D, 0x00, 0xA7, 0xC9, 0xCD, 0x8F, 0xCE, 0xD3, 0x30, 0xDB, 0x34, 0x1F, + 0x38, 0x16, 0xED, 0xA2, 0x04, 0xDB, 0x34, 0x1F, 0x38, 0x0E, 0xED, 0xA2, 0xC2, 0x5D, 0xCE, 0xDB, + 0x34, 0xCB, 0x4F, 0x20, 0x10, 0x1F, 0x30, 0xF7, 0xCD, 0xCF, 0xCF, 0xDB, 0x30, 0x32, 0x71, 0x00, + 0xE6, 0x9C, 0xC8, 0x18, 0x08, 0xCD, 0xCF, 0xCF, 0x3E, 0x80, 0x32, 0x71, 0x00, 0x37, 0xC9, 0xCD, + 0x40, 0xCF, 0x57, 0xF3, 0xCD, 0xC6, 0xCF, 0xC6, 0x88, 0x5F, 0x7A, 0xD3, 0x34, 0x7B, 0xC9, 0xCD, + 0xE4, 0xCF, 0xCD, 0x40, 0xCF, 0x57, 0xF3, 0xCD, 0xC6, 0xCF, 0xC6, 0xA8, 0x5F, 0x7A, 0xD3, 0x34, + 0x7B, 0xD3, 0x30, 0xDB, 0x34, 0x1F, 0x38, 0x12, 0xED, 0xA3, 0x04, 0xDB, 0x34, 0x1F, 0x38, 0x0A, + 0xED, 0xA3, 0xC2, 0xB3, 0xCE, 0xDB, 0x34, 0x1F, 0x30, 0xFB, 0xCD, 0xCF, 0xCF, 0xCD, 0xE4, 0xCF, + 0xDB, 0x30, 0x32, 0x71, 0x00, 0xE6, 0xFC, 0x37, 0xC0, 0xA7, 0x3A, 0x7E, 0x00, 0xCB, 0x4F, 0xC8, + 0xCD, 0x00, 0xCF, 0x38, 0x0A, 0xDB, 0x34, 0x1F, 0x38, 0x04, 0xDB, 0x33, 0x18, 0xF7, 0x1C, 0xCD, + 0xCF, 0xCF, 0xDB, 0x30, 0x32, 0x71, 0x00, 0xE6, 0x9C, 0x37, 0xC0, 0x7B, 0xA7, 0xC8, 0x37, 0xC9, + 0xCD, 0x8F, 0xCE, 0xED, 0x4B, 0x79, 0x00, 0xCB, 0x38, 0xCB, 0x19, 0xCB, 0x38, 0xCB, 0x19, 0x41, + 0x1E, 0x00, 0xD3, 0x30, 0xDB, 0x34, 0x1F, 0xD8, 0xDB, 0x33, 0xAE, 0xC0, 0x23, 0xDB, 0x34, 0x1F, + 0xD8, 0xDB, 0x33, 0xAE, 0xC0, 0x23, 0xDB, 0x34, 0x1F, 0xD8, 0xDB, 0x33, 0xAE, 0xC0, 0x23, 0xDB, + 0x34, 0x1F, 0xD8, 0xDB, 0x33, 0xAE, 0xC0, 0x23, 0x10, 0xDA, 0xDB, 0x34, 0x1F, 0x30, 0xFB, 0xC9, + 0xDB, 0x33, 0x3E, 0x80, 0xCD, 0x55, 0xCF, 0x2A, 0x79, 0x00, 0xCB, 0x1C, 0xCB, 0x1D, 0x45, 0x0E, + 0x33, 0x2A, 0x7B, 0x00, 0xC9, 0x4F, 0xDB, 0x34, 0xE6, 0x04, 0x28, 0x04, 0x97, 0x32, 0x72, 0x00, + 0xCD, 0xA8, 0xCF, 0xD3, 0x34, 0xF5, 0xE5, 0xCD, 0xD6, 0xCF, 0xE6, 0x5F, 0xD3, 0x04, 0x3A, 0x72, + 0x00, 0xA7, 0x28, 0x21, 0x21, 0x90, 0x01, 0x3A, 0x73, 0x00, 0xB8, 0x20, 0x1B, 0x3A, 0x74, 0x00, + 0x67, 0x3A, 0x78, 0x00, 0x32, 0x74, 0x00, 0xBC, 0x20, 0x06, 0xDB, 0x34, 0xE6, 0x20, 0x20, 0x0B, + 0xCD, 0xE4, 0xCF, 0x18, 0x06, 0x21, 0x20, 0x4E, 0xCD, 0xF1, 0xCF, 0xE1, 0x78, 0x32, 0x73, 0x00, + 0x3E, 0x01, 0x32, 0x72, 0x00, 0xF1, 0xB1, 0xC9, 0x3A, 0x77, 0x00, 0x47, 0x04, 0x97, 0x37, 0x17, + 0x10, 0xFD, 0x47, 0x3A, 0x7E, 0x00, 0xCB, 0x57, 0x28, 0x02, 0xCB, 0xE0, 0xCB, 0x47, 0x28, 0x02, + 0xCB, 0xF0, 0x78, 0xF6, 0x20, 0xC9, 0xDB, 0x34, 0x2F, 0xE6, 0x20, 0xC8, 0x3E, 0x04, 0xC9, 0xCD, + 0xD6, 0xCF, 0xD3, 0x04, 0xAF, 0xC9, 0xC5, 0x06, 0x7F, 0x3A, 0x78, 0x00, 0xA7, 0x28, 0x02, 0x06, + 0x7D, 0x78, 0xC1, 0xC9, 0x21, 0x08, 0x00, 0x3A, 0x7E, 0x00, 0xCB, 0x57, 0x20, 0x03, 0x21, 0x0C, + 0x00, 0xC5, 0x2B, 0x06, 0x1C, 0x10, 0xFE, 0x00, 0x00, 0x7D, 0xB4, 0x20, 0xF5, 0xC1, 0xC9, 0xFF, + 0xF3, 0x18, 0x3C, 0xC3, 0x30, 0xC0, 0xC3, 0x04, 0xC5, 0xC3, 0x37, 0xC0, 0xC3, 0x3B, 0xC0, 0xC3, + 0x9E, 0xCB, 0xC3, 0x37, 0xCD, 0xC3, 0xD4, 0xC4, 0xC3, 0x52, 0xCD, 0xC3, 0xAB, 0xC5, 0xC3, 0x4B, + 0xC2, 0xC3, 0x6C, 0xCC, 0xC3, 0x76, 0xCC, 0xC3, 0xEA, 0xCB, 0xC3, 0xFE, 0xC7, 0xC3, 0x97, 0xCC, + 0x32, 0x77, 0x00, 0x78, 0xC3, 0x87, 0xC3, 0x32, 0x75, 0x00, 0xC9, 0x32, 0x76, 0x00, 0xC9, 0xAF, + 0xD3, 0x03, 0x47, 0xD9, 0x2F, 0xD3, 0x04, 0x3E, 0xD0, 0xD3, 0x30, 0x21, 0x2E, 0x00, 0xF9, 0x25, + 0x20, 0xFD, 0x74, 0x2C, 0x20, 0xFC, 0x24, 0x22, 0x62, 0x00, 0x22, 0x64, 0x00, 0xCD, 0x4B, 0xC2, + 0xDB, 0x34, 0xE6, 0x40, 0xC2, 0x39, 0xC1, 0xDB, 0x04, 0x2F, 0xE6, 0x03, 0x32, 0x77, 0x00, 0xCD, + 0x06, 0xC8, 0x50, 0x72, 0x65, 0x70, 0x61, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x62, + 0x6F, 0x6F, 0x74, 0x2C, 0x20, 0x45, 0x53, 0x43, 0x20, 0x74, 0x6F, 0x20, 0x61, 0x62, 0x6F, 0x72, + 0x74, 0x8D, 0xCD, 0xA8, 0xCF, 0x57, 0xD3, 0x34, 0x06, 0x64, 0xCD, 0x28, 0xC1, 0x21, 0x64, 0x00, + 0xCD, 0xF1, 0xCF, 0x10, 0xF5, 0x32, 0x75, 0x00, 0x32, 0x7D, 0x00, 0x32, 0x78, 0x00, 0x3C, 0x32, + 0x76, 0x00, 0xCD, 0xF7, 0xC1, 0x32, 0x7E, 0x00, 0x21, 0x80, 0x00, 0x22, 0x7B, 0x00, 0x22, 0x79, + 0x00, 0x3E, 0x42, 0x32, 0x70, 0x00, 0x06, 0x02, 0xC5, 0xCD, 0x37, 0xCD, 0xD4, 0xCB, 0xCD, 0xD4, + 0x52, 0xCD, 0xC1, 0x30, 0x13, 0xCD, 0x28, 0xC1, 0x10, 0xEE, 0xCD, 0x06, 0xC8, 0x0D, 0x55, 0x6E, + 0x61, 0x62, 0x6C, 0x65, 0x20, 0xF4, 0x18, 0x2D, 0x3A, 0x80, 0x00, 0xFE, 0x40, 0x28, 0x04, 0xFE, + 0xE5, 0x20, 0x07, 0xCD, 0x06, 0xC8, 0x0D, 0xCE, 0x18, 0x1B, 0xCD, 0x28, 0xC1, 0xCD, 0xA8, 0xCF, + 0x57, 0x3A, 0x77, 0x00, 0x08, 0xCD, 0x06, 0xC8, 0x0D, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x62, 0x79, + 0x8D, 0x37, 0xC3, 0x80, 0x00, 0xCD, 0x06, 0xC8, 0x6F, 0x20, 0x62, 0x6F, 0x6F, 0x74, 0x8D, 0x3A, + 0x71, 0x00, 0xB7, 0xC4, 0x59, 0xC3, 0x18, 0x09, 0xCD, 0x76, 0xCC, 0xC4, 0x6C, 0xCC, 0xFE, 0x1B, + 0xC0, 0x3E, 0xD0, 0xD3, 0x30, 0x3E, 0x7C, 0xD3, 0x04, 0xCD, 0x06, 0xC8, 0x0D, 0x43, 0x72, 0x6F, + 0x6D, 0x65, 0x6D, 0x63, 0x6F, 0x20, 0x52, 0x44, 0x4F, 0x53, 0x20, 0x30, 0x32, 0x2E, 0x35, 0x32, + 0x8D, 0xAF, 0x32, 0x6C, 0x00, 0x3A, 0x7E, 0x00, 0x47, 0xCD, 0xE2, 0xC1, 0x31, 0x2E, 0x00, 0xCD, + 0x06, 0xC8, 0xBB, 0xCD, 0xA3, 0xC7, 0xCD, 0x14, 0xC8, 0xA7, 0x28, 0xE5, 0xCD, 0xC1, 0xC2, 0x28, + 0xE4, 0x78, 0xFE, 0x17, 0x30, 0x47, 0x87, 0x21, 0x8B, 0xC1, 0xCD, 0x86, 0xC1, 0x7E, 0x23, 0x66, + 0x6F, 0xCD, 0xC7, 0xC1, 0x18, 0xCF, 0x85, 0x6F, 0xD0, 0x24, 0xC9, 0xFD, 0xCC, 0xC8, 0xC1, 0xBD, + 0xC1, 0x2B, 0xC7, 0x2A, 0xC6, 0xBD, 0xC1, 0xC4, 0xC1, 0xBD, 0xC1, 0x45, 0xC2, 0xBD, 0xC1, 0xBD, + 0xC1, 0x39, 0xC4, 0x45, 0xC6, 0xBD, 0xC1, 0x36, 0xC6, 0xBD, 0xC1, 0xC2, 0xC6, 0x16, 0xC5, 0x7A, + 0xC6, 0x41, 0xC9, 0xBD, 0xC1, 0x52, 0xC6, 0x1A, 0xC5, 0xAF, 0x32, 0x6C, 0x00, 0xCD, 0x06, 0xC8, + 0x3F, 0x8D, 0x18, 0x91, 0xCD, 0x53, 0xC8, 0xE9, 0xCD, 0x14, 0xC8, 0xB7, 0xCA, 0x67, 0xC0, 0xFE, + 0x45, 0xD2, 0x2A, 0xC4, 0xD6, 0x41, 0xDA, 0x2A, 0xC4, 0xF5, 0x13, 0xCD, 0x27, 0xC8, 0xF1, 0xC3, + 0x6C, 0xC0, 0x3A, 0x6C, 0x00, 0xB7, 0xC8, 0xCD, 0xFE, 0xC7, 0xCB, 0x58, 0xC0, 0xCB, 0x78, 0x3E, + 0x3B, 0xC4, 0xFE, 0xC7, 0xC3, 0xFE, 0xC7, 0x7A, 0xD3, 0x34, 0x3E, 0xDF, 0xD3, 0x04, 0x3E, 0xD4, + 0xD3, 0x30, 0xDB, 0x34, 0x0F, 0x30, 0xFB, 0xDB, 0x30, 0x01, 0x00, 0x02, 0xCD, 0x3B, 0xC2, 0x3E, + 0xD4, 0xD3, 0x30, 0xCD, 0x34, 0xC2, 0x28, 0xDF, 0xDB, 0x34, 0x0F, 0x30, 0xF6, 0xDB, 0x30, 0x10, + 0xEE, 0xAF, 0xD3, 0x03, 0x79, 0xFE, 0x5A, 0x30, 0x03, 0x87, 0x87, 0x87, 0xFE, 0xB7, 0x3E, 0x80, + 0xD0, 0x3E, 0x04, 0xC9, 0xDB, 0x03, 0xFE, 0xC7, 0xC0, 0x0C, 0xC8, 0x3E, 0x01, 0xD3, 0x03, 0x3E, + 0xFA, 0xD3, 0x05, 0x18, 0xEF, 0xCD, 0x27, 0xC8, 0xCD, 0x97, 0xCC, 0xDB, 0x04, 0xE6, 0x08, 0x28, + 0x5D, 0x3E, 0x0A, 0xD3, 0x02, 0x21, 0xD0, 0x07, 0xCD, 0xF1, 0xCF, 0x3E, 0x08, 0xD3, 0x02, 0x16, + 0x64, 0x15, 0x28, 0xED, 0x21, 0xB9, 0xC2, 0x0E, 0x00, 0x3E, 0x19, 0x06, 0x09, 0xD3, 0x02, 0xED, + 0xA3, 0x28, 0xEE, 0xCD, 0x98, 0xC2, 0xCD, 0x98, 0xC2, 0x38, 0xE9, 0xFE, 0x0D, 0x3E, 0x09, 0x20, + 0xEC, 0x3E, 0x0D, 0xD3, 0x01, 0x21, 0xA0, 0x0F, 0xCD, 0xF1, 0xCF, 0xCD, 0x76, 0xCC, 0xC4, 0x6C, + 0xCC, 0xFE, 0x0D, 0x28, 0xEC, 0xC3, 0x97, 0xCC, 0xD5, 0x11, 0xA0, 0x8C, 0xCD, 0x76, 0xCC, 0x28, + 0x05, 0xCD, 0x6C, 0xCC, 0x18, 0x06, 0x1B, 0x7A, 0xB3, 0x20, 0xF1, 0x37, 0xD1, 0xC9, 0x3E, 0x09, + 0xD3, 0x02, 0x3E, 0x84, 0xD3, 0x00, 0xC3, 0x97, 0xCC, 0x90, 0xC0, 0xA0, 0x90, 0x88, 0x84, 0x82, + 0x01, 0xD6, 0x41, 0xDA, 0xBD, 0xC1, 0x47, 0x13, 0x1A, 0xFE, 0x3B, 0xC0, 0x78, 0xFE, 0x04, 0xD2, + 0x2A, 0xC4, 0xC6, 0x41, 0x32, 0x6C, 0x00, 0xCD, 0xF6, 0xC3, 0x13, 0x1A, 0xFE, 0x3B, 0x06, 0x0C, + 0x20, 0x0B, 0x13, 0x1A, 0xFE, 0x3B, 0x06, 0x04, 0x20, 0x03, 0x06, 0x80, 0x13, 0xC5, 0xCD, 0xB7, + 0xC3, 0xC1, 0x70, 0x30, 0x06, 0x3A, 0x6D, 0x00, 0xB0, 0x77, 0x37, 0xF5, 0xCD, 0x84, 0xC3, 0x32, + 0x78, 0x00, 0x32, 0x7D, 0x00, 0x3C, 0x32, 0x76, 0x00, 0xCD, 0x04, 0xC6, 0x3E, 0x48, 0x32, 0x70, + 0x00, 0xCD, 0x37, 0xCD, 0xF5, 0xCD, 0x1E, 0xC6, 0xF1, 0xDA, 0x0D, 0xC4, 0xF1, 0xDA, 0xB5, 0xC3, + 0xCD, 0x04, 0xC6, 0x21, 0x00, 0x01, 0x22, 0x7B, 0x00, 0xCD, 0xCB, 0xCD, 0xCD, 0x52, 0xCD, 0xF5, + 0xCD, 0x1E, 0xC6, 0xF1, 0x30, 0x2D, 0x3A, 0x71, 0x00, 0xB7, 0xF2, 0x45, 0xC3, 0x21, 0x64, 0x00, + 0xCD, 0xF1, 0xCF, 0x18, 0xDB, 0xCD, 0x06, 0xC8, 0x43, 0x61, 0x6E, 0x27, 0x74, 0x20, 0x72, 0x65, + 0x61, 0x64, 0x20, 0x4C, 0x61, 0x62, 0x65, 0x6C, 0x8D, 0x1E, 0x01, 0xCD, 0xF2, 0xC5, 0xCD, 0x13, + 0xC4, 0xAF, 0xC9, 0x01, 0x10, 0x00, 0x11, 0x7A, 0x01, 0xCD, 0xEE, 0xC3, 0x0E, 0x01, 0xCD, 0xEE, + 0xC3, 0x3A, 0x78, 0x01, 0xFE, 0x43, 0x20, 0x02, 0xCB, 0xC8, 0x3A, 0x7E, 0x00, 0xE6, 0xCC, 0xB0, + 0x2A, 0x6A, 0x00, 0x77, 0xCD, 0xF6, 0xC3, 0x32, 0x7E, 0x00, 0xCB, 0x47, 0x11, 0x0A, 0x10, 0x21, + 0x00, 0x02, 0x20, 0x0D, 0xCB, 0x4F, 0x11, 0x05, 0x08, 0x20, 0x06, 0x11, 0x12, 0x1A, 0x21, 0x80, + 0x00, 0x22, 0x79, 0x00, 0xCB, 0x7F, 0x3E, 0x4C, 0x42, 0x28, 0x03, 0x3E, 0x27, 0x43, 0x32, 0x6F, + 0x00, 0x78, 0x32, 0x6E, 0x00, 0xAF, 0xC9, 0xCD, 0x14, 0xC8, 0xB7, 0xC8, 0x01, 0x10, 0x00, 0xCD, + 0xDE, 0xC3, 0x0E, 0x01, 0xCD, 0xDE, 0xC3, 0xCD, 0x14, 0xC8, 0xFE, 0x43, 0x20, 0x06, 0xCB, 0xC8, + 0x13, 0xCD, 0x14, 0xC8, 0xB7, 0xC2, 0xB9, 0xC1, 0x78, 0x32, 0x6D, 0x00, 0x37, 0xC9, 0xCD, 0x14, + 0xC8, 0x13, 0xFE, 0x53, 0xC8, 0xFE, 0x44, 0xC2, 0xB9, 0xC1, 0x78, 0xB1, 0x47, 0xC9, 0x1A, 0x13, + 0x13, 0xFE, 0x44, 0xC0, 0x18, 0xF4, 0x3A, 0x6C, 0x00, 0xD6, 0x41, 0x32, 0x77, 0x00, 0x21, 0x66, + 0x00, 0xCD, 0x86, 0xC1, 0x22, 0x6A, 0x00, 0x7E, 0xB7, 0xC9, 0xCD, 0xF2, 0xC5, 0xCD, 0x13, 0xC4, + 0xC3, 0x55, 0xC1, 0xCD, 0x06, 0xC8, 0x20, 0x45, 0x72, 0x72, 0xAD, 0x3A, 0x70, 0x00, 0xCD, 0xFE, + 0xC7, 0x3A, 0x71, 0x00, 0xCD, 0xDB, 0xC7, 0xC3, 0x97, 0xCC, 0xCD, 0x06, 0xC8, 0x41, 0x2D, 0x44, + 0x20, 0x6F, 0x6E, 0x6C, 0x79, 0x8D, 0xC3, 0x55, 0xC1, 0xCD, 0x27, 0xC8, 0x3A, 0x77, 0x00, 0xF5, + 0x3A, 0x6C, 0x00, 0xF5, 0x3E, 0x41, 0xF5, 0x32, 0x6C, 0x00, 0xCD, 0xF6, 0xC3, 0x2A, 0x6A, 0x00, + 0x46, 0xC4, 0x63, 0xC4, 0xF1, 0x3C, 0xFE, 0x45, 0x38, 0xEC, 0xF1, 0x32, 0x6C, 0x00, 0xF1, 0x32, + 0x77, 0x00, 0xC9, 0xCD, 0x06, 0xC8, 0x20, 0xA0, 0xCD, 0xE2, 0xC1, 0xCD, 0x06, 0xC8, 0x3B, 0xA0, + 0xCB, 0x58, 0xC4, 0xFC, 0xC7, 0xCB, 0x78, 0xCC, 0xFC, 0xC7, 0xCB, 0x60, 0xCD, 0x98, 0xC4, 0xCD, + 0xFC, 0xC7, 0xCB, 0x40, 0xCD, 0x98, 0xC4, 0xCB, 0x48, 0x28, 0x0A, 0xCD, 0x06, 0xC8, 0x20, 0x43, + 0x72, 0x6F, 0x6D, 0x69, 0xF8, 0xC3, 0x97, 0xCC, 0x3E, 0x44, 0x20, 0x02, 0x3E, 0x53, 0xC3, 0xFE, + 0xC7, 0x47, 0x3A, 0x6C, 0x00, 0xB7, 0xCA, 0xBD, 0xC1, 0x78, 0xFE, 0x53, 0x28, 0x2C, 0xCD, 0xB0, + 0xC8, 0xDA, 0xBD, 0xC1, 0xE5, 0xCD, 0xE1, 0xC4, 0x3E, 0x53, 0x32, 0x70, 0x00, 0xE1, 0xAF, 0xB4, + 0xC2, 0xBD, 0xC1, 0x3A, 0x6F, 0x00, 0xBD, 0x38, 0xE8, 0x7D, 0x32, 0x75, 0x00, 0xCD, 0xD4, 0xC4, + 0xD0, 0xC3, 0x0D, 0xC4, 0xCD, 0xF8, 0xC5, 0xC3, 0xCB, 0xCD, 0x13, 0xCD, 0xE1, 0xC4, 0xC3, 0xCB, + 0xCD, 0x3A, 0x75, 0x00, 0x32, 0x7D, 0x00, 0xCD, 0xAD, 0xC8, 0xD8, 0xAF, 0xB4, 0xC2, 0xBD, 0xC1, + 0x7D, 0xB7, 0x20, 0x04, 0x32, 0x78, 0x00, 0xC9, 0x3D, 0x20, 0xF2, 0xCD, 0xF6, 0xC3, 0xCB, 0x67, + 0x28, 0x06, 0x3E, 0x01, 0x32, 0x78, 0x00, 0xC9, 0xCD, 0x06, 0xC8, 0x53, 0x2E, 0x53, 0x69, 0x64, + 0x65, 0x64, 0x8D, 0xC3, 0x55, 0xC1, 0x06, 0x52, 0x18, 0x02, 0x06, 0x57, 0x1A, 0xFE, 0x44, 0xC2, + 0xBD, 0xC1, 0x78, 0x32, 0x70, 0x00, 0xCD, 0xBB, 0xC5, 0xE5, 0xFD, 0xE1, 0x60, 0x69, 0xD5, 0xE5, + 0x7B, 0x32, 0x76, 0x00, 0xFD, 0x22, 0x7B, 0x00, 0xCD, 0xD4, 0xC4, 0x3A, 0x70, 0x00, 0xFE, 0x57, + 0x37, 0x3F, 0xCC, 0xAB, 0xC5, 0x38, 0x08, 0x3A, 0x70, 0x00, 0xFE, 0x52, 0xCC, 0x52, 0xCD, 0xE1, + 0xD1, 0xDA, 0x0A, 0xC4, 0xED, 0x4B, 0x79, 0x00, 0xFD, 0x09, 0x03, 0xED, 0x42, 0x23, 0xDA, 0xF2, + 0xC5, 0x1C, 0x3A, 0x6E, 0x00, 0xBB, 0x30, 0xC6, 0x3A, 0x75, 0x00, 0x32, 0x7D, 0x00, 0x3C, 0x47, + 0x3A, 0x6F, 0x00, 0xB8, 0x38, 0x08, 0x78, 0x32, 0x75, 0x00, 0x1E, 0x01, 0x18, 0xB0, 0x1D, 0xCD, + 0xF2, 0xC5, 0xCD, 0x06, 0xC8, 0x4E, 0x65, 0x78, 0x74, 0x20, 0x6D, 0x65, 0x6D, 0x6F, 0x72, 0x79, + 0x3A, 0xA0, 0xFD, 0xE5, 0xE1, 0xCD, 0xE2, 0xC7, 0xCD, 0x06, 0xC8, 0x0D, 0x45, 0x6E, 0x64, 0x20, + 0x6F, 0x66, 0x20, 0x44, 0x69, 0x73, 0x6B, 0x8D, 0xC3, 0x55, 0xC1, 0x21, 0x7E, 0x00, 0x46, 0xC5, + 0xCB, 0xCE, 0xCD, 0x5F, 0xCD, 0xC1, 0x78, 0x32, 0x7E, 0x00, 0xC9, 0x3A, 0x6C, 0x00, 0xB7, 0xCA, + 0xBD, 0xC1, 0x13, 0xCD, 0x2F, 0xC8, 0xAF, 0xB2, 0xC2, 0xBD, 0xC1, 0xB3, 0xCA, 0xBD, 0xC1, 0xC5, + 0xD5, 0xE5, 0xCD, 0xF8, 0xC5, 0xE1, 0xD1, 0xC1, 0x3A, 0x6E, 0x00, 0xBB, 0x38, 0xEA, 0xDB, 0x31, + 0x57, 0xEB, 0xCD, 0xFC, 0xC7, 0xCD, 0xE2, 0xC7, 0xEB, 0xCD, 0xFC, 0xC7, 0x3A, 0x78, 0x00, 0xC3, + 0xF0, 0xC7, 0xCD, 0xDE, 0xC5, 0xC3, 0x97, 0xCC, 0x3A, 0x75, 0x00, 0xB7, 0x20, 0x20, 0x3A, 0x78, + 0x00, 0xB7, 0x20, 0x1A, 0x3A, 0x7E, 0x00, 0xCB, 0x6F, 0xC0, 0xCB, 0x4F, 0x20, 0x03, 0xCB, 0x47, + 0xC8, 0x32, 0x7F, 0x00, 0xCB, 0xEF, 0xCB, 0x87, 0x32, 0x7E, 0x00, 0xC3, 0x9B, 0xC3, 0x3A, 0x7E, + 0x00, 0xCB, 0x6F, 0xC8, 0x3A, 0x7F, 0x00, 0xC3, 0x87, 0xC3, 0xCD, 0x53, 0xC8, 0x4D, 0xED, 0x78, + 0xCD, 0xE7, 0xC7, 0xC3, 0x97, 0xCC, 0xCD, 0xAD, 0xC8, 0xE5, 0xCD, 0x1B, 0xC8, 0xCD, 0x53, 0xC8, + 0xD1, 0x4D, 0xED, 0x59, 0xC9, 0xCD, 0x2F, 0xC8, 0xC5, 0xD5, 0xE5, 0xED, 0xB0, 0xE1, 0xD1, 0xC1, + 0x18, 0x03, 0xCD, 0x2F, 0xC8, 0x1A, 0xBE, 0x28, 0x19, 0xCD, 0xE2, 0xC7, 0x7E, 0xCD, 0xDB, 0xC7, + 0xCD, 0xFC, 0xC7, 0x1A, 0xCD, 0xDB, 0xC7, 0xCD, 0xFC, 0xC7, 0xEB, 0xCD, 0xE2, 0xC7, 0xEB, 0xCD, + 0x97, 0xCC, 0x13, 0x23, 0x0B, 0x78, 0xB1, 0x20, 0xDC, 0xC9, 0xCD, 0x14, 0xC8, 0xFE, 0x4D, 0xC2, + 0xA1, 0xC4, 0x13, 0x2A, 0x64, 0x00, 0xCD, 0x5B, 0xC8, 0xCD, 0xE2, 0xC7, 0x7E, 0xCD, 0xDB, 0xC7, + 0xCD, 0xFC, 0xC7, 0xCD, 0xA3, 0xC7, 0xCD, 0x14, 0xC8, 0xFE, 0x2E, 0xC8, 0xFE, 0x2D, 0x20, 0x03, + 0x2B, 0x18, 0x1A, 0xCD, 0xF1, 0xC6, 0x30, 0x07, 0xCD, 0x06, 0xC8, 0x3F, 0x8D, 0x18, 0xDA, 0xAF, + 0x80, 0x20, 0x03, 0x23, 0x18, 0x07, 0x48, 0x06, 0x00, 0xEB, 0xED, 0xB0, 0xEB, 0x22, 0x64, 0x00, + 0x18, 0xC7, 0xCD, 0x65, 0xC8, 0xC5, 0xCD, 0xF1, 0xC6, 0xD1, 0xDA, 0xBD, 0xC1, 0xAF, 0x80, 0xCA, + 0xBD, 0xC1, 0xC5, 0xD5, 0xE5, 0x11, 0x2E, 0x00, 0x1A, 0xBE, 0x20, 0x04, 0x13, 0x23, 0x10, 0xF8, + 0xE1, 0xE5, 0x06, 0x10, 0xCC, 0x60, 0xC7, 0xE1, 0xD1, 0xC1, 0x23, 0x1B, 0x7A, 0xB3, 0x20, 0xE2, + 0xC9, 0xE5, 0x06, 0x00, 0x21, 0x2E, 0x00, 0xCD, 0x14, 0xC8, 0xB7, 0x28, 0x29, 0xFE, 0x2C, 0x13, + 0x28, 0xF5, 0x4F, 0xFE, 0x27, 0x28, 0x12, 0xFE, 0x22, 0x28, 0x0E, 0x1B, 0xE5, 0xCD, 0xAD, 0xC8, + 0x7D, 0xE1, 0x38, 0x12, 0x77, 0x23, 0x04, 0x18, 0xDE, 0x1A, 0x13, 0xB7, 0x28, 0x08, 0xB9, 0x28, + 0xD6, 0x77, 0x23, 0x04, 0x18, 0xF3, 0x11, 0x2E, 0x00, 0xE1, 0xC9, 0xCD, 0x14, 0xC8, 0xFE, 0x4D, + 0x20, 0x01, 0x13, 0x01, 0x80, 0x00, 0x2A, 0x62, 0x00, 0xCD, 0x4E, 0xC8, 0x1E, 0x10, 0xAF, 0xB0, + 0x20, 0x0A, 0x3E, 0x0F, 0xB9, 0x38, 0x05, 0xAF, 0xB1, 0x28, 0x01, 0x59, 0xC5, 0x43, 0xCD, 0x60, + 0xC7, 0x22, 0x62, 0x00, 0xC1, 0x79, 0x93, 0x4F, 0x30, 0x01, 0x05, 0x78, 0xB1, 0x20, 0xDD, 0xC9, + 0xCD, 0xE2, 0xC7, 0xC5, 0xE5, 0xD5, 0x0E, 0x00, 0x1E, 0x04, 0x3E, 0x03, 0xA1, 0xCC, 0xA0, 0xC7, + 0xCD, 0xA0, 0xC7, 0x7E, 0xCD, 0xE7, 0xC7, 0x1C, 0x1C, 0x23, 0x0C, 0x10, 0xED, 0xCD, 0xA0, 0xC7, + 0x3E, 0x3A, 0xBB, 0x20, 0xF8, 0xD1, 0xE1, 0xC1, 0x7E, 0x23, 0xCD, 0x92, 0xC7, 0x10, 0xF9, 0xC3, + 0x97, 0xCC, 0xE6, 0x7F, 0xFE, 0x7F, 0x28, 0x04, 0xFE, 0x20, 0x30, 0x62, 0x3E, 0x2E, 0x18, 0x5E, + 0x1C, 0x18, 0x59, 0x3E, 0x31, 0x11, 0x2E, 0x00, 0x12, 0xD5, 0xCD, 0xEA, 0xCB, 0xE3, 0x23, 0x46, + 0x04, 0x23, 0xE5, 0x05, 0x28, 0x17, 0x7E, 0xCD, 0xD2, 0xC7, 0x77, 0x23, 0xFE, 0x22, 0x28, 0x04, + 0xFE, 0x27, 0x20, 0xEF, 0x05, 0x28, 0x06, 0xBE, 0x23, 0x20, 0xF9, 0x18, 0xE6, 0x36, 0x00, 0xD1, + 0xE1, 0xC9, 0xFE, 0x61, 0xD8, 0xFE, 0x7B, 0xD0, 0xD6, 0x20, 0xC9, 0xF5, 0xCD, 0xFC, 0xC7, 0xF1, + 0x18, 0x05, 0x7C, 0xCD, 0xE7, 0xC7, 0x7D, 0xF5, 0x1F, 0x1F, 0x1F, 0x1F, 0xCD, 0xF0, 0xC7, 0xF1, + 0xE6, 0x0F, 0xFE, 0x0A, 0x38, 0x02, 0xC6, 0x07, 0xC6, 0x30, 0x18, 0x02, 0x3E, 0x20, 0xF5, 0xE6, + 0x7F, 0xCD, 0x99, 0xCC, 0xF1, 0xC9, 0xE3, 0x7E, 0x23, 0xB7, 0x28, 0x06, 0xCD, 0xFE, 0xC7, 0xF2, + 0x07, 0xC8, 0xE3, 0xC9, 0x1A, 0xFE, 0x20, 0xC0, 0x13, 0x18, 0xF9, 0xCD, 0x14, 0xC8, 0xFE, 0x2C, + 0xC0, 0x13, 0xCD, 0x14, 0xC8, 0xAF, 0xC9, 0xCD, 0x14, 0xC8, 0xB7, 0xC8, 0xC3, 0xBD, 0xC1, 0x21, + 0x80, 0x00, 0x44, 0x4D, 0xCD, 0x68, 0xC8, 0xE5, 0xC5, 0xCD, 0x1B, 0xC8, 0xCD, 0xAD, 0xC8, 0xDA, + 0xBD, 0xC1, 0xCD, 0x27, 0xC8, 0xEB, 0xC1, 0xE1, 0xC9, 0xCD, 0x65, 0xC8, 0x18, 0xD9, 0xCD, 0x68, + 0xC8, 0x18, 0xD4, 0xCD, 0xAD, 0xC8, 0xDA, 0xBD, 0xC1, 0x18, 0xCC, 0xE5, 0xCD, 0xAD, 0xC8, 0x38, + 0x01, 0xE3, 0xE1, 0x18, 0xC2, 0x37, 0x18, 0x01, 0xB7, 0x08, 0xC5, 0xE5, 0xCD, 0xAD, 0xC8, 0x30, + 0x08, 0x08, 0xDA, 0xBD, 0xC1, 0x08, 0xE1, 0x18, 0x01, 0xF1, 0xCD, 0x87, 0xC8, 0x30, 0x06, 0x08, + 0xC1, 0xD0, 0xC3, 0xBD, 0xC1, 0xF1, 0xC9, 0xCD, 0x1B, 0xC8, 0x1A, 0xFE, 0x53, 0x20, 0x01, 0x13, + 0xE5, 0xF5, 0xCD, 0xAD, 0xC8, 0x38, 0x0F, 0x44, 0x4D, 0xF1, 0xE1, 0x28, 0x07, 0x79, 0x95, 0x4F, + 0x78, 0x9C, 0x47, 0x03, 0xB7, 0xC9, 0xF1, 0xE1, 0xCA, 0xBD, 0xC1, 0x37, 0xC9, 0xCD, 0x14, 0xC8, + 0xCD, 0xE0, 0xC8, 0xD8, 0xD5, 0x13, 0xCD, 0xE0, 0xC8, 0x30, 0xFA, 0xD1, 0xFE, 0x2E, 0x28, 0x05, + 0xCD, 0xCA, 0xC8, 0xA7, 0xC9, 0xCD, 0xF4, 0xC8, 0xA7, 0xC9, 0x21, 0x00, 0x00, 0xCD, 0xE0, 0xC8, + 0x38, 0x09, 0x29, 0x29, 0x29, 0x29, 0x85, 0x6F, 0x13, 0x18, 0xF2, 0xFE, 0x48, 0xC0, 0x13, 0xC9, + 0x1A, 0xFE, 0x30, 0xD8, 0xFE, 0x3A, 0x38, 0x09, 0xFE, 0x41, 0xD8, 0xFE, 0x47, 0x3F, 0xD8, 0xD6, + 0x07, 0xD6, 0x30, 0xC9, 0x21, 0x00, 0x00, 0xCD, 0x10, 0xC9, 0x13, 0x38, 0x0D, 0xC5, 0x29, 0x44, + 0x4D, 0x29, 0x29, 0x09, 0xC1, 0xCD, 0x86, 0xC1, 0x18, 0xED, 0xFE, 0x2E, 0xC8, 0xC3, 0xBD, 0xC1, + 0x1A, 0xFE, 0x30, 0xD8, 0xFE, 0x3A, 0x3F, 0xD8, 0xD6, 0x30, 0xC9, 0x01, 0x18, 0x00, 0x11, 0x00, + 0x01, 0x21, 0x29, 0xC9, 0xED, 0xB0, 0xC3, 0x00, 0x01, 0x01, 0x00, 0x10, 0x11, 0x00, 0x10, 0x21, + 0x00, 0xC0, 0xC5, 0xD5, 0xE5, 0xED, 0xB0, 0x3E, 0x01, 0xD3, 0x40, 0xD1, 0xE1, 0xC1, 0xED, 0xB0, + 0xC9, 0xCD, 0x14, 0xC8, 0xFE, 0x5A, 0xF5, 0x20, 0x01, 0x13, 0xCD, 0x27, 0xC8, 0xF1, 0xC4, 0x1B, + 0xC9, 0xCD, 0x06, 0xC8, 0x0D, 0x4D, 0x65, 0x6D, 0x6F, 0x72, 0x79, 0xBA, 0x01, 0x00, 0x10, 0xCD, + 0xFC, 0xC7, 0x79, 0xCD, 0xF0, 0xC7, 0x0C, 0x10, 0xF6, 0xCD, 0x97, 0xCC, 0x06, 0x07, 0xCD, 0xFC, + 0xC7, 0x10, 0xFB, 0x60, 0x68, 0xCD, 0xFC, 0xC7, 0xE5, 0x11, 0x00, 0x10, 0x7C, 0xFE, 0xC9, 0x20, + 0x09, 0x7D, 0xFE, 0x8D, 0x38, 0x04, 0xFE, 0x9C, 0x38, 0x12, 0x46, 0x3E, 0x55, 0x77, 0xBE, 0x20, + 0x05, 0x2F, 0x77, 0xBE, 0x28, 0x05, 0x70, 0x3E, 0x58, 0x18, 0x09, 0x70, 0x23, 0x1B, 0x7A, 0xB3, + 0x20, 0xDA, 0x3E, 0x5E, 0xCD, 0xFE, 0xC7, 0xE1, 0x3E, 0x10, 0x84, 0x67, 0x20, 0xC7, 0xCD, 0x06, + 0xC8, 0x0D, 0x53, 0x70, 0x65, 0x63, 0x69, 0x66, 0x79, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x20, 0x28, + 0x65, 0x67, 0x2C, 0x20, 0x41, 0x3B, 0x20, 0x6F, 0x72, 0x20, 0x41, 0x3B, 0x3B, 0x20, 0x6F, 0x72, + 0x20, 0x41, 0x3B, 0x3B, 0x3B, 0x29, 0xA0, 0xCD, 0xA3, 0xC7, 0xCD, 0x14, 0xC8, 0xB7, 0xCA, 0x97, + 0xCC, 0xCD, 0xC1, 0xC2, 0xC2, 0xB9, 0xC1, 0xCD, 0x06, 0xC8, 0x53, 0x65, 0x65, 0x6B, 0x20, 0x74, + 0x65, 0x73, 0x74, 0x73, 0x3A, 0x8D, 0x06, 0x15, 0x21, 0x20, 0xCA, 0xDB, 0x31, 0x32, 0x7D, 0x00, + 0x7E, 0xC5, 0xE5, 0xFE, 0xFF, 0x20, 0x2E, 0xCD, 0x06, 0xC8, 0x20, 0x52, 0x65, 0x73, 0x74, 0x6F, + 0x72, 0x65, 0xBA, 0xCD, 0x04, 0xC6, 0xCD, 0x37, 0xCD, 0x08, 0xCD, 0x1E, 0xC6, 0x08, 0x18, 0x2C, + 0x01, 0x02, 0x03, 0x04, 0x05, 0xFE, 0x06, 0x07, 0x08, 0x09, 0x00, 0xFE, 0x27, 0x00, 0x15, 0x00, + 0x01, 0xFE, 0xFF, 0xFE, 0x27, 0xFE, 0xFE, 0x20, 0x06, 0xCD, 0x97, 0xCC, 0xB7, 0x18, 0x12, 0x32, + 0x75, 0x00, 0xCD, 0xDB, 0xC7, 0xCD, 0x06, 0xC8, 0xBA, 0xCD, 0xD4, 0xC4, 0xF5, 0xCD, 0x7A, 0xCB, + 0xF1, 0xE1, 0xC1, 0xDA, 0x97, 0xCC, 0x23, 0x10, 0xA2, 0xCD, 0x06, 0xC8, 0x0D, 0x52, 0x65, 0x61, + 0x64, 0x2F, 0x57, 0x72, 0x69, 0x74, 0x65, 0x20, 0x74, 0x65, 0x73, 0x74, 0x73, 0x8D, 0xCD, 0x94, + 0xCB, 0xCD, 0xB0, 0xCB, 0xDA, 0x97, 0xCC, 0xCD, 0x06, 0xC8, 0x57, 0x72, 0x69, 0x74, 0x65, 0x20, + 0x74, 0x65, 0x73, 0x74, 0x20, 0x4D, 0x41, 0x59, 0x20, 0x44, 0x45, 0x53, 0x54, 0x52, 0x4F, 0x59, + 0x20, 0x64, 0x61, 0x74, 0x61, 0x0D, 0x45, 0x53, 0x43, 0x3D, 0x61, 0x62, 0x6F, 0x72, 0x74, 0x20, + 0x52, 0x45, 0x54, 0x55, 0x52, 0x4E, 0x3D, 0x70, 0x72, 0x6F, 0x63, 0x65, 0x65, 0x64, 0xA0, 0xCD, + 0xA3, 0xC7, 0x21, 0x00, 0x09, 0xCD, 0xA2, 0xCB, 0x01, 0x00, 0x02, 0x75, 0x23, 0x0B, 0x78, 0xB1, + 0x20, 0xF9, 0xCD, 0xC1, 0xCB, 0x30, 0x6E, 0xCD, 0x06, 0xC8, 0x54, 0x65, 0x73, 0x74, 0x20, 0x66, + 0x61, 0x69, 0x6C, 0x65, 0x64, 0x21, 0x0D, 0x44, 0x69, 0x73, 0x6B, 0x20, 0x64, 0x61, 0x74, 0x61, + 0x20, 0x61, 0xF4, 0x1E, 0x01, 0xCD, 0xDE, 0xC5, 0xCD, 0x06, 0xC8, 0x20, 0x6D, 0x61, 0x79, 0x20, + 0x68, 0x61, 0x76, 0x65, 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, 0x64, 0x65, 0x73, 0x74, 0x72, 0x6F, + 0x79, 0x65, 0x64, 0x0D, 0x4F, 0x72, 0x69, 0x67, 0x69, 0x6E, 0x61, 0x6C, 0x20, 0x69, 0x73, 0x20, + 0x6C, 0x6F, 0x63, 0x61, 0x74, 0x65, 0x64, 0x20, 0x61, 0x74, 0x20, 0x30, 0x44, 0x30, 0x30, 0xF3, + 0x2A, 0x79, 0x00, 0xCD, 0xE2, 0xC7, 0xCD, 0x06, 0xC8, 0x20, 0x69, 0x6E, 0x20, 0x6D, 0x65, 0x6D, + 0x6F, 0x72, 0x79, 0x8D, 0xC9, 0x21, 0x00, 0x0B, 0xCD, 0xA2, 0xCB, 0xCD, 0xB0, 0xCB, 0x38, 0x87, + 0xCD, 0x06, 0xC8, 0x50, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6E, 0x20, 0x63, 0x6F, 0x6D, 0x70, 0x61, + 0x72, 0x65, 0xA0, 0xED, 0x4B, 0x79, 0x00, 0x11, 0x00, 0x09, 0x21, 0x00, 0x0B, 0x1A, 0xBE, 0x20, + 0x09, 0x13, 0x23, 0x0B, 0x78, 0xB1, 0x20, 0xF5, 0x18, 0x01, 0x37, 0xCD, 0xD1, 0xCB, 0xCD, 0x94, + 0xCB, 0xCD, 0xC1, 0xCB, 0xDA, 0xC7, 0xCA, 0xC3, 0x97, 0xCC, 0x38, 0x06, 0xCD, 0x06, 0xC8, 0x4F, + 0xCB, 0xC9, 0xCD, 0x06, 0xC8, 0x65, 0x72, 0x72, 0x6F, 0x72, 0xA0, 0x3A, 0x71, 0x00, 0xCD, 0xE7, + 0xC7, 0xC3, 0x97, 0xCC, 0xCD, 0x06, 0xC8, 0x44, 0x61, 0x74, 0xE1, 0x21, 0x00, 0x0D, 0x22, 0x7B, + 0x00, 0xC9, 0x22, 0x7B, 0x00, 0xCD, 0x06, 0xC8, 0x50, 0x61, 0x74, 0x74, 0x65, 0x72, 0xEE, 0xC9, + 0xCD, 0xDA, 0xCB, 0xCD, 0x06, 0xC8, 0x20, 0x72, 0x65, 0x61, 0x64, 0xA0, 0xCD, 0x52, 0xCD, 0x18, + 0x10, 0xCD, 0xDA, 0xCB, 0xCD, 0x06, 0xC8, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0xA0, 0xCD, 0xAB, + 0xC5, 0xF5, 0xCD, 0x7A, 0xCB, 0xCD, 0x97, 0xCC, 0xF1, 0xC9, 0x3E, 0x27, 0x32, 0x75, 0x00, 0x32, + 0x7D, 0x00, 0x3E, 0x01, 0x32, 0x76, 0x00, 0xC3, 0xCB, 0xCD, 0xC5, 0xE5, 0x06, 0x00, 0x21, 0x02, + 0x00, 0x19, 0xCD, 0x64, 0xCC, 0xFE, 0x10, 0xCC, 0xBB, 0xCC, 0x28, 0xF6, 0xFE, 0x1B, 0xCA, 0x8E, + 0xCC, 0xFE, 0x08, 0x28, 0x04, 0xFE, 0x7F, 0x20, 0x11, 0xAF, 0xB0, 0x28, 0xE5, 0x2B, 0x05, 0xCD, + 0x4B, 0xCC, 0x7E, 0xFE, 0x20, 0xDC, 0x4B, 0xCC, 0x18, 0xD8, 0xFE, 0x0D, 0xCC, 0x45, 0xCC, 0x28, + 0x1B, 0xFE, 0x15, 0x20, 0x08, 0xCD, 0x45, 0xCC, 0xCD, 0x97, 0xCC, 0x18, 0xBF, 0x4F, 0x1A, 0x3D, + 0xB8, 0x28, 0xBF, 0x79, 0xCD, 0x45, 0xCC, 0x77, 0x23, 0x04, 0x18, 0xB6, 0x36, 0x00, 0x78, 0x13, + 0x12, 0x1B, 0xE1, 0xC1, 0xC9, 0xF5, 0xCD, 0x52, 0xCC, 0xF1, 0xC9, 0xCD, 0x06, 0xC8, 0x08, 0x20, + 0x88, 0xC9, 0xFE, 0x20, 0x30, 0x43, 0xFE, 0x0D, 0x28, 0x3F, 0xF5, 0xCD, 0x06, 0xC8, 0xDE, 0xF1, + 0xC6, 0x40, 0x18, 0x35, 0xCD, 0x23, 0xCD, 0xCD, 0x76, 0xCC, 0x28, 0xF8, 0xCD, 0x76, 0xCC, 0x28, + 0xFB, 0xDB, 0x01, 0xE6, 0x7F, 0xC9, 0xDB, 0x00, 0xE6, 0x40, 0xC9, 0xCD, 0x76, 0xCC, 0xC8, 0xCD, + 0x6C, 0xCC, 0xFE, 0x13, 0xCC, 0x6C, 0xCC, 0xFE, 0x0D, 0x28, 0x03, 0xFE, 0x1B, 0xC0, 0x31, 0x2E, + 0x00, 0xCD, 0x97, 0xCC, 0xC3, 0x55, 0xC1, 0x3E, 0x0D, 0xF5, 0xD9, 0xCB, 0x78, 0xD9, 0xC4, 0xCB, + 0xCC, 0xCD, 0x23, 0xCD, 0xDB, 0x00, 0xE6, 0x80, 0x28, 0xFA, 0xF1, 0xD3, 0x01, 0xFE, 0x0D, 0xC0, + 0x3E, 0x0A, 0xCD, 0x99, 0xCC, 0xCD, 0x7B, 0xCC, 0xFE, 0x10, 0xC0, 0xF5, 0xD9, 0x3E, 0x80, 0xA8, + 0x47, 0xCB, 0x78, 0xD9, 0xC4, 0xC9, 0xCC, 0xF1, 0xC9, 0x3E, 0x11, 0xF5, 0xE5, 0x21, 0x08, 0x00, + 0xCD, 0xF1, 0xCF, 0xE1, 0xF1, 0xF5, 0xFE, 0x11, 0x28, 0x13, 0xCD, 0x7B, 0xCC, 0xFE, 0x10, 0x20, + 0x05, 0xCD, 0xBB, 0xCC, 0xF1, 0xC9, 0xDB, 0x54, 0x2F, 0xE6, 0x20, 0x28, 0xED, 0xF1, 0xCB, 0xFF, + 0xD3, 0x54, 0xCB, 0xBF, 0xD3, 0x54, 0xCB, 0xFF, 0xD3, 0x54, 0xCB, 0xBF, 0xC9, 0xCD, 0x14, 0xC8, + 0xFE, 0x4F, 0xC2, 0xBD, 0xC1, 0x13, 0x1A, 0xFE, 0x4E, 0x28, 0x0E, 0xFE, 0x46, 0xC2, 0xBD, 0xC1, + 0xD9, 0xCB, 0xA8, 0xD9, 0x3E, 0xFF, 0xD3, 0x04, 0xC9, 0xD9, 0xCB, 0xE8, 0xD9, 0x3E, 0x01, 0x32, + 0x72, 0x00, 0xC9, 0xD9, 0xCB, 0x68, 0xD9, 0xC8, 0xC5, 0xCD, 0xA8, 0xCF, 0xC1, 0xD3, 0x34, 0xCD, + 0xD6, 0xCF, 0xEE, 0xA0, 0xD3, 0x04, 0xC9, 0x16, 0x02, 0xD5, 0xCD, 0x70, 0xCD, 0xD1, 0xD0, 0xD5, + 0x3E, 0x0A, 0x32, 0x75, 0x00, 0xCD, 0xCB, 0xCD, 0xCD, 0x70, 0xCD, 0xD1, 0xD0, 0x15, 0x20, 0xE9, + 0x18, 0x18, 0x16, 0x0A, 0xD5, 0xCD, 0x58, 0xCE, 0xD1, 0xD0, 0x15, 0x20, 0xF7, 0x18, 0x0B, 0x16, + 0x04, 0xD5, 0xCD, 0x9F, 0xCE, 0xD1, 0xD0, 0x15, 0x20, 0xF7, 0x3A, 0x71, 0x00, 0x4F, 0x37, 0xC9, + 0x97, 0x32, 0x75, 0x00, 0x32, 0x78, 0x00, 0xCD, 0x55, 0xCF, 0xD3, 0x34, 0xCD, 0x25, 0xCE, 0x38, + 0x0E, 0xD3, 0x30, 0xDB, 0x34, 0xCB, 0x57, 0x20, 0x3B, 0x1F, 0x30, 0xF7, 0xC3, 0x3E, 0xCE, 0x3E, + 0xC4, 0xD3, 0x30, 0xCD, 0xD6, 0xCF, 0xE6, 0x57, 0xD3, 0x04, 0xCD, 0xE4, 0xCF, 0xDB, 0x04, 0xE6, + 0x40, 0x20, 0x16, 0xCD, 0xCF, 0xCF, 0xDB, 0x34, 0xCB, 0x57, 0x20, 0x18, 0x1F, 0x30, 0xF7, 0x3E, + 0xD0, 0xD3, 0x30, 0x97, 0xD3, 0x31, 0xC3, 0x50, 0xCE, 0xDB, 0x34, 0xCB, 0x57, 0x20, 0x05, 0x1F, + 0x30, 0xDB, 0x18, 0xCB, 0x3E, 0x80, 0x32, 0x71, 0x00, 0x37, 0xC9, 0x97, 0xCD, 0x55, 0xCF, 0xD3, + 0x34, 0x3A, 0x75, 0x00, 0xD3, 0x33, 0x4F, 0x3A, 0x76, 0x00, 0xD3, 0x32, 0x3A, 0x7D, 0x00, 0xD3, + 0x31, 0x91, 0xCA, 0xCF, 0xCF, 0xCD, 0x25, 0xCE, 0x38, 0x0F, 0xF6, 0x10, 0xD3, 0x30, 0xDB, 0x34, + 0xCB, 0x57, 0x20, 0xD0, 0x1F, 0x30, 0xF7, 0x18, 0x45, 0xCD, 0xD6, 0xCF, 0xE6, 0x4F, 0xD3, 0x04, + 0x3E, 0x18, 0xD3, 0x30, 0xDB, 0x34, 0xCB, 0x57, 0x20, 0xBA, 0x1F, 0x30, 0xF7, 0xDB, 0x30, 0x2E, + 0x32, 0xDB, 0x04, 0xE6, 0x40, 0x20, 0xFA, 0x2D, 0x20, 0xF7, 0xDB, 0x04, 0xE6, 0x40, 0x20, 0xFA, + 0xCD, 0xCF, 0xCF, 0x18, 0x2B, 0x3A, 0x7E, 0x00, 0xCB, 0x57, 0x20, 0x0A, 0xCB, 0x5F, 0x3E, 0x0E, + 0x28, 0x02, 0x3E, 0x0C, 0xA7, 0xC9, 0xCB, 0x5F, 0x3E, 0x0F, 0x28, 0xF8, 0x37, 0xC9, 0xCD, 0xCF, + 0xCF, 0x21, 0x64, 0x00, 0xCD, 0xF1, 0xCF, 0xDB, 0x30, 0x32, 0x71, 0x00, 0xE6, 0x98, 0x37, 0xC0, + 0x3A, 0x75, 0x00, 0x32, 0x7D, 0x00, 0xA7, 0xC9, 0xCD, 0x8F, 0xCE, 0xD3, 0x30, 0xDB, 0x34, 0x1F, + 0x38, 0x16, 0xED, 0xA2, 0x04, 0xDB, 0x34, 0x1F, 0x38, 0x0E, 0xED, 0xA2, 0xC2, 0x5D, 0xCE, 0xDB, + 0x34, 0xCB, 0x4F, 0x20, 0x10, 0x1F, 0x30, 0xF7, 0xCD, 0xCF, 0xCF, 0xDB, 0x30, 0x32, 0x71, 0x00, + 0xE6, 0x9C, 0xC8, 0x18, 0x08, 0xCD, 0xCF, 0xCF, 0x3E, 0x80, 0x32, 0x71, 0x00, 0x37, 0xC9, 0xCD, + 0x40, 0xCF, 0x57, 0xF3, 0xCD, 0xC6, 0xCF, 0xC6, 0x88, 0x5F, 0x7A, 0xD3, 0x34, 0x7B, 0xC9, 0xCD, + 0xE4, 0xCF, 0xCD, 0x40, 0xCF, 0x57, 0xF3, 0xCD, 0xC6, 0xCF, 0xC6, 0xA8, 0x5F, 0x7A, 0xD3, 0x34, + 0x7B, 0xD3, 0x30, 0xDB, 0x34, 0x1F, 0x38, 0x12, 0xED, 0xA3, 0x04, 0xDB, 0x34, 0x1F, 0x38, 0x0A, + 0xED, 0xA3, 0xC2, 0xB3, 0xCE, 0xDB, 0x34, 0x1F, 0x30, 0xFB, 0xCD, 0xCF, 0xCF, 0xCD, 0xE4, 0xCF, + 0xDB, 0x30, 0x32, 0x71, 0x00, 0xE6, 0xFC, 0x37, 0xC0, 0xA7, 0x3A, 0x7E, 0x00, 0xCB, 0x4F, 0xC8, + 0xCD, 0x00, 0xCF, 0x38, 0x0A, 0xDB, 0x34, 0x1F, 0x38, 0x04, 0xDB, 0x33, 0x18, 0xF7, 0x1C, 0xCD, + 0xCF, 0xCF, 0xDB, 0x30, 0x32, 0x71, 0x00, 0xE6, 0x9C, 0x37, 0xC0, 0x7B, 0xA7, 0xC8, 0x37, 0xC9, + 0xCD, 0x8F, 0xCE, 0xED, 0x4B, 0x79, 0x00, 0xCB, 0x38, 0xCB, 0x19, 0xCB, 0x38, 0xCB, 0x19, 0x41, + 0x1E, 0x00, 0xD3, 0x30, 0xDB, 0x34, 0x1F, 0xD8, 0xDB, 0x33, 0xAE, 0xC0, 0x23, 0xDB, 0x34, 0x1F, + 0xD8, 0xDB, 0x33, 0xAE, 0xC0, 0x23, 0xDB, 0x34, 0x1F, 0xD8, 0xDB, 0x33, 0xAE, 0xC0, 0x23, 0xDB, + 0x34, 0x1F, 0xD8, 0xDB, 0x33, 0xAE, 0xC0, 0x23, 0x10, 0xDA, 0xDB, 0x34, 0x1F, 0x30, 0xFB, 0xC9, + 0xDB, 0x33, 0x3E, 0x80, 0xCD, 0x55, 0xCF, 0x2A, 0x79, 0x00, 0xCB, 0x1C, 0xCB, 0x1D, 0x45, 0x0E, + 0x33, 0x2A, 0x7B, 0x00, 0xC9, 0x4F, 0xDB, 0x34, 0xE6, 0x04, 0x28, 0x04, 0x97, 0x32, 0x72, 0x00, + 0xCD, 0xA8, 0xCF, 0xD3, 0x34, 0xF5, 0xE5, 0xCD, 0xD6, 0xCF, 0xE6, 0x5F, 0xD3, 0x04, 0x3A, 0x72, + 0x00, 0xA7, 0x28, 0x21, 0x21, 0x90, 0x01, 0x3A, 0x73, 0x00, 0xB8, 0x20, 0x1B, 0x3A, 0x74, 0x00, + 0x67, 0x3A, 0x78, 0x00, 0x32, 0x74, 0x00, 0xBC, 0x20, 0x06, 0xDB, 0x34, 0xE6, 0x20, 0x20, 0x0B, + 0xCD, 0xE4, 0xCF, 0x18, 0x06, 0x21, 0x20, 0x4E, 0xCD, 0xF1, 0xCF, 0xE1, 0x78, 0x32, 0x73, 0x00, + 0x3E, 0x01, 0x32, 0x72, 0x00, 0xF1, 0xB1, 0xC9, 0x3A, 0x77, 0x00, 0x47, 0x04, 0x97, 0x37, 0x17, + 0x10, 0xFD, 0x47, 0x3A, 0x7E, 0x00, 0xCB, 0x57, 0x28, 0x02, 0xCB, 0xE0, 0xCB, 0x47, 0x28, 0x02, + 0xCB, 0xF0, 0x78, 0xF6, 0x20, 0xC9, 0xDB, 0x34, 0x2F, 0xE6, 0x20, 0xC8, 0x3E, 0x04, 0xC9, 0xCD, + 0xD6, 0xCF, 0xD3, 0x04, 0xAF, 0xC9, 0xC5, 0x06, 0x7F, 0x3A, 0x78, 0x00, 0xA7, 0x28, 0x02, 0x06, + 0x7D, 0x78, 0xC1, 0xC9, 0x21, 0x08, 0x00, 0x3A, 0x7E, 0x00, 0xCB, 0x57, 0x20, 0x03, 0x21, 0x0C, + 0x00, 0xC5, 0x2B, 0x06, 0x1C, 0x10, 0xFE, 0x00, 0x00, 0x7D, 0xB4, 0x20, 0xF5, 0xC1, 0xC9, 0xFF +}, +{ /* RDOS 3.12 */ + 0xF3, 0x18, 0x36, 0xC3, 0x43, 0xC3, 0xC3, 0x75, 0xC3, 0xC3, 0x79, 0xC3, 0xC3, 0x7D, 0xC3, 0xC3, + 0x06, 0xCA, 0xC3, 0x88, 0xC3, 0xC3, 0xAF, 0xC3, 0xC3, 0xC0, 0xC3, 0xC3, 0xD0, 0xC3, 0xC3, 0x81, + 0xC3, 0xC3, 0xAA, 0xCF, 0xC3, 0x02, 0xD5, 0xC3, 0xF8, 0xD4, 0xC3, 0xA1, 0xD4, 0xC3, 0x1F, 0xD4, + 0xC3, 0xE4, 0xD4, 0xC3, 0xF2, 0xD4, 0xC3, 0x80, 0xD4, 0xAF, 0x47, 0xD3, 0x03, 0xD3, 0xE1, 0x2F, + 0xD3, 0x04, 0x3E, 0xD0, 0xD3, 0x30, 0x0E, 0x00, 0xD9, 0x21, 0x03, 0x00, 0x25, 0x20, 0xFD, 0x74, + 0x2C, 0xF2, 0x4F, 0xC0, 0x31, 0xF0, 0x7F, 0x3E, 0xFF, 0x32, 0x07, 0x00, 0x3E, 0x20, 0x32, 0x10, + 0x00, 0x22, 0x05, 0x00, 0x22, 0x03, 0x00, 0xCD, 0xAA, 0xCF, 0xDB, 0x34, 0xE6, 0x40, 0xCC, 0x74, + 0xC4, 0xCD, 0xF2, 0xD4, 0x43, 0x72, 0x6F, 0x6D, 0x65, 0x6D, 0x63, 0x6F, 0x20, 0x52, 0x44, 0x4F, + 0x53, 0x20, 0x30, 0x33, 0x2E, 0x31, 0x32, 0x8D, 0x3E, 0xFF, 0x32, 0x07, 0x00, 0x31, 0xF0, 0x7F, + 0xCD, 0x58, 0xD3, 0x21, 0x15, 0x00, 0x3A, 0x07, 0x00, 0xCD, 0xCB, 0xC0, 0xCD, 0x1A, 0xD4, 0xCD, + 0x45, 0xD3, 0xB7, 0x28, 0xE3, 0xD6, 0x41, 0xFE, 0x1A, 0x30, 0x4C, 0x21, 0x8D, 0xC0, 0xE5, 0x47, + 0x13, 0xCD, 0x45, 0xD3, 0xFE, 0x3B, 0x78, 0x28, 0x76, 0x87, 0x21, 0x5D, 0xD5, 0xCD, 0x84, 0xD2, + 0x7E, 0x23, 0x66, 0x6F, 0xE5, 0x21, 0x80, 0x00, 0xC3, 0x45, 0xD3, 0x28, 0x10, 0xFE, 0xFF, 0x28, + 0x15, 0xCD, 0xF2, 0xD4, 0x53, 0xD4, 0xCD, 0xFE, 0xD2, 0x3E, 0x3A, 0x18, 0x17, 0xFE, 0xFF, 0x28, + 0x05, 0xC6, 0x41, 0xCD, 0xA1, 0xD4, 0x3E, 0x3B, 0x28, 0x0A, 0xCB, 0x5E, 0xCC, 0xA1, 0xD4, 0xCB, + 0x56, 0xCC, 0xA1, 0xD4, 0xC3, 0xA1, 0xD4, 0xCD, 0xF2, 0xD4, 0x3F, 0x8D, 0x18, 0x8F, 0xCD, 0x27, + 0xC1, 0x1B, 0x1F, 0x41, 0x2D, 0xC4, 0x18, 0x0D, 0xCD, 0x27, 0xC1, 0x1B, 0x1F, 0x53, 0x54, 0x30, + 0x2D, 0x53, 0x54, 0x33, 0xC6, 0xCD, 0xF2, 0xD4, 0x20, 0x4F, 0x6E, 0x6C, 0x79, 0x8D, 0x18, 0xDC, + 0xCD, 0x27, 0xC1, 0x01, 0x07, 0xA0, 0xC9, 0xE3, 0xF5, 0xCD, 0xA9, 0xCC, 0xF1, 0xE3, 0xC9, 0xFE, + 0x04, 0x30, 0xCB, 0xF5, 0x13, 0x1A, 0xFE, 0x3B, 0x06, 0x0C, 0x20, 0x0B, 0x13, 0x1A, 0xFE, 0x3B, + 0x06, 0x04, 0x20, 0x03, 0x13, 0xAF, 0x47, 0xCD, 0x66, 0xC2, 0xD1, 0xF5, 0xAF, 0x32, 0x08, 0x00, + 0x7A, 0x32, 0x16, 0x00, 0x32, 0x07, 0x00, 0xF1, 0x21, 0x15, 0x00, 0x70, 0x38, 0x02, 0xB0, 0x77, + 0xF5, 0xCD, 0xAF, 0xC1, 0xCD, 0xB5, 0xC2, 0x3E, 0x48, 0x32, 0x09, 0x00, 0xCD, 0x88, 0xC3, 0xDA, + 0xE6, 0xCB, 0xF1, 0xD0, 0x3E, 0xD2, 0x32, 0x09, 0x00, 0x21, 0x80, 0x00, 0x22, 0x1B, 0x00, 0xCD, + 0x60, 0xD6, 0xCD, 0xD2, 0xD5, 0x30, 0x1F, 0x3A, 0x21, 0x00, 0xB7, 0xF2, 0x96, 0xC1, 0x21, 0x64, + 0x00, 0xCD, 0x7C, 0xD8, 0x18, 0xE3, 0xCD, 0xE6, 0xCB, 0xCD, 0x20, 0xC1, 0xCD, 0xF2, 0xD4, 0x4C, + 0x61, 0x62, 0x65, 0x6C, 0x8D, 0xC9, 0x21, 0xF8, 0x00, 0xCD, 0x9A, 0xC2, 0xCD, 0xB5, 0xC2, 0xAF, + 0x32, 0x08, 0x00, 0x21, 0x27, 0x00, 0x3A, 0x16, 0x00, 0xCD, 0x84, 0xD2, 0x3A, 0x15, 0x00, 0xCB, + 0xFF, 0x77, 0xC9, 0x13, 0xCD, 0xB2, 0xD3, 0xFE, 0x3A, 0xC2, 0xF7, 0xC0, 0x45, 0x7C, 0xB7, 0xC2, + 0xF7, 0xC0, 0x13, 0xCD, 0xE9, 0xD2, 0x78, 0xF5, 0xFE, 0x40, 0xD2, 0x08, 0xC1, 0x32, 0x16, 0x00, + 0x32, 0x07, 0x00, 0x3E, 0x80, 0x32, 0x08, 0x00, 0x3E, 0xD8, 0x32, 0x09, 0x00, 0xCD, 0xA3, 0xC3, + 0xCD, 0x8A, 0xD8, 0xDA, 0x8D, 0xC0, 0x21, 0x80, 0x00, 0x22, 0x1B, 0x00, 0x21, 0x00, 0x02, 0x22, + 0x1D, 0x00, 0xCD, 0x37, 0xD9, 0xF1, 0x38, 0x0F, 0xCD, 0x51, 0xDA, 0xDC, 0xF4, 0xCB, 0xCC, 0x3D, + 0xC2, 0xCD, 0x51, 0xDA, 0x11, 0xF8, 0x00, 0xCD, 0xEF, 0xC2, 0xCB, 0x77, 0xC8, 0x21, 0x1A, 0x00, + 0x34, 0xCD, 0x7D, 0xD9, 0xCD, 0x51, 0xDA, 0xD0, 0xCD, 0xF4, 0xCB, 0xCD, 0x20, 0xC1, 0xCD, 0xF2, + 0xD4, 0x53, 0x75, 0x70, 0x65, 0x72, 0x42, 0x6C, 0x6F, 0x63, 0x6B, 0x8D, 0xC9, 0x3E, 0xC8, 0x32, + 0x09, 0x00, 0x21, 0x80, 0x00, 0x22, 0x1B, 0x00, 0x21, 0xE5, 0xE5, 0x22, 0xF8, 0x00, 0xCD, 0x88, + 0xC3, 0xDA, 0xF4, 0xCB, 0x3E, 0xD2, 0x32, 0x09, 0x00, 0xCD, 0x7D, 0xD9, 0xCD, 0x51, 0xDA, 0xD0, + 0xCD, 0xF4, 0xCB, 0xC3, 0x99, 0xC1, 0xE5, 0x0E, 0x00, 0x21, 0x10, 0x44, 0xCD, 0x85, 0xC2, 0x38, + 0x0F, 0x2E, 0x01, 0xCD, 0x85, 0xC2, 0xDA, 0xF7, 0xC0, 0x21, 0x02, 0x58, 0xCD, 0x8F, 0xC2, 0xB7, + 0x79, 0xE1, 0xC3, 0xE9, 0xD2, 0xCD, 0x8F, 0xC2, 0xD0, 0xD6, 0x53, 0x28, 0x0B, 0x37, 0xC9, 0xCD, + 0x45, 0xD3, 0xBC, 0x37, 0xC0, 0x79, 0xB5, 0x4F, 0x13, 0xC9, 0x01, 0x02, 0x43, 0xCD, 0xA8, 0xC2, + 0x01, 0x10, 0x44, 0xCD, 0xA8, 0xC2, 0x0E, 0x01, 0x7E, 0x23, 0x23, 0xB8, 0xC0, 0x3A, 0x15, 0x00, + 0xB1, 0x32, 0x15, 0x00, 0xC9, 0x3A, 0x15, 0x00, 0x47, 0xCB, 0x40, 0x11, 0x10, 0x0A, 0x21, 0x00, + 0x02, 0x20, 0x0D, 0xCB, 0x48, 0x11, 0x08, 0x05, 0x20, 0x06, 0x11, 0x1A, 0x12, 0x21, 0x80, 0x00, + 0x22, 0x1D, 0x00, 0xCB, 0x50, 0x7B, 0x1E, 0x4C, 0x20, 0x03, 0x7A, 0x1E, 0x27, 0x32, 0x11, 0x00, + 0xAF, 0x57, 0xED, 0x53, 0x12, 0x00, 0xCB, 0x60, 0x28, 0x01, 0x3C, 0x32, 0x14, 0x00, 0xC9, 0x3E, + 0x80, 0x21, 0x08, 0x00, 0x77, 0x38, 0x35, 0x1A, 0xFE, 0x43, 0x20, 0x02, 0xCB, 0xF6, 0x13, 0x1A, + 0xFE, 0x53, 0x20, 0x28, 0x13, 0x1A, 0xFE, 0x54, 0x20, 0x22, 0x21, 0xEE, 0xFF, 0x19, 0xC5, 0x56, + 0x23, 0x5E, 0x23, 0xD5, 0x56, 0x23, 0x5E, 0x23, 0x4E, 0x06, 0x00, 0xEB, 0xCD, 0xBF, 0xD2, 0x7B, + 0xB2, 0x28, 0x01, 0x23, 0xD1, 0x19, 0x79, 0x3D, 0x2B, 0xC1, 0x18, 0x05, 0x3E, 0x05, 0x21, 0x31, + 0x01, 0x32, 0x14, 0x00, 0x22, 0x12, 0x00, 0x3E, 0x13, 0x32, 0x11, 0x00, 0x21, 0x00, 0x02, 0x22, + 0x1D, 0x00, 0xC9, 0x32, 0x07, 0x00, 0xFE, 0x40, 0x30, 0x08, 0x47, 0x37, 0xCD, 0xD6, 0xC1, 0xC3, + 0x57, 0xDA, 0xD6, 0x41, 0xFE, 0x04, 0x38, 0x07, 0x3E, 0xFF, 0x32, 0x07, 0x00, 0x37, 0xC9, 0x32, + 0x07, 0x00, 0x32, 0x16, 0x00, 0x78, 0x32, 0x15, 0x00, 0xD9, 0xCB, 0xA8, 0xD9, 0xDB, 0x31, 0x32, + 0x1F, 0x00, 0xC3, 0xAC, 0xC1, 0x32, 0x17, 0x00, 0xC9, 0x22, 0x18, 0x00, 0xC9, 0x32, 0x1A, 0x00, + 0xC9, 0xCD, 0x51, 0xDA, 0x47, 0xC3, 0x57, 0xDA, 0xCD, 0xA3, 0xC3, 0x20, 0x06, 0xCD, 0x3B, 0xDA, + 0xC3, 0x51, 0xDA, 0xD9, 0xCB, 0xA8, 0xD9, 0xCD, 0x12, 0xC4, 0xCD, 0x91, 0xD5, 0xF5, 0xCD, 0x30, + 0xC4, 0xF1, 0xC9, 0xAF, 0x67, 0x6F, 0x32, 0x17, 0x00, 0x22, 0x18, 0x00, 0xC3, 0xE6, 0xCE, 0xCD, + 0x58, 0xD3, 0x20, 0x06, 0xCD, 0x08, 0xC4, 0xC3, 0x60, 0xD6, 0xCD, 0x17, 0xDA, 0xC3, 0x51, 0xDA, + 0xCD, 0xEA, 0xC3, 0xD8, 0xF5, 0xC4, 0x7D, 0xD9, 0xF1, 0x20, 0x18, 0xCD, 0xD2, 0xD5, 0x18, 0x0E, + 0xCD, 0xEA, 0xC3, 0xD8, 0xF5, 0xC4, 0x04, 0xDA, 0xF1, 0x20, 0x08, 0xCD, 0xF8, 0xC3, 0xED, 0x4B, + 0x1D, 0x00, 0xC9, 0xED, 0x4B, 0x1D, 0x00, 0xC3, 0x51, 0xDA, 0xCD, 0xAF, 0xC3, 0x3A, 0x08, 0x00, + 0xCB, 0x7F, 0x20, 0x01, 0xD8, 0xE6, 0x80, 0xC9, 0x21, 0x15, 0x00, 0x46, 0xC5, 0xCB, 0xCE, 0xCD, + 0xE7, 0xD5, 0xC1, 0x78, 0x32, 0x15, 0x00, 0xC9, 0x3A, 0x18, 0x00, 0x47, 0x3A, 0x17, 0x00, 0xB0, + 0x20, 0x1E, 0xD9, 0xCB, 0x68, 0xD9, 0xC0, 0x3A, 0x15, 0x00, 0xCB, 0x4F, 0x20, 0x03, 0xCB, 0x47, + 0xC8, 0x32, 0x26, 0x00, 0xE6, 0xFC, 0x32, 0x15, 0x00, 0xD9, 0xCB, 0xE8, 0xD9, 0xC3, 0xB5, 0xC2, + 0xD9, 0xCB, 0x68, 0xCB, 0xA8, 0xD9, 0xC8, 0x3A, 0x26, 0x00, 0x32, 0x15, 0x00, 0xC3, 0xB5, 0xC2, + 0xB7, 0x28, 0x31, 0x13, 0xFE, 0x53, 0x20, 0x20, 0x1A, 0xCD, 0x2C, 0xD3, 0xFE, 0x54, 0xC2, 0x08, + 0xC1, 0x13, 0xCD, 0xB2, 0xD3, 0xB7, 0xC2, 0x08, 0xC1, 0x7C, 0xA7, 0xC2, 0x08, 0xC1, 0x7D, 0xFE, + 0x40, 0xD2, 0x08, 0xC1, 0xF6, 0x80, 0x18, 0x2F, 0xCD, 0xE9, 0xD2, 0xD6, 0x41, 0xFE, 0x04, 0xD2, + 0xFE, 0xC0, 0x18, 0x23, 0xDB, 0x04, 0x2F, 0xC5, 0xE6, 0x17, 0x47, 0xE6, 0x03, 0xCB, 0x50, 0x28, + 0x02, 0xCB, 0xFF, 0xCB, 0x60, 0x20, 0x0F, 0xCB, 0xEF, 0xCB, 0x48, 0x20, 0x09, 0xCB, 0xFF, 0x3D, + 0xCB, 0x40, 0x28, 0x02, 0xC6, 0x1F, 0xC1, 0xF5, 0xCB, 0x7F, 0x28, 0x05, 0x3E, 0x01, 0xCD, 0xB3, + 0xCB, 0xDB, 0x04, 0x2F, 0xE6, 0x08, 0xCC, 0x00, 0xCB, 0xCC, 0x80, 0xD4, 0xCD, 0xF2, 0xD4, 0x50, + 0x72, 0x65, 0x70, 0x61, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x6F, 0x20, 0x62, 0x6F, 0x6F, 0x74, + 0x2C, 0x20, 0x45, 0x53, 0x43, 0x20, 0x74, 0x6F, 0x20, 0x61, 0x62, 0x6F, 0x72, 0x74, 0x8D, 0xF1, + 0xCB, 0x7F, 0xF5, 0xF5, 0xCB, 0xBF, 0x32, 0x16, 0x00, 0x3E, 0x80, 0x20, 0x01, 0xAF, 0x32, 0x08, + 0x00, 0x3E, 0xFF, 0x32, 0x07, 0x00, 0xCD, 0xA3, 0xC3, 0x21, 0x80, 0x00, 0x22, 0x1B, 0x00, 0xF1, + 0x20, 0x65, 0xCB, 0x6F, 0x28, 0x23, 0xCD, 0xF2, 0xD4, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x20, + 0x73, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x73, 0x20, 0x6E, 0x6F, 0x74, 0x20, 0x61, 0x73, 0x73, + 0x69, 0x67, 0x6E, 0x65, 0x64, 0x8D, 0xC3, 0x71, 0xC0, 0xCD, 0x33, 0xD8, 0x57, 0xD3, 0x34, 0xCD, + 0x12, 0xC6, 0xCD, 0x2E, 0xC6, 0x32, 0x15, 0x00, 0x21, 0x80, 0x00, 0x22, 0x1D, 0x00, 0x06, 0x02, + 0xC5, 0xCD, 0x23, 0xC6, 0x3E, 0xC8, 0x32, 0x09, 0x00, 0xCD, 0x91, 0xD5, 0xD4, 0x60, 0xD6, 0x3E, + 0xD2, 0x32, 0x09, 0x00, 0xD4, 0xD2, 0xD5, 0xC1, 0x30, 0x53, 0xCD, 0x23, 0xC6, 0x10, 0xE1, 0xCD, + 0x80, 0xD4, 0xCD, 0xE3, 0xCB, 0x18, 0x5E, 0x3E, 0xC8, 0x32, 0x09, 0x00, 0x21, 0x00, 0x28, 0x22, + 0x1D, 0x00, 0xCD, 0x8A, 0xD8, 0x38, 0x48, 0x01, 0x00, 0x00, 0xC5, 0xCD, 0x23, 0xC6, 0xCD, 0x37, + 0xD9, 0xC1, 0xCD, 0x51, 0xDA, 0x28, 0x0B, 0xFE, 0x07, 0x20, 0x34, 0x0B, 0x78, 0xB1, 0x20, 0xEA, + 0x18, 0x2D, 0xCD, 0x3B, 0xDA, 0xCD, 0x51, 0xDA, 0x20, 0x25, 0xCD, 0x23, 0xC6, 0x3E, 0xD2, 0x32, + 0x09, 0x00, 0xCD, 0x6B, 0xD9, 0xCD, 0x51, 0xDA, 0x20, 0x15, 0xCD, 0x12, 0xC6, 0x3A, 0x80, 0x00, + 0xFE, 0x40, 0x28, 0x04, 0xFE, 0xE5, 0x20, 0x31, 0xCD, 0xF2, 0xD4, 0x0D, 0xCE, 0x18, 0x12, 0xCD, + 0x80, 0xD4, 0xCD, 0xF1, 0xCB, 0xCD, 0xF2, 0xD4, 0x0D, 0x55, 0x6E, 0x61, 0x62, 0x6C, 0x65, 0x20, + 0xF4, 0xCD, 0xF2, 0xD4, 0x6F, 0x20, 0x62, 0x6F, 0x6F, 0x74, 0x8D, 0x3E, 0xD0, 0xD3, 0x30, 0x3E, + 0xFF, 0xD3, 0x04, 0xCD, 0x80, 0xD4, 0xC3, 0x71, 0xC0, 0xCD, 0x58, 0xD3, 0xCC, 0x33, 0xD8, 0x57, + 0xCD, 0x23, 0xC6, 0xF1, 0x08, 0xCD, 0xF2, 0xD4, 0x0D, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x62, 0x79, + 0x8D, 0xCD, 0x58, 0xD3, 0x37, 0xCA, 0x80, 0x00, 0x21, 0x80, 0x04, 0x11, 0x00, 0x00, 0x01, 0x00, + 0x22, 0xED, 0xB0, 0x08, 0xE6, 0x7F, 0x32, 0x07, 0x04, 0x3E, 0x06, 0x32, 0x06, 0x04, 0x3E, 0xFF, + 0xD3, 0xFF, 0x01, 0xE8, 0x03, 0xCD, 0x23, 0xC6, 0x21, 0x0A, 0x00, 0xCD, 0x7C, 0xD8, 0x0B, 0x78, + 0xB1, 0x20, 0xF2, 0xCD, 0xF8, 0xD4, 0xC4, 0x0A, 0xD5, 0xFE, 0x1B, 0xC0, 0x18, 0x9D, 0x7A, 0xD3, + 0x34, 0x3E, 0xDF, 0xD3, 0x04, 0x3E, 0xD4, 0xD3, 0x30, 0xDB, 0x34, 0x0F, 0x30, 0xFB, 0xDB, 0x30, + 0x01, 0x00, 0x02, 0xCD, 0x72, 0xC6, 0x3E, 0xD4, 0xD3, 0x30, 0xCD, 0x6B, 0xC6, 0x28, 0xDF, 0xDB, + 0x34, 0x0F, 0x30, 0xF6, 0xDB, 0x30, 0x10, 0xEE, 0xAF, 0xD3, 0x03, 0x79, 0xFE, 0x5A, 0x30, 0x03, + 0x87, 0x87, 0x87, 0xFE, 0xB7, 0x3E, 0x80, 0xD0, 0x3E, 0x04, 0xC9, 0xDB, 0x03, 0xFE, 0xC7, 0xC0, + 0x0C, 0xC8, 0x3E, 0x01, 0xD3, 0x03, 0x3E, 0xFA, 0xD3, 0x05, 0x18, 0xEF, 0x13, 0xFE, 0x41, 0xCA, + 0x4B, 0xC7, 0x06, 0x52, 0x18, 0x03, 0x13, 0x06, 0x57, 0xFE, 0x44, 0xC2, 0xF7, 0xC0, 0xCD, 0x5F, + 0xD3, 0x78, 0x32, 0x09, 0x00, 0xCD, 0x84, 0xD3, 0xAF, 0xB2, 0xC2, 0xF7, 0xC0, 0xB0, 0xB1, 0xCA, + 0xF7, 0xC0, 0xCD, 0x58, 0xD3, 0x20, 0x05, 0xAF, 0xB3, 0xCA, 0xF7, 0xC0, 0x22, 0x1B, 0x00, 0x0B, + 0xC5, 0xD5, 0xD4, 0x08, 0xC4, 0xD1, 0xFD, 0xE1, 0x3A, 0x11, 0x00, 0xBB, 0xDA, 0xF7, 0xC0, 0x7B, + 0x32, 0x1A, 0x00, 0xCD, 0x28, 0xCE, 0xCD, 0x9F, 0xD4, 0xFD, 0xE5, 0x3A, 0x09, 0x00, 0xFE, 0x52, + 0x28, 0x0A, 0xFE, 0x57, 0xC2, 0xF7, 0xC0, 0xCD, 0xD0, 0xC3, 0x18, 0x03, 0xCD, 0xC0, 0xC3, 0x30, + 0x09, 0xCD, 0x58, 0xD3, 0xCA, 0xE3, 0xCB, 0xC3, 0xF1, 0xCB, 0x2A, 0x1B, 0x00, 0x09, 0x22, 0x1B, + 0x00, 0xE1, 0xB7, 0xED, 0x42, 0xDA, 0x22, 0xCE, 0xE5, 0xFD, 0xE1, 0x21, 0x1A, 0x00, 0x34, 0x3A, + 0x11, 0x00, 0xBE, 0x30, 0xC4, 0xCD, 0xE6, 0xCE, 0x2A, 0x18, 0x00, 0x7D, 0x32, 0x1F, 0x00, 0xE5, + 0x23, 0x22, 0x18, 0x00, 0xED, 0x4B, 0x12, 0x00, 0x37, 0xED, 0x42, 0xE1, 0x38, 0xAB, 0x22, 0x18, + 0x00, 0x3A, 0x11, 0x00, 0x32, 0x1A, 0x00, 0xCD, 0x22, 0xCE, 0xCD, 0xF2, 0xD4, 0x4E, 0x65, 0x78, + 0x74, 0x20, 0x3D, 0xA0, 0x2A, 0x1B, 0x00, 0xCD, 0xF9, 0xD2, 0xCD, 0xF2, 0xD4, 0x0D, 0x45, 0x6E, + 0x64, 0x20, 0x53, 0x75, 0x72, 0x66, 0x61, 0x63, 0x65, 0x8D, 0xC9, 0xCD, 0xE9, 0xD2, 0xCD, 0x5F, + 0xD3, 0xCD, 0xF1, 0xCE, 0x3E, 0xD2, 0x32, 0x09, 0x00, 0xCD, 0xE6, 0xCE, 0x3E, 0x0D, 0xCD, 0x18, + 0xD5, 0xCD, 0x13, 0xCE, 0x21, 0x80, 0x00, 0x22, 0x1B, 0x00, 0xCD, 0xC0, 0xC3, 0x38, 0x0A, 0xCD, + 0x58, 0xD3, 0x28, 0x1B, 0xCD, 0x57, 0xDA, 0x28, 0x16, 0x3A, 0x1A, 0x00, 0xCD, 0x9C, 0xD4, 0xCD, + 0x58, 0xD3, 0x20, 0x05, 0xCD, 0xE6, 0xCB, 0x18, 0x03, 0xCD, 0xF4, 0xCB, 0xCD, 0x13, 0xCE, 0xCD, + 0xC1, 0xD4, 0xCD, 0x58, 0xD3, 0x20, 0x05, 0xCD, 0x9B, 0xCE, 0x20, 0xC8, 0xCD, 0x67, 0xCE, 0x20, + 0xBB, 0xC3, 0x80, 0xD4, 0xFE, 0x54, 0xCA, 0xC3, 0xC1, 0xFE, 0x4D, 0xCA, 0x86, 0xD0, 0xF5, 0xCD, + 0x5F, 0xD3, 0xF1, 0xFE, 0x53, 0x20, 0x0A, 0x13, 0xED, 0x4B, 0x18, 0x00, 0xCD, 0x72, 0xD3, 0x18, + 0x16, 0xCD, 0xB2, 0xD3, 0x38, 0x1A, 0xE5, 0xED, 0x4B, 0x12, 0x00, 0x03, 0xED, 0x42, 0xC1, 0xD2, + 0xF7, 0xC0, 0xCD, 0x79, 0xD3, 0x38, 0x10, 0xAF, 0xB4, 0xC2, 0xF7, 0xC0, 0x3A, 0x14, 0x00, 0xBD, + 0xDA, 0xF7, 0xC0, 0x7D, 0x32, 0x17, 0x00, 0xED, 0x43, 0x18, 0x00, 0x3E, 0xD3, 0x32, 0x09, 0x00, + 0xCD, 0xAF, 0xC3, 0xD0, 0xCD, 0x58, 0xD3, 0xCA, 0xE6, 0xCB, 0xC3, 0xF4, 0xCB, 0xFE, 0x4F, 0xC2, + 0xF7, 0xC0, 0x13, 0xCD, 0x45, 0xD3, 0xFE, 0x4E, 0x28, 0x0D, 0xFE, 0x46, 0xC2, 0xF7, 0xC0, 0xD9, + 0xCB, 0xB0, 0xD9, 0x3E, 0xFF, 0x18, 0x1F, 0xD9, 0xCB, 0xF0, 0xD9, 0x3E, 0x01, 0x32, 0x23, 0x00, + 0xC9, 0xD9, 0xCB, 0x70, 0xD9, 0xC8, 0xCD, 0x58, 0xD3, 0xD8, 0xC5, 0xCD, 0x33, 0xD8, 0xC1, 0xD3, + 0x34, 0xCD, 0x61, 0xD8, 0xEE, 0xA0, 0xD3, 0x04, 0xC9, 0xFE, 0x58, 0x32, 0x2C, 0x00, 0x06, 0x81, + 0x28, 0x16, 0xD6, 0x5A, 0x06, 0x01, 0x20, 0x11, 0xCD, 0x50, 0xCA, 0xC2, 0xF7, 0xC0, 0x47, 0x3A, + 0x2B, 0x00, 0x20, 0x04, 0x3D, 0x32, 0x2C, 0x00, 0x13, 0xCD, 0xE9, 0xD2, 0x78, 0xB7, 0xF5, 0xC4, + 0xB3, 0xCB, 0xAF, 0xCD, 0xFD, 0xCA, 0xF1, 0xFC, 0x8F, 0xCB, 0xCD, 0x54, 0xCA, 0xCD, 0x80, 0xD4, + 0xCD, 0x78, 0xC9, 0xDA, 0x80, 0xD4, 0xCD, 0x27, 0xC1, 0x07, 0x2F, 0x08, 0x00, 0xF3, 0xCD, 0x80, + 0xD4, 0xCD, 0xFE, 0xC9, 0xCD, 0x19, 0xCA, 0xDA, 0x80, 0xD4, 0xCD, 0x27, 0xC1, 0x08, 0x00, 0x20, + 0x4D, 0x41, 0x59, 0x20, 0x44, 0x45, 0x53, 0x54, 0x52, 0x4F, 0x59, 0x20, 0x98, 0xCD, 0xF2, 0xD4, + 0x0D, 0x43, 0x52, 0x3D, 0x50, 0x72, 0x6F, 0x63, 0x65, 0x65, 0x64, 0x20, 0x45, 0x53, 0x43, 0x3D, + 0x41, 0x62, 0x6F, 0x72, 0x74, 0xA0, 0xCD, 0x1A, 0xD4, 0x21, 0x00, 0x06, 0xCD, 0x0A, 0xCA, 0x01, + 0x00, 0x02, 0x75, 0x23, 0x0B, 0x78, 0xB1, 0x20, 0xF9, 0xCD, 0x27, 0xCA, 0x30, 0x60, 0xCD, 0xF2, + 0xD4, 0x54, 0x65, 0x73, 0x74, 0x20, 0x66, 0x61, 0x69, 0x6C, 0x65, 0x64, 0x21, 0x0D, 0x44, 0x69, + 0x73, 0x6B, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x61, 0xF4, 0xCD, 0x4C, 0xCE, 0xCD, 0xF2, 0xD4, + 0x20, 0x6D, 0x61, 0x79, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x62, 0x65, 0x65, 0x6E, 0x20, 0x44, + 0x45, 0x53, 0x54, 0x52, 0x4F, 0x59, 0x45, 0x44, 0x0D, 0x4F, 0x72, 0x69, 0x67, 0x69, 0x6E, 0x61, + 0x6C, 0x20, 0x69, 0x73, 0x20, 0x6C, 0x6F, 0x63, 0x61, 0x74, 0x65, 0x64, 0x20, 0x61, 0x74, 0x20, + 0x34, 0x30, 0x30, 0x48, 0xF3, 0x2A, 0x1D, 0x00, 0xCD, 0x15, 0xD3, 0xC3, 0x80, 0xD4, 0x21, 0x00, + 0x08, 0xCD, 0x0A, 0xCA, 0xCD, 0x19, 0xCA, 0x38, 0x95, 0xCD, 0x0A, 0xCA, 0xCD, 0x27, 0xC1, 0x43, + 0x6F, 0x6D, 0x70, 0x61, 0x72, 0xE5, 0xED, 0x4B, 0x1D, 0x00, 0x11, 0x00, 0x06, 0x21, 0x00, 0x08, + 0x1A, 0xBE, 0x20, 0x09, 0x13, 0x23, 0x0B, 0x78, 0xB1, 0x20, 0xF5, 0x18, 0x0D, 0xCD, 0xF2, 0xD4, + 0x20, 0x66, 0x61, 0x69, 0x6C, 0x65, 0x64, 0x8D, 0x18, 0x03, 0xCD, 0x33, 0xCA, 0xCD, 0xFE, 0xC9, + 0xCD, 0x27, 0xCA, 0xDA, 0xCE, 0xC8, 0x18, 0xB3, 0xCD, 0x27, 0xC1, 0x06, 0x00, 0xF3, 0x06, 0x17, + 0x21, 0xD4, 0xC9, 0xDB, 0x31, 0x32, 0x1F, 0x00, 0x7E, 0x5F, 0x16, 0x00, 0xC5, 0xE5, 0xFE, 0xFF, + 0x20, 0x06, 0xCD, 0x80, 0xD4, 0xB7, 0x18, 0x35, 0xFE, 0xFE, 0x20, 0x13, 0xCD, 0x27, 0xC1, 0x20, + 0x19, 0x73, 0x74, 0x14, 0xE5, 0x3E, 0xC8, 0x32, 0x09, 0x00, 0xCD, 0x88, 0xC3, 0x18, 0x19, 0xFE, + 0xFD, 0x20, 0x04, 0xED, 0x5B, 0x12, 0x00, 0xED, 0x53, 0x18, 0x00, 0xEB, 0xCD, 0x15, 0xD3, 0xEB, + 0x3E, 0xD3, 0x32, 0x09, 0x00, 0xCD, 0xAF, 0xC3, 0xF5, 0xCD, 0xEB, 0xC9, 0xF1, 0xE1, 0xC1, 0xD8, + 0x23, 0x10, 0xB0, 0xC9, 0xFF, 0x01, 0x02, 0x03, 0x04, 0x05, 0xFF, 0x06, 0x07, 0x08, 0x09, 0x00, + 0xFF, 0xFD, 0x10, 0x20, 0x00, 0x01, 0xFF, 0xFE, 0xFF, 0xFD, 0xFF, 0x30, 0x09, 0xCD, 0x58, 0xD3, + 0xCA, 0xE6, 0xCB, 0xC3, 0xF4, 0xCB, 0xCD, 0xF2, 0xD4, 0x20, 0x4F, 0x4B, 0xA0, 0xC9, 0xCD, 0x27, + 0xC1, 0x20, 0x98, 0x21, 0x00, 0x04, 0x22, 0x1B, 0x00, 0xC9, 0x22, 0x1B, 0x00, 0xCD, 0x27, 0xC1, + 0x20, 0x50, 0x61, 0x74, 0x74, 0x16, 0x6E, 0xA0, 0xC9, 0x3E, 0xD2, 0xCD, 0x3C, 0xCA, 0xCD, 0x27, + 0xC1, 0x87, 0xCD, 0xC0, 0xC3, 0x18, 0x0C, 0x3E, 0xD7, 0xCD, 0x3C, 0xCA, 0xCD, 0x27, 0xC1, 0x88, + 0xCD, 0xD0, 0xC3, 0xF5, 0xCD, 0xEB, 0xC9, 0xF1, 0xD2, 0x80, 0xD4, 0xC9, 0x32, 0x09, 0x00, 0x3A, + 0x12, 0x00, 0x32, 0x18, 0x00, 0xDB, 0x31, 0x32, 0x1F, 0x00, 0x3E, 0x01, 0x32, 0x1A, 0x00, 0xC9, + 0xDB, 0x44, 0x3C, 0xC9, 0xCD, 0xF2, 0xD4, 0x0D, 0x54, 0x79, 0x70, 0x65, 0x20, 0x28, 0x46, 0x2C, + 0x20, 0x48, 0x29, 0xA0, 0xCD, 0xE9, 0xCA, 0xFE, 0x48, 0x20, 0x26, 0xCD, 0xF2, 0xD4, 0x55, 0x6E, + 0x69, 0x74, 0x20, 0x28, 0x30, 0x2D, 0x33, 0x46, 0x29, 0xA0, 0xCD, 0x1A, 0xD4, 0xCD, 0xB2, 0xD3, + 0xB7, 0xC2, 0x08, 0xC1, 0x7C, 0xA7, 0xC2, 0x08, 0xC1, 0x7D, 0x47, 0xCD, 0xD6, 0xC1, 0xC3, 0x51, + 0xDA, 0xFE, 0x46, 0xC2, 0xF7, 0xC0, 0xCD, 0x27, 0xC1, 0x0F, 0x28, 0x41, 0x2D, 0x44, 0x29, 0xA0, + 0xCD, 0xE9, 0xCA, 0xD6, 0x41, 0xFE, 0x04, 0xD2, 0xFE, 0xC0, 0x57, 0xCD, 0xF2, 0xD4, 0x53, 0x69, + 0x7A, 0x65, 0x20, 0x28, 0x4C, 0x2C, 0x20, 0x53, 0x29, 0xA0, 0xCD, 0xE9, 0xCA, 0xFE, 0x4C, 0x06, + 0x04, 0x28, 0x05, 0xD6, 0x53, 0x20, 0xCC, 0x47, 0xCD, 0xF2, 0xD4, 0x53, 0x70, 0x65, 0x65, 0x64, + 0x20, 0x28, 0x46, 0x2C, 0x20, 0x53, 0x29, 0xA0, 0xCD, 0xE9, 0xCA, 0xFE, 0x53, 0x28, 0x06, 0xFE, + 0x46, 0x20, 0xB0, 0xCB, 0xD8, 0x37, 0xC3, 0x4B, 0xC1, 0xCD, 0x02, 0xD5, 0xCD, 0xD1, 0xD4, 0xCD, + 0x2C, 0xD3, 0xFE, 0x0D, 0xCA, 0xD8, 0xD4, 0xCD, 0x8C, 0xD4, 0xC3, 0x80, 0xD4, 0xCD, 0x80, 0xD4, + 0xCD, 0xF2, 0xD4, 0x42, 0x61, 0x6E, 0x6B, 0xA0, 0x47, 0xCD, 0x07, 0xD3, 0xCD, 0x51, 0xD3, 0x78, + 0xCD, 0x89, 0xD2, 0x08, 0x01, 0x00, 0x10, 0xAF, 0xC4, 0x9F, 0xD4, 0x79, 0xCD, 0x07, 0xD3, 0x0C, + 0x10, 0xF6, 0xCD, 0x80, 0xD4, 0x06, 0x08, 0xCD, 0x9F, 0xD4, 0x10, 0xFB, 0x60, 0x68, 0xCD, 0x9F, + 0xD4, 0xE5, 0x01, 0x00, 0x10, 0xE5, 0xE5, 0x21, 0x00, 0x00, 0x11, 0x62, 0xCB, 0xA7, 0xED, 0x52, + 0xEB, 0xE1, 0x19, 0xE1, 0x30, 0x11, 0xE5, 0xE5, 0x21, 0x00, 0x00, 0x11, 0x71, 0xCB, 0xA7, 0xED, + 0x52, 0xEB, 0xE1, 0x19, 0xE1, 0x30, 0x1A, 0x08, 0xFE, 0x01, 0x28, 0x02, 0xD3, 0x40, 0x08, 0x56, + 0x3E, 0x55, 0x77, 0xBE, 0x20, 0x05, 0x2F, 0x77, 0xBE, 0x28, 0x05, 0x72, 0x16, 0x58, 0x18, 0x09, + 0x72, 0x23, 0x0B, 0x78, 0xB1, 0x20, 0xBE, 0x16, 0x5E, 0x08, 0x47, 0x08, 0x3E, 0x01, 0xB8, 0x28, + 0x02, 0xD3, 0x40, 0x7A, 0xCD, 0xA1, 0xD4, 0xE1, 0x3E, 0x10, 0x84, 0x67, 0x20, 0xA0, 0xC9, 0x21, + 0xB2, 0xCB, 0x36, 0xAA, 0x01, 0x01, 0x06, 0x79, 0xCD, 0x89, 0xD2, 0xD3, 0x40, 0x3E, 0x55, 0xBE, + 0x3E, 0x01, 0xD3, 0x40, 0x79, 0xC5, 0xE5, 0xCC, 0xFD, 0xCA, 0xE1, 0xC1, 0x0C, 0x10, 0xE8, 0x36, + 0x55, 0xC9, 0x55, 0x01, 0x22, 0x00, 0x11, 0x5E, 0x00, 0x21, 0xC1, 0xCB, 0xED, 0xB0, 0xC3, 0x5E, + 0x00, 0x01, 0x00, 0x20, 0x11, 0x00, 0x01, 0x21, 0x00, 0xC0, 0xC5, 0xD5, 0xE5, 0xED, 0xB0, 0xD1, + 0xE1, 0xC1, 0xD3, 0x40, 0xED, 0xB0, 0x3E, 0x55, 0x32, 0xB2, 0xCB, 0x32, 0x2B, 0x00, 0x3E, 0x01, + 0xD3, 0x40, 0xC9, 0xCD, 0x22, 0xCE, 0x3A, 0x21, 0x00, 0xCD, 0x0E, 0xCC, 0xCD, 0x1F, 0xCC, 0x18, + 0x12, 0xCD, 0x22, 0xCE, 0x3A, 0x44, 0x00, 0xCD, 0x0E, 0xCC, 0x3A, 0x45, 0x00, 0xCD, 0xFE, 0xD2, + 0xCD, 0x7C, 0xCC, 0xCD, 0x80, 0xD4, 0x3A, 0x09, 0x00, 0xB7, 0xF8, 0xC3, 0x8D, 0xC0, 0xF5, 0xCD, + 0x27, 0xC1, 0x20, 0x02, 0xAD, 0x3A, 0x09, 0x00, 0xCD, 0xA1, 0xD4, 0xF1, 0xC3, 0xF3, 0xD2, 0x2E, + 0xD9, 0x3A, 0x09, 0x00, 0xE6, 0x7F, 0xFE, 0x48, 0x28, 0x0F, 0xFE, 0x53, 0x28, 0x0B, 0x2E, 0x9F, + 0xFE, 0x52, 0x28, 0x05, 0x2E, 0xFF, 0xFE, 0x57, 0xC0, 0xCD, 0x51, 0xD3, 0x3A, 0x21, 0x00, 0xA5, + 0x21, 0x59, 0xCC, 0x17, 0xD4, 0x35, 0xD3, 0x30, 0x0C, 0xF5, 0xCD, 0xA9, 0xCC, 0xF1, 0xB7, 0xC8, + 0xCD, 0xF2, 0xD4, 0x2C, 0xA0, 0xB7, 0xC8, 0x18, 0xEA, 0x0F, 0x10, 0x07, 0xF9, 0x08, 0x97, 0x08, + 0x20, 0x9A, 0x19, 0x63, 0x14, 0x64, 0x20, 0x10, 0x46, 0x6F, 0x75, 0x6E, 0xE4, 0x0C, 0x82, 0x18, + 0x4C, 0x6F, 0x73, 0xF4, 0x18, 0x19, 0x71, 0x75, 0x65, 0x73, 0xF4, 0x9E, 0xCD, 0x51, 0xD3, 0x3A, + 0x44, 0x00, 0xF5, 0x21, 0xC8, 0xCC, 0xCD, 0x9F, 0xCC, 0xE1, 0x3A, 0x45, 0x00, 0x28, 0x0D, 0x6F, + 0x3C, 0xC8, 0x84, 0xFE, 0x10, 0xC8, 0x7D, 0xCD, 0xF2, 0xD4, 0x3B, 0xA0, 0x21, 0x46, 0xCD, 0x3C, + 0xC8, 0x3D, 0x28, 0x05, 0xCD, 0x35, 0xD3, 0x18, 0xF8, 0x7E, 0xE6, 0x7F, 0xFE, 0x20, 0xD4, 0xA1, + 0xD4, 0x30, 0x0F, 0xE5, 0x21, 0x90, 0xCD, 0x3D, 0xF4, 0x35, 0xD3, 0xF2, 0xB7, 0xCC, 0xCD, 0xA9, + 0xCC, 0xE1, 0x7E, 0x23, 0xB7, 0xF8, 0x18, 0xE1, 0x01, 0x06, 0x20, 0x26, 0x20, 0x07, 0x20, 0x8E, + 0x01, 0x06, 0x11, 0x84, 0x03, 0x09, 0x0A, 0x86, 0x01, 0x06, 0x20, 0x43, 0x14, 0x72, 0x12, 0x20, + 0x54, 0x72, 0x61, 0x63, 0xEB, 0x01, 0x07, 0x20, 0x8E, 0x01, 0x05, 0x11, 0x84, 0x03, 0x09, 0x0B, + 0x85, 0x0F, 0x10, 0x07, 0xF9, 0x01, 0x08, 0x11, 0x03, 0x82, 0x01, 0x0D, 0x0B, 0x88, 0x01, 0x07, + 0x11, 0x03, 0x82, 0x01, 0x07, 0x11, 0x0C, 0x82, 0x43, 0x61, 0x6E, 0x10, 0x4C, 0x6F, 0x63, 0x61, + 0x74, 0x65, 0x20, 0x53, 0x12, 0x94, 0x0F, 0x08, 0x97, 0x01, 0x53, 0x65, 0x6C, 0x12, 0x20, 0x9B, + 0x01, 0x53, 0x65, 0x6C, 0x12, 0x20, 0x48, 0x65, 0x61, 0xE4, 0x49, 0x6E, 0x64, 0x65, 0x78, 0x20, + 0x50, 0x75, 0x6C, 0x73, 0x65, 0x20, 0x84, 0x06, 0x20, 0x52, 0x61, 0x6E, 0x67, 0x65, 0x20, 0x82, + 0x1D, 0x42, 0x75, 0x66, 0x66, 0x96, 0x1D, 0x13, 0x66, 0x72, 0x6F, 0x6D, 0x20, 0x9B, 0x0F, 0x1E, + 0x11, 0x13, 0x4C, 0x6F, 0xF7, 0x04, 0x20, 0x09, 0x0A, 0x85, 0x03, 0x19, 0x70, 0x14, 0x74, 0x95, + 0x01, 0x07, 0x11, 0x0C, 0x82, 0x0E, 0x20, 0x44, 0x6F, 0x65, 0x1F, 0x10, 0x43, 0x6F, 0x6D, 0x70, + 0x61, 0x72, 0xE5, 0x01, 0x0D, 0x0B, 0x88, 0x18, 0x41, 0x6C, 0x69, 0x67, 0x6E, 0x6D, 0x65, 0x6E, + 0x74, 0x20, 0x82, 0x0E, 0x20, 0x41, 0x6C, 0x69, 0x67, 0x6E, 0x6D, 0x65, 0x6E, 0x74, 0x20, 0x82, + 0x20, 0x54, 0x65, 0x73, 0xF4, 0x46, 0x61, 0x69, 0x6C, 0x15, 0x20, 0x74, 0x6F, 0xA0, 0x45, 0x72, + 0x72, 0x94, 0x1A, 0xA0, 0x54, 0x69, 0x6D, 0x65, 0x6F, 0x75, 0xF4, 0x19, 0x5A, 0x16, 0xEF, 0x53, + 0x65, 0x65, 0xEB, 0x19, 0x61, 0xE4, 0x57, 0x1C, 0x74, 0xE5, 0x4F, 0x63, 0x63, 0x75, 0x72, 0x72, + 0x95, 0x20, 0x44, 0x75, 0x1C, 0x6E, 0x67, 0xA0, 0x20, 0x41, 0x66, 0x74, 0x16, 0xA0, 0x43, 0x52, + 0x43, 0xA0, 0x56, 0x16, 0x69, 0x66, 0xF9, 0x48, 0x65, 0x61, 0x64, 0x96, 0x1B, 0xA0, 0x6E, 0x6F, + 0x74, 0xA0, 0x2C, 0xA0, 0x65, 0x63, 0xF4, 0x41, 0x43, 0x4B, 0xA0, 0x6F, 0xF2, 0x65, 0xE4, 0x65, + 0xF2, 0x20, 0x50, 0x72, 0x6F, 0x74, 0x12, 0x95, 0x44, 0x61, 0x74, 0x61, 0xA0, 0x52, 0xE5, 0x46, + 0x61, 0x75, 0x6C, 0xF4, 0x44, 0x1C, 0x76, 0xE5, 0x72, 0xE9, 0x4E, 0x6F, 0xA0, 0x42, 0x75, 0x73, + 0xF9, 0x73, 0xA0, 0x21, 0x1A, 0x00, 0x7E, 0xF5, 0x36, 0xFF, 0xCD, 0x28, 0xCE, 0xF1, 0x32, 0x1A, + 0x00, 0xC9, 0xCD, 0x28, 0xCE, 0xC3, 0x80, 0xD4, 0xCD, 0x58, 0xD3, 0x28, 0x1F, 0xCD, 0x9F, 0xD4, + 0x3A, 0x17, 0x00, 0xCD, 0x07, 0xD3, 0xCD, 0x9F, 0xD4, 0x2A, 0x18, 0x00, 0x7C, 0xCD, 0x07, 0xD3, + 0x7D, 0xCD, 0xFE, 0xD2, 0x3A, 0x1A, 0x00, 0xB7, 0xF8, 0xC3, 0xF3, 0xD2, 0xED, 0x5B, 0x1A, 0x00, + 0x3A, 0x18, 0x00, 0x57, 0xCD, 0x9F, 0xD4, 0x3A, 0x17, 0x00, 0xCD, 0x07, 0xD3, 0xCD, 0x9F, 0xD4, + 0x7A, 0xCD, 0xFE, 0xD2, 0x7B, 0x18, 0xE0, 0x21, 0x17, 0x00, 0x3A, 0x0C, 0x00, 0xFE, 0xFF, 0x46, + 0x38, 0x09, 0x34, 0x3A, 0x14, 0x00, 0xBE, 0x3C, 0xD0, 0x36, 0x00, 0x2A, 0x18, 0x00, 0x7D, 0x32, + 0x1F, 0x00, 0xE5, 0xED, 0x5B, 0x0A, 0x00, 0xB7, 0xED, 0x52, 0xE1, 0x28, 0x09, 0x23, 0x38, 0x02, + 0x2B, 0x2B, 0x22, 0x18, 0x00, 0xC9, 0x78, 0x32, 0x17, 0x00, 0xC9, 0x3A, 0x11, 0x00, 0x3C, 0x47, + 0x21, 0x1A, 0x00, 0xCD, 0x58, 0xD3, 0x28, 0x09, 0x3E, 0x01, 0x86, 0x77, 0xB8, 0xD8, 0x90, 0x77, + 0xC9, 0x3A, 0x15, 0x00, 0xE6, 0x07, 0xE5, 0x21, 0xDE, 0xCE, 0xCD, 0x84, 0xD2, 0x7E, 0xE1, 0xF5, + 0x86, 0xB8, 0x38, 0x02, 0x05, 0x90, 0x77, 0x47, 0xF1, 0xFE, 0x04, 0x28, 0x06, 0xFE, 0x06, 0x28, + 0x02, 0x05, 0xC9, 0x3E, 0x02, 0x05, 0x28, 0x03, 0x05, 0xC0, 0x3D, 0x77, 0x3D, 0xC9, 0x05, 0x04, + 0x02, 0x04, 0x06, 0x0B, 0x03, 0x06, 0x3A, 0x08, 0x00, 0x07, 0x2F, 0xE6, 0x01, 0x32, 0x1A, 0x00, + 0xC9, 0xCD, 0xF2, 0xD4, 0x53, 0x74, 0x61, 0x72, 0xF4, 0x21, 0x00, 0x00, 0xCD, 0x73, 0xCF, 0x38, + 0xF0, 0x22, 0x18, 0x00, 0xCD, 0xF2, 0xD4, 0x45, 0x6E, 0xE4, 0x2A, 0x12, 0x00, 0xCD, 0x73, 0xCF, + 0x38, 0xF2, 0x22, 0x0A, 0x00, 0xAF, 0x32, 0x17, 0x00, 0x32, 0x0C, 0x00, 0x3A, 0x14, 0x00, 0xB7, + 0xC8, 0xCD, 0xF2, 0xD4, 0x53, 0x75, 0x72, 0x66, 0x61, 0x63, 0x65, 0x20, 0xA8, 0x47, 0x04, 0x3E, + 0x00, 0xF5, 0xFE, 0x10, 0x38, 0x05, 0xCD, 0xFE, 0xD2, 0x18, 0x03, 0xCD, 0x07, 0xD3, 0xCD, 0xF2, + 0xD4, 0xAF, 0xF1, 0x3C, 0x10, 0xEB, 0xCD, 0xF2, 0xD4, 0x41, 0x6C, 0x6C, 0x29, 0x20, 0x5B, 0x41, + 0x6C, 0x6C, 0x5D, 0xA0, 0xCD, 0x1A, 0xD4, 0x21, 0xFF, 0x00, 0xCD, 0x79, 0xD3, 0xAF, 0xB4, 0x20, + 0xB4, 0x7D, 0x32, 0x0C, 0x00, 0xFE, 0xFF, 0xC8, 0x3A, 0x14, 0x00, 0xBD, 0x38, 0xA7, 0x7D, 0x32, + 0x17, 0x00, 0xC9, 0xCD, 0x27, 0xC1, 0x69, 0x6E, 0x67, 0x20, 0x43, 0x79, 0x6C, 0x69, 0x6E, 0x64, + 0x16, 0x20, 0x28, 0x30, 0xAD, 0xE5, 0x2A, 0x12, 0x00, 0xCD, 0x15, 0xD3, 0xE1, 0xCD, 0xF2, 0xD4, + 0x29, 0x20, 0xDB, 0xCD, 0x15, 0xD3, 0xCD, 0xF2, 0xD4, 0x5D, 0xA0, 0xCD, 0x1A, 0xD4, 0xCD, 0x79, + 0xD3, 0xEB, 0x2A, 0x12, 0x00, 0xB7, 0xED, 0x52, 0xEB, 0xC9, 0xDB, 0x04, 0xE6, 0x08, 0x20, 0x14, + 0x3E, 0x09, 0xD3, 0x02, 0x3E, 0x84, 0xD3, 0x00, 0xD9, 0x0E, 0x00, 0xD9, 0x18, 0x3B, 0xCD, 0x33, + 0xD0, 0xCD, 0x22, 0xD0, 0x3E, 0x0A, 0xCD, 0x06, 0xD0, 0x21, 0xD0, 0x07, 0xCD, 0x7C, 0xD8, 0x3E, + 0x08, 0xCD, 0x06, 0xD0, 0x16, 0x64, 0x15, 0x28, 0xEB, 0x21, 0x2B, 0xD0, 0x3E, 0x19, 0x06, 0x09, + 0xCD, 0x06, 0xD0, 0xD9, 0x79, 0xD9, 0x4F, 0xED, 0xA3, 0x28, 0xEB, 0xCD, 0x0F, 0xD0, 0xCD, 0x0F, + 0xD0, 0x28, 0xE6, 0xFE, 0x0D, 0x3E, 0x09, 0x20, 0xE7, 0x3E, 0xFF, 0xCD, 0x18, 0xD5, 0x3E, 0x0D, + 0xCD, 0x18, 0xD5, 0xC3, 0x80, 0xD4, 0xD9, 0x0C, 0x0C, 0xED, 0x79, 0x0D, 0x0D, 0xD9, 0xC9, 0xD5, + 0x11, 0xA0, 0x8C, 0xCD, 0xF8, 0xD4, 0xC4, 0x0A, 0xD5, 0x20, 0x05, 0x1B, 0x7A, 0xB3, 0x20, 0xF3, + 0xD1, 0xC9, 0x06, 0x08, 0xAF, 0xCD, 0x18, 0xD5, 0x10, 0xFA, 0xC9, 0x90, 0xC0, 0xA0, 0x90, 0x88, + 0x84, 0x82, 0x01, 0xCD, 0x79, 0xD3, 0xD8, 0x7D, 0xFE, 0x08, 0xD2, 0xF7, 0xC0, 0x21, 0x4F, 0xD0, + 0xCD, 0x84, 0xD2, 0x4E, 0xED, 0x78, 0x3C, 0xCA, 0xF7, 0xC0, 0x79, 0xD9, 0x4F, 0xD9, 0xC9, 0x00, + 0x20, 0x50, 0x60, 0x70, 0x80, 0x90, 0xF0, 0xCD, 0x84, 0xD3, 0xC5, 0xD5, 0xE5, 0xED, 0xB0, 0xE1, + 0xD1, 0xC1, 0x18, 0x03, 0xCD, 0x84, 0xD3, 0x1A, 0xBE, 0x28, 0x13, 0xCD, 0xF9, 0xD2, 0x7E, 0xCD, + 0x9C, 0xD4, 0x1A, 0xCD, 0x9C, 0xD4, 0xEB, 0xCD, 0xF9, 0xD2, 0xEB, 0xCD, 0x80, 0xD4, 0x13, 0x23, + 0x0B, 0x78, 0xB1, 0x20, 0xE2, 0xC9, 0x13, 0x2A, 0x05, 0x00, 0xCD, 0x79, 0xD3, 0xCD, 0xF9, 0xD2, + 0x7E, 0xCD, 0x9C, 0xD4, 0xCD, 0x1A, 0xD4, 0xCD, 0xFA, 0xD0, 0x30, 0x07, 0xCD, 0xF2, 0xD4, 0x3F, + 0x8D, 0x18, 0xEA, 0xF5, 0xAF, 0x80, 0x20, 0x07, 0xF1, 0xB7, 0x20, 0x0B, 0x23, 0x18, 0x08, 0x48, + 0x06, 0x00, 0xEB, 0xED, 0xB0, 0xEB, 0xF1, 0x22, 0x05, 0x00, 0xFE, 0x2E, 0xC8, 0xFE, 0x2D, 0x20, + 0xCC, 0x2B, 0x22, 0x05, 0x00, 0x18, 0xC6, 0xCD, 0x90, 0xD3, 0x38, 0x05, 0xC5, 0xCD, 0xFA, 0xD0, + 0xD1, 0xDA, 0xF7, 0xC0, 0xC2, 0xF7, 0xC0, 0x80, 0xCA, 0xF7, 0xC0, 0xC5, 0xD5, 0xE5, 0x11, 0x5E, + 0x00, 0x1A, 0xBE, 0x20, 0x04, 0x13, 0x23, 0x10, 0xF8, 0xE1, 0xE5, 0x06, 0x10, 0xCC, 0x6B, 0xD1, + 0xE1, 0xD1, 0xC1, 0x23, 0x1B, 0x7A, 0xB3, 0x20, 0xE2, 0xC9, 0xE5, 0x06, 0x00, 0x21, 0x5E, 0x00, + 0xCD, 0x3E, 0xD3, 0xB7, 0x28, 0x2D, 0xFE, 0x2D, 0x28, 0x29, 0xFE, 0x2E, 0x28, 0x25, 0x13, 0x4F, + 0xFE, 0x27, 0x28, 0x12, 0xFE, 0x22, 0x28, 0x0E, 0x1B, 0xE5, 0xCD, 0xB2, 0xD3, 0x7D, 0xE1, 0x38, + 0x13, 0x77, 0x23, 0x04, 0x18, 0xDA, 0x1A, 0x13, 0xB7, 0x28, 0x08, 0xB9, 0x28, 0xD2, 0x77, 0x23, + 0x04, 0x18, 0xF3, 0xB7, 0x11, 0x5E, 0x00, 0xE1, 0xC9, 0xFE, 0x4D, 0x20, 0x01, 0x13, 0x01, 0x80, + 0x00, 0x2A, 0x03, 0x00, 0xCD, 0x7F, 0xD3, 0x1E, 0x10, 0xAF, 0xB0, 0x20, 0x0A, 0x3E, 0x0F, 0xB9, + 0x38, 0x05, 0xAF, 0xB1, 0x28, 0x01, 0x59, 0xC5, 0x43, 0xCD, 0x6B, 0xD1, 0x22, 0x03, 0x00, 0xC1, + 0x79, 0x93, 0x4F, 0x30, 0x01, 0x05, 0x78, 0xB1, 0x20, 0xDD, 0xC9, 0xCD, 0xF9, 0xD2, 0xC5, 0xE5, + 0xD5, 0x0E, 0x00, 0x1E, 0x04, 0x3E, 0x03, 0xA1, 0xCC, 0xAD, 0xD1, 0xCD, 0xAD, 0xD1, 0x7E, 0xCD, + 0xFE, 0xD2, 0x1C, 0x1C, 0x23, 0x0C, 0x10, 0xED, 0xCD, 0xAD, 0xD1, 0x3E, 0x3A, 0xBB, 0x20, 0xF8, + 0xD1, 0xE1, 0xC1, 0x7E, 0x23, 0xCD, 0x9D, 0xD1, 0x10, 0xF9, 0xC3, 0x80, 0xD4, 0xE6, 0x7F, 0xFE, + 0x7F, 0x28, 0x05, 0xFE, 0x20, 0xD2, 0xA1, 0xD4, 0x3E, 0x2E, 0xC3, 0xA1, 0xD4, 0x1C, 0xC3, 0x9F, + 0xD4, 0xCD, 0x90, 0xD3, 0x38, 0x04, 0xC5, 0xCD, 0xFA, 0xD0, 0xDA, 0xF7, 0xC0, 0xC2, 0xF7, 0xC0, + 0x80, 0xCA, 0xF7, 0xC0, 0xC1, 0xE5, 0xEB, 0xED, 0xA0, 0xE2, 0xD3, 0xD1, 0x3D, 0x20, 0xF8, 0xE1, + 0xED, 0xB0, 0xC9, 0xE1, 0xC9, 0xCD, 0x72, 0xD3, 0xE9, 0xCD, 0x72, 0xD3, 0x4D, 0xED, 0x78, 0xCD, + 0xFE, 0xD2, 0xC3, 0x80, 0xD4, 0xCD, 0xB2, 0xD3, 0x45, 0xCD, 0x72, 0xD3, 0x4D, 0xED, 0x41, 0xC9, + 0xCD, 0xB2, 0xD3, 0xDA, 0xF7, 0xC0, 0xCD, 0x45, 0xD3, 0xA7, 0x28, 0x74, 0xE5, 0xFE, 0x2B, 0x28, + 0x2D, 0xFE, 0x2D, 0x28, 0x36, 0xFE, 0x2A, 0x28, 0x41, 0xFE, 0x2F, 0x28, 0x50, 0xCD, 0xB2, 0xD3, + 0xDA, 0xF7, 0xC0, 0xCD, 0x45, 0xD3, 0xA7, 0xC2, 0xF7, 0xC0, 0xEB, 0xE1, 0xE5, 0xD5, 0x19, 0xCD, + 0x76, 0xD2, 0xCD, 0xF2, 0xD4, 0x2C, 0xA0, 0xD1, 0xE1, 0xA7, 0xED, 0x52, 0x18, 0x42, 0x13, 0xCD, + 0xB2, 0xD3, 0xDA, 0xF7, 0xC0, 0xEB, 0xE3, 0x19, 0xD1, 0x18, 0xBB, 0x13, 0xCD, 0xB2, 0xD3, 0xDA, + 0xF7, 0xC0, 0xEB, 0xE3, 0xA7, 0xED, 0x52, 0xD1, 0x18, 0xAC, 0x13, 0xCD, 0xB2, 0xD3, 0xDA, 0xF7, + 0xC0, 0xEB, 0xE3, 0xC5, 0x42, 0x4B, 0xCD, 0xA6, 0xD2, 0xC1, 0xD1, 0x18, 0x99, 0x13, 0xCD, 0xB2, + 0xD3, 0xDA, 0xF7, 0xC0, 0xEB, 0xE3, 0xC5, 0x42, 0x4B, 0xCD, 0xBF, 0xD2, 0xC1, 0xD1, 0x18, 0x86, + 0xCD, 0x76, 0xD2, 0xC3, 0x80, 0xD4, 0xCD, 0xF9, 0xD2, 0xCD, 0x9F, 0xD4, 0xCD, 0x96, 0xD2, 0x3E, + 0x2E, 0xC3, 0xA1, 0xD4, 0x85, 0x6F, 0xD0, 0x24, 0xC9, 0xC5, 0x47, 0x3E, 0x01, 0x05, 0xFA, 0x94, + 0xD2, 0x07, 0x30, 0xF9, 0xC1, 0xC9, 0x01, 0x0A, 0x00, 0xCD, 0xBF, 0xD2, 0x7B, 0xF5, 0x7C, 0xB5, + 0xC4, 0x96, 0xD2, 0xF1, 0x18, 0x61, 0x11, 0x00, 0x00, 0xEB, 0x3E, 0x10, 0xB7, 0xCB, 0x43, 0x28, + 0x01, 0x09, 0xCB, 0x1C, 0xCB, 0x1D, 0xCB, 0x1A, 0xCB, 0x1B, 0x3D, 0x20, 0xEF, 0xEB, 0xC9, 0x11, + 0x00, 0x00, 0x7A, 0xB8, 0x20, 0x02, 0x7B, 0xB9, 0x3F, 0xD8, 0xEB, 0x3E, 0x10, 0x37, 0xCB, 0x13, + 0xCB, 0x12, 0xCB, 0x15, 0xCB, 0x14, 0x30, 0x05, 0xB7, 0xED, 0x42, 0x18, 0x06, 0xED, 0x42, 0x30, + 0x02, 0x1D, 0x09, 0x3D, 0x20, 0xE7, 0xEB, 0xB7, 0xC9, 0xF5, 0xCD, 0x45, 0xD3, 0xB7, 0xC2, 0xF7, + 0xC0, 0xF1, 0xC9, 0xCD, 0xF2, 0xD4, 0xA0, 0x18, 0x05, 0x7C, 0xCD, 0xFE, 0xD2, 0x7D, 0xF5, 0x0F, + 0x0F, 0x0F, 0x0F, 0xCD, 0x07, 0xD3, 0xF1, 0xE6, 0x0F, 0xC6, 0x30, 0xFE, 0x3A, 0xDA, 0xA1, 0xD4, + 0xC6, 0x07, 0xC3, 0xA1, 0xD4, 0x7C, 0xB7, 0x28, 0x0C, 0xCD, 0x07, 0xD3, 0x7D, 0xCD, 0xFE, 0xD2, + 0xCD, 0xF2, 0xD4, 0xC8, 0xC9, 0x7D, 0xFE, 0x0A, 0x30, 0xF3, 0x18, 0xDB, 0xFE, 0x61, 0xD8, 0xFE, + 0x7B, 0xD0, 0xD6, 0x20, 0xC9, 0xF5, 0x7E, 0x23, 0x3D, 0xF2, 0x36, 0xD3, 0xF1, 0xC9, 0xCD, 0x45, + 0xD3, 0xFE, 0x2C, 0xC0, 0x13, 0x1A, 0xFE, 0x20, 0x28, 0x04, 0xFE, 0x09, 0x20, 0xDE, 0x13, 0x18, + 0xF4, 0xCD, 0xF2, 0xD4, 0x20, 0x3E, 0xA0, 0xC9, 0x3A, 0x08, 0x00, 0xE6, 0x80, 0x07, 0xC9, 0x3A, + 0x07, 0x00, 0xFE, 0xFF, 0xC0, 0xCD, 0x27, 0xC1, 0x1D, 0x0F, 0x53, 0x65, 0x6C, 0x12, 0x95, 0xC3, + 0xDE, 0xD4, 0xCD, 0x79, 0xD3, 0xD0, 0xC3, 0xF7, 0xC0, 0xCD, 0xB2, 0xD3, 0xC3, 0xE9, 0xD2, 0xCD, + 0x90, 0xD3, 0x18, 0xF8, 0xCD, 0x90, 0xD3, 0x38, 0xED, 0xE5, 0xCD, 0x72, 0xD3, 0xEB, 0xE1, 0xC9, + 0xCD, 0xB2, 0xD3, 0xCD, 0x3E, 0xD3, 0xFE, 0x53, 0xE5, 0x20, 0x0A, 0x13, 0xCD, 0xB2, 0xD3, 0x38, + 0xD5, 0x44, 0x4D, 0xE1, 0xC9, 0xCD, 0xB2, 0xD3, 0x38, 0xF9, 0xC1, 0xC5, 0xED, 0x42, 0x23, 0xB7, + 0x18, 0xEF, 0xCD, 0x3E, 0xD3, 0xD5, 0xE5, 0xCD, 0xEE, 0xD3, 0xFE, 0x2E, 0xE1, 0xD1, 0x28, 0x0D, + 0xCD, 0x09, 0xD4, 0xD8, 0xCD, 0xEE, 0xD3, 0xFE, 0x48, 0x28, 0x09, 0xB7, 0xC9, 0xCD, 0xFE, 0xD3, + 0xD8, 0xCD, 0xD9, 0xD3, 0xCD, 0x4E, 0xD3, 0xB7, 0xC9, 0x21, 0x00, 0x00, 0xCD, 0xFE, 0xD3, 0xD8, + 0x13, 0xC5, 0x44, 0x4D, 0x29, 0x29, 0x09, 0x29, 0xC1, 0xCD, 0x84, 0xD2, 0x18, 0xEE, 0x21, 0x00, + 0x00, 0xCD, 0x09, 0xD4, 0xD8, 0x13, 0x29, 0x29, 0x29, 0x29, 0x85, 0x6F, 0x18, 0xF3, 0x1A, 0xFE, + 0x30, 0xD8, 0xFE, 0x3A, 0x3F, 0xD8, 0xD6, 0x30, 0xC9, 0xCD, 0xFE, 0xD3, 0xD0, 0xCD, 0x2C, 0xD3, + 0xFE, 0x41, 0xD8, 0xFE, 0x47, 0x3F, 0xD8, 0xD6, 0x37, 0xC9, 0x11, 0x5E, 0x00, 0x3E, 0x24, 0xC5, + 0xE5, 0x4F, 0x06, 0x00, 0x62, 0x6B, 0xCD, 0x02, 0xD5, 0xCD, 0xC7, 0xD4, 0xFE, 0x10, 0x28, 0xF6, + 0xFE, 0x05, 0xCC, 0x80, 0xD4, 0x28, 0xEF, 0xFE, 0x0D, 0x28, 0x3F, 0xFE, 0x08, 0x28, 0x04, 0xFE, + 0x7F, 0x20, 0x10, 0x05, 0xFA, 0x22, 0xD4, 0x2B, 0xCD, 0x85, 0xD4, 0x7E, 0xFE, 0x20, 0xDC, 0x85, + 0xD4, 0x18, 0xD3, 0xFE, 0x16, 0x20, 0x10, 0x05, 0xFA, 0x22, 0xD4, 0x2B, 0xCD, 0x85, 0xD4, 0x7E, + 0xFE, 0x20, 0xDC, 0x85, 0xD4, 0x18, 0xF0, 0xF5, 0xCD, 0x8C, 0xD4, 0xF1, 0xFE, 0x15, 0xCC, 0x80, + 0xD4, 0x28, 0xAF, 0x77, 0x23, 0x04, 0x79, 0xB8, 0x20, 0xAC, 0x36, 0x00, 0x78, 0xE1, 0xC1, 0xB7, + 0xCD, 0xF2, 0xD4, 0x8D, 0xC9, 0xCD, 0xF2, 0xD4, 0x08, 0x20, 0x88, 0xC9, 0xFE, 0x20, 0x30, 0x11, + 0xFE, 0x0D, 0x28, 0x0D, 0xC6, 0x40, 0xCD, 0xF2, 0xD4, 0xDE, 0x18, 0x05, 0xCD, 0xF3, 0xD2, 0x3E, + 0x20, 0xF5, 0xE6, 0x7F, 0xD9, 0xCB, 0x78, 0xD9, 0xC4, 0x29, 0xD5, 0xD9, 0xCB, 0x60, 0xD9, 0xCC, + 0x18, 0xD5, 0xFE, 0x0D, 0x3E, 0x0A, 0xCC, 0xA1, 0xD4, 0xCC, 0xC1, 0xD4, 0xCD, 0x21, 0xC8, 0xF1, + 0xC9, 0xCD, 0xF8, 0xD4, 0xC4, 0x0A, 0xD5, 0xFE, 0x10, 0xCC, 0x4D, 0xD5, 0xFE, 0x13, 0xCC, 0x02, + 0xD5, 0xFE, 0x03, 0x28, 0x03, 0xFE, 0x1B, 0xC0, 0x31, 0xF0, 0x7F, 0xCD, 0x8C, 0xD4, 0xCD, 0x80, + 0xD4, 0xC3, 0x8D, 0xC0, 0xF5, 0x7E, 0x23, 0xB7, 0x28, 0x06, 0xCD, 0xA1, 0xD4, 0xF2, 0xE5, 0xD4, + 0xF1, 0xC9, 0xE3, 0xCD, 0xE4, 0xD4, 0xE3, 0xC9, 0xD9, 0xED, 0x78, 0xD9, 0xE6, 0x40, 0xC8, 0x3E, + 0xFF, 0xC9, 0xCD, 0x21, 0xC8, 0xCD, 0xF8, 0xD4, 0x28, 0xF8, 0xCD, 0xF8, 0xD4, 0x28, 0xFB, 0xD9, + 0x0C, 0xED, 0x78, 0x0D, 0xD9, 0xE6, 0x7F, 0xC9, 0xF5, 0xD9, 0xED, 0x78, 0xE6, 0x80, 0x28, 0xFA, + 0x0C, 0xF1, 0xED, 0x79, 0xF5, 0x0D, 0xD9, 0xF1, 0xC9, 0xF5, 0xC5, 0x06, 0xF7, 0x10, 0xFE, 0xC1, + 0xCD, 0xC1, 0xD4, 0xFE, 0x10, 0x28, 0x24, 0xDB, 0x54, 0xE6, 0x20, 0x20, 0xF3, 0xF1, 0xCB, 0xFF, + 0xD3, 0x54, 0xCB, 0xBF, 0xD3, 0x54, 0xCB, 0xFF, 0xD3, 0x54, 0xCB, 0xBF, 0xC9, 0xF5, 0xD9, 0x3E, + 0x80, 0xA8, 0x47, 0xD9, 0xCB, 0x7F, 0x3E, 0x11, 0xC4, 0x3E, 0xD5, 0xF1, 0xC9, 0xFD, 0xC7, 0x40, + 0xC4, 0xF7, 0xC0, 0x39, 0xD1, 0xD9, 0xD1, 0xF7, 0xC0, 0xD5, 0xD1, 0xF0, 0xD1, 0xBE, 0xCF, 0xF7, + 0xC0, 0xF7, 0xC0, 0xF7, 0xC0, 0x57, 0xD0, 0xF7, 0xC0, 0xE5, 0xD1, 0xF7, 0xC0, 0xC7, 0xD0, 0x7C, + 0xC6, 0xA4, 0xC7, 0x39, 0xC8, 0xF7, 0xC0, 0x64, 0xD0, 0x86, 0xC6, 0xF7, 0xC0, 0xF7, 0xC0, 0xB1, + 0xD1, 0x16, 0x02, 0xD5, 0xCD, 0x02, 0xD6, 0xD1, 0xD0, 0xD5, 0x3E, 0x0A, 0x32, 0x18, 0x00, 0xCD, + 0x60, 0xD6, 0xCD, 0x02, 0xD6, 0xD1, 0xD0, 0x15, 0x20, 0xE9, 0x18, 0x50, 0xD5, 0x3A, 0x17, 0x00, + 0xF5, 0x3A, 0x18, 0x00, 0xF5, 0x3A, 0x15, 0x00, 0xF5, 0xCB, 0x87, 0x32, 0x15, 0x00, 0xCD, 0x02, + 0xD6, 0xF1, 0x32, 0x15, 0x00, 0xF1, 0x32, 0x18, 0x00, 0xF1, 0x32, 0x17, 0x00, 0xCD, 0x60, 0xD6, + 0xD1, 0xC9, 0x1E, 0x02, 0x16, 0x0A, 0xD5, 0xCD, 0xE5, 0xD6, 0xD1, 0xD0, 0x15, 0x20, 0xF7, 0x1D, + 0x28, 0x1A, 0xCD, 0xAC, 0xD5, 0x18, 0xED, 0x1E, 0x02, 0x16, 0x04, 0xD5, 0xCD, 0x2B, 0xD7, 0xD1, + 0xD0, 0x15, 0x20, 0xF7, 0x1D, 0x28, 0x05, 0xCD, 0xAC, 0xD5, 0x18, 0xED, 0x3A, 0x21, 0x00, 0x4F, + 0x37, 0xC9, 0x97, 0x32, 0x18, 0x00, 0x32, 0x17, 0x00, 0x32, 0x1F, 0x00, 0xCD, 0xE0, 0xD7, 0xD3, + 0x34, 0xCD, 0xBA, 0xD6, 0x38, 0x0E, 0xD3, 0x30, 0xDB, 0x34, 0xCB, 0x57, 0x20, 0x3B, 0x1F, 0x30, + 0xF7, 0xC3, 0xCB, 0xD6, 0x3E, 0xC4, 0xD3, 0x30, 0xCD, 0x61, 0xD8, 0xE6, 0x57, 0xD3, 0x04, 0xCD, + 0x6F, 0xD8, 0xDB, 0x04, 0xE6, 0x40, 0x20, 0x16, 0xCD, 0x5A, 0xD8, 0xDB, 0x34, 0xCB, 0x57, 0x20, + 0x18, 0x1F, 0x30, 0xF7, 0x3E, 0xD0, 0xD3, 0x30, 0x97, 0xD3, 0x31, 0xC3, 0xDD, 0xD6, 0xDB, 0x34, + 0xCB, 0x57, 0x20, 0x05, 0x1F, 0x30, 0xDB, 0x18, 0xCB, 0x3E, 0x80, 0x32, 0x21, 0x00, 0x37, 0xC9, + 0x97, 0xCD, 0xE0, 0xD7, 0xD3, 0x34, 0x3A, 0x18, 0x00, 0xD3, 0x33, 0x4F, 0x3A, 0x1A, 0x00, 0xD3, + 0x32, 0x3A, 0x1F, 0x00, 0xD3, 0x31, 0x91, 0xCA, 0x5A, 0xD8, 0xCD, 0xBA, 0xD6, 0x38, 0x0F, 0xF6, + 0x10, 0xD3, 0x30, 0xDB, 0x34, 0xCB, 0x57, 0x20, 0xD0, 0x1F, 0x30, 0xF7, 0x18, 0x3D, 0xCD, 0x61, + 0xD8, 0xE6, 0x4F, 0xD3, 0x04, 0x3E, 0x18, 0xD3, 0x30, 0xDB, 0x34, 0xCB, 0x57, 0x20, 0xBA, 0x1F, + 0x30, 0xF7, 0xDB, 0x30, 0x2E, 0x32, 0xDB, 0x04, 0xE6, 0x40, 0x20, 0xFA, 0x2D, 0x20, 0xF7, 0xDB, + 0x04, 0xE6, 0x40, 0x20, 0xFA, 0xCD, 0x5A, 0xD8, 0x18, 0x23, 0x3A, 0x15, 0x00, 0xCB, 0x5F, 0x3E, + 0x0E, 0x28, 0x06, 0xE6, 0x04, 0x37, 0xC0, 0x3E, 0x0C, 0xA7, 0xC9, 0xCD, 0x5A, 0xD8, 0x21, 0x64, + 0x00, 0xCD, 0x7C, 0xD8, 0xDB, 0x30, 0x32, 0x21, 0x00, 0xE6, 0x98, 0x37, 0xC0, 0x3A, 0x18, 0x00, + 0x32, 0x1F, 0x00, 0xA7, 0xC9, 0xCD, 0x1C, 0xD7, 0xD3, 0x30, 0xDB, 0x34, 0x1F, 0x38, 0x16, 0xED, + 0xA2, 0x04, 0xDB, 0x34, 0x1F, 0x38, 0x0E, 0xED, 0xA2, 0xC2, 0xEA, 0xD6, 0xDB, 0x34, 0xCB, 0x4F, + 0x20, 0x10, 0x1F, 0x30, 0xF7, 0xCD, 0x5A, 0xD8, 0xDB, 0x30, 0x32, 0x21, 0x00, 0xE6, 0x9C, 0xC8, + 0x18, 0x08, 0xCD, 0x5A, 0xD8, 0x3E, 0x80, 0x32, 0x21, 0x00, 0x37, 0xC9, 0xCD, 0xCB, 0xD7, 0x57, + 0xCD, 0x51, 0xD8, 0xC6, 0x88, 0x5F, 0x7A, 0xD3, 0x34, 0x7B, 0xC9, 0xCD, 0x6F, 0xD8, 0xCD, 0xCB, + 0xD7, 0x57, 0xCD, 0x51, 0xD8, 0xC6, 0xA8, 0x5F, 0x7A, 0xD3, 0x34, 0x7B, 0xD3, 0x30, 0xDB, 0x34, + 0x1F, 0x38, 0x12, 0xED, 0xA3, 0x04, 0xDB, 0x34, 0x1F, 0x38, 0x0A, 0xED, 0xA3, 0xC2, 0x3E, 0xD7, + 0xDB, 0x34, 0x1F, 0x30, 0xFB, 0xCD, 0x5A, 0xD8, 0xCD, 0x6F, 0xD8, 0xDB, 0x30, 0x32, 0x21, 0x00, + 0xE6, 0xFC, 0x37, 0xC0, 0xA7, 0x3A, 0x15, 0x00, 0xCB, 0x4F, 0xC8, 0xCD, 0x8B, 0xD7, 0x38, 0x0A, + 0xDB, 0x34, 0x1F, 0x38, 0x04, 0xDB, 0x33, 0x18, 0xF7, 0x1C, 0xCD, 0x5A, 0xD8, 0xDB, 0x30, 0x32, + 0x21, 0x00, 0xE6, 0x9C, 0x37, 0xC0, 0x7B, 0xA7, 0xC8, 0x37, 0xC9, 0xCD, 0x1C, 0xD7, 0xED, 0x4B, + 0x1D, 0x00, 0xCB, 0x38, 0xCB, 0x19, 0xCB, 0x38, 0xCB, 0x19, 0x41, 0x1E, 0x00, 0xD3, 0x30, 0xDB, + 0x34, 0x1F, 0xD8, 0xDB, 0x33, 0xAE, 0xC0, 0x23, 0xDB, 0x34, 0x1F, 0xD8, 0xDB, 0x33, 0xAE, 0xC0, + 0x23, 0xDB, 0x34, 0x1F, 0xD8, 0xDB, 0x33, 0xAE, 0xC0, 0x23, 0xDB, 0x34, 0x1F, 0xD8, 0xDB, 0x33, + 0xAE, 0xC0, 0x23, 0x10, 0xDA, 0xDB, 0x34, 0x1F, 0x30, 0xFB, 0xC9, 0xDB, 0x33, 0x3E, 0x80, 0xCD, + 0xE0, 0xD7, 0x2A, 0x1D, 0x00, 0xCB, 0x1C, 0xCB, 0x1D, 0x45, 0x0E, 0x33, 0x2A, 0x1B, 0x00, 0xC9, + 0x4F, 0xDB, 0x34, 0xE6, 0x04, 0x28, 0x04, 0x97, 0x32, 0x23, 0x00, 0xCD, 0x33, 0xD8, 0xD3, 0x34, + 0xF5, 0xE5, 0xCD, 0x61, 0xD8, 0xE6, 0x5F, 0xD3, 0x04, 0x3A, 0x23, 0x00, 0xA7, 0x28, 0x21, 0x21, + 0x90, 0x01, 0x3A, 0x24, 0x00, 0xB8, 0x20, 0x1B, 0x3A, 0x25, 0x00, 0x67, 0x3A, 0x17, 0x00, 0x32, + 0x25, 0x00, 0xBC, 0x20, 0x06, 0xDB, 0x34, 0xE6, 0x20, 0x20, 0x0B, 0xCD, 0x6F, 0xD8, 0x18, 0x06, + 0x21, 0x20, 0x4E, 0xCD, 0x7C, 0xD8, 0xE1, 0x78, 0x32, 0x24, 0x00, 0x3E, 0x01, 0x32, 0x23, 0x00, + 0xF1, 0xB1, 0xC9, 0x3A, 0x16, 0x00, 0x47, 0x04, 0x97, 0x37, 0x17, 0x10, 0xFD, 0x47, 0x3A, 0x15, + 0x00, 0xCB, 0x57, 0x28, 0x02, 0xCB, 0xE0, 0xCB, 0x47, 0x28, 0x02, 0xCB, 0xF0, 0x78, 0xF6, 0x20, + 0xC9, 0xDB, 0x34, 0x2F, 0xE6, 0x20, 0xC8, 0x3E, 0x04, 0xC9, 0xCD, 0x61, 0xD8, 0xD3, 0x04, 0xAF, + 0xC9, 0xC5, 0x06, 0x7F, 0x3A, 0x17, 0x00, 0xA7, 0x28, 0x02, 0x06, 0x7D, 0x78, 0xC1, 0xC9, 0x21, + 0x08, 0x00, 0x3A, 0x15, 0x00, 0xCB, 0x57, 0x20, 0x03, 0x21, 0x0C, 0x00, 0xC5, 0x2B, 0x06, 0x1C, + 0x10, 0xFE, 0x00, 0x00, 0x7D, 0xB4, 0x20, 0xF5, 0xC1, 0xC9, 0x3A, 0x2D, 0x00, 0xA7, 0x28, 0x05, + 0xFE, 0x01, 0xC8, 0x18, 0x4F, 0x3C, 0x32, 0x2D, 0x00, 0xDB, 0xF8, 0xA7, 0x28, 0x04, 0xFE, 0x01, + 0x20, 0x42, 0x21, 0x29, 0xD9, 0x11, 0x2E, 0x00, 0x01, 0x0E, 0x00, 0xED, 0xB0, 0x21, 0x2E, 0x00, + 0x7C, 0x32, 0x32, 0x00, 0x7D, 0x32, 0x34, 0x00, 0x06, 0x07, 0x0E, 0x00, 0x21, 0x2E, 0x00, 0x7E, + 0x23, 0xD3, 0xF8, 0x81, 0x4F, 0xCD, 0x10, 0xD9, 0x38, 0x1A, 0x10, 0xF3, 0x79, 0xD3, 0xF8, 0x21, + 0x2E, 0x00, 0x11, 0x2F, 0x00, 0x01, 0x2F, 0x00, 0x36, 0x00, 0xED, 0xB0, 0xDB, 0xF8, 0xA7, 0xC8, + 0xFE, 0x01, 0x20, 0xF8, 0xCD, 0xF2, 0xD4, 0x43, 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x20, 0x69, 0x6E, + 0x69, 0x74, 0x69, 0x61, 0x6C, 0x69, 0x7A, 0x65, 0x20, 0x53, 0x54, 0x44, 0x43, 0x20, 0x63, 0x6F, + 0x6E, 0x74, 0x72, 0x6F, 0x6C, 0x6C, 0x65, 0x72, 0x8D, 0x3E, 0xFF, 0x32, 0x2D, 0x00, 0x37, 0xC9, + 0xD5, 0xC5, 0x4E, 0x23, 0x06, 0x0A, 0x11, 0x00, 0x00, 0xDB, 0xF8, 0xB9, 0x28, 0x08, 0x1B, 0x7A, + 0xB3, 0x20, 0xF6, 0x10, 0xF1, 0x37, 0xC1, 0xD1, 0xC9, 0x11, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, + 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xCD, 0x5D, 0xDA, 0x3E, 0xFF, 0x32, 0x0D, 0x00, 0x3E, + 0x12, 0xF5, 0x7E, 0xE6, 0x60, 0x77, 0xF1, 0xD3, 0xF8, 0xC5, 0xD5, 0x06, 0x1E, 0x11, 0x00, 0x00, + 0x7E, 0xCB, 0x7F, 0x20, 0x13, 0x1B, 0x7A, 0xB3, 0x20, 0xF6, 0x10, 0xF1, 0xAF, 0x32, 0x45, 0x00, + 0x3E, 0x07, 0x32, 0x44, 0x00, 0x3E, 0x01, 0x77, 0xD1, 0xC1, 0xC9, 0xCD, 0x5D, 0xDA, 0x3A, 0x16, + 0x00, 0x32, 0x2F, 0x00, 0x3E, 0x81, 0x32, 0x2E, 0x00, 0x3E, 0x19, 0x18, 0xC4, 0xCD, 0xA5, 0xD9, + 0x3E, 0xFF, 0x32, 0x0D, 0x00, 0x32, 0x2E, 0x00, 0x20, 0x11, 0xE5, 0xD5, 0xC5, 0x21, 0x4B, 0x00, + 0x11, 0x0D, 0x00, 0x01, 0x03, 0x00, 0xED, 0xB0, 0xC1, 0xD1, 0xE1, 0x3E, 0x17, 0xCD, 0x41, 0xD9, + 0xED, 0x53, 0x44, 0x00, 0xC9, 0xCD, 0x5D, 0xDA, 0xE5, 0x11, 0x0D, 0x00, 0x21, 0x47, 0x00, 0x06, + 0x03, 0x1A, 0xBE, 0x20, 0x04, 0x23, 0x13, 0x10, 0xF8, 0xE1, 0x11, 0xFF, 0xFF, 0xC8, 0x0E, 0xFF, + 0x06, 0x0A, 0x3E, 0x15, 0xCD, 0x41, 0xD9, 0xED, 0x5B, 0x44, 0x00, 0xE6, 0x02, 0xC0, 0x3E, 0xFF, + 0xBA, 0x20, 0x02, 0xBB, 0xC8, 0x4A, 0x10, 0xEA, 0xBB, 0xC0, 0x79, 0xFE, 0x05, 0x20, 0x04, 0x3E, + 0x03, 0x18, 0x1A, 0xFE, 0x04, 0x20, 0x04, 0x3E, 0x0B, 0x18, 0x12, 0xFE, 0x07, 0x38, 0x04, 0x3E, + 0x0C, 0x18, 0x0A, 0xFE, 0x06, 0x20, 0x04, 0x3E, 0x09, 0x18, 0x02, 0x3E, 0x07, 0x32, 0x44, 0x00, + 0x5F, 0x51, 0xA7, 0xC9, 0xCD, 0xA5, 0xD9, 0xC0, 0x3E, 0x80, 0x32, 0x2E, 0x00, 0x3E, 0x17, 0xCD, + 0x41, 0xD9, 0x3E, 0x16, 0xC3, 0x41, 0xD9, 0xCD, 0x5D, 0xDA, 0x3E, 0xFF, 0x32, 0x0D, 0x00, 0x3E, + 0x13, 0xCD, 0x41, 0xD9, 0xED, 0x5B, 0x44, 0x00, 0x3E, 0xFF, 0xBB, 0xC0, 0xBA, 0x20, 0x06, 0x06, + 0x0A, 0xCD, 0xC2, 0xD9, 0xC8, 0x3E, 0x00, 0x32, 0x44, 0x00, 0xC9, 0xCD, 0x5D, 0xDA, 0x3E, 0x14, + 0xCD, 0x41, 0xD9, 0x3A, 0x44, 0x00, 0xFE, 0xFF, 0xC0, 0x32, 0x2E, 0x00, 0x3E, 0x1B, 0xC3, 0x41, + 0xD9, 0x3A, 0x44, 0x00, 0xFE, 0xFF, 0xC9, 0x3A, 0x45, 0x00, 0xFE, 0xFF, 0xC9, 0x21, 0x2E, 0x00, + 0x11, 0x2F, 0x00, 0x01, 0x2F, 0x00, 0x36, 0x00, 0xED, 0xB0, 0xDD, 0xE5, 0xDD, 0x21, 0x2E, 0x00, + 0x3A, 0x16, 0x00, 0xF6, 0x1F, 0xDD, 0x77, 0x01, 0x3A, 0x17, 0x00, 0xDD, 0x77, 0x19, 0x2A, 0x18, + 0x00, 0xDD, 0x74, 0x1A, 0xDD, 0x75, 0x1B, 0x3A, 0x1A, 0x00, 0xDD, 0x77, 0x18, 0x2A, 0x1B, 0x00, + 0xDD, 0x74, 0x0A, 0xDD, 0x75, 0x0B, 0x2A, 0x1D, 0x00, 0xDD, 0x74, 0x06, 0xDD, 0x75, 0x07, 0x3A, + 0x10, 0x00, 0xE6, 0x60, 0xDD, 0x77, 0x15, 0xDD, 0xE1, 0x21, 0x43, 0x00, 0xC9, 0x1A, 0x1A, 0x1A, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +} +}; + + + +/* returns TRUE iff there exists a disk with VERBOSE */ +static int32 cromfdc_hasProperty(uint32 property) { + int32 i; + for (i = 0; i < CROMFDC_MAX_DRIVES; i++) + if (cromfdc_dev.units[i].flags & property) return TRUE; + return FALSE; +} + +static uint8 motor_timeout = 0; + +/* Unit service routine */ +t_stat cromfdc_svc (UNIT *uptr) +{ + + if(cromfdc_info->motor_on == 1) { + motor_timeout ++; + if(motor_timeout == MOTOR_TO_LIMIT) { + cromfdc_info->motor_on = 0; + TRACE_PRINT(DRIVE_MSG, ("CROMFDC: Motor OFF" NLP)) + } + } + + cromfdc_info->rtc ++; + + sim_activate (cromfdc_unit, cromfdc_unit->wait); /* requeue! */ + + return SCPE_OK; +} + + +/* Reset routine */ +static t_stat cromfdc_reset(DEVICE *dptr) +{ + PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; + + if(dptr->flags & DEV_DIS) { /* Disconnect ROM and I/O Ports */ + if (cromfdc_hasProperty(UNIT_CROMFDC_ROM)) { + sim_map_resource(pnp->mem_base, pnp->mem_size, RESOURCE_TYPE_MEMORY, &cromfdcrom, TRUE); + } + /* Unmap I/O Ports (0x3-4,0x5-9,0x34,0x40 */ + sim_map_resource(0x03, 2, RESOURCE_TYPE_IO, &cromfdc_ext, TRUE); + sim_map_resource(0x05, 5, RESOURCE_TYPE_IO, &cromfdc_timer, TRUE); + sim_map_resource(0x34, 1, RESOURCE_TYPE_IO, &cromfdc_control, TRUE); +/* sim_map_resource(0x40, 1, RESOURCE_TYPE_IO, &cromfdc_banksel, TRUE);*/ + } else { + /* Connect CROMFDC ROM at base address */ + if (cromfdc_hasProperty(UNIT_CROMFDC_ROM)) { + TRACE_PRINT(VERBOSE_MSG, ("CROMFDC: ROM Enabled." NLP)) + if(sim_map_resource(pnp->mem_base, pnp->mem_size, RESOURCE_TYPE_MEMORY, &cromfdcrom, FALSE) != 0) { + printf("%s: error mapping MEM resource at 0x%04x\n", __FUNCTION__, pnp->io_base); + return SCPE_ARG; + } + } else { + TRACE_PRINT(VERBOSE_MSG, ("CROMFDC: ROM Disabled." NLP)) + } + /* Connect CROMFDC Interrupt, and Aux Disk Registers */ + if(sim_map_resource(0x03, 0x02, RESOURCE_TYPE_IO, &cromfdc_ext, FALSE) != 0) { + printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->io_base); + return SCPE_ARG; + } + + /* Connect CROMFDC Timer Registers */ + if(sim_map_resource(0x05, 0x05, RESOURCE_TYPE_IO, &cromfdc_timer, FALSE) != 0) { + printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->io_base); + return SCPE_ARG; + } + + /* Connect CROMFDC Disk Flags and Control Register */ + if(sim_map_resource(0x34, 0x01, RESOURCE_TYPE_IO, &cromfdc_control, FALSE) != 0) { + printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->io_base); + return SCPE_ARG; + } + + /* Connect CROMFDC Bank Select Register */ +/* if(sim_map_resource(0x40, 0x1, RESOURCE_TYPE_IO, &cromfdc_banksel, FALSE) != 0) { + printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->io_base); + return SCPE_ARG; + } +*/ + } + + cromfdc_info->rom_disabled = FALSE; + sim_activate (cromfdc_unit, cromfdc_unit->wait); /* requeue! */ + return SCPE_OK; +} + +static t_stat cromfdc_boot(int32 unitno, DEVICE *dptr) +{ + if((crofdc_type != 4) && (crofdc_type != 16) && (crofdc_type != 64)) { + printf("Invalid fdc_type: %d, must be 4, 16, or 64." NLP, crofdc_type); + return SCPE_ARG; + } + + DBG_PRINT(("Booting %dFDC Controller, bootstrap=%d" NLP, crofdc_type, bootstrap)); + + /* Re-enable the ROM in case it was disabled */ + cromfdc_info->rom_disabled = FALSE; + + /* Set the PC to 0, and go. */ + *((int32 *) sim_PC->loc) = 0xC000; + return SCPE_OK; +} + +/* Attach routine */ +static t_stat cromfdc_attach(UNIT *uptr, char *cptr) +{ + t_stat r; + r = wd179x_attach(uptr, cptr); + + return r; +} + +/* Detach routine */ +static t_stat cromfdc_detach(UNIT *uptr) +{ + t_stat r; + + r = wd179x_detach(uptr); + + return r; +} + +static int32 cromfdcrom(const int32 Addr, const int32 write, const int32 data) +{ +/* DBG_PRINT(("CROMFDC: ROM %s, Addr %04x" NLP, write ? "WR" : "RD", Addr)); */ + if(write) { + cromfdcram[Addr & CROMFDC_ADDR_MASK] = data; + return 0; + } else { + if(cromfdc_info->rom_disabled == FALSE) { + return(cromfdc_rom[bootstrap][Addr & CROMFDC_ADDR_MASK]); + } else { + return(cromfdcram[Addr & CROMFDC_ADDR_MASK]); + } + } +} + +/* Disk Control/Flags Register, 0x34 */ +static int32 cromfdc_control(const int32 port, const int32 io, const int32 data) +{ + int32 result = 0; + if(io) { /* I/O Write */ + switch(data & 0x0F) { + case 0: + wd179x_info->sel_drive = 0xFF; + break; + case CROMFDC_CTRL_DS1: + wd179x_info->sel_drive = 0; + break; + case CROMFDC_CTRL_DS2: + wd179x_info->sel_drive = 1; + break; + case CROMFDC_CTRL_DS3: + wd179x_info->sel_drive = 2; + break; + case CROMFDC_CTRL_DS4: + wd179x_info->sel_drive = 3; + break; + default: + TRACE_PRINT(STATUS_MSG, + ("CROMFDC: " ADDRESS_FORMAT " WR CTRL = 0x%02x: Invalid drive selected." NLP, PCX, data & 0xFF)); + break; + } + if(data & CROMFDC_CTRL_MAXI) { + wd179x_info->drivetype = 8; + } else { + wd179x_info->drivetype = 5; + } + + if(data & CROMFDC_CTRL_MTRON) { + cromfdc_info->motor_on = 1; + motor_timeout = 0; + } + + if(data & CROMFDC_CTRL_DDENS) { + if(crofdc_type == 4) { /* 4FDC */ + TRACE_PRINT(DRIVE_MSG, + ("CROMFDC: " ADDRESS_FORMAT " WR CTRL: Cannot set double density on 4FDC" NLP, PCX)); + } else { + wd179x_info->ddens = 1; + } + } else { + wd179x_info->ddens = 0; + } + if(data & CROMFDC_CTRL_AUTOWAIT) { + cromfdc_info->autowait = 1; + } else { + cromfdc_info->autowait = 0; + } + + TRACE_PRINT(DRIVE_MSG, + ("CROMFDC: " ADDRESS_FORMAT " WR CTRL: sel_drive=%d, drivetype=%d, motor=%d, dens=%d, aw=%d" NLP, PCX, + wd179x_info->sel_drive, wd179x_info->drivetype, cromfdc_info->motor_on, wd179x_info->ddens, cromfdc_info->autowait)); + } else { /* I/O Read */ + result = (crofdc_boot) ? 0 : CROMFDC_FLAG_BOOT; + result |= (wd179x_info->intrq) ? CROMFDC_FLAG_EOJ : 0; + result |= (wd179x_info->drq) ? CROMFDC_FLAG_DRQ : 0; + result |= (motor_timeout < MOTOR_TO_LIMIT) ? CROMFDC_FLAG_SEL_REQ : 0; + if(crofdc_type > 4) { /* 16, 64FDC */ + result |= (cromfdc_info->motor_on) ? CROMFDC_FLAG_MTRON : 0; + result |= (motor_timeout == MOTOR_TO_LIMIT) ? CROMFDC_FLAG_MTO : 0; + result |= (crofdc_inh_init) ? 0 : CROMFDC_FLAG_INH_INIT; + } + TRACE_PRINT(VERBOSE_MSG, + ("CROMFDC: " ADDRESS_FORMAT " Read DISK FLAGS, Port 0x%02x Result 0x%02x" NLP, PCX, port, result)) + } + + return result; +} + +/* 64FDC Interrupt and Auxiliary Disk Status */ +/* 0x03-04 */ +static int32 cromfdc_ext(const int32 port, const int32 io, const int32 data) +{ + int32 result; + if(io) { /* I/O Write */ + if(port == 0x4) { + if((data & CROMFDC_AUX_CMD_SIDE) == 0) { + if(crofdc_type == 4) { /* 4FDC */ + TRACE_PRINT(DRIVE_MSG, + ("CROMFDC: " ADDRESS_FORMAT " WR CTRL: Cannot set side 1 on 4FDC" NLP, PCX)); + } else { + wd179x_info->fdc_head = 1; + } + } else { + wd179x_info->fdc_head = 0; + } +#if 0 /* hharte - nothing implemented for these */ + if((data & CROMFDC_AUX_EJECT) == 0) { + printf("CROMFDC: Eject\n"); + } + if((data & CROMFDC_AUX_SEL_OVERRIDE) == 0) { + printf("CROMFDC: Sel Override\n"); + } + if((data & CROMFDC_AUX_CTRL_OUT) == 0) { + printf("CROMFDC: Ctrl Out\n"); + } +#endif /* 0 */ + if((data & CROMFDC_AUX_RESTORE) == 0) { + wd179x_external_restore(); + } + } else if (port == 0x3) { /* Interrupt Address */ + } else { + } + + TRACE_PRINT(DRIVE_MSG, + ("CROMFDC: " ADDRESS_FORMAT " AUX OUT, Port 0x%02x Data 0x%02x" NLP, PCX, port, data)) + result = 0; + } else { /* I/O Read */ + if(port == 0x4) { + result = dipswitch & 0x1F; + result |= 0x00; /* Bit 6 is Seek in Progress for Persci drives. */ + result |= (cromfdc_info->rtc & 1) ? 0x80 : 0; + } else if (port == 0x3) { /* Interrupt Address */ + result = 0xD7; /* end of job */ + } else { + result = 0xFF; + } + TRACE_PRINT(VERBOSE_MSG, + ("CROMFDC: " ADDRESS_FORMAT " AUX IN, Port 0x%02x Result 0x%02x" NLP, PCX, port, result)) + } + return result; +} + +/* 64FDC Timer registers */ +static int32 cromfdc_timer(const int32 port, const int32 io, const int32 data) +{ + static int32 result = 0; + if(io) { + TRACE_PRINT(VERBOSE_MSG, + ("CROMFDC: " ADDRESS_FORMAT " TIMER OUT, Port 0x%02x Data 0x%02x" NLP, PCX, port, data)) + result = 0; + } else { + result++; + TRACE_PRINT(VERBOSE_MSG, + ("CROMFDC: " ADDRESS_FORMAT " TIMER IN, Port 0x%02x Result 0x%02x" NLP, PCX, port, result)) + } + return result; +} + +/* 64FDC Bank Select (Write Disables boot ROM) */ +static int32 cromfdc_banksel(const int32 port, const int32 io, const int32 data) +{ + int32 result; + if(io) { + TRACE_PRINT(VERBOSE_MSG, + ("CROMFDC: " ADDRESS_FORMAT " BANKSEL OUT, Port 0x%02x Data 0x%02x" NLP, PCX, port, data)) + /* Unmap Boot ROM */ + cromfdc_info->rom_disabled = TRUE; + result = 0; + } else { + result = 0xFF; + TRACE_PRINT(VERBOSE_MSG, + ("CROMFDC: " ADDRESS_FORMAT " BANKSEL IN, Port 0x%02x Result 0x%02x" NLP, PCX, port, result)) + } + return result; +} diff --git a/AltairZ80/s100_disk1a.c b/AltairZ80/s100_disk1a.c new file mode 100644 index 00000000..3b607efb --- /dev/null +++ b/AltairZ80/s100_disk1a.c @@ -0,0 +1,853 @@ +/************************************************************************* + * * + * $Id: s100_disk1a.c 1771 2008-01-09 07:10:46Z hharte $ * + * * + * Copyright (c) 2007-2008 Howard M. Harte. * + * http://www.hartetec.com * + * * + * 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 HOWARD M. HARTE 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 Howard M. Harte shall * + * not be used in advertising or otherwise to promote the sale, use or * + * other dealings in this Software without prior written authorization * + * Howard M. Harte. * + * * + * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. * + * * + * Module Description: * + * CompuPro DISK1A Floppy Controller module for SIMH. * + * This module is a wrapper around the i8272 FDC module, and adds the * + * CompuPro-specific registers as well as the CompuPro Boot ROM. * + * * + * Environment: * + * User mode only * + * * + *************************************************************************/ + +/*#define DBG_MSG */ + +#include "altairz80_defs.h" + +#if defined (_WIN32) +#include +#endif + +#include "sim_defs.h" /* simulator definitions */ +#include "i8272.h" + +#ifdef DBG_MSG +#define DBG_PRINT(args) printf args +#else +#define DBG_PRINT(args) +#endif + +#define SEEK_MSG 0x01 +#define CMD_MSG 0x04 +#define RD_DATA_MSG 0x08 +#define WR_DATA_MSG 0x10 +#define STATUS_MSG 0x20 +#define VERBOSE_MSG 0x80 + +#define DISK1A_MAX_DRIVES 4 + +typedef struct { + PNP_INFO pnp; /* Plug and Play */ + uint32 dma_addr; /* DMA Transfer Address */ + uint8 rom_disabled; /* TRUE if ROM has been disabled */ +} DISK1A_INFO; + +static DISK1A_INFO disk1a_info_data = { { 0x0, 512, 0xC0, 4 } }; +static DISK1A_INFO *disk1a_info = &disk1a_info_data; + +extern t_stat set_membase(UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat show_membase(FILE *st, UNIT *uptr, int32 val, void *desc); +extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc); +extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, + int32 (*routine)(const int32, const int32, const int32), uint8 unmap); + +extern REG *sim_PC; +extern uint32 PCX; /* external view of PC */ + +#define UNIT_V_DISK1A_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_DISK1A_WLK (1 << UNIT_V_DISK1A_WLK) +#define UNIT_V_DISK1A_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ +#define UNIT_DISK1A_VERBOSE (1 << UNIT_V_DISK1A_VERBOSE) +#define UNIT_V_DISK1A_ROM (UNIT_V_UF + 2) /* boot ROM enabled */ +#define UNIT_DISK1A_ROM (1 << UNIT_V_DISK1A_ROM) +#define DISK1A_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */ + +static t_stat disk1a_reset(DEVICE *disk1a_dev); +static t_stat disk1a_boot(int32 unitno, DEVICE *dptr); +static t_stat disk1a_attach(UNIT *uptr, char *cptr); +static t_stat disk1a_detach(UNIT *uptr); + +static int32 disk1adev(const int32 port, const int32 io, const int32 data); +static int32 disk1arom(const int32 port, const int32 io, const int32 data); + +static uint8 DISK1A_Read(const uint32 Addr); +static uint8 DISK1A_Write(const uint32 Addr, uint8 cData); + +static int32 trace_level = 0; /* Disable all tracing by default */ +static int32 bootstrap = 0; + +/* The DISK1A does not really have RAM associated with it, but for ease of integration with the + * SIMH/AltairZ80 Resource Mapping Scheme, rather than Map and Unmap the ROM, simply implement our + * own RAM that can be swapped in when the DISK1A Boot ROM is disabled. + */ +static uint8 disk1aram[512]; + +static UNIT disk1a_unit[] = { + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DISK1A_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DISK1A_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DISK1A_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DISK1A_CAPACITY) } +}; + +static REG disk1a_reg[] = { + { HRDATA (TRACELEVEL, trace_level, 16), }, + { DRDATA (BOOTSTRAP, bootstrap, 10), }, + { NULL } +}; + +static MTAB disk1a_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE", &set_membase, &show_membase, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL }, + { UNIT_DISK1A_WLK, 0, "WRTENB", "WRTENB", NULL }, + { UNIT_DISK1A_WLK, UNIT_DISK1A_WLK, "WRTLCK", "WRTLCK", NULL }, + /* quiet, no warning messages */ + { UNIT_DISK1A_VERBOSE, 0, "QUIET", "QUIET", NULL }, + /* verbose, show warning messages */ + { UNIT_DISK1A_VERBOSE, UNIT_DISK1A_VERBOSE, "VERBOSE", "VERBOSE", NULL }, + { UNIT_DISK1A_ROM, 0, "NOROM", "NOROM", NULL }, + { UNIT_DISK1A_ROM, UNIT_DISK1A_ROM, "ROM", "ROM", NULL }, + { 0 } +}; + +DEVICE disk1a_dev = { + "DISK1A", disk1a_unit, disk1a_reg, disk1a_mod, + DISK1A_MAX_DRIVES, 10, 31, 1, DISK1A_MAX_DRIVES, DISK1A_MAX_DRIVES, + NULL, NULL, &disk1a_reset, + &disk1a_boot, &disk1a_attach, &disk1a_detach, + &disk1a_info_data, (DEV_DISABLE | DEV_DIS), 0, + NULL, NULL, NULL +}; + +/* This is the DISK1A Boot ROM. + * It consists of an 8K ROM, broken down into 16 bootstraps of + * 512-bytes each. See the DISK1A Manual for details of each + * bootstrap. Bootstrap 0 is the default, but others can be + * selected with 'd disk1a bootstrap ' at the SIMH SCP Prompt. + */ +static uint8 disk1a_rom[16][512] = { +{ 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x80, 0x3E, 0xFF, 0xD3, 0xC3, 0x01, 0x00, 0x40, 0xE3, 0xE3, /* 0 */ + 0x0B, 0x78, 0xB1, 0xC2, 0x0E, 0x00, 0x21, 0x00, 0x02, 0x11, 0x00, 0x82, 0x7E, 0x12, 0x1B, 0x2B, + 0x7D, 0xB4, 0xC2, 0x1C, 0x00, 0x11, 0x5D, 0x00, 0x3E, 0x85, 0x12, 0x13, 0x3E, 0x81, 0x12, 0x13, + 0x3E, 0x00, 0x12, 0x11, 0x50, 0x00, 0x12, 0x13, 0x13, 0x12, 0xC3, 0x49, 0x80, 0x01, 0x00, 0xC0, + 0xE3, 0xE3, 0x0B, 0x78, 0xB1, 0xC2, 0x40, 0x80, 0xC9, 0x3E, 0xFE, 0xD3, 0xC3, 0x11, 0x70, 0x81, + 0x06, 0x03, 0xDB, 0xC0, 0xB7, 0xF2, 0x52, 0x80, 0x1A, 0xD3, 0xC1, 0x13, 0x05, 0xC2, 0x52, 0x80, + 0x06, 0x02, 0xDB, 0xC0, 0xB7, 0xF2, 0x62, 0x80, 0x1A, 0xD3, 0xC1, 0x13, 0x05, 0xC2, 0x62, 0x80, + 0xDB, 0xC2, 0xB7, 0xF2, 0x70, 0x80, 0x3E, 0x08, 0xD3, 0xC1, 0xCD, 0x3D, 0x80, 0xDB, 0xC0, 0xB7, + 0xF2, 0x7D, 0x80, 0xDB, 0xC1, 0xEE, 0x20, 0x4F, 0xDB, 0xC0, 0xB7, 0xF2, 0x88, 0x80, 0xDB, 0xC1, + 0xB1, 0xC2, 0xDD, 0x80, 0x06, 0x03, 0x1A, 0xD3, 0xC2, 0x13, 0x05, 0xC2, 0x96, 0x80, 0x06, 0x09, + 0xDB, 0xC0, 0xB7, 0xF2, 0xA0, 0x80, 0x1A, 0xD3, 0xC1, 0x13, 0x05, 0xC2, 0xA0, 0x80, 0xDB, 0xC2, + 0xB7, 0xF2, 0xAE, 0x80, 0xDB, 0xC0, 0xB7, 0xF2, 0xB4, 0x80, 0xDB, 0xC1, 0xD6, 0x40, 0x67, 0xDB, + 0xC0, 0xB7, 0xF2, 0xBF, 0x80, 0xDB, 0xC1, 0xEE, 0x80, 0x6F, 0x06, 0x05, 0xDB, 0xC0, 0xB7, 0xF2, + 0xCC, 0x80, 0xDB, 0xC1, 0x05, 0xC2, 0xCC, 0x80, 0x7D, 0xB4, 0xCA, 0x53, 0x81, 0x3E, 0x01, 0xD3, + 0x90, 0xAF, 0x32, 0x86, 0x81, 0xD3, 0x90, 0xCD, 0x3D, 0x80, 0x3A, 0x86, 0x81, 0xB7, 0xFA, 0x13, + 0x81, 0xAF, 0x32, 0x86, 0x81, 0xD3, 0x90, 0xCD, 0x3D, 0x80, 0x3A, 0x86, 0x81, 0xB7, 0xFA, 0x13, + 0x81, 0xC3, 0x49, 0x80, 0xAF, 0x12, 0xD3, 0x90, 0x1A, 0xB7, 0xCA, 0x08, 0x81, 0x07, 0xF8, 0xC1, + 0xC3, 0x49, 0x80, 0x11, 0x96, 0x81, 0xCD, 0x04, 0x81, 0x11, 0xA6, 0x81, 0xCD, 0x04, 0x81, 0x11, + 0xB6, 0x81, 0x2A, 0xBF, 0x81, 0xCD, 0x04, 0x81, 0x11, 0x81, 0x81, 0x06, 0x04, 0x1A, 0xBE, 0xC2, + 0x49, 0x80, 0x23, 0x13, 0x05, 0xC2, 0x2D, 0x81, 0x11, 0xC6, 0x81, 0xCD, 0x04, 0x81, 0x11, 0xD6, + 0x81, 0xCD, 0x04, 0x81, 0x11, 0xE6, 0x81, 0x2A, 0xEF, 0x81, 0xCD, 0x04, 0x81, 0x7E, 0xFE, 0xE5, + 0xCA, 0x49, 0x80, 0xDB, 0xC2, 0x0F, 0x0F, 0xE6, 0x01, 0xF6, 0x02, 0x4F, 0xC3, 0x00, 0x01, 0x52, + 0x52, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x8F, 0x24, 0x07, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1A, 0x07, + 0x80, 0x43, 0x6F, 0x6D, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x95, 0x81, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xA5, 0x81, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xB5, 0x81, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x01, 0x00, 0xC5, 0x81, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x01, 0x00, 0xD5, 0x81, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0xE5, 0x81, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, + 0x01, 0x00, 0x50, 0x00, 0x00, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A }, + +{ 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x80, 0x01, 0x00, 0x40, 0xE3, 0xE3, 0x0B, 0x78, 0xB1, 0xC2, /* 1 */ + 0x0A, 0x00, 0x21, 0x00, 0x02, 0x11, 0x00, 0x82, 0x7E, 0x12, 0x1B, 0x2B, 0x7D, 0xB4, 0xC2, 0x18, + 0x00, 0x11, 0x5D, 0x00, 0x3E, 0xD2, 0x12, 0x13, 0x3E, 0x80, 0x12, 0x13, 0x3E, 0x00, 0x12, 0x11, + 0x50, 0x00, 0x12, 0x13, 0x13, 0x12, 0xC3, 0x39, 0x80, 0x3E, 0xFE, 0xD3, 0xC3, 0x3E, 0x01, 0xD3, + 0x90, 0xAF, 0x32, 0xD3, 0x80, 0xD3, 0x90, 0x01, 0x00, 0x14, 0x0B, 0x78, 0xB1, 0xC2, 0x4A, 0x80, + 0x3A, 0xD3, 0x80, 0xB7, 0xFA, 0x7F, 0x80, 0xAF, 0x32, 0xD3, 0x80, 0xD3, 0x90, 0x01, 0x00, 0x14, + 0x0B, 0x78, 0xB1, 0xC2, 0x60, 0x80, 0x3A, 0xD3, 0x80, 0xB7, 0xFA, 0x7F, 0x80, 0xC3, 0x39, 0x80, + 0xAF, 0x12, 0xD3, 0x90, 0x1A, 0xB7, 0xCA, 0x74, 0x80, 0x07, 0xF8, 0xC1, 0xC3, 0x39, 0x80, 0x11, + 0xE3, 0x80, 0xCD, 0x70, 0x80, 0x11, 0xF3, 0x80, 0xCD, 0x70, 0x80, 0x11, 0x03, 0x81, 0x2A, 0x0C, + 0x81, 0xCD, 0x70, 0x80, 0x11, 0xCE, 0x80, 0x06, 0x04, 0x1A, 0xBE, 0xC2, 0x39, 0x80, 0x23, 0x13, + 0x05, 0xC2, 0x99, 0x80, 0x11, 0x13, 0x81, 0xCD, 0x70, 0x80, 0x11, 0x23, 0x81, 0xCD, 0x70, 0x80, + 0x11, 0x33, 0x81, 0x2A, 0x3C, 0x81, 0xCD, 0x70, 0x80, 0x7E, 0xFE, 0xE5, 0xCA, 0x39, 0x80, 0xDB, + 0xC2, 0x0F, 0x0F, 0xE6, 0x01, 0xF6, 0x02, 0x4F, 0xC3, 0x00, 0x01, 0x52, 0x52, 0x32, 0x43, 0x6F, + 0x6D, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, + 0x80, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF2, + 0x80, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x81, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x12, + 0x81, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x22, + 0x81, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x32, + 0x81, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x01, 0x00, 0x50, + 0x00, 0x00, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + +{ 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x80, 0x3E, 0xFF, 0xD3, 0xC3, 0x01, 0x00, 0x40, 0xE3, 0xE3, /* 2 */ + 0x0B, 0x78, 0xB1, 0xC2, 0x0E, 0x00, 0x21, 0x00, 0x02, 0x11, 0x00, 0x82, 0x7E, 0x12, 0x1B, 0x2B, + 0x7D, 0xB4, 0xC2, 0x1C, 0x00, 0xC3, 0x34, 0x80, 0x01, 0x00, 0xC0, 0xE3, 0xE3, 0x0B, 0x78, 0xB1, + 0xC2, 0x2B, 0x80, 0xC9, 0x11, 0x00, 0x81, 0x3E, 0xFE, 0xD3, 0xC3, 0x1A, 0xD3, 0xC0, 0xCD, 0x28, + 0x80, 0x13, 0x06, 0x03, 0xDB, 0xC0, 0xB7, 0xF2, 0x44, 0x80, 0x1A, 0xD3, 0xC1, 0x13, 0x05, 0xC2, + 0x44, 0x80, 0xCD, 0x28, 0x80, 0x06, 0x02, 0xDB, 0xC0, 0xB7, 0xF2, 0x57, 0x80, 0x1A, 0xD3, 0xC1, + 0x13, 0x05, 0xC2, 0x57, 0x80, 0xDB, 0xC2, 0xB7, 0xF2, 0x65, 0x80, 0x3E, 0x08, 0xD3, 0xC1, 0xCD, + 0x28, 0x80, 0xDB, 0xC0, 0xB7, 0xF2, 0x72, 0x80, 0xDB, 0xC1, 0xEE, 0x20, 0x4F, 0xDB, 0xC0, 0xB7, + 0xF2, 0x7D, 0x80, 0xDB, 0xC1, 0xB1, 0xE6, 0xFC, 0xC2, 0xD6, 0x80, 0x06, 0x03, 0x1A, 0xD3, 0xC2, + 0x13, 0x05, 0xC2, 0x8D, 0x80, 0x06, 0x09, 0xDB, 0xC0, 0xB7, 0xF2, 0x97, 0x80, 0x1A, 0xD3, 0xC1, + 0x13, 0x05, 0xC2, 0x97, 0x80, 0xDB, 0xC2, 0xB7, 0xF2, 0xA5, 0x80, 0xDB, 0xC0, 0xB7, 0xF2, 0xAB, + 0x80, 0xDB, 0xC1, 0xD6, 0x40, 0xE6, 0xFC, 0x67, 0xDB, 0xC0, 0xB7, 0xF2, 0xB8, 0x80, 0xDB, 0xC1, + 0xEE, 0x80, 0x6F, 0x06, 0x05, 0xDB, 0xC0, 0xB7, 0xF2, 0xC5, 0x80, 0xDB, 0xC1, 0x05, 0xC2, 0xC5, + 0x80, 0x7D, 0xB4, 0xCA, 0xE7, 0x80, 0x7B, 0xFE, 0x18, 0xCA, 0x34, 0x80, 0xFE, 0x24, 0xCA, 0x34, + 0x80, 0x11, 0x12, 0x81, 0xC3, 0x37, 0x80, 0xDB, 0xC2, 0x0F, 0x0F, 0xE6, 0x01, 0xF6, 0x02, 0x4F, + 0xC3, 0x00, 0x01, 0x52, 0x52, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x8F, 0x24, 0x07, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1A, + 0x07, 0x80, 0x28, 0x03, 0xDF, 0x1E, 0x07, 0x02, 0x00, 0x01, 0x00, 0x46, 0x02, 0x00, 0x00, 0x01, + 0x03, 0x05, 0x35, 0xFF, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, + 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, + 0x72, 0x79, 0x2E, 0x20, 0x20, 0x43, 0x6F, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x31, + 0x39, 0x38, 0x33, 0x20, 0x62, 0x79, 0x20, 0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6C, 0x20, 0x52, + 0x65, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2E, 0x00, 0x24, 0x4C, 0x53, 0x54, 0x3A, 0x00, 0x00, + 0x1A, 0x00, 0x00, 0x00, 0xC4, 0x09, 0x00, 0x00, 0xFF, 0xFF, 0xC4, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x3C, 0x3E, 0x2E, 0x2C, 0x3D, 0x3A, 0x7C, 0x5B, 0x5D, 0x2A, 0x0A, 0x0D, 0x00, 0x00, 0x00, 0x00, + 0x63, 0x68, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6F, 0x72, 0x74, 0x73, 0x20, 0x6E, 0x61, 0x6D, 0x65, + 0x20, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x0A, 0x00, 0x43, 0x6F, 0x75, 0x6C, 0x64, 0x20, + 0x6E, 0x6F, 0x74, 0x20, 0x6C, 0x6F, 0x67, 0x6F, 0x6E, 0x20, 0x74, 0x6F, 0x20, 0x74, 0x68, 0x65 }, + +{ 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x80, 0x3E, 0xFF, 0xD3, 0xC3, 0x01, 0x00, 0x40, 0xE3, 0xE3, /* 3 */ + 0x0B, 0x78, 0xB1, 0xC2, 0x0E, 0x00, 0x21, 0x00, 0x02, 0x11, 0x00, 0x82, 0x7E, 0x12, 0x1B, 0x2B, + 0x7D, 0xB4, 0xC2, 0x1C, 0x00, 0x11, 0x5D, 0x00, 0x3E, 0x85, 0x12, 0x13, 0x3E, 0x81, 0x12, 0x13, + 0x3E, 0x00, 0x12, 0x11, 0x50, 0x00, 0x12, 0x13, 0x13, 0x12, 0xC3, 0x49, 0x80, 0x01, 0x00, 0x80, + 0xE3, 0xE3, 0x0B, 0x78, 0xB1, 0xC2, 0x40, 0x80, 0xC9, 0x3E, 0xFE, 0xD3, 0xC3, 0x3E, 0x28, 0xD3, + 0xC0, 0xCD, 0x3D, 0x80, 0x11, 0x70, 0x81, 0x06, 0x03, 0xDB, 0xC0, 0xB7, 0xF2, 0x59, 0x80, 0x1A, + 0xD3, 0xC1, 0x13, 0x05, 0xC2, 0x59, 0x80, 0x06, 0x02, 0xDB, 0xC0, 0xB7, 0xF2, 0x69, 0x80, 0x1A, + 0xD3, 0xC1, 0x13, 0x05, 0xC2, 0x69, 0x80, 0xDB, 0xC2, 0xB7, 0xF2, 0x77, 0x80, 0x3E, 0x08, 0xD3, + 0xC1, 0xCD, 0x3D, 0x80, 0xDB, 0xC0, 0xB7, 0xF2, 0x84, 0x80, 0xDB, 0xC1, 0xEE, 0x20, 0x4F, 0xDB, + 0xC0, 0xB7, 0xF2, 0x8F, 0x80, 0xDB, 0xC1, 0xB1, 0xE6, 0xFC, 0xC2, 0xE8, 0x80, 0x06, 0x03, 0x1A, + 0xD3, 0xC2, 0x13, 0x05, 0xC2, 0x9F, 0x80, 0x06, 0x09, 0xDB, 0xC0, 0xB7, 0xF2, 0xA9, 0x80, 0x1A, + 0xD3, 0xC1, 0x13, 0x05, 0xC2, 0xA9, 0x80, 0xDB, 0xC2, 0xB7, 0xF2, 0xB7, 0x80, 0xDB, 0xC0, 0xB7, + 0xF2, 0xBD, 0x80, 0xDB, 0xC1, 0xD6, 0x40, 0xE6, 0xFC, 0x67, 0xDB, 0xC0, 0xB7, 0xF2, 0xCA, 0x80, + 0xDB, 0xC1, 0xEE, 0x80, 0x6F, 0x06, 0x05, 0xDB, 0xC0, 0xB7, 0xF2, 0xD7, 0x80, 0xDB, 0xC1, 0x05, + 0xC2, 0xD7, 0x80, 0x7D, 0xB4, 0xCA, 0x5E, 0x81, 0x3E, 0x01, 0xD3, 0x90, 0xAF, 0x32, 0x86, 0x81, + 0xD3, 0x90, 0xCD, 0x3D, 0x80, 0x3A, 0x86, 0x81, 0xB7, 0xFA, 0x1E, 0x81, 0xAF, 0x32, 0x86, 0x81, + 0xD3, 0x90, 0xCD, 0x3D, 0x80, 0x3A, 0x86, 0x81, 0xB7, 0xFA, 0x1E, 0x81, 0xC3, 0x49, 0x80, 0xAF, + 0x12, 0xD3, 0x90, 0x1A, 0xB7, 0xCA, 0x13, 0x81, 0x07, 0xF8, 0xC1, 0xC3, 0x49, 0x80, 0x11, 0x96, + 0x81, 0xCD, 0x0F, 0x81, 0x11, 0xA6, 0x81, 0xCD, 0x0F, 0x81, 0x11, 0xB6, 0x81, 0x2A, 0xBF, 0x81, + 0xCD, 0x0F, 0x81, 0x11, 0x81, 0x81, 0x06, 0x04, 0x1A, 0xBE, 0xC2, 0x49, 0x80, 0x23, 0x13, 0x05, + 0xC2, 0x38, 0x81, 0x11, 0xC6, 0x81, 0xCD, 0x0F, 0x81, 0x11, 0xD6, 0x81, 0xCD, 0x0F, 0x81, 0x11, + 0xE6, 0x81, 0x2A, 0xEF, 0x81, 0xCD, 0x0F, 0x81, 0x7E, 0xFE, 0xE5, 0xCA, 0x49, 0x80, 0xDB, 0xC2, + 0x0F, 0x0F, 0xE6, 0x01, 0xF6, 0x02, 0x4F, 0xC3, 0x00, 0x01, 0x52, 0x52, 0x34, 0x00, 0x00, 0x00, + 0x03, 0xDF, 0x1E, 0x07, 0x02, 0x00, 0x01, 0x00, 0x46, 0x02, 0x00, 0x00, 0x01, 0x03, 0x05, 0x20, + 0xFF, 0x43, 0x6F, 0x6D, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x95, 0x81, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xA5, 0x81, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xB5, 0x81, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x01, 0x00, 0xC5, 0x81, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, + 0x01, 0x00, 0xD5, 0x81, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0xE5, 0x81, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, + 0x01, 0x00, 0x50, 0x00, 0x00, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A }, + +{ 0xDB, 0xFD, 0x90, 0x90, 0xB0, 0xFF, 0xE6, 0xC3, 0xB9, 0x00, 0xD0, 0x50, 0x58, 0xE2, 0xFC, 0x33, /* 4 */ + 0xC0, 0x8E, 0xC0, 0x8E, 0xD8, 0x8E, 0xD0, 0xBC, 0x04, 0x00, 0xBA, 0x90, 0x00, 0xBE, 0x00, 0x00, + 0x8B, 0xFE, 0xB9, 0x00, 0x01, 0xF3, 0xA5, 0xEB, 0x0F, 0xFC, 0x33, 0xC0, 0xE4, 0xC0, 0x0A, 0xC0, + 0x79, 0xFA, 0xAC, 0xE6, 0xC1, 0xE2, 0xF5, 0xC3, 0xB0, 0xFE, 0xE6, 0xC3, 0xB9, 0x03, 0x00, 0xBE, + 0xC6, 0x00, 0xE8, 0xE4, 0xFF, 0xB9, 0x02, 0x00, 0xE8, 0xDE, 0xFF, 0xEB, 0x13, 0x52, 0x52, 0x31, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, + 0xE4, 0xC2, 0x0A, 0xC0, 0x79, 0xFA, 0xB0, 0x08, 0xE6, 0xC1, 0xB9, 0x00, 0xF0, 0x50, 0x58, 0xE2, + 0xFC, 0xE4, 0xC0, 0x0A, 0xC0, 0x79, 0xFA, 0xE4, 0xC1, 0x34, 0x20, 0x8A, 0xE0, 0xE4, 0xC0, 0x0A, + 0xC0, 0x79, 0xFA, 0xE4, 0xC1, 0x0A, 0xC4, 0x74, 0x03, 0xE9, 0x84, 0x00, 0xB9, 0x03, 0x00, 0xAC, + 0xE6, 0xC2, 0xE2, 0xFB, 0xB9, 0x09, 0x00, 0xE8, 0x8F, 0xFF, 0xE4, 0xC0, 0x0A, 0xC0, 0x79, 0xFA, + 0xE4, 0xC1, 0x2C, 0x40, 0x8A, 0xD8, 0xE4, 0xC0, 0x0A, 0xC0, 0x79, 0xFA, 0xE4, 0xC1, 0x34, 0x80, + 0x8A, 0xF8, 0xB9, 0x05, 0x00, 0xE4, 0xC0, 0x0A, 0xC0, 0x79, 0xFA, 0xE4, 0xC1, 0xE2, 0xF6, 0x0A, + 0xFB, 0x74, 0x24, 0xE9, 0x4A, 0x00, 0x03, 0x8F, 0x46, 0x07, 0x00, 0x00, 0x02, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x1A, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0x00, 0x02, 0xAC, + 0x3C, 0xE5, 0x75, 0x03, 0xE9, 0x51, 0xFF, 0xBE, 0x00, 0x02, 0xBF, 0x00, 0x01, 0xB9, 0x00, 0x12, + 0xF3, 0xA5, 0x33, 0xC0, 0xE4, 0xC2, 0xB1, 0x02, 0xD3, 0xD8, 0x24, 0x01, 0x0C, 0x02, 0x8B, 0xC8, + 0x43, 0x6F, 0x6D, 0x70, 0x33, 0xC0, 0xEE, 0x0A, 0x44, 0x01, 0x74, 0xFB, 0x79, 0x01, 0xC3, 0x58, + 0xBE, 0x50, 0x00, 0xB0, 0x01, 0xEE, 0xB0, 0x00, 0x88, 0x44, 0x01, 0xEE, 0xB9, 0x00, 0xF0, 0x50, + 0x58, 0xE2, 0xFC, 0x0A, 0x44, 0x01, 0x75, 0x13, 0x88, 0x44, 0x01, 0xEF, 0xB9, 0x00, 0xF0, 0x50, + 0x58, 0xE2, 0xFC, 0x0A, 0x44, 0x01, 0x75, 0x03, 0xE9, 0xFD, 0xFE, 0xC7, 0x04, 0x05, 0x00, 0xE8, + 0xC2, 0xFF, 0xC7, 0x44, 0x04, 0x08, 0x01, 0xC7, 0x04, 0x02, 0x00, 0xE8, 0xB6, 0xFF, 0xC7, 0x44, + 0x04, 0x00, 0x00, 0xC7, 0x44, 0x0A, 0x00, 0x02, 0xC7, 0x44, 0x08, 0x02, 0x00, 0xC6, 0x44, 0x03, + 0x01, 0xC7, 0x04, 0x08, 0x00, 0xE8, 0x9C, 0xFF, 0xBE, 0x00, 0x02, 0xBF, 0x00, 0x01, 0xB9, 0x04, + 0x00, 0xF3, 0xA6, 0x75, 0xC3, 0xBE, 0x50, 0x00, 0xC7, 0x44, 0x0A, 0x10, 0x02, 0xC7, 0x04, 0x03, + 0x00, 0xE8, 0x80, 0xFF, 0xC7, 0x44, 0x0A, 0x00, 0x06, 0xC7, 0x04, 0x04, 0x00, 0xE8, 0x74, 0xFF, + 0xC7, 0x44, 0x0A, 0x00, 0x02, 0xC7, 0x44, 0x08, 0x09, 0x00, 0xC6, 0x44, 0x03, 0x01, 0x33, 0xC0, + 0x89, 0x44, 0x04, 0x89, 0x44, 0x06, 0xC7, 0x04, 0x08, 0x00, 0xE8, 0x57, 0xFF, 0xE9, 0x2C, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEA, 0x04, 0x00, 0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x00, 0x00, 0x00 }, + +{ 0xDB, 0xFD, 0x33, 0xC0, 0x8E, 0xC0, 0x8E, 0xD8, 0x8E, 0xD0, 0xBC, 0x1D, 0x00, 0xBA, 0x90, 0x00, + 0xBE, 0x00, 0x00, 0x8B, 0xFE, 0xFC, 0xB9, 0x00, 0x01, 0xF3, 0xA5, 0xEB, 0x18, 0x43, 0x6F, 0x6D, + 0x70, 0xB9, 0x00, 0xD0, 0x50, 0x58, 0xE2, 0xFC, 0xC3, 0x33, 0xC0, 0xEE, 0x0A, 0x44, 0x01, 0x74, + 0xFB, 0x79, 0x01, 0xC3, 0x58, 0xB0, 0xFE, 0xE6, 0xC3, 0xBE, 0x50, 0x00, 0xB0, 0x01, 0xEE, 0xEB, + 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, + 0xB0, 0x00, 0x88, 0x44, 0x01, 0xEE, 0xE8, 0xB8, 0xFF, 0x0A, 0x44, 0x01, 0x75, 0x0C, 0x88, 0x44, + 0x01, 0xEE, 0xE8, 0xAC, 0xFF, 0x0A, 0x44, 0x01, 0x74, 0xBB, 0xC7, 0x04, 0x05, 0x00, 0xE8, 0xA8, + 0xFF, 0xC7, 0x44, 0x04, 0x08, 0x01, 0xC7, 0x04, 0x02, 0x00, 0xE8, 0x9C, 0xFF, 0xC7, 0x44, 0x04, + 0x00, 0x00, 0xC7, 0x44, 0x0A, 0x00, 0x01, 0xC7, 0x44, 0x08, 0x02, 0x00, 0xC6, 0x44, 0x03, 0x01, + 0xC7, 0x04, 0x08, 0x00, 0xE8, 0x82, 0xFF, 0xBE, 0x00, 0x01, 0xBF, 0x1D, 0x00, 0xB9, 0x02, 0x00, + 0xF3, 0xA7, 0x75, 0x81, 0xBE, 0x50, 0x00, 0xC7, 0x44, 0x0A, 0x10, 0x01, 0xC7, 0x04, 0x03, 0x00, + 0xE8, 0x66, 0xFF, 0xC7, 0x44, 0x0A, 0x00, 0x05, 0xC7, 0x04, 0x04, 0x00, 0xE8, 0x5A, 0xFF, 0xC7, + 0x44, 0x0A, 0x00, 0x01, 0xC7, 0x44, 0x08, 0x09, 0x00, 0xC6, 0x44, 0x03, 0x01, 0x33, 0xC0, 0x89, + 0x44, 0x04, 0x89, 0x44, 0x06, 0xC7, 0x04, 0x08, 0x00, 0xE8, 0x3D, 0xFF, 0x33, 0xC0, 0xEB, 0x04, + 0x00, 0x00, 0x00, 0x00, 0xE4, 0xC2, 0xB1, 0x02, 0xD3, 0xD8, 0x24, 0x01, 0x0C, 0x02, 0x8B, 0xC8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEA, 0x02, 0x00, 0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x00, 0x00, 0x00 }, + +{ 0xDB, 0xFD, 0x90, 0x90, 0xB0, 0xFF, 0xE6, 0xC3, 0xB9, 0x00, 0xD0, 0x50, 0x58, 0xE2, 0xFC, 0x33, + 0xC0, 0x8E, 0xC0, 0x8E, 0xD8, 0x8E, 0xD0, 0xBC, 0x04, 0x00, 0xBE, 0x00, 0x00, 0x8B, 0xFE, 0xB9, + 0x80, 0x00, 0xF3, 0xA5, 0xEB, 0x17, 0xFC, 0x33, 0xC0, 0xE4, 0xC0, 0x0A, 0xC0, 0x79, 0xFA, 0xAC, + 0xE6, 0xC1, 0xE2, 0xF5, 0xC3, 0xB9, 0x00, 0xF0, 0x50, 0x58, 0xE2, 0xFC, 0xC3, 0xBE, 0xCA, 0x00, + 0xB0, 0xFE, 0xE6, 0xC3, 0xFC, 0xAC, 0xE6, 0xC0, 0xE8, 0xEA, 0xFF, 0xB9, 0x03, 0x00, 0xE8, 0xD5, + 0xFF, 0xB9, 0x02, 0x00, 0xE8, 0xCF, 0xFF, 0xE4, 0xC2, 0x0A, 0xC0, 0x79, 0xFA, 0xB0, 0x08, 0xE6, + 0xC1, 0xE8, 0xD1, 0xFF, 0xE4, 0xC0, 0x0A, 0xC0, 0x79, 0xFA, 0xE4, 0xC1, 0x34, 0x20, 0x8A, 0xE0, + 0xE4, 0xC0, 0x0A, 0xC0, 0x79, 0xFA, 0xE4, 0xC1, 0x0A, 0xC4, 0x24, 0xFC, 0x74, 0x03, 0xE9, 0x39, + 0x00, 0xB9, 0x03, 0x00, 0xAC, 0xE6, 0xC2, 0xE2, 0xFB, 0xB9, 0x09, 0x00, 0xE8, 0x97, 0xFF, 0xE4, + 0xC0, 0x0A, 0xC0, 0x79, 0xFA, 0xE4, 0xC1, 0x2C, 0x40, 0x24, 0xFC, 0x8A, 0xD8, 0xE4, 0xC0, 0x0A, + 0xC0, 0x79, 0xFA, 0xE4, 0xC1, 0x34, 0x80, 0x8A, 0xF8, 0xB9, 0x05, 0x00, 0xE4, 0xC0, 0x0A, 0xC0, + 0x79, 0xFA, 0xE4, 0xC1, 0xE2, 0xF6, 0x0A, 0xFB, 0x74, 0x38, 0x8B, 0xC6, 0x3D, 0xE2, 0x00, 0x7D, + 0x06, 0xBE, 0xDC, 0x00, 0xE9, 0x79, 0xFF, 0xE9, 0x73, 0xFF, 0x00, 0x03, 0x8F, 0x46, 0x07, 0x00, + 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1A, 0x07, 0x80, 0x28, 0x03, 0xDF, 0x1E, + 0x07, 0x02, 0x00, 0x01, 0x00, 0x46, 0x02, 0x00, 0x00, 0x01, 0x03, 0x05, 0x35, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x33, 0xC0, 0xE4, 0xC2, 0xB1, 0x02, 0xD3, 0xD8, 0x24, 0x01, 0x0C, 0x02, 0x8B, 0xC8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x52, 0x52, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEA, 0x04, 0x00, 0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x00, 0x00, 0x00 }, +{ 0xDB, 0xFD, 0x90, 0x90, 0xB0, 0xFF, 0xE6, 0xC3, 0xB9, 0x00, 0xA0, 0x50, 0x58, 0xE2, 0xFC, 0x33, + 0xC0, 0x8E, 0xC0, 0x8E, 0xD8, 0x8E, 0xD0, 0xBC, 0x04, 0x00, 0xBA, 0x90, 0x00, 0xBE, 0x00, 0x00, + 0x8B, 0xFE, 0xB9, 0x00, 0x01, 0xF3, 0xA5, 0xB0, 0xFE, 0xE6, 0xC3, 0xB0, 0x28, 0xE6, 0xC0, 0xB9, + 0x00, 0xA0, 0x50, 0x58, 0xE2, 0xFC, 0xB9, 0x03, 0x00, 0xBE, 0xCA, 0x00, 0xE8, 0xC1, 0x00, 0xB9, + 0x02, 0x00, 0xE8, 0xBB, 0x00, 0xEB, 0x19, 0x52, 0x52, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, + 0xE4, 0xC2, 0x0A, 0xC0, 0x79, 0xFA, 0xB0, 0x08, 0xE6, 0xC1, 0xB9, 0x00, 0xF0, 0x50, 0x58, 0xE2, + 0xFC, 0xE4, 0xC0, 0x0A, 0xC0, 0x79, 0xFA, 0xE4, 0xC1, 0x34, 0x20, 0x8A, 0xE0, 0xE4, 0xC0, 0x0A, + 0xC0, 0x79, 0xFA, 0xE4, 0xC1, 0x0A, 0xC4, 0x24, 0xFC, 0x74, 0x03, 0xE9, 0x91, 0x00, 0xB9, 0x03, + 0x00, 0xAC, 0xE6, 0xC2, 0xE2, 0xFB, 0xB9, 0x09, 0x00, 0xE8, 0x64, 0x00, 0xE4, 0xC0, 0x0A, 0xC0, + 0x79, 0xFA, 0xE4, 0xC1, 0x2C, 0x40, 0x24, 0xFC, 0x8A, 0xD8, 0xE4, 0xC0, 0x0A, 0xC0, 0x79, 0xFA, + 0xE4, 0xC1, 0x34, 0x80, 0x8A, 0xF8, 0xB9, 0x05, 0x00, 0xE4, 0xC0, 0x0A, 0xC0, 0x79, 0xFA, 0xE4, + 0xC1, 0xE2, 0xF6, 0x0A, 0xFB, 0x74, 0x20, 0xE9, 0x55, 0x00, 0x03, 0xDF, 0x1E, 0x07, 0x02, 0x00, + 0x02, 0x00, 0x46, 0x02, 0x00, 0x00, 0x01, 0x03, 0x05, 0x20, 0xFF, 0x00, 0xBE, 0x00, 0x02, 0xAC, + 0x3C, 0xE5, 0x75, 0x03, 0xE9, 0x40, 0xFF, 0xBE, 0x00, 0x02, 0xBF, 0x00, 0x01, 0xB9, 0x00, 0x12, + 0xF3, 0xA5, 0x33, 0xC0, 0xE4, 0xC2, 0xB1, 0x02, 0xD3, 0xD8, 0x24, 0x01, 0x0C, 0x02, 0x8B, 0xC8, + 0xFC, 0x33, 0xC0, 0xE4, 0xC0, 0x0A, 0xC0, 0x79, 0xFA, 0xAC, 0xE6, 0xC1, 0xE2, 0xF5, 0xC3, 0x43, + 0x6F, 0x6D, 0x70, 0x33, 0xC0, 0xEE, 0x0A, 0x44, 0x01, 0x74, 0xFB, 0x79, 0x01, 0xC3, 0x58, 0xBE, + 0x50, 0x00, 0xB0, 0x01, 0xEE, 0xB0, 0x00, 0x88, 0x44, 0x01, 0xEE, 0xB9, 0x00, 0xF0, 0x50, 0x58, + 0xE2, 0xFC, 0x0A, 0x44, 0x01, 0x75, 0x13, 0x88, 0x44, 0x01, 0xEE, 0xB9, 0x00, 0xF0, 0x50, 0x58, + 0xE2, 0xFC, 0x0A, 0x44, 0x01, 0x75, 0x03, 0xE9, 0xDD, 0xFE, 0xC7, 0x04, 0x05, 0x00, 0xE8, 0xC2, + 0xFF, 0xC7, 0x44, 0x04, 0x08, 0x01, 0xC7, 0x04, 0x02, 0x00, 0xE8, 0xB6, 0xFF, 0xC7, 0x44, 0x04, + 0x00, 0x00, 0xC7, 0x44, 0x0A, 0x00, 0x02, 0xC7, 0x44, 0x08, 0x02, 0x00, 0xC6, 0x44, 0x03, 0x01, + 0xC7, 0x04, 0x08, 0x00, 0xE8, 0x9C, 0xFF, 0xBE, 0x00, 0x02, 0xBF, 0x0F, 0x01, 0xB9, 0x04, 0x00, + 0xA6, 0x74, 0x03, 0xE9, 0xA1, 0xFE, 0xE2, 0xF8, 0xBE, 0x50, 0x00, 0xC7, 0x44, 0x0A, 0x10, 0x02, + 0xC7, 0x04, 0x03, 0x00, 0xE8, 0x7C, 0xFF, 0xC7, 0x44, 0x0A, 0x00, 0x06, 0xC7, 0x04, 0x04, 0x00, + 0xE8, 0x70, 0xFF, 0xC7, 0x44, 0x0A, 0x00, 0x02, 0xC7, 0x44, 0x08, 0x09, 0x00, 0xC6, 0x44, 0x03, + 0x01, 0x33, 0xC0, 0x89, 0x44, 0x04, 0x89, 0x44, 0x06, 0xC7, 0x04, 0x08, 0x00, 0xE8, 0x53, 0xFF, + 0xE9, 0x19, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEA, 0x04, 0x00, 0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x00, 0x00, 0x00 }, + +{ 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x3C, 0x00, 0x00, 0x00, 0x7F, 0x43, 0xF8, + 0x00, 0x00, 0x24, 0x7C, 0x00, 0x00, 0x80, 0x00, 0x24, 0xD9, 0x51, 0xC8, 0xFF, 0xFC, 0x24, 0x7C, + 0x00, 0x00, 0x80, 0x2C, 0x42, 0x39, 0x00, 0xFF, 0x00, 0xC3, 0x4E, 0xD2, 0x49, 0xF9, 0x00, 0xFF, + 0x00, 0xC0, 0x4B, 0xEC, 0x00, 0x01, 0x4D, 0xEC, 0x00, 0x02, 0x43, 0xEC, 0x00, 0x02, 0x19, 0x7C, + 0x00, 0x80, 0x00, 0x03, 0x76, 0x07, 0x20, 0x7C, 0x00, 0x00, 0x81, 0xCC, 0x42, 0x14, 0x42, 0x16, + 0x42, 0x16, 0x42, 0x16, 0x70, 0x04, 0x07, 0x14, 0x67, 0xFC, 0x1A, 0x98, 0x51, 0xC8, 0xFF, 0xF8, + 0x60, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x74, 0x80, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x84, 0x80, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x94, 0x80, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0xA4, 0x80, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0xB4, 0x80, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x50, 0x80, 0x00, 0x07, 0x16, 0x67, 0xFC, 0x1A, 0xBC, 0x00, 0x08, 0x3C, 0x3C, 0x00, 0x03, + 0x70, 0xFF, 0x4E, 0x71, 0x4E, 0x71, 0x4E, 0x71, 0x51, 0xC8, 0xFF, 0xF8, 0x51, 0xCE, 0xFF, 0xF2, + 0x07, 0x14, 0x67, 0xFC, 0x14, 0x15, 0x94, 0x3C, 0x00, 0x20, 0x07, 0x14, 0x67, 0xFC, 0x84, 0x15, + 0x66, 0x00, 0x00, 0x48, 0x74, 0x08, 0x07, 0x14, 0x67, 0xFC, 0x1A, 0x98, 0x51, 0xCA, 0xFF, 0xF8, + 0x07, 0x16, 0x67, 0xFC, 0x07, 0x14, 0x67, 0xFC, 0x10, 0x15, 0x90, 0x3C, 0x00, 0x40, 0x07, 0x14, + 0x67, 0xFC, 0xD0, 0x15, 0x90, 0x3C, 0x00, 0x80, 0x74, 0x04, 0x07, 0x14, 0x67, 0xFC, 0x1E, 0x15, + 0x51, 0xCA, 0xFF, 0xF8, 0x4A, 0x00, 0x66, 0x00, 0x00, 0x12, 0x1E, 0x11, 0xCE, 0xBC, 0x00, 0x00, + 0x00, 0x04, 0xE4, 0x07, 0x54, 0x07, 0x4E, 0xF8, 0x00, 0x00, 0x4D, 0xF9, 0x00, 0xFF, 0x00, 0x90, + 0x2A, 0x7C, 0x00, 0x00, 0x80, 0x64, 0x21, 0xFC, 0x00, 0x64, 0x80, 0x00, 0x00, 0x5C, 0x42, 0x2D, + 0x00, 0x01, 0x1C, 0xBC, 0x00, 0x01, 0x42, 0x16, 0x70, 0xFF, 0x4E, 0x71, 0x4E, 0x71, 0x4E, 0x71, + 0x51, 0xC8, 0xFF, 0xF8, 0x4A, 0x2D, 0x00, 0x01, 0x6C, 0x00, 0xFE, 0xC2, 0x42, 0x2D, 0x00, 0x11, + 0x42, 0x16, 0x4A, 0x2D, 0x00, 0x11, 0x67, 0xFA, 0x6E, 0x00, 0xFE, 0xB2, 0x42, 0x2D, 0x00, 0x21, + 0x42, 0x16, 0x4A, 0x2D, 0x00, 0x21, 0x67, 0xFA, 0x6E, 0x00, 0xFE, 0xA2, 0x0C, 0xB8, 0x43, 0x6F, + 0x6D, 0x70, 0x00, 0x00, 0x66, 0x00, 0xFE, 0x96, 0x42, 0x2D, 0x00, 0x31, 0x42, 0x16, 0x4A, 0x2D, + 0x00, 0x31, 0x67, 0xFA, 0x6E, 0x00, 0xFE, 0x86, 0x42, 0x2D, 0x00, 0x41, 0x42, 0x16, 0x4A, 0x2D, + 0x00, 0x41, 0x67, 0xFA, 0x6E, 0x00, 0xFE, 0x76, 0x42, 0x2D, 0x00, 0x51, 0x42, 0x16, 0x4A, 0x2D, + 0x00, 0x51, 0x67, 0xFA, 0x6E, 0x00, 0xFE, 0x66, 0x60, 0x00, 0xFF, 0x60, 0x03, 0x8F, 0x46, 0x07, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1A, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + +{ 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x08, 0x43, 0xF9, 0x00, 0xFF, 0x00, 0x90, 0x20, 0x3C, + 0x00, 0x00, 0x00, 0x7F, 0x45, 0xF8, 0x00, 0x00, 0x26, 0x7C, 0x00, 0x00, 0x80, 0x00, 0x26, 0xDA, + 0x51, 0xC8, 0xFF, 0xFC, 0x24, 0x7C, 0x00, 0x00, 0x80, 0x34, 0x41, 0xF9, 0x00, 0xFF, 0x00, 0xC3, + 0x42, 0x10, 0x4E, 0xD2, 0x2A, 0x7C, 0x00, 0x00, 0x80, 0x66, 0x21, 0xFC, 0x00, 0x66, 0x80, 0x00, + 0x00, 0x5C, 0x42, 0x2D, 0x00, 0x01, 0x12, 0xBC, 0x00, 0x01, 0x42, 0x11, 0x70, 0xFF, 0x4E, 0x71, + 0x4E, 0x71, 0x4E, 0x71, 0x4E, 0x71, 0x4E, 0x71, 0x51, 0xC8, 0xFF, 0xF4, 0x4A, 0x2D, 0x00, 0x01, + 0x6C, 0xD2, 0x60, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x76, 0x80, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x86, 0x80, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x96, 0x80, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0xA6, 0x80, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0xB6, 0x80, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, + 0x00, 0x00, 0x00, 0x50, 0x80, 0x00, 0x42, 0x2D, 0x00, 0x11, 0x42, 0x11, 0x4A, 0x2D, 0x00, 0x11, + 0x67, 0xFA, 0x6E, 0x00, 0xFF, 0x60, 0x42, 0x2D, 0x00, 0x21, 0x42, 0x11, 0x4A, 0x2D, 0x00, 0x21, + 0x67, 0xFA, 0x6E, 0x00, 0xFF, 0x50, 0x20, 0x38, 0x00, 0x00, 0xB0, 0xBC, 0x43, 0x6F, 0x6D, 0x70, + 0x66, 0x00, 0xFF, 0x42, 0x42, 0x2D, 0x00, 0x31, 0x42, 0x11, 0x4A, 0x2D, 0x00, 0x31, 0x67, 0xFA, + 0x6E, 0x00, 0xFF, 0x32, 0x42, 0x2D, 0x00, 0x41, 0x42, 0x11, 0x4A, 0x2D, 0x00, 0x41, 0x67, 0xFA, + 0x6E, 0x00, 0xFF, 0x22, 0x42, 0x2D, 0x00, 0x51, 0x42, 0x11, 0x4A, 0x2D, 0x00, 0x51, 0x67, 0xFA, + 0x6E, 0x00, 0xFF, 0x12, 0x53, 0x88, 0x1E, 0x10, 0xCE, 0xBC, 0x00, 0x00, 0x00, 0x04, 0xE4, 0x07, + 0x54, 0x07, 0x4E, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + +{ 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x3C, 0x00, 0x00, 0x00, 0x7F, 0x41, 0xF8, + 0x00, 0x00, 0x22, 0x7C, 0x00, 0x00, 0x80, 0x00, 0x22, 0xD8, 0x51, 0xC8, 0xFF, 0xFC, 0x24, 0x7C, + 0x00, 0x00, 0x80, 0x2C, 0x42, 0x39, 0x00, 0xFF, 0x00, 0xC3, 0x4E, 0xD2, 0x41, 0xF9, 0x00, 0xFF, + 0x00, 0xC0, 0x43, 0xE8, 0x00, 0x01, 0x45, 0xE8, 0x00, 0x02, 0x47, 0xE8, 0x00, 0x03, 0x17, 0x7C, + 0x00, 0x80, 0x00, 0x00, 0x70, 0x07, 0x42, 0x10, 0x28, 0x7C, 0x00, 0x00, 0x81, 0x42, 0x42, 0x12, + 0x42, 0x12, 0x42, 0x12, 0x72, 0x02, 0x01, 0x10, 0x67, 0xFC, 0x12, 0x9C, 0x51, 0xC9, 0xFF, 0xF8, + 0x72, 0xFF, 0x4E, 0x71, 0x51, 0xC9, 0xFF, 0xFC, 0x72, 0x01, 0x01, 0x10, 0x67, 0xFC, 0x12, 0x9C, + 0x51, 0xC9, 0xFF, 0xF8, 0x01, 0x12, 0x67, 0xFC, 0x12, 0xBC, 0x00, 0x08, 0x72, 0xFF, 0x4E, 0x71, + 0x4E, 0x71, 0x4E, 0x71, 0x4E, 0x71, 0x4E, 0x71, 0x51, 0xC9, 0xFF, 0xF4, 0x01, 0x10, 0x67, 0xFC, + 0x12, 0x11, 0x92, 0x3C, 0x00, 0x20, 0x01, 0x10, 0x67, 0xFC, 0x82, 0x11, 0x67, 0x00, 0x00, 0x5C, + 0xD9, 0xFC, 0x00, 0x00, 0x00, 0x09, 0x10, 0xBC, 0x00, 0x28, 0x72, 0x02, 0x01, 0x10, 0x67, 0xFC, + 0x12, 0x9C, 0x51, 0xC9, 0xFF, 0xF8, 0x72, 0xFF, 0x4E, 0x71, 0x51, 0xC9, 0xFF, 0xFC, 0x72, 0x01, + 0x01, 0x10, 0x67, 0xFC, 0x12, 0x9C, 0x51, 0xC9, 0xFF, 0xF8, 0x01, 0x12, 0x67, 0xFC, 0x12, 0xBC, + 0x00, 0x08, 0x72, 0xFF, 0x4E, 0x71, 0x4E, 0x71, 0x4E, 0x71, 0x4E, 0x71, 0x4E, 0x71, 0x51, 0xC9, + 0xFF, 0xF4, 0x01, 0x10, 0x67, 0xFC, 0x12, 0x11, 0x92, 0x3C, 0x00, 0x20, 0x01, 0x10, 0x67, 0xFC, + 0x82, 0x11, 0xC2, 0x3C, 0x00, 0xFC, 0x66, 0x00, 0xFF, 0x4E, 0x72, 0x08, 0x01, 0x10, 0x67, 0xFC, + 0x12, 0x9C, 0x51, 0xC9, 0xFF, 0xF8, 0x01, 0x12, 0x67, 0xFC, 0x01, 0x10, 0x67, 0xFC, 0x14, 0x11, + 0x94, 0x3C, 0x00, 0x40, 0x01, 0x10, 0x67, 0xFC, 0xD4, 0x11, 0x94, 0x3C, 0x00, 0x80, 0x72, 0x04, + 0x01, 0x10, 0x67, 0xFC, 0x1E, 0x11, 0x51, 0xC9, 0xFF, 0xF8, 0xC4, 0x3C, 0x00, 0xF8, 0x66, 0x00, + 0xFF, 0x16, 0x1E, 0x12, 0xCE, 0xBC, 0x00, 0x00, 0x00, 0x04, 0xE4, 0x07, 0x54, 0x07, 0x4E, 0xF8, + 0x00, 0x00, 0x03, 0x8F, 0x46, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1A, 0x07, 0x80, + 0x03, 0xEF, 0x1E, 0x07, 0x02, 0xC6, 0x02, 0x00, 0x00, 0x01, 0x03, 0x05, 0x20, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + +{ 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x3C, 0x00, 0x00, 0x00, 0x7F, 0x43, 0xF8, + 0x00, 0x00, 0x24, 0x7C, 0x00, 0x00, 0x80, 0x00, 0x24, 0xD9, 0x51, 0xC8, 0xFF, 0xFC, 0x24, 0x7C, + 0x00, 0x00, 0x80, 0x2C, 0x42, 0x39, 0x00, 0xFF, 0x00, 0xC3, 0x4E, 0xD2, 0x49, 0xF9, 0x00, 0xFF, + 0x00, 0xC0, 0x4B, 0xEC, 0x00, 0x01, 0x4D, 0xEC, 0x00, 0x02, 0x43, 0xEC, 0x00, 0x02, 0x19, 0x7C, + 0x00, 0x80, 0x00, 0x03, 0x76, 0x07, 0x18, 0xBC, 0x00, 0x28, 0x20, 0x7C, 0x00, 0x00, 0x81, 0xCE, + 0x42, 0x16, 0x42, 0x16, 0x42, 0x16, 0x70, 0x04, 0x07, 0x14, 0x67, 0xFC, 0x1A, 0x98, 0x51, 0xC8, + 0xFF, 0xF8, 0x60, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x76, 0x80, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x86, 0x80, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x96, 0x80, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0xA6, 0x80, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0xB6, 0x80, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, + 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x07, 0x16, 0x67, 0xFC, 0x1A, 0xBC, 0x00, 0x08, 0x3C, 0x3C, + 0x00, 0x03, 0x70, 0xFF, 0x4E, 0x71, 0x4E, 0x71, 0x4E, 0x71, 0x51, 0xC8, 0xFF, 0xF8, 0x51, 0xCE, + 0xFF, 0xF2, 0x07, 0x14, 0x67, 0xFC, 0x14, 0x15, 0x94, 0x3C, 0x00, 0x22, 0x07, 0x14, 0x67, 0xFC, + 0x84, 0x15, 0x66, 0x00, 0x00, 0x48, 0x74, 0x08, 0x07, 0x14, 0x67, 0xFC, 0x1A, 0x98, 0x51, 0xCA, + 0xFF, 0xF8, 0x07, 0x16, 0x67, 0xFC, 0x07, 0x14, 0x67, 0xFC, 0x10, 0x15, 0x90, 0x3C, 0x00, 0x42, + 0x07, 0x14, 0x67, 0xFC, 0xD0, 0x15, 0x90, 0x3C, 0x00, 0x80, 0x74, 0x03, 0x07, 0x14, 0x67, 0xFC, + 0x1E, 0x15, 0x51, 0xCA, 0xFF, 0xF8, 0x4A, 0x00, 0x66, 0x00, 0x00, 0x12, 0x1E, 0x11, 0xCE, 0xBC, + 0x00, 0x00, 0x00, 0x04, 0xE4, 0x07, 0x54, 0x07, 0x4E, 0xF8, 0x00, 0x00, 0x4D, 0xF9, 0x00, 0xFF, + 0x00, 0x90, 0x2A, 0x7C, 0x00, 0x00, 0x80, 0x66, 0x21, 0xFC, 0x00, 0x66, 0x80, 0x00, 0x00, 0x5C, + 0x42, 0x2D, 0x00, 0x01, 0x1C, 0xBC, 0x00, 0x01, 0x42, 0x16, 0x70, 0xFF, 0x4E, 0x71, 0x4E, 0x71, + 0x4E, 0x71, 0x51, 0xC8, 0xFF, 0xF8, 0x4A, 0x2D, 0x00, 0x01, 0x6C, 0x00, 0xFE, 0xC0, 0x42, 0x2D, + 0x00, 0x11, 0x42, 0x16, 0x4A, 0x2D, 0x00, 0x11, 0x67, 0xFA, 0x6E, 0x00, 0xFE, 0xB0, 0x42, 0x2D, + 0x00, 0x21, 0x42, 0x16, 0x4A, 0x2D, 0x00, 0x21, 0x67, 0xFA, 0x6E, 0x00, 0xFE, 0xA0, 0x0C, 0xB8, + 0x43, 0x6F, 0x6D, 0x70, 0x00, 0x00, 0x66, 0x00, 0xFE, 0x94, 0x42, 0x2D, 0x00, 0x31, 0x42, 0x16, + 0x4A, 0x2D, 0x00, 0x31, 0x67, 0xFA, 0x6E, 0x00, 0xFE, 0x84, 0x42, 0x2D, 0x00, 0x41, 0x42, 0x16, + 0x4A, 0x2D, 0x00, 0x41, 0x67, 0xFA, 0x6E, 0x00, 0xFE, 0x74, 0x42, 0x2D, 0x00, 0x51, 0x42, 0x16, + 0x4A, 0x2D, 0x00, 0x51, 0x67, 0xFA, 0x6E, 0x00, 0xFE, 0x64, 0x60, 0x00, 0xFF, 0x60, 0x03, 0xEF, + 0x1E, 0x07, 0x02, 0xC6, 0x02, 0x00, 0x00, 0x01, 0x03, 0x05, 0x20, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + +{ 0x17, 0xA0, 0x00, 0x00, 0x00, 0x80, 0x5F, 0x08, 0x5F, 0x10, 0x0E, 0x03, 0x00, 0x27, 0xA9, 0xC0, + 0xFE, 0x00, 0xC0, 0x67, 0x61, 0x01, 0xA7, 0x61, 0x02, 0x67, 0x60, 0x03, 0x54, 0xA2, 0x80, 0x00, + 0xDC, 0x1B, 0x5C, 0x60, 0x00, 0xE7, 0xA9, 0xC0, 0x00, 0x01, 0xCD, 0x5C, 0x70, 0x00, 0x5C, 0x71, + 0x00, 0x5C, 0x70, 0x00, 0xDC, 0x12, 0x34, 0x1B, 0x00, 0x9A, 0x7D, 0x54, 0x7B, 0x00, 0x00, 0x8C, + 0x38, 0xCC, 0x17, 0x75, 0xEA, 0xC0, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x90, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0xA0, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0xB0, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x02, 0x00, 0x50, 0x00, 0x00, + 0xB4, 0x1B, 0x00, 0x9A, 0x7D, 0x54, 0xA3, 0x08, 0x00, 0xDD, 0x17, 0xA2, 0xA2, 0xA2, 0xCD, 0x17, + 0x7D, 0x34, 0x1B, 0x00, 0x9A, 0x7D, 0x94, 0x68, 0x00, 0xA0, 0xA0, 0x20, 0x34, 0x1B, 0x00, 0x9A, + 0x7D, 0x98, 0x68, 0x00, 0x1C, 0x10, 0x1A, 0xC0, 0x00, 0x00, 0x56, 0x94, 0xA0, 0x09, 0x34, 0x1B, + 0x00, 0x9A, 0x7D, 0x54, 0x7B, 0x00, 0x00, 0x8C, 0x38, 0xCC, 0x17, 0x75, 0xB4, 0x1B, 0x00, 0x9A, + 0x7D, 0x34, 0x1B, 0x00, 0x9A, 0x7D, 0x14, 0x68, 0x00, 0x20, 0xA0, 0x40, 0x34, 0x1B, 0x00, 0x9A, + 0x7D, 0x00, 0x68, 0x00, 0x20, 0xA0, 0x80, 0xDC, 0x12, 0x34, 0x1B, 0x00, 0x9A, 0x7D, 0xD4, 0x69, + 0x00, 0xCC, 0x17, 0x78, 0x1C, 0x00, 0x1A, 0xC0, 0x00, 0x00, 0x16, 0xCE, 0xD8, 0x71, 0x00, 0xE8, + 0xA1, 0x04, 0x4E, 0xC4, 0xA1, 0xFE, 0x0C, 0x39, 0x7F, 0xAA, 0x82, 0x00, 0xA7, 0xA9, 0xC0, 0xFE, + 0x00, 0x90, 0x5C, 0xA8, 0x80, 0x61, 0xDC, 0x70, 0x00, 0x5C, 0x70, 0x00, 0xDD, 0x07, 0xA2, 0xA2, + 0xA2, 0xCD, 0x07, 0x7D, 0x9C, 0xAF, 0x80, 0x61, 0x1A, 0xBE, 0xB5, 0x5C, 0xA8, 0x80, 0x71, 0x5C, + 0x70, 0x00, 0x1C, 0xA8, 0x80, 0x71, 0x0A, 0x7C, 0x9C, 0xAF, 0x80, 0x71, 0x1A, 0xBE, 0xA1, 0x5C, + 0xA8, 0x80, 0x81, 0x5C, 0x70, 0x00, 0x1C, 0xA8, 0x80, 0x81, 0x0A, 0x7C, 0x9C, 0xAF, 0x80, 0x81, + 0x1A, 0xBE, 0x8D, 0x47, 0xA5, 0x70, 0x6D, 0x6F, 0x43, 0x82, 0x00, 0x1A, 0xBE, 0x82, 0x5C, 0xA8, + 0x80, 0x91, 0x5C, 0x70, 0x00, 0x1C, 0xA8, 0x80, 0x91, 0x0A, 0x7C, 0x9C, 0xAF, 0x80, 0x91, 0x1A, + 0xBE, 0x6E, 0x5C, 0xA8, 0x80, 0xA1, 0x5C, 0x70, 0x00, 0x1C, 0xA8, 0x80, 0xA1, 0x0A, 0x7C, 0x9C, + 0xAF, 0x80, 0xA1, 0x1A, 0xBE, 0x5A, 0x5C, 0xA8, 0x80, 0xB1, 0x5C, 0x70, 0x00, 0x1C, 0xA8, 0x80, + 0xB1, 0x0A, 0x7C, 0x9C, 0xAF, 0x80, 0xB1, 0x1A, 0xBE, 0x46, 0xEA, 0xBF, 0x61, 0x03, 0x8F, 0x1E, + 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1A, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + +{ 0xA7, 0xA9, 0xC0, 0xFE, 0x00, 0x90, 0x17, 0xA0, 0x00, 0x00, 0x00, 0x80, 0x5F, 0x08, 0x5F, 0x10, + 0x0E, 0x03, 0x00, 0x67, 0xA8, 0xC0, 0xFE, 0x00, 0xC3, 0x5C, 0x48, 0x00, 0x5C, 0xA8, 0xC0, 0x00, + 0x00, 0x61, 0xDC, 0x70, 0x00, 0x5C, 0x70, 0x00, 0xDD, 0x07, 0xA2, 0xA2, 0xA2, 0xCD, 0x07, 0x7D, + 0x9C, 0xAF, 0xC0, 0x00, 0x00, 0x61, 0x1A, 0x66, 0xEA, 0xC0, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x90, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0xA0, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0xB0, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x02, 0x00, 0x50, 0x00, 0x00, + 0x5C, 0xA8, 0x80, 0x71, 0x5C, 0x70, 0x00, 0x1C, 0xA8, 0x80, 0x71, 0x0A, 0x7C, 0x9C, 0xAF, 0x80, + 0x71, 0x1A, 0xBF, 0x4B, 0x5C, 0xA8, 0x80, 0x81, 0x5C, 0x70, 0x00, 0x1C, 0xA8, 0x80, 0x81, 0x0A, + 0x7C, 0x9C, 0xAF, 0x80, 0x81, 0x1A, 0xBF, 0x37, 0x47, 0xA5, 0x70, 0x6D, 0x6F, 0x43, 0x82, 0x00, + 0x1A, 0xBF, 0x2C, 0x5C, 0xA8, 0x80, 0x91, 0x5C, 0x70, 0x00, 0x1C, 0xA8, 0x80, 0x91, 0x0A, 0x7C, + 0x9C, 0xAF, 0x80, 0x91, 0x1A, 0xBF, 0x18, 0x5C, 0xA8, 0x80, 0xA1, 0x5C, 0x70, 0x00, 0x1C, 0xA8, + 0x80, 0xA1, 0x0A, 0x7C, 0x9C, 0xAF, 0x80, 0xA1, 0x1A, 0xBF, 0x04, 0x5C, 0xA8, 0x80, 0xB1, 0x5C, + 0x70, 0x00, 0x1C, 0xA8, 0x80, 0xB1, 0x0A, 0x7C, 0x9C, 0xAF, 0x80, 0xB1, 0x1A, 0xBE, 0xF0, 0x8F, + 0x0F, 0xCE, 0xD8, 0x49, 0x00, 0xE8, 0xA1, 0x04, 0x4E, 0xC4, 0xA1, 0xFE, 0x0C, 0x39, 0x7F, 0xAA, + 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + +{ 0x17, 0xA0, 0x00, 0x00, 0x00, 0x80, 0x5F, 0x08, 0x5F, 0x10, 0x0E, 0x03, 0x00, 0x27, 0xA9, 0xC0, + 0xFE, 0x00, 0xC0, 0x67, 0x61, 0x01, 0xA7, 0x61, 0x02, 0x67, 0x60, 0x03, 0x54, 0xA2, 0x80, 0x00, + 0xDC, 0x1B, 0x5C, 0x60, 0x00, 0xE7, 0xA9, 0xC0, 0x00, 0x01, 0x33, 0x5C, 0x70, 0x00, 0x5C, 0x71, + 0x00, 0x5C, 0x70, 0x00, 0xDC, 0x11, 0x34, 0x1B, 0x00, 0x9A, 0x7D, 0x54, 0x7B, 0x00, 0x00, 0x8C, + 0x38, 0xCC, 0x17, 0x75, 0xDC, 0x07, 0xA2, 0xA2, 0xCC, 0x07, 0x7E, 0x5C, 0x11, 0x34, 0x1B, 0x00, + 0x9A, 0x7D, 0x54, 0x7B, 0x00, 0x00, 0x8C, 0x38, 0xCC, 0x17, 0x75, 0xB4, 0x1B, 0x00, 0x9A, 0x7D, + 0x54, 0xA3, 0x08, 0x00, 0xDD, 0x17, 0xA2, 0xA2, 0xA2, 0xCD, 0x17, 0x7D, 0x34, 0x1B, 0x00, 0x9A, + 0x7D, 0x94, 0x68, 0x00, 0xA0, 0xA0, 0x20, 0x34, 0x1B, 0x00, 0x9A, 0x7D, 0x98, 0x68, 0x00, 0x1C, + 0x10, 0x0A, 0xC0, 0x00, 0x00, 0x60, 0xC1, 0xA1, 0x00, 0x09, 0x14, 0xA3, 0x28, 0x00, 0xDC, 0x11, + 0x34, 0x1B, 0x00, 0x9A, 0x7D, 0x54, 0x7B, 0x00, 0x00, 0x8C, 0x38, 0xCC, 0x17, 0x75, 0xDC, 0x07, + 0xA2, 0xA2, 0xCC, 0x07, 0x7E, 0x5C, 0x11, 0x34, 0x1B, 0x00, 0x9A, 0x7D, 0x54, 0x7B, 0x00, 0x00, + 0x8C, 0x38, 0xCC, 0x17, 0x75, 0xB4, 0x1B, 0x00, 0x9A, 0x7D, 0x54, 0xA3, 0x08, 0x00, 0xDD, 0x17, + 0xA2, 0xA2, 0xA2, 0xCD, 0x17, 0x7D, 0x34, 0x1B, 0x00, 0x9A, 0x7D, 0x94, 0x68, 0x00, 0xA0, 0xA0, + 0x20, 0x34, 0x1B, 0x00, 0x9A, 0x7D, 0x98, 0x68, 0x00, 0xA8, 0xA0, 0xFC, 0x1C, 0x10, 0x1A, 0xBF, + 0x44, 0x94, 0xA0, 0x09, 0x34, 0x1B, 0x00, 0x9A, 0x7D, 0x54, 0x7B, 0x00, 0x00, 0x8C, 0x38, 0xCC, + 0x17, 0x75, 0xB4, 0x1B, 0x00, 0x9A, 0x7D, 0x34, 0x1B, 0x00, 0x9A, 0x7D, 0x14, 0x68, 0x00, 0x20, + 0xA0, 0x40, 0x34, 0x1B, 0x00, 0x9A, 0x7D, 0x00, 0x68, 0x00, 0x20, 0xA0, 0x80, 0xDC, 0x12, 0x34, + 0x1B, 0x00, 0x9A, 0x7D, 0xD4, 0x69, 0x00, 0xCC, 0x17, 0x78, 0x28, 0xA0, 0xF8, 0x1C, 0x00, 0x1A, + 0xBF, 0x03, 0xCE, 0xD8, 0x71, 0x00, 0xE8, 0xA1, 0x04, 0x4E, 0xC4, 0xA1, 0xFE, 0x0C, 0x39, 0x7F, + 0xAA, 0x82, 0x00, 0x03, 0x8F, 0x46, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1A, 0x07, + 0x80, 0x03, 0xEF, 0x1E, 0x07, 0x02, 0xC6, 0x02, 0x00, 0x00, 0x01, 0x03, 0x05, 0x20, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + +{ 0x17, 0xA0, 0x00, 0x00, 0x00, 0x80, 0x5F, 0x08, 0x5F, 0x10, 0x0E, 0x03, 0x00, 0x27, 0xA9, 0xC0, + 0xFE, 0x00, 0xC0, 0x67, 0x61, 0x01, 0xA7, 0x61, 0x02, 0x67, 0x60, 0x03, 0x54, 0xA2, 0x80, 0x00, + 0xDC, 0x1B, 0x14, 0xA3, 0x28, 0x00, 0xE7, 0xA9, 0xC0, 0x00, 0x01, 0xCD, 0x5C, 0x70, 0x00, 0x5C, + 0x71, 0x00, 0x5C, 0x70, 0x00, 0xDC, 0x12, 0x34, 0x1B, 0x00, 0x9A, 0x7D, 0x54, 0x7B, 0x00, 0x00, + 0x8C, 0x38, 0xCC, 0x17, 0x75, 0xEA, 0xC0, 0x00, 0x00, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x90, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0xA0, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0xB0, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x02, 0x00, 0x50, 0x00, 0x00, + 0xB4, 0x1B, 0x00, 0x9A, 0x7D, 0x54, 0xA3, 0x08, 0x00, 0xDD, 0x17, 0xA2, 0xA2, 0xA2, 0xCD, 0x17, + 0x7D, 0x34, 0x1B, 0x00, 0x9A, 0x7D, 0x94, 0x68, 0x00, 0xA0, 0xA0, 0x22, 0x34, 0x1B, 0x00, 0x9A, + 0x7D, 0x98, 0x68, 0x00, 0x1C, 0x10, 0x1A, 0xC0, 0x00, 0x00, 0x56, 0x94, 0xA0, 0x09, 0x34, 0x1B, + 0x00, 0x9A, 0x7D, 0x54, 0x7B, 0x00, 0x00, 0x8C, 0x38, 0xCC, 0x17, 0x75, 0xB4, 0x1B, 0x00, 0x9A, + 0x7D, 0x34, 0x1B, 0x00, 0x9A, 0x7D, 0x14, 0x68, 0x00, 0x20, 0xA0, 0x42, 0x34, 0x1B, 0x00, 0x9A, + 0x7D, 0x00, 0x68, 0x00, 0x20, 0xA0, 0x80, 0xDC, 0x12, 0x34, 0x1B, 0x00, 0x9A, 0x7D, 0xD4, 0x69, + 0x00, 0xCC, 0x17, 0x78, 0x1C, 0x00, 0x1A, 0xC0, 0x00, 0x00, 0x16, 0xCE, 0xD8, 0x71, 0x00, 0xE8, + 0xA1, 0x04, 0x4E, 0xC4, 0xA1, 0xFE, 0x0C, 0x39, 0x7F, 0xAA, 0x82, 0x00, 0xA7, 0xA9, 0xC0, 0xFE, + 0x00, 0x90, 0x5C, 0xA8, 0x80, 0x61, 0xDC, 0x70, 0x00, 0x5C, 0x70, 0x00, 0xDD, 0x07, 0xA2, 0xA2, + 0xA2, 0xCD, 0x07, 0x7D, 0x9C, 0xAF, 0x80, 0x61, 0x1A, 0xBE, 0xB5, 0x5C, 0xA8, 0x80, 0x71, 0x5C, + 0x70, 0x00, 0x1C, 0xA8, 0x80, 0x71, 0x0A, 0x7C, 0x9C, 0xAF, 0x80, 0x71, 0x1A, 0xBE, 0xA1, 0x5C, + 0xA8, 0x80, 0x81, 0x5C, 0x70, 0x00, 0x1C, 0xA8, 0x80, 0x81, 0x0A, 0x7C, 0x9C, 0xAF, 0x80, 0x81, + 0x1A, 0xBE, 0x8D, 0x47, 0xA5, 0x70, 0x6D, 0x6F, 0x43, 0x82, 0x00, 0x1A, 0xBE, 0x82, 0x5C, 0xA8, + 0x80, 0x91, 0x5C, 0x70, 0x00, 0x1C, 0xA8, 0x80, 0x91, 0x0A, 0x7C, 0x9C, 0xAF, 0x80, 0x91, 0x1A, + 0xBE, 0x6E, 0x5C, 0xA8, 0x80, 0xA1, 0x5C, 0x70, 0x00, 0x1C, 0xA8, 0x80, 0xA1, 0x0A, 0x7C, 0x9C, + 0xAF, 0x80, 0xA1, 0x1A, 0xBE, 0x5A, 0x5C, 0xA8, 0x80, 0xB1, 0x5C, 0x70, 0x00, 0x1C, 0xA8, 0x80, + 0xB1, 0x0A, 0x7C, 0x9C, 0xAF, 0x80, 0xB1, 0x1A, 0xBE, 0x46, 0xEA, 0xBF, 0x61, 0x03, 0xEF, 0x1E, + 0x07, 0x02, 0xC6, 0x02, 0x00, 0x00, 0x01, 0x03, 0x05, 0x20, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +}; + + +/* returns TRUE iff there exists a disk with VERBOSE */ +static int32 disk1a_hasProperty(uint32 property) { + int32 i; + for (i = 0; i < DISK1A_MAX_DRIVES; i++) + if (disk1a_dev.units[i].flags & property) return TRUE; + return FALSE; +} + +/* Reset routine */ +static t_stat disk1a_reset(DEVICE *dptr) +{ + PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; + + if(dptr->flags & DEV_DIS) { /* Disconnect ROM and I/O Ports */ + if (disk1a_hasProperty(UNIT_DISK1A_ROM)) + sim_map_resource(pnp->mem_base, pnp->mem_size, RESOURCE_TYPE_MEMORY, &disk1arom, TRUE); + sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &disk1adev, TRUE); + } else { + /* Connect DISK1A ROM at base address */ + if (disk1a_hasProperty(UNIT_DISK1A_ROM)) + if(sim_map_resource(pnp->mem_base, pnp->mem_size, RESOURCE_TYPE_MEMORY, &disk1arom, FALSE) != 0) { + printf("%s: error mapping MEM resource at 0x%04x\n", __FUNCTION__, pnp->io_base); + return SCPE_ARG; + } + + /* Connect DISK1A at base address */ + if(sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &disk1adev, FALSE) != 0) { + printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->io_base); + return SCPE_ARG; + } + } + return SCPE_OK; +} + +static t_stat disk1a_boot(int32 unitno, DEVICE *dptr) +{ + DBG_PRINT(("Booting DISK1A Controller, bootstrap=%d" NLP, bootstrap)); + + /* Re-enable the ROM in case it was disabled */ + disk1a_info->rom_disabled = FALSE; + + /* Set the PC to 0, and go. */ + *((int32 *) sim_PC->loc) = 0; + return SCPE_OK; +} + +/* Attach routine */ +static t_stat disk1a_attach(UNIT *uptr, char *cptr) +{ + t_stat r; + r = i8272_attach(uptr, cptr); + + return r; +} + +/* Detach routine */ +static t_stat disk1a_detach(UNIT *uptr) +{ + t_stat r; + + r = i8272_detach(uptr); + + return r; +} + +static int32 disk1arom(const int32 Addr, const int32 write, const int32 data) +{ +/* DBG_PRINT(("DISK1A: ROM %s, Addr %04x" NLP, write ? "WR" : "RD", Addr)); */ + if(write) { + disk1aram[Addr & 0x1FF] = data; + return 0; + } else { + if(disk1a_info->rom_disabled == FALSE) { + return(disk1a_rom[bootstrap][Addr & 0x1FF]); + } else { + return(disk1aram[Addr & 0x1FF]); + } + } +} + +static int32 disk1adev(const int32 port, const int32 io, const int32 data) +{ + int32 result; + if(io) { + TRACE_PRINT(VERBOSE_MSG, + ("DISK1A: " ADDRESS_FORMAT " OUT, Port 0x%02x Data 0x%02x" NLP, PCX, port, data)) + DISK1A_Write(port, data); + result = 0; + } else { + result = DISK1A_Read(port); + TRACE_PRINT(VERBOSE_MSG, + ("DISK1A: " ADDRESS_FORMAT " IN, Port 0x%02x Result 0x%02x" NLP, PCX, port, result)) + } + return result; +} + +#define DISK1A_DRIVE_STATUS 2 /* R=Drive Status Register / W=DMA Address Register */ +#define DISK1A_MOTOR 3 /* R=Unused / W=Motor Control Register */ +#define BOOT_PROM_DISABLE 0x01 +#define FLOPPY_MOTORS 0xF0 + +static uint8 DISK1A_Read(const uint32 Addr) +{ + uint8 cData; + + cData = 0x00; + + switch(Addr & 0x3) { + case I8272_FDC_MSR: + case I8272_FDC_DATA: + cData = I8272_Read(Addr); + break; + case DISK1A_DRIVE_STATUS: + cData = 0x81; /* Ready */ + TRACE_PRINT(STATUS_MSG, + ("DISK1A: " ADDRESS_FORMAT " RD STATUS = 0x%02x" NLP, PCX, cData)) + break; + case DISK1A_MOTOR: + TRACE_PRINT(VERBOSE_MSG, + ("DISK1A: " ADDRESS_FORMAT " Error, can't read from MOTOR register." NLP, PCX)) + cData = 0xFF; /* Return High-Z data */ + break; + } + + return (cData); +} + +static uint8 DISK1A_Write(const uint32 Addr, uint8 cData) +{ + uint8 result = 0; + + switch(Addr & 0x3) { + case I8272_FDC_MSR: + case I8272_FDC_DATA: + result = I8272_Write(Addr, cData); + break; + + case DISK1A_DRIVE_STATUS: /* DMA Address */ + disk1a_info->dma_addr <<= 8; + disk1a_info->dma_addr &= 0x00FFFF00; + disk1a_info->dma_addr |= cData; + TRACE_PRINT(RD_DATA_MSG, ("DISK1A: " ADDRESS_FORMAT " DMA Address=%06x" NLP, + PCX, disk1a_info->dma_addr)) + I8272_Set_DMA(disk1a_info->dma_addr); + break; + case DISK1A_MOTOR: + TRACE_PRINT(CMD_MSG, + ("DISK1A: " ADDRESS_FORMAT " write Motor Reg=0x%02x" NLP, PCX, cData)) + + if((cData & BOOT_PROM_DISABLE) == 0) { + TRACE_PRINT(CMD_MSG, + ("DISK1A: " ADDRESS_FORMAT " Boot ROM disabled" NLP, PCX)) + + /* Unmap Boot ROM */ + disk1a_info->rom_disabled = TRUE; + } + + TRACE_PRINT(CMD_MSG, ("DISK1A: " ADDRESS_FORMAT " Motors = %x" NLP, + PCX, (cData & FLOPPY_MOTORS) >> 4)) + break; + } + + return (result); +} + diff --git a/AltairZ80/s100_disk2.c b/AltairZ80/s100_disk2.c new file mode 100644 index 00000000..25d6a7b9 --- /dev/null +++ b/AltairZ80/s100_disk2.c @@ -0,0 +1,574 @@ +/************************************************************************* + * * + * $Id: s100_disk2.c 1771 2008-01-09 07:10:46Z hharte $ * + * * + * Copyright (c) 2007-2008 Howard M. Harte. * + * http://www.hartetec.com * + * * + * 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 HOWARD M. HARTE 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 Howard M. Harte shall * + * not be used in advertising or otherwise to promote the sale, use or * + * other dealings in this Software without prior written authorization * + * Howard M. Harte. * + * * + * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. * + * * + * Module Description: * + * CompuPro DISK2 Hard Disk Controller module for SIMH. * + * This module must be used in conjunction with the CompuPro Selector * + * Channel Module for proper operation. * + * * + * Environment: * + * User mode only * + * * + *************************************************************************/ + +#include "altairz80_defs.h" + +#if defined (_WIN32) +#include +#endif + +#include "sim_imd.h" + +#define SEEK_MSG 0x01 +#define BUG_MSG 0x02 +#define CMD_MSG 0x04 +#define RD_DATA_MSG 0x08 +#define WR_DATA_MSG 0x10 +#define STATUS_MSG 0x20 +#define VERBOSE_MSG 0x80 + +#define DISK2_MAX_DRIVES 4 + +typedef union { + uint8 raw[2051]; + struct { + uint8 header[3]; + uint8 data[2048]; + } u; +} SECTOR_FORMAT; + +static SECTOR_FORMAT sdata; + +typedef struct { + UNIT *uptr; + DISK_INFO *imd; + uint16 ntracks; /* number of tracks */ + uint8 nheads; /* number of heads */ + uint8 nsectors; /* number of sectors/track */ + uint32 sectsize; /* sector size, not including pre/postamble */ + uint16 track; /* Current Track */ + uint8 ready; /* Is drive ready? */ +} DISK2_DRIVE_INFO; + +typedef struct { + PNP_INFO pnp; /* Plug and Play */ + uint8 sel_drive; /* Currently selected drive */ + uint8 head_sel; /* Head select (signals to drive itself) */ + uint8 head; /* Head set by write to the HEAD register */ + uint8 cyl; /* Cyl that the current operation is targetting */ + uint8 sector; /* Sector the current READ/WRITE operation is targetting */ + uint8 hdr_sector; /* Current sector for WRITE_HEADER */ + uint8 ctl_attn; + uint8 ctl_run; + uint8 ctl_op; + uint8 ctl_fault_clr; + uint8 ctl_us; + uint8 timeout; + uint8 crc_error; + uint8 overrun; + uint8 seek_complete; + uint8 write_fault; + DISK2_DRIVE_INFO drive[DISK2_MAX_DRIVES]; +} DISK2_INFO; + +static DISK2_INFO disk2_info_data = { { 0x0, 0, 0xC8, 2 } }; +static DISK2_INFO *disk2_info = &disk2_info_data; + +extern uint32 PCX; +extern REG *sim_PC; +extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc); +extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, + int32 (*routine)(const int32, const int32, const int32), uint8 unmap); +extern int32 selchan_dma(uint8 *buf, uint32 len); +extern int32 find_unit_index(UNIT *uptr); + +/* These are needed for DMA. PIO Mode has not been implemented yet. */ +extern void PutBYTEWrapper(const uint32 Addr, const uint32 Value); +extern uint8 GetBYTEWrapper(const uint32 Addr); + +#define UNIT_V_DISK2_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_DISK2_WLK (1 << UNIT_V_DISK2_WLK) +#define UNIT_V_DISK2_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ +#define UNIT_DISK2_VERBOSE (1 << UNIT_V_DISK2_VERBOSE) +#define DISK2_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */ +#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */ +#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */ +#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */ + +static t_stat disk2_reset(DEVICE *disk2_dev); +static t_stat disk2_attach(UNIT *uptr, char *cptr); +static t_stat disk2_detach(UNIT *uptr); + +static int32 disk2dev(const int32 port, const int32 io, const int32 data); + +static uint8 DISK2_Read(const uint32 Addr); +static uint8 DISK2_Write(const uint32 Addr, uint8 cData); + +static int32 trace_level = 0; /* Disable all tracing by default */ + +static UNIT disk2_unit[] = { + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DISK2_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DISK2_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DISK2_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DISK2_CAPACITY) } +}; + +static REG disk2_reg[] = { + { HRDATA (TRACELEVEL, trace_level, 16), }, + { NULL } +}; + +static MTAB disk2_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL }, + { UNIT_DISK2_WLK, 0, "WRTENB", "WRTENB", NULL }, + { UNIT_DISK2_WLK, UNIT_DISK2_WLK, "WRTLCK", "WRTLCK", NULL }, + /* quiet, no warning messages */ + { UNIT_DISK2_VERBOSE, 0, "QUIET", "QUIET", NULL }, + /* verbose, show warning messages */ + { UNIT_DISK2_VERBOSE, UNIT_DISK2_VERBOSE, "VERBOSE", "VERBOSE", NULL }, + { 0 } +}; + +DEVICE disk2_dev = { + "DISK2", disk2_unit, disk2_reg, disk2_mod, + DISK2_MAX_DRIVES, 10, 31, 1, DISK2_MAX_DRIVES, DISK2_MAX_DRIVES, + NULL, NULL, &disk2_reset, + NULL, &disk2_attach, &disk2_detach, + &disk2_info_data, (DEV_DISABLE | DEV_DIS), 0, + NULL, NULL, NULL +}; + +/* Reset routine */ +static t_stat disk2_reset(DEVICE *dptr) +{ + PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; + + if(dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */ + sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &disk2dev, TRUE); + } else { + /* Connect DISK2 at base address */ + if(sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &disk2dev, FALSE) != 0) { + printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->io_base); + return SCPE_ARG; + } + } + return SCPE_OK; +} + + +/* Attach routine */ +static t_stat disk2_attach(UNIT *uptr, char *cptr) +{ + t_stat r = SCPE_OK; + DISK2_DRIVE_INFO *pDrive; + char header[4]; + unsigned int i = 0; + + i = find_unit_index(uptr); + if (i == -1) { + return (SCPE_IERR); + } + pDrive = &disk2_info->drive[i]; + + pDrive->ready = 1; + disk2_info->write_fault = 1; + pDrive->track = 5; + pDrive->ntracks = 243; + pDrive->nheads = 8; + pDrive->nsectors = 11; + pDrive->sectsize = 1024; + + r = attach_unit(uptr, cptr); /* attach unit */ + if ( r != SCPE_OK) /* error? */ + return r; + + /* Determine length of this disk */ + if(sim_fsize(uptr->fileref) != 0) { + uptr->capac = sim_fsize(uptr->fileref); + } else { + uptr->capac = (pDrive->ntracks * pDrive->nsectors * pDrive->nheads * pDrive->sectsize); + } + + pDrive->uptr = uptr; + + /* Default for new file is DSK */ + uptr->u3 = IMAGE_TYPE_DSK; + + if(uptr->capac > 0) { + fgets(header, 4, uptr->fileref); + if(!strcmp(header, "IMD")) { + uptr->u3 = IMAGE_TYPE_IMD; + } else if(!strcmp(header, "CPT")) { + printf("CPT images not yet supported\n"); + uptr->u3 = IMAGE_TYPE_CPT; + disk2_detach(uptr); + return SCPE_OPENERR; + } else { + uptr->u3 = IMAGE_TYPE_DSK; + } + } + + if (uptr->flags & UNIT_DISK2_VERBOSE) + printf("DISK2%d, attached to '%s', type=%s, len=%d\n", i, cptr, + uptr->u3 == IMAGE_TYPE_IMD ? "IMD" : uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK", + uptr->capac); + + if(uptr->u3 == IMAGE_TYPE_IMD) { + if(uptr->capac < 318000) { + printf("Cannot create IMD files with SIMH.\nCopy an existing file and format it with CP/M.\n"); + disk2_detach(uptr); + return SCPE_OPENERR; + } + + if (uptr->flags & UNIT_DISK2_VERBOSE) + printf("--------------------------------------------------------\n"); + disk2_info->drive[i].imd = diskOpen((uptr->fileref), (uptr->flags & UNIT_DISK2_VERBOSE)); + if (uptr->flags & UNIT_DISK2_VERBOSE) printf("\n"); + } else { + disk2_info->drive[i].imd = NULL; + } + + return SCPE_OK; +} + + +/* Detach routine */ +t_stat disk2_detach(UNIT *uptr) +{ + t_stat r; + int8 i; + + i = find_unit_index(uptr); + + if (i == -1) { + return (SCPE_IERR); + } + + if (uptr->flags & UNIT_DISK2_VERBOSE) + printf("Detach DISK2%d\n", i); + + r = detach_unit(uptr); /* detach unit */ + if ( r != SCPE_OK) + return r; + + return SCPE_OK; +} + + +static int32 disk2dev(const int32 port, const int32 io, const int32 data) +{ +/* TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " IO %s, Port %02x" NLP, PCX, io ? "WR" : "RD", port)); */ + if(io) { + DISK2_Write(port, data); + return 0; + } else { + return(DISK2_Read(port)); + } +} + +#define DISK2_CSR 0 /* R=DISK2 Status / W=DISK2 Control Register */ +#define DISK2_DATA 1 /* R=Step Pulse / W=Write Data Register */ + +static uint8 DISK2_Read(const uint32 Addr) +{ + uint8 cData; + DISK2_DRIVE_INFO *pDrive; + + pDrive = &disk2_info->drive[disk2_info->sel_drive]; + cData = 0x00; + + switch(Addr & 0x1) { + case DISK2_CSR: + cData = (disk2_info->ctl_attn) << 7; + cData |= (disk2_info->timeout) << 6; + cData |= (disk2_info->crc_error) << 5; + cData |= (disk2_info->overrun) << 4; + cData |= (pDrive->ready == 0) ? 0x08 : 0x00; + cData |= (disk2_info->seek_complete == 0) ? 0x04 : 0x00; + cData |= (disk2_info->write_fault) << 1; + cData |= ((pDrive->track != 0) || (disk2_info->seek_complete == 0)) ? 0x01 : 0x00; + TRACE_PRINT(STATUS_MSG, ("DISK2: " ADDRESS_FORMAT " RD STATUS = 0x%02x" NLP, PCX, cData)); + + disk2_info->seek_complete = 1; + break; + case DISK2_DATA: + if(disk2_info->ctl_op & 0x04) { + if(pDrive->track < pDrive->ntracks) { + pDrive->track ++; + } + } else { + if(pDrive->track > 0) { + pDrive->track --; + } + } + TRACE_PRINT(SEEK_MSG, ("DISK2: " ADDRESS_FORMAT " Step %s, Track=%d" NLP, + PCX, disk2_info->ctl_op & 0x04 ? "IN" : "OUT", pDrive->track)); + disk2_info->seek_complete = 0; + cData = 0xFF; /* Return High-Z data */ + break; + } + + return (cData); +} + +#define DISK2_OP_DRIVE 0x00 +#define DISK2_OP_CYL 0x01 +#define DISK2_OP_HEAD 0x02 +#define DISK2_OP_SECTOR 0x03 + +#define DISK2_CMD_NULL 0x00 +#define DISK2_CMD_READ_DATA 0x01 +#define DISK2_CMD_WRITE_DATA 0x02 +#define DISK2_CMD_WRITE_HEADER 0x03 +#define DISK2_CMD_READ_HEADER 0x04 + +static uint8 DISK2_Write(const uint32 Addr, uint8 cData) +{ + uint32 track_offset; + uint8 result = 0; + uint8 i; + long file_offset; + DISK2_DRIVE_INFO *pDrive; + + pDrive = &disk2_info->drive[disk2_info->sel_drive]; + + switch(Addr & 0x1) { + case DISK2_CSR: /* Write CTL register */ + disk2_info->ctl_attn = (cData & 0x80) >> 7; + disk2_info->ctl_run = (cData & 0x40) >> 6; + disk2_info->ctl_op = (cData & 0x38) >> 3; + disk2_info->ctl_fault_clr = (cData & 0x04) >> 2; + if(disk2_info->ctl_fault_clr == 1) { + disk2_info->timeout = 0; + } + disk2_info->ctl_us = (cData & 0x03); + TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " ATTN*=%d, RUN=%d, OP=%d, FAULT_CLR=%d, US=%d" NLP, + PCX, + disk2_info->ctl_attn, + disk2_info->ctl_run, + disk2_info->ctl_op, + disk2_info->ctl_fault_clr, + disk2_info->ctl_us)); + + /* FIXME: seek_complete = 1 is needed by CP/M, but why? Also, maybe related, + * there appears to be a bug in the seeking logic. For some reason, the + * pDrive->track does not equal the disk2_info->cyl, when doing READ_DATA and + * WRITE_DATA commands. For this reason, disk2_info->cyl is used instead of + * pDrive->track for these commands. For READ_HEADER and WRITE_HEADER, + * pDrive->track is used, because the DISK2 format program (DISK2.COM) does not + * issue DISK2_OP_CYL. The root cause of this anomaly needs to be determined, + * because it is surely a bug in the logic somewhere. + */ + /* pDrive->track may be different from disk2_info->cyl when a program such as DISK2.COM + moves the position of the track without informing the CP/M BIOS which stores the + current track for each drive. This appears to be an application program bug. + */ + disk2_info->seek_complete = 1; + + if(disk2_info->ctl_run == 1) { + disk2_info->timeout = 0; + track_offset = disk2_info->cyl * pDrive->nheads * pDrive->nsectors * (pDrive->sectsize + 3); + + switch(disk2_info->ctl_op) { + case DISK2_CMD_NULL: + TRACE_PRINT(CMD_MSG, ("DISK2: " ADDRESS_FORMAT " NULL Command" NLP, PCX)); + break; + case DISK2_CMD_READ_DATA: + TRACE_PRINT(RD_DATA_MSG, ("DISK2: " ADDRESS_FORMAT " READ_DATA: (C:%d/H:%d/S:%d)" NLP, + PCX, + disk2_info->cyl, + disk2_info->head, + disk2_info->sector)); + if(disk2_info->head_sel != disk2_info->head) { + printf("DISK2: " ADDRESS_FORMAT " READ_DATA: head_sel != head" NLP, PCX); + } + /* See FIXME above... that might be why this does not work properly... */ + if(disk2_info->cyl != pDrive->track) { /* problem, should not happen, see above */ + TRACE_PRINT(BUG_MSG, ("DISK2: " ADDRESS_FORMAT " READ_DATA: cyl=%d, track=%d" NLP, + PCX, disk2_info->cyl, pDrive->track)); + pDrive->track = disk2_info->cyl; /* update track */ + } + fseek((pDrive->uptr)->fileref, track_offset + (disk2_info->head_sel * pDrive->nsectors * (pDrive->sectsize + 3)), SEEK_SET); + for(i=0;insectors;i++) { + /* Read sector */ + fread(sdata.raw, (pDrive->sectsize + 3), 1, (pDrive->uptr)->fileref); + if(sdata.u.header[2] == disk2_info->sector) { + if(sdata.u.header[0] != disk2_info->cyl) { /*pDrive->track) { */ + printf("DISK2: " ADDRESS_FORMAT " READ_DATA Incorrect header: track" NLP, PCX); + disk2_info->timeout = 1; + } + if(sdata.u.header[1] != disk2_info->head) { + printf("DISK2: " ADDRESS_FORMAT " READ_DATA Incorrect header: head" NLP, PCX); + disk2_info->timeout = 1; + } + + selchan_dma(sdata.u.data, pDrive->sectsize); + break; + } + if(i == pDrive->nsectors) { + printf("DISK2: " ADDRESS_FORMAT " Sector not found" NLP, PCX); + disk2_info->timeout = 1; + } + } + + break; + case DISK2_CMD_WRITE_DATA: + TRACE_PRINT(WR_DATA_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_DATA: (C:%d/H:%d/S:%d)" NLP, + PCX, + disk2_info->cyl, + disk2_info->head, + disk2_info->sector)); + if(disk2_info->head_sel != disk2_info->head) { + printf("DISK2: " ADDRESS_FORMAT " WRITE_DATA: head_sel != head" NLP, PCX); + } + if(disk2_info->cyl != pDrive->track) { /* problem, should not happen, see above */ + TRACE_PRINT(BUG_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_DATA = 0x%02x, cyl=%d, track=%d" NLP, + PCX, cData, disk2_info->cyl, pDrive->track)); + pDrive->track = disk2_info->cyl; /* update track */ + } + + fseek((pDrive->uptr)->fileref, track_offset + (disk2_info->head_sel * pDrive->nsectors * (pDrive->sectsize + 3)), SEEK_SET); + for(i=0;insectors;i++) { + /* Read sector */ + file_offset = ftell((pDrive->uptr)->fileref); + fread(sdata.raw, 3, 1, (pDrive->uptr)->fileref); + if(sdata.u.header[2] == disk2_info->sector) { + if(sdata.u.header[0] != disk2_info->cyl) { + printf("DISK2: " ADDRESS_FORMAT " WRITE_DATA Incorrect header: track" NLP, PCX); + disk2_info->timeout = 1; + } + if(sdata.u.header[1] != disk2_info->head) { + printf("DISK2: " ADDRESS_FORMAT " WRITE_DATA Incorrect header: head" NLP, PCX); + disk2_info->timeout = 1; + } + + selchan_dma(sdata.u.data, pDrive->sectsize); + fseek((pDrive->uptr)->fileref, file_offset+3, SEEK_SET); + fwrite(sdata.u.data, (pDrive->sectsize), 1, (pDrive->uptr)->fileref); + break; + } + fread(sdata.raw, pDrive->sectsize, 1, (pDrive->uptr)->fileref); + if(i == pDrive->nsectors) { + printf("DISK2: " ADDRESS_FORMAT " Sector not found" NLP, PCX); + disk2_info->timeout = 1; + } + } + break; + case DISK2_CMD_WRITE_HEADER: + track_offset = pDrive->track * pDrive->nheads * pDrive->nsectors * (pDrive->sectsize + 3); + TRACE_PRINT(CMD_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_HEADER Command: track=%d (%d), Head=%d, Sector=%d" NLP, + PCX, + pDrive->track, + disk2_info->cyl, + disk2_info->head_sel, + disk2_info->hdr_sector)); + + i = disk2_info->hdr_sector; + selchan_dma(sdata.raw, 3); + fseek((pDrive->uptr)->fileref, track_offset + (disk2_info->head_sel * (pDrive->sectsize + 3) * pDrive->nsectors) + (i * (pDrive->sectsize + 3)), SEEK_SET); + fwrite(sdata.raw, 3, 1, (pDrive->uptr)->fileref); + + disk2_info->hdr_sector++; + if(disk2_info->hdr_sector >= pDrive->nsectors) { + disk2_info->hdr_sector = 0; + disk2_info->timeout = 1; + } + break; + case DISK2_CMD_READ_HEADER: + track_offset = pDrive->track * pDrive->nheads * pDrive->nsectors * (pDrive->sectsize + 3); + TRACE_PRINT(CMD_MSG, ("DISK2: " ADDRESS_FORMAT " READ_HEADER Command" NLP, PCX)); + fseek((pDrive->uptr)->fileref, track_offset + (disk2_info->head_sel * pDrive->nsectors * (pDrive->sectsize + 3)), SEEK_SET); + fread(sdata.raw, 3, 1, (pDrive->uptr)->fileref); + selchan_dma(sdata.raw, 3); + break; + default: + printf("DISK2: " ADDRESS_FORMAT " Unknown CMD=%d" NLP, PCX, disk2_info->ctl_op); + break; + } + + disk2_info->ctl_attn = 0; + } + + break; + case DISK2_DATA: + switch(disk2_info->ctl_op) { + case DISK2_OP_DRIVE: + switch(cData >> 4) { + case 0x01: + disk2_info->sel_drive = 0; + break; + case 0x02: + disk2_info->sel_drive = 1; + break; + case 0x04: + disk2_info->sel_drive = 2; + break; + case 0x08: + disk2_info->sel_drive = 3; + break; + default: + printf("DISK2: " ADDRESS_FORMAT " Error, invalid drive select=0x%x" NLP, PCX, cData >> 4); + break; + } + + disk2_info->head_sel = cData & 0x0F; + + TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write DATA [DRIVE]=%d, Head=%d" NLP, + PCX, disk2_info->sel_drive, disk2_info->head)); + break; + case DISK2_OP_CYL: + disk2_info->cyl = cData; + TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write DATA [CYL] = %02x" NLP, + PCX, cData)); + break; + case DISK2_OP_HEAD: + disk2_info->head = cData; + TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write DATA [HEAD] = %02x" NLP, + PCX, cData)); + break; + case DISK2_OP_SECTOR: + disk2_info->sector = cData; + TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write Register [SECTOR] = %02x" NLP, + PCX, cData)); + break; + default: + TRACE_PRINT(VERBOSE_MSG, ("DISK2: " ADDRESS_FORMAT " Write Register unknown op [%d] = %02x" NLP, + PCX, disk2_info->ctl_op, cData)); + break; + } + } + + return (result); +} + diff --git a/AltairZ80/s100_fif.c b/AltairZ80/s100_fif.c new file mode 100644 index 00000000..62ddfa8b --- /dev/null +++ b/AltairZ80/s100_fif.c @@ -0,0 +1,467 @@ +/* $Id: s100_fif.c 1773 2008-01-11 05:46:19Z hharte $ + + IMSAI FIF Disk Controller by Ernie Price + + Based on altairz80_dsk.c, Copyright (c) 2002-2008, Peter Schorn + + Plug-n-Play added by Howard M. Harte + + 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 + PETER SCHORN 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 Peter Schorn shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Peter Schorn. + +*/ + +#include "altairz80_defs.h" + +#define UNIT_V_DSK_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_DSK_WLK (1 << UNIT_V_DSK_WLK) +#define UNIT_V_DSK_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ +#define UNIT_DSK_VERBOSE (1 << UNIT_V_DSK_VERBOSE) +#define DSK_SECTSIZE 137 /* size of sector */ +#define DSK_SECT 32 /* sectors per track */ +#define MAX_TRACKS 254 /* number of tracks, original Altair has 77 tracks only */ +#define DSK_TRACSIZE (DSK_SECTSIZE * DSK_SECT) +#define MAX_DSK_SIZE (DSK_TRACSIZE * MAX_TRACKS) + +static t_stat fif_reset(DEVICE *dptr); +static t_stat fif_set_verbose(UNIT *uptr, int32 value, char *cptr, void *desc); +static int32 fif_io(const int32 port, const int32 io, const int32 data); + +extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc); +extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, + int32 (*routine)(const int32, const int32, const int32), uint8 unmap); +extern uint8 GetBYTEWrapper(const uint32 Addr); +extern void PutBYTEWrapper(const uint32 Addr, const uint32 Value); + +extern uint32 PCX; +extern char messageBuffer[]; +extern void printMessage(void); + +/* global data on status */ + +/* currently selected drive (values are 0 .. NUM_OF_DSK) + current_disk < NUM_OF_DSK implies that the corresponding disk is attached to a file */ +static int32 current_disk = NUM_OF_DSK; +static int32 warnLevelDSK = 3; +static int32 warnLock [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; +static int32 warnAttached [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; +static int32 warnDSK11 = 0; + +/* 88DSK Standard I/O Data Structures */ + +typedef struct { + PNP_INFO pnp; /* Plug and Play */ +} FIF_INFO; + +FIF_INFO fif_info_data = { { 0x0000, 0, 0xFD, 1 } }; +FIF_INFO *fif_info = &fif_info_data; + +static UNIT fif_unit[] = { + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) } +}; + +static REG fif_reg[] = { + { DRDATA (DISK, current_disk, 4) }, + { DRDATA (DSKWL, warnLevelDSK, 32) }, + { BRDATA (WARNLOCK, warnLock, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO }, + { BRDATA (WARNATTACHED, warnAttached, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO }, + { DRDATA (WARNDSK11, warnDSK11, 4), REG_RO }, + { NULL } +}; + +static MTAB fif_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL }, + { UNIT_DSK_WLK, 0, "WRTENB", "WRTENB", NULL }, + { UNIT_DSK_WLK, UNIT_DSK_WLK, "WRTLCK", "WRTLCK", NULL }, + /* quiet, no warning messages */ + { UNIT_DSK_VERBOSE, 0, "QUIET", "QUIET", NULL }, + /* verbose, show warning messages */ + { UNIT_DSK_VERBOSE, UNIT_DSK_VERBOSE, "VERBOSE", "VERBOSE", &fif_set_verbose }, + { 0 } +}; + +DEVICE fif_dev = { + "FIF", fif_unit, fif_reg, fif_mod, + 8, 10, 31, 1, 8, 8, + NULL, NULL, &fif_reset, + NULL, NULL, NULL, + &fif_info_data, (DEV_DISABLE | DEV_DIS), 0, + NULL, NULL, NULL +}; + +static void resetDSKWarningFlags(void) { + int32 i; + for (i = 0; i < NUM_OF_DSK; i++) { + warnLock[i] = 0; + warnAttached[i] = 0; + } + warnDSK11 = 0; +} + +static t_stat fif_set_verbose(UNIT *uptr, int32 value, char *cptr, void *desc) { + resetDSKWarningFlags(); + return SCPE_OK; +} + +/* returns TRUE iff there exists a disk with VERBOSE */ +static int32 hasVerbose(void) { + int32 i; + for (i = 0; i < NUM_OF_DSK; i++) { + if (((fif_dev.units + i) -> flags) & UNIT_DSK_VERBOSE) { + return TRUE; + } + } + return FALSE; +} + +/* service routines to handle simulator functions */ + +/* Reset routine */ +static t_stat fif_reset(DEVICE *dptr) +{ + PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; + + resetDSKWarningFlags(); + current_disk = NUM_OF_DSK; + + if(dptr->flags & DEV_DIS) { + sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &fif_io, TRUE); + } else { + /* Connect HDSK at base address */ + if(sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &fif_io, FALSE) != 0) { + printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->mem_base); + dptr->flags |= DEV_DIS; + return SCPE_ARG; + } + } + return SCPE_OK; +} + +typedef struct desc_t +{ + uint8 + cmd_unit, /* (cmd << 4) | unit : 1 = A: */ + result, /* result: 0 == busy, 1 = normal completion, */ + nn, /* number of secs ? */ + track, /* track */ + sector, /* sector */ + addr_l, /* low (transfer address) */ + addr_h; /* high (transfer address) */ +} desc_t; + +static desc_t mydesc; + +enum {NONE, WRITE_SEC, READ_SEC, FMT_TRACK}; + +#define SEC_SZ 128 +#define SPT 26 +#define UMASK 0xf + +static uint8 blanksec[SEC_SZ]; +/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +static const uint8 utrans[] = {0,1,2,0,3,0,0,0,4,0,0,0,0,0,0,0}; + +/************************************************** + + Translate an IMSAI FIF disk request into an access into the harddrive file + +*/ +static int DoDiskOperation(desc_t *dsc, uint8 val) +{ + int32 current_disk_flags; + int kt, + addr; + FILE *cpx; + UNIT *uptr; + +#if 0 + printf("%02x %02x %02x %02x %02x %02x %02x %02x \n", + val, + dsc->cmd_unit, + dsc->result, + dsc->nn, + dsc->track, + dsc->sector, + dsc->addr_l, + dsc->addr_h); +#endif + + current_disk = (utrans[dsc->cmd_unit & UMASK]) - 1; /* 0 <= current_disk < NUM_OF_DSK */ + if (current_disk >= NUM_OF_DSK) { + if (hasVerbose() && (warnDSK11 < warnLevelDSK)) { + warnDSK11++; +/*03*/ MESSAGE_2("Attempt disk io on illegal disk %d - ignored.", current_disk + 1); + } + return 0; /* no drive selected - can do nothing */ + } + current_disk_flags = (fif_dev.units + current_disk) -> flags; + if ((current_disk_flags & UNIT_ATT) == 0) { /* nothing attached? */ + if ( (current_disk_flags & UNIT_DSK_VERBOSE) && (warnAttached[current_disk] < warnLevelDSK) ) { + warnAttached[current_disk]++; +/*02*/MESSAGE_2("Attempt to select unattached DSK%d - ignored.", current_disk); + } + current_disk = NUM_OF_DSK; + return 2; + } + + uptr = fif_dev.units + current_disk; + cpx = uptr->fileref; + + /* decode request: */ + switch (dsc->cmd_unit >> 4) { + case FMT_TRACK: + /*printf("%c", dsc->track % 10 ? '*' : '0' + + dsc->track / 10); */ + /*Sleep(250); */ + memset(blanksec, 0, SEC_SZ); + addr = dsc->track * SPT; + fseek(cpx, addr * SEC_SZ, SEEK_SET); + + /* write a track worth of sectors */ + for (kt=0; kt < SPT; kt++) { + fwrite(blanksec, 1, sizeof(blanksec), cpx); + } + break; + + case READ_SEC: + addr = (dsc->track * SPT) + dsc->sector - 1; + fseek(cpx, addr * SEC_SZ, SEEK_SET); + fread(blanksec, 1, SEC_SZ, cpx); + addr = dsc->addr_l + (dsc->addr_h << 8); /* no assumption on endianness */ + for (kt = 0; kt < SEC_SZ; kt++) { + PutBYTEWrapper(addr++, blanksec[kt]); + } + break; + + case WRITE_SEC: + addr = (dsc->track * SPT) + dsc->sector - 1; + fseek(cpx, addr * SEC_SZ, SEEK_SET); + addr = dsc->addr_l + (dsc->addr_h << 8); /* no assumption on endianness */ + for (kt = 0; kt < SEC_SZ; kt++) { + blanksec[kt] = GetBYTEWrapper(addr++); + } + fwrite(blanksec, 1, SEC_SZ, cpx); + break; + + default: + ; + } + return 1; +} + +/********************************************************************** + + Copy the disk descriptor from target RAM + +*/ +static void getdesc(uint16 addr) { + int32 x; + uint8 *p1 = (uint8*)&mydesc; + + for (x = 0; x < sizeof(mydesc); x++) { + *p1++ = GetBYTEWrapper(addr++); + } +} + +/********************************************************************** + + handle the IMSAI FIF floppy controller + +*/ +static int32 fif_io(const int32 port, const int32 io, const int32 data) { + + static int32 fdstate = 0; /* chan 0xfd state */ + static int32 desc; + static uint16 fdAdr[16]; /* disk descriptor address in 8080/z80 RAM */ + + /* cmd | desc# */ + /* cmd == 0x00 do operation */ + /* cmd == 0x10 next 2 transfers are desc address */ + /* desc# is one of 16 0x0 - 0xf */ + + if (!io) { + return 0; + } + + switch (fdstate) { + case 0: + desc = data & 0xf; + if ((data & 0x10) != 0) { /* prefix 0x10 */ + fdstate++; /* means desc address is next 2 out (fd),a */ + } + else { /* do what descriptor says */ + getdesc(fdAdr[desc]); + PutBYTEWrapper(fdAdr[desc] + 1, + (uint8)DoDiskOperation(&mydesc, (uint8)data)); + } + break; + + case 1: + /*printf("D1 %02x %02x\n", desc, data); */ + fdAdr[desc] = data; /* LSB of descriptor address */ + fdstate++; + break; + + case 2: + /*printf("D2 %02x %02x\n", desc, data); */ + fdAdr[desc] |= data << 8; /* MSB of descriptor address */ + fdstate = 0; + break; + } + return 0; +} + +#define ERNIES_FTP 0 +#if ERNIES_FTP + +#define WRK_BUF_SZ 150 +#define FCB_SIZE 32 +#define NAME_LTH 8 +#define EXT_LTH 3 + + +/************************************************** +*/ +static void xfero(int32 addr, char *src, int32 lth) +{ + while (lth--) { + PutBYTEWrapper(addr++, *src++); + } +} + +/************************************************** +*/ +static void xferi(int32 addr, char *dst, int32 lth) +{ + while (lth--) { + *dst++ = GetBYTEWrapper(addr++); + } +} + +#if !defined (_WIN32) +static void strupr(char *fn) { /* psco added */ + while (*fn) { + if (('a' <= *fn) && (*fn <= 'z')) *fn -= 'a' - 'A'; + fn++; + } +} +#endif + +/************************************************** +*/ +static void initfcb(char *fcb, char *fn, int32 flg) +{ + char *p1 = fcb; + + if (flg) + { + strupr(fn); + } + memset (fcb, 0 , FCB_SIZE); + memset (fcb + 1, ' ', NAME_LTH + EXT_LTH); + p1++; + while (*fn && (*fn != '.')) + { + *p1++ = *fn++; + } + if (*fn == '.') + { + fn++; + } + p1 = fcb + NAME_LTH + 1; + while (*fn && (*fn != '.')) + { + *p1++ = *fn++; + } +} + +/************************************************** + + FTP interface - most of the work is done here + The IMDOS/CPM application only does minimal work + +*/ + +char message[WRK_BUF_SZ]; +char temp [WRK_BUF_SZ]; +FILE * myfile; + +uint8 FTP(int32 BC, int32 DE) +{ + char *p1, *p2; + int32 retval; + + xferi(DE, temp, SEC_SZ); + p1 = temp; + switch (BC & 0x7f) + { + case 0: + memcpy(message, p1 + 2, *(p1 + 1)); + *(message + *(p1 + 1)) = 0; + p2 = strtok(message, " \t"); + if (!strcmp(p2, "get")) + { + p2 = strtok(NULL, " \t"); + if (myfile = fopen(p2, "rb")) + { + initfcb(temp, p2, 1); + xfero(DE + 2, temp, 32); + retval = 0; + break; + } + } + if (!strcmp(p2, "era")) + { + p2 = strtok(NULL, " \t"); + initfcb(temp, p2, 0); + xfero(DE + 2, temp, 32); + retval = 1; + break; + } + retval = 0xff; + break; + + case 20: + memset(temp, 0x1a, SEC_SZ); + retval = fread(temp, 1, SEC_SZ, myfile) ? 0 : 1; + xfero( DE, temp, SEC_SZ); + if (retval) + { + fclose(myfile); + } + break; + } + return retval; +} + +#endif /* ERNIES_FTP */ + +/* end of the source */ + + + diff --git a/AltairZ80/s100_mdriveh.c b/AltairZ80/s100_mdriveh.c new file mode 100644 index 00000000..8f29e430 --- /dev/null +++ b/AltairZ80/s100_mdriveh.c @@ -0,0 +1,260 @@ +/************************************************************************* + * * + * $Id: s100_mdriveh.c 1773 2008-01-11 05:46:19Z hharte $ * + * * + * Copyright (c) 2007-2008 Howard M. Harte. * + * http://www.hartetec.com * + * * + * 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 HOWARD M. HARTE 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 Howard M. Harte shall * + * not be used in advertising or otherwise to promote the sale, use or * + * other dealings in this Software without prior written authorization * + * Howard M. Harte. * + * * + * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. * + * * + * Module Description: * + * CompuPro M-DRIVE/H Controller module for SIMH. * + * * + * Environment: * + * User mode only * + * * + *************************************************************************/ + +/*#define DBG_MSG */ + +#include "altairz80_defs.h" + +#if defined (_WIN32) +#include +#endif + +#ifdef DBG_MSG +#define DBG_PRINT(args) printf args +#else +#define DBG_PRINT(args) +#endif + +#define SEEK_MSG 0x01 +#define RD_DATA_MSG 0x08 +#define WR_DATA_MSG 0x10 +#define VERBOSE_MSG 0x80 + +#define MDRIVEH_MAX_DRIVES 8 + +typedef struct { + PNP_INFO pnp; /* Plug and Play */ + uint32 dma_addr; /* DMA Transfer Address */ + UNIT uptr[MDRIVEH_MAX_DRIVES]; + uint8 *storage[MDRIVEH_MAX_DRIVES]; +} MDRIVEH_INFO; + +static MDRIVEH_INFO mdriveh_info_data = { { 0x0, 0, 0xC6, 2 } }; +static MDRIVEH_INFO *mdriveh_info = &mdriveh_info_data; + +extern uint32 PCX; +extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc); +extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, + int32 (*routine)(const int32, const int32, const int32), uint8 unmap); + +extern REG *sim_PC; + +#define UNIT_V_MDRIVEH_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_MDRIVEH_WLK (1 << UNIT_V_MDRIVEH_WLK) +#define UNIT_V_MDRIVEH_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ +#define UNIT_MDRIVEH_VERBOSE (1 << UNIT_V_MDRIVEH_VERBOSE) +#define MDRIVEH_CAPACITY (512 * 1000) /* Default M-DRIVE/H Capacity */ +#define MDRIVEH_NONE 0 + +static t_stat mdriveh_reset(DEVICE *mdriveh_dev); +static int32 mdrivehdev(const int32 port, const int32 io, const int32 data); +static uint8 MDRIVEH_Read(const uint32 Addr); +static uint8 MDRIVEH_Write(const uint32 Addr, uint8 cData); + +static int32 trace_level = 0; /* Disable all tracing by default */ + +static UNIT mdriveh_unit[] = { + { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ROABLE, MDRIVEH_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_DIS + UNIT_ROABLE, MDRIVEH_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_DIS + UNIT_ROABLE, MDRIVEH_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_DIS + UNIT_ROABLE, MDRIVEH_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_DIS + UNIT_ROABLE, MDRIVEH_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_DIS + UNIT_ROABLE, MDRIVEH_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_DIS + UNIT_ROABLE, MDRIVEH_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_DIS + UNIT_ROABLE, MDRIVEH_CAPACITY) } +}; + +static REG mdriveh_reg[] = { + { HRDATA (TRACELEVEL, trace_level, 16), }, + { NULL } +}; + +static MTAB mdriveh_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL }, + { UNIT_MDRIVEH_WLK, 0, "WRTENB", "WRTENB", NULL }, + { UNIT_MDRIVEH_WLK, UNIT_MDRIVEH_WLK, "WRTLCK", "WRTLCK", NULL }, + /* quiet, no warning messages */ + { UNIT_MDRIVEH_VERBOSE, 0, "QUIET", "QUIET", NULL }, + /* verbose, show warning messages */ + { UNIT_MDRIVEH_VERBOSE, UNIT_MDRIVEH_VERBOSE, "VERBOSE", "VERBOSE", NULL }, + { 0 } +}; + +DEVICE mdriveh_dev = { + "MDRIVEH", mdriveh_unit, mdriveh_reg, mdriveh_mod, + MDRIVEH_MAX_DRIVES, 10, 31, 1, MDRIVEH_MAX_DRIVES, MDRIVEH_MAX_DRIVES, + NULL, NULL, &mdriveh_reset, + NULL, NULL, NULL, + &mdriveh_info_data, (DEV_DISABLE | DEV_DIS), 0, + NULL, NULL, NULL +}; + + +/* Reset routine */ +static t_stat mdriveh_reset(DEVICE *dptr) +{ + uint8 i; + PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; + + if(dptr->flags & DEV_DIS) { /* Disconnect ROM and I/O Ports */ + sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &mdrivehdev, TRUE); + } else { + /* Connect MDRIVEH at base address */ + if(sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &mdrivehdev, FALSE) != 0) { + printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->io_base); + return SCPE_ARG; + } + } + + for(i=0; iuptr[i] = dptr->units[i]; + if((dptr->flags & DEV_DIS) || (dptr->units[i].flags & UNIT_DIS)) { + if (dptr->units[i].flags & UNIT_MDRIVEH_VERBOSE) + printf("MDRIVEH: Unit %d disabled", i); + if(mdriveh_info->storage[i] != NULL) { + if (dptr->units[i].flags & UNIT_MDRIVEH_VERBOSE) + printf(", freed 0x%p\n", mdriveh_info->storage[i]); + free(mdriveh_info->storage[i]); + mdriveh_info->storage[i] = NULL; + } else if (dptr->units[i].flags & UNIT_MDRIVEH_VERBOSE) { + printf(".\n"); + } + } else { + if(mdriveh_info->storage[i] == NULL) { + mdriveh_info->storage[i] = calloc(1, 524288); + } + if (dptr->units[i].flags & UNIT_MDRIVEH_VERBOSE) + printf("MDRIVEH: Unit %d enabled, 512K at 0x%p\n", i, mdriveh_info->storage[i]); + } + } + + return SCPE_OK; +} + +static int32 mdrivehdev(const int32 port, const int32 io, const int32 data) +{ + DBG_PRINT(("MDRIVEH: " ADDRESS_FORMAT " IO %s, Port %02x" NLP, PCX, io ? "WR" : "RD", port)); + if(io) { + MDRIVEH_Write(port, data); + return 0; + } else { + return(MDRIVEH_Read(port)); + } +} + +#define MDRIVEH_DATA 0 /* R=Drive Status Register / W=DMA Address Register */ +#define MDRIVEH_ADDR 1 /* R=Unused / W=Motor Control Register */ + +static uint8 MDRIVEH_Read(const uint32 Addr) +{ + uint8 cData; + uint8 unit; + uint32 offset; + + cData = 0xFF; /* default is High-Z Data */ + + switch(Addr & 0x1) { + case MDRIVEH_ADDR: + TRACE_PRINT(VERBOSE_MSG, ("MDRIVEH: " ADDRESS_FORMAT " RD Addr = 0x%02x" NLP, + PCX, cData)); + break; + case MDRIVEH_DATA: + unit = (mdriveh_info->dma_addr & 0x380000) >> 19; + offset = mdriveh_info->dma_addr & 0x7FFFF; + + if(mdriveh_info->storage[unit] != NULL) { + cData = mdriveh_info->storage[unit][offset]; + } + + TRACE_PRINT(RD_DATA_MSG, ("MDRIVEH: " ADDRESS_FORMAT " RD Data [%x:%05x] = 0x%02x" NLP, + PCX, unit, offset, cData)); + + /* Increment M-DRIVE/H Data Address */ + mdriveh_info->dma_addr++; + mdriveh_info->dma_addr &= 0x3FFFFF; + break; + } + + return (cData); +} + +static uint8 MDRIVEH_Write(const uint32 Addr, uint8 cData) +{ + uint8 result = 0; + uint8 unit; + uint32 offset; + + switch(Addr & 0x1) { + case MDRIVEH_ADDR: + mdriveh_info->dma_addr <<= 8; + mdriveh_info->dma_addr &= 0x003FFF00; + mdriveh_info->dma_addr |= cData; + TRACE_PRINT(SEEK_MSG, ("MDRIVEH: " ADDRESS_FORMAT " DMA Address=%06x" NLP, + PCX, mdriveh_info->dma_addr)); + break; + case MDRIVEH_DATA: + unit = (mdriveh_info->dma_addr & 0x380000) >> 19; + offset = mdriveh_info->dma_addr & 0x7FFFF; + + if(mdriveh_info->storage[unit] != NULL) { + if(mdriveh_info->uptr[unit].flags & UNIT_MDRIVEH_WLK) { + TRACE_PRINT(WR_DATA_MSG, ("MDRIVEH: " ADDRESS_FORMAT " WR Data [%x:%05x] = Unit Write Locked" NLP, + PCX, unit, offset)); + } else { + TRACE_PRINT(WR_DATA_MSG, ("MDRIVEH: " ADDRESS_FORMAT " WR Data [%x:%05x] = 0x%02x" NLP, + PCX, unit, offset, cData)); + mdriveh_info->storage[unit][offset] = cData; + } + } else { + TRACE_PRINT(WR_DATA_MSG, ("MDRIVEH: " ADDRESS_FORMAT " WR Data [%x:%05x] = Unit OFFLINE" NLP, + PCX, unit, offset)); + } + + /* Increment M-DRIVE/H Data Address */ + mdriveh_info->dma_addr++; + mdriveh_info->dma_addr &= 0x3FFFFF; + break; + } + + return (result); +} + diff --git a/AltairZ80/s100_mdsad.c b/AltairZ80/s100_mdsad.c new file mode 100644 index 00000000..db33491a --- /dev/null +++ b/AltairZ80/s100_mdsad.c @@ -0,0 +1,802 @@ +/************************************************************************* + * * + * $Id: s100_mdsad.c 1773 2008-01-11 05:46:19Z hharte $ * + * * + * Copyright (c) 2007-2008 Howard M. Harte. * + * http://www.hartetec.com * + * * + * 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 HOWARD M. HARTE 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 Howard M. Harte shall * + * not be used in advertising or otherwise to promote the sale, use or * + * other dealings in this Software without prior written authorization * + * Howard M. Harte. * + * * + * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. * + * * + * Module Description: * + * Northstar MDS-AD Disk Controller module for SIMH * + * Only Double-Density is supported for now. * + * * + * Environment: * + * User mode only * + * * + *************************************************************************/ + +/*#define DBG_MSG*/ +#include "altairz80_defs.h" + +#if defined (_WIN32) +#include +#endif + +#include "sim_imd.h" + +#ifdef DBG_MSG +#define DBG_PRINT(args) printf args +#else +#define DBG_PRINT(args) +#endif + +#define SEEK_MSG 0x01 +#define ORDERS_MSG 0x02 +#define CMD_MSG 0x04 +#define RD_DATA_MSG 0x08 +#define WR_DATA_MSG 0x10 +#define STATUS_MSG 0x20 +#define RD_DATA_DETAIL_MSG 0x40 +#define WR_DATA_DETAIL_MSG 0x80 + +extern uint32 PCX; +extern t_stat set_membase(UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat show_membase(FILE *st, UNIT *uptr, int32 val, void *desc); +extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, + int32 (*routine)(const int32, const int32, const int32), uint8 unmap); +extern REG *sim_PC; + +#define MDSAD_MAX_DRIVES 4 +#define MDSAD_SECTOR_LEN 512 +#define MDSAD_SECTORS_PER_TRACK 10 +#define MDSAD_TRACKS 35 +#define MDSAD_RAW_LEN (32 + 2 + MDSAD_SECTOR_LEN + 1) + +typedef union { + struct { + uint8 zeros[32]; + uint8 sync[2]; + uint8 data[MDSAD_SECTOR_LEN]; + uint8 checksum; + } u; + uint8 raw[MDSAD_RAW_LEN]; + +} SECTOR_FORMAT; + +typedef struct { + UNIT *uptr; + DISK_INFO *imd; + uint8 track; + uint8 wp; /* Disk write protected */ + uint8 sector; /* Current Sector number */ + uint32 sector_wait_count; +} MDSAD_DRIVE_INFO; + +typedef struct { + uint8 dd; /* Controls density on write DD=1 for double density and DD=0 for single density. */ + uint8 ss; /* Specifies the side of a double-sided diskette. The bottom side (and only side of a single-sided diskette) is selected when SS=0. The second (top) side is selected when SS=1. */ + uint8 dp; /* has shared use. During stepping operations, DP=O specifies a step out and DP=1 specifies a step in. During write operations, write procompensation is invoked if and only if DP=1. */ + uint8 st; /* controls the level of the head step signal to the disk drives. */ + uint8 ds; /* is the drive select field, encoded as follows: */ + /* 0=no drive selected + * 1=drive 1 selected + * 2=drive 2 selected + * 4=drive 3 selected + * 8=drive 4 selected + */ +} ORDERS; + +typedef struct { + uint8 sf; /* Sector Flag: set when sector hole detected, reset by software. */ + uint8 ix; /* Index Detect: true if index hole detected during previous sector. */ + uint8 dd; /* Double Density Indicator: true if data being read is encoded in double density. */ + uint8 mo; /* Motor On: true while motor(s) are on. */ +} COM_STATUS; + +typedef struct { + uint8 wi; /* Window: true during 96-microsecond window at beginning of sector. */ + uint8 re; /* Read Enable: true while phase-locked loop is enabled. */ + uint8 sp; /* Spare: reserved for future use. */ + uint8 bd; /* Body: set when sync character is detected. */ +} A_STATUS; + +typedef struct { + uint8 wr; /* Write: true during valid write operation. */ + uint8 sp; /* Spare: reserved for future use. */ + uint8 wp; /* Write Protect: true while the diskette installed in the selected drive is write protected. */ + uint8 t0; /* Track 0: true if selected drive is at track zero. */ +} B_STATUS; + +typedef struct { + uint8 sc; /* Sector Counter: indicates the current sector position. */ +} C_STATUS; + +typedef struct { + PNP_INFO pnp; /* Plug and Play */ + + ORDERS orders; + COM_STATUS com_status; + A_STATUS a_status; + B_STATUS b_status; + C_STATUS c_status; + + uint8 int_enable; /* Interrupt Enable */ + uint32 datacount; /* Number of data bytes transferred from controller for current sector */ + MDSAD_DRIVE_INFO drive[MDSAD_MAX_DRIVES]; +} MDSAD_INFO; + +static MDSAD_INFO mdsad_info_data = { { 0xE800, 1024, 0, 0 } }; +static MDSAD_INFO *mdsad_info = &mdsad_info_data; + +static SECTOR_FORMAT sdata; + +#define UNIT_V_MDSAD_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_MDSAD_WLK (1 << UNIT_V_MDSAD_WLK) +#define UNIT_V_MDSAD_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ +#define UNIT_MDSAD_VERBOSE (1 << UNIT_V_MDSAD_VERBOSE) +#define MDSAD_CAPACITY (70*10*MDSAD_SECTOR_LEN) /* Default North Star Disk Capacity */ +#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */ +#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */ +#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */ + +/* MDS-AD Controller Subcases */ +#define MDSAD_READ_ROM 0 +#define MDSAD_WRITE_DATA 1 +#define MDSAD_CTLR_ORDERS 2 +#define MDSAD_CTLR_COMMAND 3 + +/* MDS-AD Controller Commands */ +#define MDSAD_CMD_NOP 0 +#define MDSAD_CMD_RESET_SF 1 +#define MDSAD_CMD_INTR_DIS 2 +#define MDSAD_CMD_INTR_ARM 3 +#define MDSAD_CMD_SET_BODY 4 +#define MDSAD_CMD_MOTORS_ON 5 +#define MDSAD_CMD_BEGIN_WR 6 +#define MDSAD_CMD_RESET 7 + +/* MDS-AD Data returned on DI bus */ +#define MDSAD_A_STATUS 1 +#define MDSAD_B_STATUS 2 +#define MDSAD_C_STATUS 3 +#define MDSAD_READ_DATA 4 + +/* MDS-AD status byte masks */ +/* A-Status */ +#define MDSAD_A_SF 0x80 +#define MDSAD_A_IX 0x40 +#define MDSAD_A_DD 0x20 +#define MDSAD_A_MO 0x10 +#define MDSAD_A_WI 0x08 +#define MDSAD_A_RE 0x04 +#define MDSAD_A_SP 0x02 +#define MDSAD_A_BD 0x01 + +/* B-Status */ +#define MDSAD_B_SF 0x80 +#define MDSAD_B_IX 0x40 +#define MDSAD_B_DD 0x20 +#define MDSAD_B_MO 0x10 +#define MDSAD_B_WR 0x08 +#define MDSAD_B_SP 0x04 +#define MDSAD_B_WP 0x02 +#define MDSAD_B_T0 0x01 + +/* C-Status */ +#define MDSAD_C_SF 0x80 +#define MDSAD_C_IX 0x40 +#define MDSAD_C_DD 0x20 +#define MDSAD_C_MO 0x10 +#define MDSAD_C_SC 0x0f + +/* Local function prototypes */ +static t_stat mdsad_reset(DEVICE *mdsad_dev); +static t_stat mdsad_attach(UNIT *uptr, char *cptr); +static t_stat mdsad_detach(UNIT *uptr); +static t_stat mdsad_boot(int32 unitno, DEVICE *dptr); +static uint8 MDSAD_Read(const uint32 Addr); + +static int32 mdsaddev(const int32 Addr, const int32 rw, const int32 data); + +static int32 trace_level = 0; + +static UNIT mdsad_unit[] = { + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MDSAD_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MDSAD_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MDSAD_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MDSAD_CAPACITY) } +}; + +static REG mdsad_reg[] = { + { HRDATA (TRACELEVEL, trace_level, 16), }, + { NULL } +}; + +static MTAB mdsad_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE", &set_membase, &show_membase, NULL }, + { UNIT_MDSAD_WLK, 0, "WRTENB", "WRTENB", NULL }, + { UNIT_MDSAD_WLK, UNIT_MDSAD_WLK, "WRTLCK", "WRTLCK", NULL }, + /* quiet, no warning messages */ + { UNIT_MDSAD_VERBOSE, 0, "QUIET", "QUIET", NULL }, + /* verbose, show warning messages */ + { UNIT_MDSAD_VERBOSE, UNIT_MDSAD_VERBOSE, "VERBOSE", "VERBOSE", NULL }, + { 0 } +}; + +DEVICE mdsad_dev = { + "MDSAD", mdsad_unit, mdsad_reg, mdsad_mod, + MDSAD_MAX_DRIVES, 10, 31, 1, MDSAD_MAX_DRIVES, MDSAD_MAX_DRIVES, + NULL, NULL, &mdsad_reset, + &mdsad_boot, &mdsad_attach, &mdsad_detach, + &mdsad_info_data, (DEV_DISABLE | DEV_DIS), 0, + NULL, NULL, NULL +}; + +/* Reset routine */ +t_stat mdsad_reset(DEVICE *dptr) +{ + PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; + + if(dptr->flags & DEV_DIS) { + sim_map_resource(pnp->mem_base, pnp->mem_size, + RESOURCE_TYPE_MEMORY, &mdsaddev, TRUE); + } else { + /* Connect MDSAD at base address */ + if(sim_map_resource(pnp->mem_base, pnp->mem_size, + RESOURCE_TYPE_MEMORY, &mdsaddev, FALSE) != 0) { + printf("%s: error mapping resource at 0x%04x\n", + __FUNCTION__, pnp->mem_base); + dptr->flags |= DEV_DIS; + return SCPE_ARG; + } + } + return SCPE_OK; +} + +/* Attach routine */ +t_stat mdsad_attach(UNIT *uptr, char *cptr) +{ + char header[4]; + t_stat r; + unsigned int i = 0; + + r = attach_unit(uptr, cptr); /* attach unit */ + if(r != SCPE_OK) /* error? */ + return r; + + /* Determine length of this disk */ + if(sim_fsize(uptr->fileref) != 0) { + uptr->capac = sim_fsize(uptr->fileref); + } else { + uptr->capac = MDSAD_CAPACITY; + } + + for(i = 0; i < MDSAD_MAX_DRIVES; i++) { + mdsad_info->drive[i].uptr = &mdsad_dev.units[i]; + } + + for(i = 0; i < MDSAD_MAX_DRIVES; i++) { + if(mdsad_dev.units[i].fileref == uptr->fileref) { + break; + } + } + + /* Default for new file is DSK */ + uptr->u3 = IMAGE_TYPE_DSK; + + if(uptr->capac > 0) { + fgets(header, 4, uptr->fileref); + if(!strcmp(header, "IMD")) { + uptr->u3 = IMAGE_TYPE_IMD; + } else if(!strcmp(header, "CPT")) { + printf("CPT images not yet supported\n"); + uptr->u3 = IMAGE_TYPE_CPT; + mdsad_detach(uptr); + return SCPE_OPENERR; + } else { + uptr->u3 = IMAGE_TYPE_DSK; + } + } + + if (uptr->flags & UNIT_MDSAD_VERBOSE) + printf("MDSAD%d, attached to '%s', type=%s, len=%d\n", i, cptr, + uptr->u3 == IMAGE_TYPE_IMD ? "IMD" : uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK", + uptr->capac); + + if(uptr->u3 == IMAGE_TYPE_IMD) { + if(uptr->capac < 318000) { + printf("Cannot create IMD files with SIMH.\nCopy an existing file and format it with CP/M.\n"); + mdsad_detach(uptr); + return SCPE_OPENERR; + } + + if (uptr->flags & UNIT_MDSAD_VERBOSE) + printf("--------------------------------------------------------\n"); + mdsad_info->drive[i].imd = diskOpen((uptr->fileref), (uptr->flags & UNIT_MDSAD_VERBOSE)); + if (uptr->flags & UNIT_MDSAD_VERBOSE) + printf("\n"); + } else { + mdsad_info->drive[i].imd = NULL; + } + + return SCPE_OK; +} + + +/* Detach routine */ +t_stat mdsad_detach(UNIT *uptr) +{ + t_stat r; + int8 i; + + for(i = 0; i < MDSAD_MAX_DRIVES; i++) { + if(mdsad_dev.units[i].fileref == uptr->fileref) { + break; + } + } + + if (i >= MDSAD_MAX_DRIVES) return SCPE_ARG; + + DBG_PRINT(("Detach MDSAD%d\n", i)); + diskClose(mdsad_info->drive[i].imd); + + r = detach_unit(uptr); /* detach unit */ + if(r != SCPE_OK) + return r; + + mdsad_dev.units[i].fileref = NULL; /* psco check if ok */ + return SCPE_OK; +} + +static t_stat mdsad_boot(int32 unitno, DEVICE *dptr) +{ + + PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; + + DBG_PRINT(("Booting MDSAD Controller at 0x%04x, unit %d" NLP, + pnp->mem_base+1+(unitno&3), unitno & 3)); + + /* Unit 3 can't be booted yet. This involves modifying the A register. */ + *((int32 *) sim_PC->loc) = pnp->mem_base+1+(unitno&3); + return SCPE_OK; +} + +static int32 mdsaddev(const int32 Addr, const int32 rw, const int32 data) +{ + if(rw == 0) { /* Read */ + return(MDSAD_Read(Addr)); + } else { /* Write */ + DBG_PRINT(("MDSAD: write attempt at 0x%04x ignored." NLP, Addr)); + return (-1); + } +} + +/* This ROM image is taken from the Solace Emulator, which uses */ +/* a ROM from a "Micro Complex Phase Lock II" dual- */ +/* density controller card. It is supposedly compatible with the */ +/* Northstar-designed dual density floppy controller. It has the */ +/* interesting property that by jumping to base_addr+0 (or +1) and */ +/* it boots from floppy 0; jump to base_addr+2 you boot from floppy 1; */ +/* jump to base_addr+3 and you boot from floppy 2. You can boot from */ +/* floppy 3 by loading A with 08H and jumping to base_addr+7. */ +static uint8 mdsad_rom[] = { + 0x44, 0x01, 0x01, 0x01, 0x82, 0x84, 0x78, 0xE6, 0x07, 0x4F, 0x00, 0x31, 0x30, 0x00, 0x21, 0x29, /* 0x00 */ + 0x00, 0xE5, 0x21, 0x2C, 0xC2, 0xE5, 0x21, 0x77, 0x13, 0xE5, 0x21, 0xC9, 0x1A, 0xE5, 0xCD, 0x28, /* 0x10 */ + 0x00, 0x21, 0x30, 0x00, 0x5B, 0x52, 0x44, 0x54, 0x5D, 0x3A, 0x27, 0x00, 0x57, 0xC3, 0x29, 0x00, /* 0x20 */ + 0x14, 0x14, 0x1E, 0x15, 0x1A, 0x26, 0x30, 0xCD, 0xD9, 0x00, 0x42, 0x05, 0x0A, 0xCD, 0xD4, 0x00, /* 0x30 */ + 0x2E, 0x0D, 0x2D, 0xCA, 0x43, 0x00, 0xCD, 0xD7, 0x00, 0x1A, 0xE6, 0x40, 0xCA, 0x42, 0x00, 0x3E, /* 0x40 */ + 0x0A, 0xF5, 0xCD, 0xC1, 0x00, 0x1E, 0x20, 0x1A, 0xE6, 0x01, 0xC2, 0x63, 0x00, 0xCD, 0xC5, 0x00, /* 0x50 */ + 0xC3, 0x55, 0x00, 0x2E, 0x04, 0xCD, 0xE7, 0x00, 0x1E, 0x10, 0x1A, 0xE6, 0x04, 0xCA, 0x68, 0x00, /* 0x60 */ + 0x3E, 0x09, 0x3D, 0xC2, 0x72, 0x00, 0x1A, 0xE6, 0x20, 0xC2, 0x84, 0x00, 0xCD, 0xC1, 0x00, 0x2E, /* 0x70 */ + 0x08, 0xCD, 0xE7, 0x00, 0x06, 0xA3, 0x1E, 0x10, 0x05, 0xCA, 0xF4, 0x00, 0x1A, 0x0F, 0xD2, 0x88, /* 0x80 */ + 0x00, 0x1E, 0x40, 0x1A, 0x67, 0x2E, 0x00, 0x36, 0x59, 0x07, 0x47, 0x23, 0x1A, 0x77, 0xA8, 0x07, /* 0x90 */ + 0x47, 0x2C, 0xC2, 0x9C, 0x00, 0x24, 0x1A, 0x77, 0xA8, 0x07, 0x47, 0x2C, 0xC2, 0xA6, 0x00, 0x1A, /* 0xA0 */ + 0xA8, 0xC2, 0xF4, 0x00, 0x25, 0x2E, 0x03, 0x71, 0x2D, 0x36, 0x59, 0xC2, 0xB8, 0x00, 0x2E, 0x0A, /* 0xB0 */ + 0xE9, 0x3E, 0x20, 0x81, 0x4F, 0x0A, 0x3E, 0x10, 0x81, 0x4F, 0x0A, 0x3E, 0xF0, 0x81, 0x4F, 0x0A, /* 0xC0 */ + 0x79, 0xE6, 0x0F, 0x4F, 0xCD, 0xD7, 0x00, 0x26, 0x01, 0x1E, 0x11, 0x1A, 0x1D, 0x1A, 0xB7, 0xF2, /* 0xD0 */ + 0xDD, 0x00, 0x25, 0xC2, 0xD9, 0x00, 0xC9, 0xCD, 0xD7, 0x00, 0x1E, 0x35, 0x1A, 0xE6, 0x0F, 0xBD, /* 0xE0 */ + 0xC2, 0xE7, 0x00, 0xC9, 0xF1, 0x3D, 0xF5, 0xC2, 0x55, 0x00, 0xC3, 0xFA, 0x00, 0x52, 0x44, 0x54 /* 0xF0 */ +}; + +static void showdata(int32 isRead) { + int32 i; + printf("MDSAD: " ADDRESS_FORMAT " %s Sector =" NLP "\t", PCX, isRead ? "Read" : "Write"); + for(i=0; i < MDSAD_SECTOR_LEN; i++) { + printf("%02X ", sdata.u.data[i]); + if(((i+1) & 0xf) == 0) printf(NLP "\t"); + } + printf(NLP); +} + +static int checksum; +static uint32 sec_offset; + +static uint8 MDSAD_Read(const uint32 Addr) +{ + uint8 cData; + uint8 ds; + MDSAD_DRIVE_INFO *pDrive; + + cData = 0x00; + + pDrive = &mdsad_info->drive[mdsad_info->orders.ds]; + + switch( (Addr & 0x300) >> 8 ) { + case MDSAD_READ_ROM: + cData = mdsad_rom[Addr & 0xFF]; + break; + case MDSAD_WRITE_DATA: + { + unsigned int flags = 0; + unsigned int writelen; + + if(mdsad_info->datacount == 0) { + TRACE_PRINT(WR_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT + " WRITE Start: Drive: %d, Track=%d, Head=%d, Sector=%d" NLP, + PCX, + mdsad_info->orders.ds, + pDrive->track, + mdsad_info->orders.ss, + pDrive->sector)); + + sec_offset = (pDrive->track * (MDSAD_SECTOR_LEN * MDSAD_SECTORS_PER_TRACK)) + + (mdsad_info->orders.ss * ((MDSAD_SECTOR_LEN * MDSAD_SECTORS_PER_TRACK) * MDSAD_TRACKS)) + + (pDrive->sector * MDSAD_SECTOR_LEN); + + } + + DBG_PRINT(("MDSAD: " ADDRESS_FORMAT + " WRITE-DATA[offset:%06x+%03x]=%02x" NLP, + PCX, sec_offset, mdsad_info->datacount, Addr & 0xFF)); + mdsad_info->datacount++; + if(mdsad_info->datacount < MDSAD_RAW_LEN) + sdata.raw[mdsad_info->datacount] = Addr & 0xFF; + + if(mdsad_info->datacount == (MDSAD_RAW_LEN - 1)) { + TRACE_PRINT(WR_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT + " Write Complete" NLP, PCX)); + + if ((pDrive->uptr == NULL) || (pDrive->uptr->fileref == NULL)) { + TRACE_PRINT(WR_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT + " Drive: %d not attached - write ignored." NLP, + PCX, mdsad_info->orders.ds)); + return 0x00; + } + if(trace_level & WR_DATA_DETAIL_MSG) showdata(FALSE); + switch((pDrive->uptr)->u3) + { + case IMAGE_TYPE_IMD: + if(pDrive->imd == NULL) { + printf(".imd is NULL!" NLP); + } + sectWrite(pDrive->imd, + pDrive->track, + mdsad_info->orders.ss, + pDrive->sector, + sdata.u.data, + MDSAD_SECTOR_LEN, + &flags, + &writelen); + break; + case IMAGE_TYPE_DSK: + if(pDrive->uptr->fileref == NULL) { + printf(".fileref is NULL!" NLP); + } else { + fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET); + fwrite(sdata.u.data, MDSAD_SECTOR_LEN, 1, + (pDrive->uptr)->fileref); + } + break; + case IMAGE_TYPE_CPT: + printf("%s: CPT Format not supported" NLP, __FUNCTION__); + break; + default: + printf("%s: Unknown image Format" NLP, __FUNCTION__); + break; + } + } + break; + } + case MDSAD_CTLR_ORDERS: + mdsad_info->orders.dd = (Addr & 0x80) >> 7; + mdsad_info->orders.ss = (Addr & 0x40) >> 6; + mdsad_info->orders.dp = (Addr & 0x20) >> 5; + mdsad_info->orders.st = (Addr & 0x10) >> 4; + mdsad_info->orders.ds = (Addr & 0x0F); + + ds = mdsad_info->orders.ds; + switch(mdsad_info->orders.ds) { + case 0: + case 1: + mdsad_info->orders.ds = 0; + break; + case 2: + mdsad_info->orders.ds = 1; + break; + case 4: + mdsad_info->orders.ds = 2; + break; + case 8: + mdsad_info->orders.ds = 3; + break; + } + + TRACE_PRINT(ORDERS_MSG, ("MDSAD: " ADDRESS_FORMAT + " Controller Orders: Drive=%x[%x], DD=%d, SS=%d, DP=%d, ST=%d" NLP, + PCX, + mdsad_info->orders.ds, ds, + mdsad_info->orders.dd, + mdsad_info->orders.ss, + mdsad_info->orders.dp, + mdsad_info->orders.st)); + + /* use latest selected drive */ + pDrive = &mdsad_info->drive[mdsad_info->orders.ds]; + + if(mdsad_info->orders.st == 1) { + if(mdsad_info->orders.dp == 0) { + TRACE_PRINT(SEEK_MSG, ("MDSAD: " ADDRESS_FORMAT + " Step out: Track=%d%s" NLP, PCX, pDrive->track, + pDrive->track == 0 ? "[Warn: already at 0]" : "")); + if(pDrive->track > 0) /* anything to do? */ + pDrive->track--; + } else { + TRACE_PRINT(SEEK_MSG, ("MDSAD: " ADDRESS_FORMAT + " Step in: Track=%d%s" NLP, PCX, pDrive->track, + pDrive->track == (MDSAD_TRACKS - 1) ? + "[Warn: already at highest track]" : "")); + if(pDrive->track < (MDSAD_TRACKS - 1)) /* anything to do? */ + pDrive->track++; + } + } + /* always update t0 */ + mdsad_info->b_status.t0 = (pDrive->track == 0); + break; + case MDSAD_CTLR_COMMAND: +/* TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT " DM=%x" NLP, PCX, (Addr & 0xF0) >> 4)); */ + switch(Addr & 0x0F) { + case MDSAD_CMD_MOTORS_ON: + TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT + " CMD=Motors On" NLP, PCX)); + mdsad_info->com_status.mo = 1; /* Turn motors on */ + break; + + case MDSAD_CMD_NOP: + pDrive->sector_wait_count++; + switch(pDrive->sector_wait_count) { + case 10: + { + mdsad_info->com_status.sf = 1; + mdsad_info->a_status.wi = 0; + mdsad_info->a_status.re = 0; + mdsad_info->a_status.bd = 0; + pDrive->sector_wait_count = 0; + pDrive->sector++; + if(pDrive->sector >= MDSAD_SECTORS_PER_TRACK) { + pDrive->sector = 0; + mdsad_info->com_status.ix = 1; + } else { + mdsad_info->com_status.ix = 0; + } + break; + } + case 2: + mdsad_info->a_status.wi = 1; + break; + case 3: + mdsad_info->a_status.re = 1; + mdsad_info->a_status.bd = 1; + break; + default: + break; + } + break; + case MDSAD_CMD_RESET_SF: + TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT + " CMD=Reset Sector Flag" NLP, PCX)); + mdsad_info->com_status.sf = 0; + mdsad_info->datacount = 0; + break; + case MDSAD_CMD_INTR_DIS: + TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT + " CMD=Disarm Interrupt" NLP, PCX)); + mdsad_info->int_enable = 0; + break; + case MDSAD_CMD_INTR_ARM: + TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT + " CMD=Arm Interrupt" NLP, PCX)); + mdsad_info->int_enable = 1; + break; + case MDSAD_CMD_SET_BODY: + TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT + " CMD=Set Body (Diagnostic)" NLP, PCX)); + break; + case MDSAD_CMD_BEGIN_WR: + TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT + " CMD=Begin Write" NLP, PCX)); + break; + case MDSAD_CMD_RESET: + TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT + " CMD=Reset Controller" NLP, PCX)); + mdsad_info->com_status.mo = 0; /* Turn motors off */ + break; + default: + TRACE_PRINT(CMD_MSG, ("MDSAD: " ADDRESS_FORMAT + " Unsupported CMD=0x%x" NLP, PCX, Addr & 0x0F)); + break; + } + + /* Always Double-Density for now... */ + mdsad_info->com_status.dd = 1; + + cData = (mdsad_info->com_status.sf & 1) << 7; + cData |= (mdsad_info->com_status.ix & 1) << 6; + cData |= (mdsad_info->com_status.dd & 1) << 5; + cData |= (mdsad_info->com_status.mo & 1) << 4; + + mdsad_info->c_status.sc = pDrive->sector; + + switch( (Addr & 0xF0) >> 4) { + case MDSAD_A_STATUS: /* A-STATUS */ + cData |= (mdsad_info->a_status.wi & 1) << 3; + cData |= (mdsad_info->a_status.re & 1) << 2; + cData |= (mdsad_info->a_status.sp & 1) << 1; + cData |= (mdsad_info->a_status.bd & 1); + TRACE_PRINT(STATUS_MSG, ("MDSAD: " ADDRESS_FORMAT + " A-Status = <%s %s %s %s %s %s %s %s>" NLP, PCX, + cData & MDSAD_A_SF ? "SF" : " ", + cData & MDSAD_A_IX ? "IX" : " ", + cData & MDSAD_A_DD ? "DD" : " ", + cData & MDSAD_A_MO ? "MO" : " ", + cData & MDSAD_A_WI ? "WI" : " ", + cData & MDSAD_A_RE ? "RE" : " ", + cData & MDSAD_A_SP ? "SP" : " ", + cData & MDSAD_A_BD ? "BD" : " ")); + break; + case MDSAD_B_STATUS: /* B-STATUS */ + cData |= (mdsad_info->b_status.wr & 1) << 3; + cData |= (mdsad_info->b_status.sp & 1) << 2; + cData |= (mdsad_info->b_status.wp & 1) << 1; + cData |= (mdsad_info->b_status.t0 & 1); + TRACE_PRINT(STATUS_MSG, ("MDSAD: " ADDRESS_FORMAT + " B-Status = <%s %s %s %s %s %s %s %s>" NLP, PCX, + cData & MDSAD_B_SF ? "SF" : " ", + cData & MDSAD_B_IX ? "IX" : " ", + cData & MDSAD_B_DD ? "DD" : " ", + cData & MDSAD_B_MO ? "MO" : " ", + cData & MDSAD_B_WR ? "WR" : " ", + cData & MDSAD_B_SP ? "SP" : " ", + cData & MDSAD_B_WP ? "WP" : " ", + cData & MDSAD_B_T0 ? "T0" : " ")); + break; + case MDSAD_C_STATUS: /* C-STATUS */ + cData |= (mdsad_info->c_status.sc & 0xF); + TRACE_PRINT(STATUS_MSG, ("MDSAD: " ADDRESS_FORMAT + " C-Status = <%s %s %s %s %i>" NLP, PCX, + cData & MDSAD_C_SF ? "SF" : " ", + cData & MDSAD_C_IX ? "IX" : " ", + cData & MDSAD_C_DD ? "DD" : " ", + cData & MDSAD_C_MO ? "MO" : " ", cData & MDSAD_C_SC)); + break; + case MDSAD_READ_DATA: /* READ DATA */ + { + unsigned int flags; + unsigned int readlen; + + if(mdsad_info->datacount == 0) { + TRACE_PRINT(RD_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT + " READ Start: Drive: %d, Track=%d, Head=%d, Sector=%d" NLP, + PCX, + mdsad_info->orders.ds, + pDrive->track, + mdsad_info->orders.ss, + pDrive->sector)); + + checksum = 0; + + sec_offset = (pDrive->track * (MDSAD_SECTOR_LEN * MDSAD_SECTORS_PER_TRACK)) + + (mdsad_info->orders.ss * ((MDSAD_SECTOR_LEN * MDSAD_SECTORS_PER_TRACK) * MDSAD_TRACKS)) + + (pDrive->sector * MDSAD_SECTOR_LEN); + + if ((pDrive->uptr == NULL) || + (pDrive->uptr->fileref == NULL)) { + TRACE_PRINT(RD_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT + " Drive: %d not attached - read ignored." NLP, + PCX, mdsad_info->orders.ds)); + return 0xe5; + } + + switch((pDrive->uptr)->u3) + { + case IMAGE_TYPE_IMD: + if(pDrive->imd == NULL) { + printf(".imd is NULL!" NLP); + } +/* DBG_PRINT(("%s: Read: imd=%p" NLP, __FUNCTION__, mdsad_info->drive[mdsad_info->sel_drive].imd)); */ + sectRead(pDrive->imd, + pDrive->track, + mdsad_info->orders.ss, + pDrive->sector, + sdata.u.data, + MDSAD_SECTOR_LEN, + &flags, + &readlen); + break; + case IMAGE_TYPE_DSK: + if(pDrive->uptr->fileref == NULL) { + printf(".fileref is NULL!" NLP); + } else { + fseek((pDrive->uptr)->fileref, + sec_offset, SEEK_SET); + fread(&sdata.u.data[0], MDSAD_SECTOR_LEN, + 1, (pDrive->uptr)->fileref); + } + break; + case IMAGE_TYPE_CPT: + printf("%s: CPT Format not supported" + NLP, __FUNCTION__); + break; + default: + printf("%s: Unknown image Format" + NLP, __FUNCTION__); + break; + } + if(trace_level & RD_DATA_DETAIL_MSG) showdata(TRUE); + } + + if(mdsad_info->datacount < 0x200) { + cData = sdata.u.data[mdsad_info->datacount]; + + /* Exclusive OR */ + checksum ^= cData; + /* Rotate Left Circular */ + checksum = ((checksum << 1) | ((checksum & 0x80) != 0)) & 0xff; + + DBG_PRINT(("MDSAD: " ADDRESS_FORMAT + " READ-DATA[offset:%06x+%03x]=%02x" NLP, + PCX, sec_offset, mdsad_info->datacount, cData)); + } else { /* checksum */ + cData = checksum; + TRACE_PRINT(RD_DATA_MSG, ("MDSAD: " ADDRESS_FORMAT + " READ-DATA: Checksum is: 0x%02x" NLP, + PCX, cData)); + } + + mdsad_info->datacount++; + break; + } + default: + DBG_PRINT(("MDSAD: " ADDRESS_FORMAT + " Invalid DM=%x" NLP, PCX, Addr & 0xF)); + break; + } + + break; + } + return (cData); +} diff --git a/AltairZ80/s100_scp300f.c b/AltairZ80/s100_scp300f.c new file mode 100644 index 00000000..e6b7d0b4 --- /dev/null +++ b/AltairZ80/s100_scp300f.c @@ -0,0 +1,425 @@ +/************************************************************************* + * * + * $Id: s100_scp300f.c 1902 2008-05-11 02:40:41Z hharte $ * + * * + * Copyright (c) 2007-2008 Howard M. Harte. * + * http://www.hartetec.com * + * * + * 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 HOWARD M. HARTE 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 Howard M. Harte shall * + * not be used in advertising or otherwise to promote the sale, use or * + * other dealings in this Software without prior written authorization * + * Howard M. Harte. * + * * + * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. * + * * + * Module Description: * + * Seattle Computer Products SCP300F Support Board module for SIMH. * + * * + * Environment: * + * User mode only * + * * + *************************************************************************/ + +/* #define DBG_MSG */ + +#include "altairz80_defs.h" + +#if defined (_WIN32) +#include +#endif + +#ifdef DBG_MSG +#define DBG_PRINT(args) printf args +#else +#define DBG_PRINT(args) +#endif + +#define PIO_MSG 0x01 +#define UART_MSG 0x02 +#define RTC_MSG 0x04 +#define MPCL_MSG 0x08 +#define ROM_MSG 0x10 +#define TRACE_MSG 0x80 + +#define SCP300F_MAX_DRIVES 1 +#define SCP300F_ROM_SIZE (2048) +#define SCP300F_ADDR_MASK (SCP300F_ROM_SIZE - 1) + +#define UNIT_V_SCP300F_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ +#define UNIT_SCP300F_VERBOSE (1 << UNIT_V_SCP300F_VERBOSE) + +typedef struct { + PNP_INFO pnp; /* Plug and Play */ + uint8 *ram; + uint8 *rom; + uint8 rom_enabled; +} SCP300F_INFO; + +static SCP300F_INFO scp300f_info_data = { { 0xFF800, SCP300F_ROM_SIZE, 0xF0, 16 } }; +static SCP300F_INFO *scp300f_info = &scp300f_info_data; + +extern t_stat set_membase(UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat show_membase(FILE *st, UNIT *uptr, int32 val, void *desc); +extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc); +extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, + int32 (*routine)(const int32, const int32, const int32), uint8 unmap); +extern uint32 PCX; +extern REG *sim_PC; +extern int32 find_unit_index (UNIT *uptr); + +static t_stat scp300f_reset(DEVICE *scp300f_dev); + +static uint8 SCP300F_Read(const uint32 Addr); +static uint8 SCP300F_Write(const uint32 Addr, uint8 cData); + +static int32 scp300fdev(const int32 port, const int32 io, const int32 data); +static int32 scp300f_mem(const int32 port, const int32 io, const int32 data); + +static int32 trace_level = 0x00; /* Disable all tracing by default */ +static int32 scp300f_sr = 0x00; /* Sense Switch Register */ + +static UNIT scp300f_unit[] = { + { UDATA (NULL, UNIT_FIX + UNIT_DISABLE, 0) } +}; + +static REG scp300f_reg[] = { + { HRDATA (TRACELEVEL, trace_level, 16), }, + { HRDATA (SR, scp300f_sr, 8), }, + { NULL } +}; + +static MTAB scp300f_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE", &set_membase, &show_membase, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL }, + /* quiet, no warning messages */ + { UNIT_SCP300F_VERBOSE, 0, "QUIET", "QUIET", NULL }, + /* verbose, show warning messages */ + { UNIT_SCP300F_VERBOSE, UNIT_SCP300F_VERBOSE, "VERBOSE", "VERBOSE", NULL }, + { 0 } +}; + +DEVICE scp300f_dev = { + "SCP300F", scp300f_unit, scp300f_reg, scp300f_mod, + SCP300F_MAX_DRIVES, 10, 31, 1, SCP300F_MAX_DRIVES, SCP300F_MAX_DRIVES, + NULL, NULL, &scp300f_reset, + NULL, NULL, NULL, + &scp300f_info_data, (DEV_DISABLE | DEV_DIS), 0, + NULL, NULL, NULL +}; + +/* Reset routine */ +static t_stat scp300f_reset(DEVICE *dptr) +{ + PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; + + TRACE_PRINT(TRACE_MSG, ("SCP300F: Reset." NLP)); + + if(dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */ + sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &scp300fdev, TRUE); + sim_map_resource(pnp->mem_base, pnp->mem_size, RESOURCE_TYPE_MEMORY, &scp300f_mem, TRUE); + } else { + /* Connect SCP300F at base address */ + if(sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &scp300fdev, FALSE) != 0) { + printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->io_base); + return SCPE_ARG; + } + /* Connect SCP300F Memory (512K RAM, 1MB FLASH) */ + if(sim_map_resource(pnp->mem_base, pnp->mem_size, RESOURCE_TYPE_MEMORY, &scp300f_mem, FALSE) != 0) { + printf("%s: error mapping MEM resource at 0x%04x\n", __FUNCTION__, pnp->mem_base); + return SCPE_ARG; + } + + /* Re-enable ROM */ + scp300f_info->rom_enabled = 1; + } + return SCPE_OK; +} + + +static uint8 scp300f_ram[SCP300F_ROM_SIZE]; + +/* ; Seattle Computer Products 8086 Monitor version 1.5 3-19-82. + * ; by Tim Paterson + * ; This software is not copyrighted. + * + * This was assembled from source (MON.ASM) using 86DOS ASM.COM running under Windows XP. + */ +static uint8 scp300f_rom[SCP300F_ROM_SIZE] = { + 0xFC, 0x33, 0xC0, 0x8E, 0xD0, 0x8E, 0xD8, 0x8E, 0xC0, 0xBF, 0x9C, 0x01, 0xB9, 0x0E, 0x00, 0xF3, + 0xAB, 0x80, 0x0E, 0xB7, 0x01, 0x02, 0xB1, 0x04, 0xB0, 0x40, 0xBF, 0xAC, 0x01, 0xF3, 0xAB, 0xC6, + 0x06, 0xA5, 0x01, 0x0C, 0xBC, 0x9C, 0x01, 0xB0, 0x17, 0xE6, 0xF5, 0xB0, 0xF3, 0xE6, 0xF4, 0xB8, + 0x84, 0x05, 0xE7, 0xF4, 0xBE, 0x33, 0x07, 0xBA, 0xF0, 0x00, 0x2E, 0xAC, 0x8A, 0xC8, 0xE3, 0x05, + 0x2E, 0xAC, 0xEE, 0xE2, 0xFB, 0x42, 0x80, 0xFA, 0xF8, 0x75, 0xEF, 0xE8, 0x19, 0x00, 0xBE, 0xF5, + 0x07, 0xB8, 0x23, 0xE8, 0xE7, 0xF4, 0xB0, 0x0D, 0xE6, 0xF5, 0x2E, 0xAD, 0xE6, 0xF4, 0x8A, 0xC4, + 0xE6, 0xF4, 0xE8, 0x02, 0x00, 0xEB, 0xF3, 0xE8, 0x98, 0x00, 0xE8, 0x95, 0x00, 0x3C, 0x0D, 0x74, + 0x01, 0xC3, 0xBF, 0x18, 0x01, 0xC6, 0x05, 0x0D, 0xE4, 0xFF, 0xA8, 0x01, 0x74, 0x03, 0xE9, 0xF5, + 0x06, 0xBE, 0x51, 0x07, 0xE8, 0x8B, 0x00, 0xFC, 0x33, 0xC0, 0x8E, 0xD8, 0x8E, 0xC0, 0xBC, 0x9C, + 0x01, 0xC7, 0x06, 0x64, 0x00, 0xBB, 0x06, 0x8C, 0x0E, 0x66, 0x00, 0xB0, 0x3E, 0xE8, 0xC8, 0x00, + 0xE8, 0x1E, 0x00, 0xE8, 0x7F, 0x00, 0x74, 0xDF, 0x8A, 0x05, 0x2C, 0x42, 0x72, 0x10, 0x3C, 0x13, + 0x73, 0x0C, 0x47, 0xD0, 0xE0, 0x98, 0x93, 0x2E, 0xFF, 0x97, 0x7D, 0x01, 0xEB, 0xC9, 0xE9, 0xA8, + 0x02, 0xBF, 0x18, 0x01, 0x33, 0xC9, 0xE8, 0x39, 0x00, 0x3C, 0x20, 0x72, 0x1B, 0x3C, 0x7F, 0x74, + 0x0E, 0xE8, 0x94, 0x00, 0x3C, 0x40, 0x74, 0x25, 0xAA, 0x41, 0x83, 0xF9, 0x50, 0x76, 0xE7, 0xE3, + 0xE5, 0x4F, 0x49, 0xE8, 0x29, 0x00, 0xEB, 0xDE, 0x3C, 0x08, 0x74, 0xF3, 0x3C, 0x0D, 0x75, 0xD6, + 0xAA, 0xBF, 0x18, 0x01, 0xB0, 0x0D, 0xE8, 0x6F, 0x00, 0xB0, 0x0A, 0xEB, 0x6B, 0xE8, 0xF4, 0xFF, + 0xEB, 0x85, 0xFA, 0xE4, 0xF7, 0xA8, 0x02, 0x74, 0xF9, 0xE4, 0xF6, 0x24, 0x7F, 0xFB, 0xC3, 0xBE, + 0x73, 0x07, 0x2E, 0xAC, 0xE8, 0x51, 0x00, 0xD0, 0xE0, 0x73, 0xF7, 0xC3, 0xE8, 0x06, 0x00, 0x82, + 0x3D, 0x2C, 0x75, 0x0A, 0x47, 0xB0, 0x20, 0x51, 0xB1, 0xFF, 0xF3, 0xAE, 0x4F, 0x59, 0x82, 0x3D, + 0x0D, 0xC3, 0x8C, 0xDA, 0xB4, 0x00, 0xE8, 0x78, 0x00, 0x03, 0xD6, 0xEB, 0x09, 0x8C, 0xC2, 0xB4, + 0x00, 0xE8, 0x6D, 0x00, 0x03, 0xD7, 0x82, 0xD4, 0x00, 0xE8, 0x12, 0x00, 0x8A, 0xC6, 0xE8, 0x02, + 0x00, 0x8A, 0xC2, 0x8A, 0xE0, 0x51, 0xB1, 0x04, 0xD2, 0xE8, 0x59, 0xE8, 0x02, 0x00, 0x8A, 0xC4, + 0x24, 0x0F, 0x04, 0x90, 0x27, 0x14, 0x40, 0x27, 0x50, 0xE4, 0xF7, 0x24, 0x01, 0x74, 0xFA, 0x58, + 0xE6, 0xF6, 0xC3, 0xB0, 0x20, 0xEB, 0xF1, 0xE8, 0xF9, 0xFF, 0xE2, 0xFB, 0xC3, 0x76, 0x07, 0x68, + 0x03, 0x0D, 0x02, 0x88, 0x03, 0x97, 0x02, 0x6A, 0x06, 0x68, 0x03, 0x4C, 0x06, 0x68, 0x03, 0x68, + 0x03, 0x68, 0x03, 0x6A, 0x02, 0x68, 0x03, 0x59, 0x06, 0x68, 0x03, 0x68, 0x03, 0x2F, 0x04, 0xBA, + 0x02, 0x6A, 0x05, 0x8A, 0xC2, 0x24, 0x0F, 0xE8, 0x07, 0x00, 0x8A, 0xD0, 0x8A, 0xC6, 0x32, 0xF6, + 0xC3, 0xD1, 0xE2, 0xD0, 0xD4, 0xD1, 0xE2, 0xD0, 0xD4, 0xD1, 0xE2, 0xD0, 0xD4, 0xD1, 0xE2, 0xD0, + 0xD4, 0xC3, 0xB9, 0x05, 0x00, 0xE8, 0x22, 0x01, 0x50, 0x52, 0xE8, 0x4F, 0xFF, 0x82, 0x3D, 0x4C, + 0x74, 0x1C, 0xBA, 0x80, 0x00, 0xE8, 0x30, 0x01, 0x72, 0x1B, 0xB9, 0x05, 0x00, 0xE8, 0x0A, 0x01, + 0x8B, 0xCA, 0x5A, 0x5B, 0x2B, 0xCA, 0x1A, 0xE7, 0x75, 0x1D, 0x93, 0x41, 0xEB, 0x0B, 0x47, 0xB9, + 0x04, 0x00, 0xE8, 0xF5, 0x00, 0x8B, 0xCA, 0x5A, 0x58, 0x8B, 0xDA, 0x81, 0xE3, 0x0F, 0x00, 0xE3, + 0x04, 0x03, 0xD9, 0x73, 0x9E, 0x74, 0x9C, 0xB8, 0x52, 0x47, 0xE9, 0x1F, 0x03, 0xE8, 0xB2, 0xFF, + 0x50, 0xE8, 0x4E, 0x01, 0x1F, 0x8B, 0xF2, 0xE8, 0x18, 0xFF, 0x56, 0xE8, 0x55, 0xFF, 0xAC, 0xE8, + 0x31, 0xFF, 0x5A, 0x49, 0x74, 0x17, 0x8B, 0xC6, 0xA8, 0x0F, 0x74, 0x0C, 0x52, 0xA8, 0x07, 0x75, + 0xEA, 0xB0, 0x2D, 0xE8, 0x32, 0xFF, 0xEB, 0xE6, 0xE8, 0x02, 0x00, 0xEB, 0xDA, 0x51, 0x8B, 0xC6, + 0x8B, 0xF2, 0x2B, 0xC2, 0x8B, 0xD8, 0xD1, 0xE0, 0x03, 0xC3, 0xB9, 0x33, 0x00, 0x2B, 0xC8, 0xE8, + 0x25, 0xFF, 0x8B, 0xCB, 0xAC, 0x24, 0x7F, 0x3C, 0x7F, 0x74, 0x04, 0x3C, 0x20, 0x73, 0x02, 0xB0, + 0x2E, 0xE8, 0x04, 0xFF, 0xE2, 0xEE, 0x59, 0xE9, 0x8A, 0xFE, 0xE8, 0x55, 0xFF, 0x51, 0x50, 0x8B, + 0xF2, 0xB9, 0x05, 0x00, 0xE8, 0x73, 0x00, 0xE8, 0xE8, 0x00, 0xE8, 0x26, 0xFF, 0x8B, 0xFA, 0x5B, + 0x8E, 0xDB, 0x8E, 0xC0, 0x59, 0x3B, 0xFE, 0x1B, 0xC3, 0x72, 0x07, 0x49, 0x03, 0xF1, 0x03, 0xF9, + 0xFD, 0x41, 0xA4, 0x49, 0xF3, 0xA4, 0xC3, 0xE8, 0x28, 0xFF, 0x51, 0x50, 0x52, 0xE8, 0xB4, 0x00, + 0x5F, 0x07, 0x59, 0x3B, 0xD9, 0xBE, 0x18, 0x01, 0xE3, 0x02, 0x73, 0xE6, 0x2B, 0xCB, 0x87, 0xD9, + 0x57, 0xF3, 0xA4, 0x5E, 0x8B, 0xCB, 0x06, 0x1F, 0xEB, 0xD8, 0xE8, 0x05, 0xFF, 0x51, 0x50, 0x52, + 0xE8, 0x91, 0x00, 0x4B, 0x5F, 0x07, 0x59, 0x2B, 0xCB, 0xBE, 0x18, 0x01, 0xAC, 0xAE, 0xE0, 0xFD, + 0x75, 0xC4, 0x53, 0x87, 0xCB, 0x57, 0xF3, 0xA6, 0x8B, 0xCB, 0x5F, 0x5B, 0x75, 0x08, 0x4F, 0xE8, + 0x5B, 0xFE, 0x47, 0xE8, 0x0E, 0xFE, 0xE3, 0xAE, 0xEB, 0xDF, 0xE8, 0x2F, 0xFE, 0x33, 0xD2, 0x8A, + 0xE6, 0xE8, 0x14, 0x00, 0x72, 0x73, 0x8A, 0xD0, 0x47, 0x49, 0xE8, 0x0B, 0x00, 0x72, 0x97, 0xE3, + 0x68, 0xE8, 0xAD, 0xFE, 0x0A, 0xD0, 0xEB, 0xF0, 0x8A, 0x05, 0x2C, 0x30, 0x72, 0x88, 0x3C, 0x0A, + 0xF5, 0x73, 0x83, 0x2C, 0x07, 0x3C, 0x0A, 0x72, 0x03, 0x3C, 0x10, 0xF5, 0xC3, 0xE8, 0xFC, 0xFD, + 0xE8, 0xE5, 0xFF, 0x72, 0x0B, 0xB9, 0x02, 0x00, 0xE8, 0xBF, 0xFF, 0x88, 0x17, 0x43, 0xF8, 0xC3, + 0x8A, 0x05, 0x3C, 0x27, 0x74, 0x06, 0x3C, 0x22, 0x74, 0x02, 0xF9, 0xC3, 0x8A, 0xE0, 0x47, 0x8A, + 0x05, 0x47, 0x3C, 0x0D, 0x74, 0x23, 0x3A, 0xC4, 0x75, 0x05, 0x3A, 0x25, 0x75, 0xE0, 0x47, 0x88, + 0x07, 0x43, 0xEB, 0xEB, 0xBB, 0x18, 0x01, 0xE8, 0xC3, 0xFF, 0x73, 0xFB, 0x81, 0xEB, 0x18, 0x01, + 0x74, 0x07, 0xE8, 0xC0, 0xFD, 0x75, 0x02, 0xC3, 0x4F, 0x81, 0xEF, 0x17, 0x01, 0x8B, 0xCF, 0xE8, + 0x05, 0xFE, 0xBE, 0x6A, 0x07, 0xE8, 0x9A, 0xFD, 0xE9, 0x0C, 0xFD, 0xE8, 0xD6, 0xFF, 0x5F, 0x07, + 0xBE, 0x18, 0x01, 0x8B, 0xCB, 0xF3, 0xA4, 0xC3, 0xB9, 0x05, 0x00, 0xE8, 0x5C, 0xFF, 0xE8, 0x12, + 0xFE, 0x82, 0xEC, 0x08, 0x80, 0xC6, 0x80, 0x50, 0x52, 0xE8, 0x89, 0xFD, 0x75, 0xDD, 0x5F, 0x07, + 0xE8, 0x9A, 0xFD, 0xE8, 0xCD, 0xFD, 0x26, 0x8A, 0x05, 0xE8, 0xA7, 0xFD, 0xB0, 0x2E, 0xE8, 0xB7, + 0xFD, 0xB9, 0x02, 0x00, 0xBA, 0x00, 0x00, 0xE8, 0x48, 0xFD, 0x8A, 0xE0, 0xE8, 0x4B, 0xFF, 0x86, + 0xE0, 0x72, 0x0C, 0xE8, 0xA2, 0xFD, 0x8A, 0xF2, 0x8A, 0xD4, 0xE2, 0xEB, 0xE8, 0x33, 0xFD, 0x3C, + 0x08, 0x74, 0x19, 0x3C, 0x7F, 0x74, 0x15, 0x3C, 0x2D, 0x74, 0x4D, 0x3C, 0x0D, 0x74, 0x2F, 0x3C, + 0x20, 0x74, 0x31, 0xB0, 0x07, 0xE8, 0x80, 0xFD, 0xE3, 0xE2, 0xEB, 0xCB, 0x82, 0xF9, 0x02, 0x74, + 0xC6, 0xFE, 0xC1, 0x8A, 0xD6, 0x8A, 0xF5, 0xE8, 0x15, 0xFD, 0xEB, 0xBB, 0x82, 0xF9, 0x02, 0x74, + 0x0B, 0x51, 0xB1, 0x04, 0xD2, 0xE6, 0x59, 0x0A, 0xD6, 0x26, 0x88, 0x15, 0x47, 0xC3, 0xE8, 0xEB, + 0xFF, 0xE9, 0xE0, 0xFC, 0xE8, 0xE5, 0xFF, 0x41, 0x41, 0xE8, 0x5B, 0xFD, 0x8B, 0xC7, 0x24, 0x07, + 0x75, 0x84, 0xE8, 0xCF, 0xFC, 0xE9, 0x78, 0xFF, 0xE8, 0xD1, 0xFF, 0x4F, 0x4F, 0xEB, 0xF3, 0xE8, + 0xEA, 0xFC, 0x74, 0x62, 0x8A, 0x15, 0x47, 0x8A, 0x35, 0x82, 0xFE, 0x0D, 0x74, 0x76, 0x47, 0xE8, + 0x20, 0xFF, 0x82, 0xFE, 0x20, 0x74, 0x6D, 0xBF, 0xD7, 0x06, 0x92, 0x0E, 0x07, 0xB9, 0x0E, 0x00, + 0xF2, 0xAF, 0x75, 0x3C, 0x0B, 0xC9, 0x75, 0x06, 0x4F, 0x4F, 0x2E, 0x8B, 0x45, 0xFE, 0xE8, 0x07, + 0xFD, 0x8A, 0xC4, 0xE8, 0x02, 0xFD, 0xE8, 0x0A, 0xFD, 0x1E, 0x07, 0x8D, 0x9D, 0xC3, 0xFA, 0x8B, + 0x17, 0xE8, 0xD8, 0xFC, 0xE8, 0x7D, 0xFC, 0xB0, 0x3A, 0xE8, 0xEC, 0xFC, 0xE8, 0x42, 0xFC, 0xE8, + 0xA3, 0xFC, 0x74, 0x0B, 0xB9, 0x04, 0x00, 0xE8, 0x63, 0xFE, 0xE8, 0xD5, 0xFE, 0x89, 0x17, 0xC3, + 0xB8, 0x42, 0x52, 0xE9, 0x96, 0x00, 0xBE, 0xD7, 0x06, 0xBB, 0x9C, 0x01, 0xB9, 0x08, 0x00, 0xE8, + 0x65, 0x00, 0xE8, 0x4F, 0xFC, 0xB9, 0x05, 0x00, 0xE8, 0x5C, 0x00, 0xE8, 0xC5, 0xFC, 0xE8, 0x93, + 0x00, 0xE9, 0x40, 0xFC, 0x82, 0xFA, 0x46, 0x75, 0xD7, 0xE8, 0x88, 0x00, 0xB0, 0x2D, 0xE8, 0xA7, + 0xFC, 0xE8, 0xFD, 0xFB, 0xE8, 0x5E, 0xFC, 0x33, 0xDB, 0x8B, 0x16, 0xB6, 0x01, 0x8B, 0xF7, 0xAD, + 0x3C, 0x0D, 0x74, 0x66, 0x82, 0xFC, 0x0D, 0x74, 0x66, 0xBF, 0xF3, 0x06, 0xB9, 0x20, 0x00, 0x0E, + 0x07, 0xF2, 0xAF, 0x75, 0x5A, 0x8A, 0xE9, 0x80, 0xE1, 0x0F, 0xB8, 0x01, 0x00, 0xD3, 0xC0, 0x85, + 0xC3, 0x75, 0x33, 0x0B, 0xD8, 0x0B, 0xD0, 0xF6, 0xC5, 0x10, 0x75, 0x02, 0x33, 0xD0, 0x8B, 0xFE, + 0x1E, 0x07, 0xE8, 0x17, 0xFC, 0xEB, 0xC6, 0x2E, 0xAD, 0xE8, 0x5C, 0xFC, 0x8A, 0xC4, 0xE8, 0x57, + 0xFC, 0xB0, 0x3D, 0xE8, 0x52, 0xFC, 0x8B, 0x17, 0x43, 0x43, 0xE8, 0x2F, 0xFC, 0xE8, 0x53, 0xFC, + 0xE8, 0x50, 0xFC, 0xE2, 0xE2, 0xC3, 0xB8, 0x44, 0x46, 0xE8, 0x0E, 0x00, 0xE8, 0x39, 0xFC, 0x8A, + 0xC4, 0xE8, 0x34, 0xFC, 0xBE, 0x6B, 0x07, 0xE9, 0x3B, 0xFE, 0x89, 0x16, 0xB6, 0x01, 0xC3, 0xB8, + 0x42, 0x46, 0xEB, 0xE5, 0xBE, 0xF3, 0x06, 0xB9, 0x10, 0x00, 0x8B, 0x16, 0xB6, 0x01, 0x2E, 0xAD, + 0xD1, 0xE2, 0x72, 0x04, 0x2E, 0x8B, 0x44, 0x1E, 0x0B, 0xC0, 0x74, 0x0B, 0xE8, 0x09, 0xFC, 0x8A, + 0xC4, 0xE8, 0x04, 0xFC, 0xE8, 0x0C, 0xFC, 0xE2, 0xE5, 0xC3, 0xE8, 0xAF, 0xFB, 0xE8, 0x98, 0xFD, + 0xBA, 0x01, 0x00, 0x72, 0x06, 0xB9, 0x04, 0x00, 0xE8, 0x6F, 0xFD, 0x89, 0x16, 0x02, 0x01, 0xE8, + 0xE0, 0xFD, 0xC7, 0x06, 0x00, 0x01, 0x00, 0x00, 0x80, 0x0E, 0xB7, 0x01, 0x01, 0xC7, 0x06, 0x0C, + 0x00, 0xD1, 0x05, 0x8C, 0x0E, 0x0E, 0x00, 0xC7, 0x06, 0x04, 0x00, 0xD8, 0x05, 0x8C, 0x0E, 0x06, + 0x00, 0xFA, 0xC7, 0x06, 0x64, 0x00, 0xD8, 0x05, 0x8C, 0x0E, 0x66, 0x00, 0xBC, 0x9C, 0x01, 0x58, + 0x5B, 0x59, 0x5A, 0x5D, 0x5D, 0x5E, 0x5F, 0x07, 0x07, 0x17, 0x8B, 0x26, 0xA4, 0x01, 0xFF, 0x36, + 0xB6, 0x01, 0xFF, 0x36, 0xB2, 0x01, 0xFF, 0x36, 0xB4, 0x01, 0x8E, 0x1E, 0xAC, 0x01, 0xCF, 0xEB, + 0xB1, 0x87, 0xEC, 0xFF, 0x4E, 0x00, 0x87, 0xEC, 0x2E, 0x89, 0x26, 0xA4, 0x09, 0x2E, 0x8C, 0x16, + 0xB0, 0x09, 0x33, 0xE4, 0x8E, 0xD4, 0xBC, 0xB0, 0x01, 0x06, 0x1E, 0x57, 0x56, 0x55, 0x4C, 0x4C, + 0x52, 0x51, 0x53, 0x50, 0x16, 0x1F, 0x8B, 0x26, 0xA4, 0x01, 0x8E, 0x16, 0xB0, 0x01, 0x8F, 0x06, + 0xB4, 0x01, 0x8F, 0x06, 0xB2, 0x01, 0x58, 0x80, 0xE4, 0xFE, 0xA3, 0xB6, 0x01, 0x89, 0x26, 0xA4, + 0x01, 0x1E, 0x07, 0x1E, 0x17, 0xBC, 0x9C, 0x01, 0xC7, 0x06, 0x64, 0x00, 0xBB, 0x06, 0xB0, 0x20, + 0xE6, 0xF2, 0xFB, 0xFC, 0xE8, 0xCD, 0xFA, 0xE8, 0x6C, 0xFE, 0xFF, 0x0E, 0x02, 0x01, 0x75, 0x9F, + 0xBE, 0x04, 0x01, 0x8B, 0x0E, 0x00, 0x01, 0xE3, 0x10, 0x8B, 0x54, 0x14, 0xAD, 0x50, 0xE8, 0x62, + 0xFB, 0x8E, 0xC0, 0x8B, 0xFA, 0x58, 0xAA, 0xE2, 0xF0, 0xE9, 0x3B, 0xFA, 0xB9, 0x04, 0x00, 0xE8, + 0x98, 0xFC, 0xEC, 0xE8, 0xFD, 0xFA, 0xE9, 0x9B, 0xFA, 0xB9, 0x04, 0x00, 0xE8, 0x8B, 0xFC, 0x52, + 0xB9, 0x02, 0x00, 0xE8, 0x84, 0xFC, 0x92, 0x5A, 0xEE, 0xC3, 0xBB, 0x18, 0x01, 0x33, 0xF6, 0xE8, + 0xAA, 0xFA, 0x74, 0x19, 0xB9, 0x05, 0x00, 0xE8, 0x70, 0xFC, 0x89, 0x17, 0x88, 0x67, 0xED, 0x43, + 0x43, 0x46, 0x83, 0xFE, 0x0B, 0x75, 0xE8, 0xB8, 0x42, 0x50, 0xE9, 0x9F, 0xFE, 0x89, 0x36, 0x00, + 0x01, 0xE8, 0xCE, 0xFC, 0x8B, 0xCE, 0xE3, 0x1A, 0xBE, 0x04, 0x01, 0x8B, 0x54, 0x14, 0xAD, 0xE8, + 0x01, 0xFB, 0x8E, 0xD8, 0x8B, 0xFA, 0x8A, 0x05, 0xC6, 0x05, 0xCC, 0x06, 0x1F, 0x88, 0x44, 0xFE, + 0xE2, 0xE9, 0xC7, 0x06, 0x02, 0x01, 0x01, 0x00, 0xE9, 0xD2, 0xFE, 0x50, 0xB0, 0x20, 0xE6, 0xF2, + 0xE4, 0xF6, 0x24, 0x7F, 0x3C, 0x13, 0x75, 0x03, 0xE8, 0x37, 0xFA, 0x3C, 0x03, 0x74, 0x02, 0x58, + 0xCF, 0xE8, 0x20, 0xFA, 0xE9, 0xB0, 0xF9, 0x41, 0x58, 0x42, 0x58, 0x43, 0x58, 0x44, 0x58, 0x53, + 0x50, 0x42, 0x50, 0x53, 0x49, 0x44, 0x49, 0x44, 0x53, 0x45, 0x53, 0x53, 0x53, 0x43, 0x53, 0x49, + 0x50, 0x50, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x56, 0x44, 0x4E, 0x45, + 0x49, 0x00, 0x00, 0x4E, 0x47, 0x5A, 0x52, 0x00, 0x00, 0x41, 0x43, 0x00, 0x00, 0x50, 0x45, 0x00, + 0x00, 0x43, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x56, 0x55, 0x50, 0x44, + 0x49, 0x00, 0x00, 0x50, 0x4C, 0x4E, 0x5A, 0x00, 0x00, 0x4E, 0x41, 0x00, 0x00, 0x50, 0x4F, 0x00, + 0x00, 0x4E, 0x43, 0x01, 0x19, 0x04, 0x10, 0x02, 0x0F, 0xFD, 0x01, 0x19, 0x04, 0x18, 0x01, 0x0B, + 0xFD, 0x06, 0x63, 0x0B, 0x07, 0x00, 0x06, 0x00, 0x02, 0x70, 0x05, 0x00, 0x04, 0xB7, 0x77, 0xCE, + 0x37, 0x0D, 0x0A, 0x0A, 0x53, 0x43, 0x50, 0x20, 0x38, 0x30, 0x38, 0x36, 0x20, 0x4D, 0x6F, 0x6E, + 0x69, 0x74, 0x6F, 0x72, 0x20, 0x31, 0x2E, 0x35, 0x0D, 0x8A, 0x5E, 0x20, 0x45, 0x72, 0x72, 0x6F, + 0x72, 0x0D, 0x8A, 0x08, 0x20, 0x88, 0x57, 0xB0, 0x01, 0xE6, 0x02, 0xB0, 0x84, 0xE6, 0x00, 0xB0, + 0x7F, 0xE6, 0x04, 0xB6, 0x21, 0xB0, 0xD0, 0xE6, 0x30, 0xD4, 0x0A, 0xD4, 0x0A, 0xD4, 0x0A, 0xD4, + 0x0A, 0x80, 0xF6, 0x10, 0x8A, 0xC6, 0xE6, 0x34, 0xBF, 0x00, 0x02, 0xB0, 0x0F, 0xE6, 0x30, 0xE4, + 0x34, 0xD0, 0xC8, 0x73, 0xFA, 0xE4, 0x30, 0x24, 0x98, 0x75, 0xDA, 0xB0, 0x01, 0xE6, 0x32, 0x8A, + 0xC6, 0x0C, 0x80, 0xE6, 0x34, 0xB2, 0x33, 0xB0, 0x8C, 0xE6, 0x30, 0xEB, 0x02, 0xEC, 0xAA, 0xE4, + 0x34, 0xD0, 0xC8, 0x73, 0xF8, 0xE4, 0x30, 0x24, 0x9C, 0x75, 0xBA, 0xC7, 0x06, 0xB2, 0x01, 0x00, + 0x00, 0xC7, 0x06, 0xB4, 0x01, 0x00, 0x02, 0x5F, 0xE9, 0x8F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEA, 0x00, 0x00, 0x80, 0xFF, 0x0D, 0x00, 0x68, 0x00, 0xA0, 0x01, 0x40, 0x03, 0x78, 0x04, 0x00 +}; + + static int32 scp300f_mem(const int32 Addr, const int32 write, const int32 data) +{ +/* DBG_PRINT(("SCP300F: ROM %s, Addr %04x" NLP, write ? "WR" : "RD", Addr)); */ + if(write) { + if(scp300f_info->rom_enabled) + { + TRACE_PRINT(ROM_MSG, ("SCP300F: " ADDRESS_FORMAT " WR ROM[0x%05x]: Cannot write to ROM." NLP, PCX, Addr)); + } else { + } + return 0; + } else { + if(scp300f_info->rom_enabled) + { + return scp300f_rom[Addr & SCP300F_ADDR_MASK]; + } else { + return scp300f_ram[Addr & SCP300F_ADDR_MASK]; + } + } +} + +static int32 scp300fdev(const int32 port, const int32 io, const int32 data) +{ +/* DBG_PRINT(("SCP300F: IO %s, Port %02x\n", io ? "WR" : "RD", port)); */ + if(io) { + SCP300F_Write(port, data); + return 0; + } else { + return(SCP300F_Read(port)); + } +} + +#define SCP300F_MPIC_0 0x00 /* Master PIC */ +#define SCP300F_MPIC_1 0x01 /* Master PIC */ +#define SCP300F_SPIC_0 0x02 /* Slave PIC */ +#define SCP300F_SPIC_1 0x03 /* Slave PIC */ +#define SCP300F_9513_DATA 0x04 /* 9513 counter/timer Data Port */ +#define SCP300F_9513_STATUS 0x05 /* 9513 counter/timer Status/Control Port */ +#define SCP300F_UART_DATA 0x06 /* UART Data Register */ +#define SCP300F_UART_STATUS 0x07 /* UART Status */ + +#define SCP300F_PIO_DATA 0x0C /* PIO Data */ +#define SCP300F_PIO_STATUS 0x0D /* PIO Status */ +#define SCP300F_EPROM_DIS 0x0E /* EPROM Disable */ +#define SCP300F_SENSE_SW 0x0F /* Sense Switch */ + +extern int32 sio0d(const int32 port, const int32 io, const int32 data); +extern int32 sio0s(const int32 port, const int32 io, const int32 data); + +static uint8 SCP300F_Read(const uint32 Addr) +{ + uint8 cData = 0xFF; + + switch(Addr & 0xF) { + case SCP300F_MPIC_0: + case SCP300F_MPIC_1: + TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " Master 8259 DATA RD[%02x]: not implemented." NLP, PCX, Addr)); + break; + case SCP300F_SPIC_0: + case SCP300F_SPIC_1: + TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " Slave 8259 DATA RD[%02x]: not implemented." NLP, PCX, Addr)); + break; + case SCP300F_9513_DATA: + TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " 9513 DATA RD[%02x]: not implemented." NLP, PCX, Addr)); + break; + case SCP300F_9513_STATUS: + TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " 9513 STAT RD[%02x]: not implemented." NLP, PCX, Addr)); + break; + case SCP300F_UART_DATA: /* UART is handled by the 2SIO, if this gets called, then the 2SIO was not */ + case SCP300F_UART_STATUS: /* configured properly. */ + TRACE_PRINT(TRACE_MSG, ("SCP300F: " ADDRESS_FORMAT " RD[%02x]: UART not configured properly." NLP, PCX, Addr)); + break; + case SCP300F_PIO_DATA: + TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " PIO DATA RD[%02x]: not implemented." NLP, PCX, Addr)); + break; + case SCP300F_PIO_STATUS: + TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " PIO STATUS RD[%02x]: not implemented." NLP, PCX, Addr)); + break; + case SCP300F_SENSE_SW: /* Sense Switch */ + cData = scp300f_sr; + break; + default: + TRACE_PRINT(TRACE_MSG, ("SCP300F: " ADDRESS_FORMAT " RD[%02x]: not Implemented." NLP, PCX, Addr)); + break; + } + + return (cData); + +} + +static uint8 SCP300F_Write(const uint32 Addr, uint8 cData) +{ + + switch(Addr & 0xF) { + case SCP300F_MPIC_0: + case SCP300F_MPIC_1: + TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " Master 8259 DATA WR[%02x]=%02x: not implemented." NLP, PCX, Addr, cData)); + break; + case SCP300F_SPIC_0: + case SCP300F_SPIC_1: + TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " Slave 8259 DATA WR[%02x]=%02x: not implemented." NLP, PCX, Addr, cData)); + break; + case SCP300F_9513_DATA: + TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " 9513 DATA WR[%02x]=%02x: not implemented." NLP, PCX, Addr, cData)); + break; + case SCP300F_9513_STATUS: + TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " 9513 STAT WR[%02x]=%02x: not implemented." NLP, PCX, Addr, cData)); + break; + case SCP300F_UART_DATA: /* UART is handled by the 2SIO, if this gets called, then the 2SIO was not */ + case SCP300F_UART_STATUS: /* configured properly. */ + TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " WR[%02x]: UART not configured properly." NLP, PCX, Addr)); + break; + case SCP300F_PIO_DATA: + TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " PIO DATA WR[%02x]=%02x: not implemented." NLP, PCX, Addr, cData)); + break; + case SCP300F_PIO_STATUS: + TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " WR[%02x]: Cannot write to PIO STATUS." NLP, PCX, Addr)); + break; + case SCP300F_SENSE_SW: + TRACE_PRINT(UART_MSG, ("SCP300F: " ADDRESS_FORMAT " WR[%02x]: Cannot write to SR." NLP, PCX, Addr)); + break; + default: + TRACE_PRINT(TRACE_MSG, ("SCP300F: " ADDRESS_FORMAT " WR[0x%02x]=0x%02x: not Implemented." NLP, PCX, Addr, cData)); + break; + } + + return(0); +} + diff --git a/AltairZ80/s100_selchan.c b/AltairZ80/s100_selchan.c new file mode 100644 index 00000000..09c508ae --- /dev/null +++ b/AltairZ80/s100_selchan.c @@ -0,0 +1,208 @@ +/************************************************************************* + * * + * $Id: s100_selchan.c 1771 2008-01-09 07:10:46Z hharte $ * + * * + * Copyright (c) 2007-2008 Howard M. Harte. * + * http://www.hartetec.com * + * * + * 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 HOWARD M. HARTE 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 Howard M. Harte shall * + * not be used in advertising or otherwise to promote the sale, use or * + * other dealings in this Software without prior written authorization * + * Howard M. Harte. * + * * + * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. * + * * + * Module Description: * + * CompuPro Selector Channel module for SIMH. * + * * + * Environment: * + * User mode only * + * * + *************************************************************************/ + +/*#define DBG_MSG */ + +#include "altairz80_defs.h" + +#if defined (_WIN32) +#include +#endif + +#ifdef DBG_MSG +#define DBG_PRINT(args) printf args +#else +#define DBG_PRINT(args) +#endif + +#define TRACE_MSG 0x01 +#define DMA_MSG 0x02 + +#define SELCHAN_MAX_DRIVES 1 + +#define UNIT_V_SELCHAN_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ +#define UNIT_SELCHAN_VERBOSE (1 << UNIT_V_SELCHAN_VERBOSE) + +typedef struct { + PNP_INFO pnp; /* Plug and Play */ + uint32 selchan; /* Selector Channel Register */ + uint32 dma_addr; /* DMA Transfer Address */ + uint32 dma_mode; /* DMA Mode register */ + uint8 reg_cnt; /* Counter for selchan register */ +} SELCHAN_INFO; + +static SELCHAN_INFO selchan_info_data = { { 0x0, 0, 0xF0, 1 } }; +static SELCHAN_INFO *selchan_info = &selchan_info_data; +int32 selchan_dma(uint8 *buf, uint32 len); + +extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc); +extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, + int32 (*routine)(const int32, const int32, const int32), uint8 unmap); +extern uint32 PCX; +extern REG *sim_PC; + +/* These are needed for DMA. PIO Mode has not been implemented yet. */ +extern void PutBYTEWrapper(const uint32 Addr, const uint32 Value); +extern uint8 GetBYTEWrapper(const uint32 Addr); + +static t_stat selchan_reset(DEVICE *selchan_dev); + +static int32 selchandev(const int32 port, const int32 io, const int32 data); + +static int32 trace_level = 0; /* Disable all tracing by default */ + +static UNIT selchan_unit[] = { + { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ROABLE, 0) } +}; + +static REG selchan_reg[] = { + { HRDATA (TRACELEVEL, trace_level, 16), }, + { NULL } +}; + +static MTAB selchan_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL }, + /* quiet, no warning messages */ + { UNIT_SELCHAN_VERBOSE, 0, "QUIET", "QUIET", NULL }, + /* verbose, show warning messages */ + { UNIT_SELCHAN_VERBOSE, UNIT_SELCHAN_VERBOSE, "VERBOSE", "VERBOSE", NULL }, + { 0 } +}; + +DEVICE selchan_dev = { + "SELCHAN", selchan_unit, selchan_reg, selchan_mod, + SELCHAN_MAX_DRIVES, 10, 31, 1, SELCHAN_MAX_DRIVES, SELCHAN_MAX_DRIVES, + NULL, NULL, &selchan_reset, + NULL, NULL, NULL, + &selchan_info_data, (DEV_DISABLE | DEV_DIS), 0, + NULL, NULL, NULL +}; + +/* Reset routine */ +static t_stat selchan_reset(DEVICE *dptr) +{ + PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; + + if(dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */ + sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &selchandev, TRUE); + } else { + /* Connect SELCHAN at base address */ + if(sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &selchandev, FALSE) != 0) { + printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->io_base); + return SCPE_ARG; + } + } + return SCPE_OK; +} + +#define SELCHAN_MODE_WRITE 0x80 /* Selector Channel Memory or I/O Write */ +#define SELCHAN_MODE_IO 0x40 /* Set if I/O Access, otherwise memory */ +#define SELCHAN_MODE_CNT_UP 0x20 /* Set = DMA Address Count Up, otherwise down. (Mem only */ +#define SELCHAN_MODE_WAIT 0x10 /* Insert one wait state. */ +#define SELCHAN_MODE_DMA_MASK 0x0F /* Mask for DMA Priority field */ + +static int32 selchandev(const int32 port, const int32 io, const int32 data) +{ + DBG_PRINT(("SELCHAN: IO %s, Port %02x" NLP, io ? "WR" : "RD", port)); + if(io) { + selchan_info->selchan <<= 8; + selchan_info->selchan &= 0xFFFFFF00; + selchan_info->selchan |= data; + + selchan_info->dma_addr = (selchan_info->selchan & 0xFFFFF00) >> 8; + selchan_info->dma_mode = (selchan_info->selchan & 0xFF); + + selchan_info->reg_cnt ++; + + if(selchan_info->reg_cnt == 4) { + TRACE_PRINT(TRACE_MSG, ("SELCHAN: " ADDRESS_FORMAT " DMA=0x%06x, Mode=0x%02x (%s, %s, %s)" NLP, + PCX, + selchan_info->dma_addr, + selchan_info->dma_mode, + selchan_info->dma_mode & SELCHAN_MODE_WRITE ? "WR" : "RD", + selchan_info->dma_mode & SELCHAN_MODE_IO ? "I/O" : "MEM", + selchan_info->dma_mode & SELCHAN_MODE_IO ? "FIX" : selchan_info->dma_mode & SELCHAN_MODE_CNT_UP ? "INC" : "DEC")); + } + + return 0; + } else { + TRACE_PRINT(TRACE_MSG, ("SELCHAN: " ADDRESS_FORMAT " Reset" NLP, PCX)); + selchan_info->reg_cnt = 0; + return(0xFF); + } +} + +int32 selchan_dma(uint8 *buf, uint32 len) +{ + uint32 i; + + if(selchan_info->reg_cnt != 4) { + printf("SELCHAN: " ADDRESS_FORMAT " Programming error: selector channel disabled." NLP, + PCX); + return (-1); + } + + if(selchan_info->dma_mode & SELCHAN_MODE_IO) + { + printf("SELCHAN: " ADDRESS_FORMAT " I/O Not supported" NLP, PCX); + return (-1); + } else { + TRACE_PRINT(DMA_MSG, ("SELCHAN: " ADDRESS_FORMAT " DMA %s Transfer, len=%d" NLP, + PCX, + (selchan_info->dma_mode & SELCHAN_MODE_WRITE) ? "WR" : "RD", len)); + for(i=0;idma_mode & SELCHAN_MODE_WRITE) { + PutBYTEWrapper(selchan_info->dma_addr + i, buf[i]); + } else { + buf[i] = GetBYTEWrapper(selchan_info->dma_addr + i); + } + } + + if(selchan_info->dma_mode & SELCHAN_MODE_CNT_UP) { + selchan_info->dma_addr += i; + } else { + selchan_info->dma_addr -= i; + } + } + + return(0); +} diff --git a/AltairZ80/s100_ss1.c b/AltairZ80/s100_ss1.c new file mode 100644 index 00000000..39b93879 --- /dev/null +++ b/AltairZ80/s100_ss1.c @@ -0,0 +1,246 @@ +/************************************************************************* + * * + * $Id: s100_ss1.c 1773 2008-01-11 05:46:19Z hharte $ * + * * + * Copyright (c) 2007-2008 Howard M. Harte. * + * http://www.hartetec.com * + * * + * 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 HOWARD M. HARTE 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 Howard M. Harte shall * + * not be used in advertising or otherwise to promote the sale, use or * + * other dealings in this Software without prior written authorization * + * Howard M. Harte. * + * * + * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. * + * * + * Module Description: * + * CompuPro System Support 1 module for SIMH. * + * Note this does not include the Boot ROM on the System Support 1 Card * + * * + * Environment: * + * User mode only * + * * + *************************************************************************/ + +/*#define DBG_MSG */ + +#include "altairz80_defs.h" + +#if defined (_WIN32) +#include +#endif + +#ifdef DBG_MSG +#define DBG_PRINT(args) printf args +#else +#define DBG_PRINT(args) +#endif + +#define TRACE_MSG 0x01 +#define DMA_MSG 0x02 + +#define SS1_MAX_DRIVES 1 + +#define UNIT_V_SS1_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ +#define UNIT_SS1_VERBOSE (1 << UNIT_V_SS1_VERBOSE) + +typedef struct { + PNP_INFO pnp; /* Plug and Play */ +} SS1_INFO; + +static SS1_INFO ss1_info_data = { { 0x0, 0, 0x50, 12 } }; +/* static SS1_INFO *ss1_info = &ss1_info_data;*/ + +extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc); +extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, + int32 (*routine)(const int32, const int32, const int32), uint8 unmap); +extern uint32 PCX; +extern REG *sim_PC; + +/* These are needed for DMA. PIO Mode has not been implemented yet. */ +extern void PutBYTEWrapper(const uint32 Addr, const uint32 Value); +extern uint8 GetBYTEWrapper(const uint32 Addr); + +static t_stat ss1_reset(DEVICE *ss1_dev); +static uint8 SS1_Read(const uint32 Addr); +static uint8 SS1_Write(const uint32 Addr, uint8 cData); + + +static int32 ss1dev(const int32 port, const int32 io, const int32 data); + +static int32 trace_level = 0x00; /* Disable all tracing by default */ + +static UNIT ss1_unit[] = { + { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ROABLE, 0) } +}; + +static REG ss1_reg[] = { + { HRDATA (TRACELEVEL, trace_level, 16), }, + { NULL } +}; + +static MTAB ss1_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL }, + /* quiet, no warning messages */ + { UNIT_SS1_VERBOSE, 0, "QUIET", "QUIET", NULL }, + /* verbose, show warning messages */ + { UNIT_SS1_VERBOSE, UNIT_SS1_VERBOSE, "VERBOSE", "VERBOSE", NULL }, + { 0 } +}; + +DEVICE ss1_dev = { + "SS1", ss1_unit, ss1_reg, ss1_mod, + SS1_MAX_DRIVES, 10, 31, 1, SS1_MAX_DRIVES, SS1_MAX_DRIVES, + NULL, NULL, &ss1_reset, + NULL, NULL, NULL, + &ss1_info_data, (DEV_DISABLE | DEV_DIS), 0, + NULL, NULL, NULL +}; + +/* Reset routine */ +static t_stat ss1_reset(DEVICE *dptr) +{ + PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; + + if(dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */ + sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &ss1dev, TRUE); + } else { + /* Connect SS1 at base address */ + if(sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &ss1dev, FALSE) != 0) { + printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->io_base); + return SCPE_ARG; + } + } + return SCPE_OK; +} + +static int32 ss1dev(const int32 port, const int32 io, const int32 data) +{ + DBG_PRINT(("SS1: IO %s, Port %02x\n", io ? "WR" : "RD", port)); + if(io) { + SS1_Write(port, data); + return 0; + } else { + return(SS1_Read(port)); + } +} + +#define SS1_M8259_L 0x00 +#define SS1_M8259_H 0x01 +#define SS1_S8259_L 0x02 +#define SS1_S8259_H 0x03 +#define SS1_8253_TC0 0x04 +#define SS1_8253_TC1 0x05 +#define SS1_8253_TC2 0x06 +#define SS1_8253_CTL 0x07 +#define SS1_9511A_DATA 0x08 +#define SS1_9511A_CMD 0x09 +#define SS1_RTC_CMD 0x0A +#define SS1_RTC_DATA 0x0B +#define SS1_UART_DATA 0x0C +#define SS1_UART_STAT 0x0D +#define SS1_UART_MODE 0x0E +#define SS1_UART_CMD 0x0F + +extern int32 sio0d(const int32 port, const int32 io, const int32 data); +extern int32 sio0s(const int32 port, const int32 io, const int32 data); + +static uint8 SS1_Read(const uint32 Addr) +{ + uint8 cData = 0x00; + + switch(Addr & 0x0F) { + case SS1_M8259_L: + case SS1_M8259_H: + case SS1_S8259_L: + case SS1_S8259_H: + TRACE_PRINT(TRACE_MSG, ("SS1: " ADDRESS_FORMAT " RD: Interrupt Controller not Implemented." NLP, PCX)); + break; + case SS1_8253_TC0: + case SS1_8253_TC1: + case SS1_8253_TC2: + case SS1_8253_CTL: + TRACE_PRINT(TRACE_MSG, ("SS1: " ADDRESS_FORMAT " RD: Timer not Implemented." NLP, PCX)); + break; + case SS1_9511A_DATA: + case SS1_9511A_CMD: + TRACE_PRINT(TRACE_MSG, ("SS1: " ADDRESS_FORMAT " RD: Math Coprocessor not Implemented." NLP, PCX)); + break; + case SS1_RTC_CMD: + case SS1_RTC_DATA: + TRACE_PRINT(TRACE_MSG, ("SS1: " ADDRESS_FORMAT " RD: RTC not Implemented." NLP, PCX)); + break; + case SS1_UART_DATA: + cData = sio0d(Addr, 0, 0); + break; + case SS1_UART_STAT: + cData = sio0s(Addr, 0, 0); + break; + case SS1_UART_MODE: + case SS1_UART_CMD: + TRACE_PRINT(TRACE_MSG, ("SS1: " ADDRESS_FORMAT " RD: UART not Implemented." NLP, PCX)); + break; + } + + return (cData); + +} + +static uint8 SS1_Write(const uint32 Addr, uint8 cData) +{ + + switch(Addr & 0x0F) { + case SS1_M8259_L: + case SS1_M8259_H: + case SS1_S8259_L: + case SS1_S8259_H: + TRACE_PRINT(TRACE_MSG, ("SS1: " ADDRESS_FORMAT " WR: Interrupt Controller not Implemented." NLP, PCX)); + break; + case SS1_8253_TC0: + case SS1_8253_TC1: + case SS1_8253_TC2: + case SS1_8253_CTL: + TRACE_PRINT(TRACE_MSG, ("SS1: " ADDRESS_FORMAT " WR: Timer not Implemented." NLP, PCX)); + break; + case SS1_9511A_DATA: + case SS1_9511A_CMD: + TRACE_PRINT(TRACE_MSG, ("SS1: " ADDRESS_FORMAT " WR: Math Coprocessor not Implemented." NLP, PCX)); + break; + case SS1_RTC_CMD: + case SS1_RTC_DATA: + TRACE_PRINT(TRACE_MSG, ("SS1: " ADDRESS_FORMAT " WR: RTC not Implemented." NLP, PCX)); + break; + case SS1_UART_DATA: + sio0d(Addr, 1, cData); + break; + case SS1_UART_STAT: + sio0s(Addr, 1, cData); + break; + case SS1_UART_MODE: + case SS1_UART_CMD: + TRACE_PRINT(TRACE_MSG, ("SS1: " ADDRESS_FORMAT " WR: UART not Implemented." NLP, PCX)); + break; + } + + return(0); +} + diff --git a/AltairZ80/sim_imd.c b/AltairZ80/sim_imd.c new file mode 100644 index 00000000..37a7a5b3 --- /dev/null +++ b/AltairZ80/sim_imd.c @@ -0,0 +1,365 @@ +/************************************************************************* + * * + * $Id: sim_imd.c 1904 2008-05-21 06:57:57Z hharte $ * + * * + * Copyright (c) 2007-2008 Howard M. Harte. * + * http://www.hartetec.com * + * * + * 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 HOWARD M. HARTE 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 Howard M. Harte shall * + * not be used in advertising or otherwise to promote the sale, use or * + * other dealings in this Software without prior written authorization * + * Howard M. Harte. * + * * + * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. * + * * + * Module Description: * + * ImageDisk Disk Image File access module for SIMH, definitions. * + * see : * + * for details on the ImageDisk format and other utilities. * + * * + * Environment: * + * User mode only * + * * + *************************************************************************/ + +#include "altairz80_defs.h" +#include "sim_imd.h" + +/* #define DBG_MSG */ + +#ifdef DBG_MSG +#define DBG_PRINT(args) printf args +#else +#define DBG_PRINT(args) +#endif + + +DISK_INFO * diskOpen(FILE *fileref, int isVerbose) +{ + char cBuf[256]; + char sectorMap[256]; + char sectorHeadMap[256]; + char sectorCylMap[256]; + unsigned int sectorSize, sectRecordType; + unsigned int i; + unsigned char start_sect; + DISK_INFO *myDisk = NULL; + + unsigned int TotalSectorCount = 0; + IMD_HEADER imd; + + myDisk = (DISK_INFO *)malloc(sizeof(DISK_INFO)); + + myDisk->file = fileref; + + /* rewind to the beginning of the file. */ + fseek(myDisk->file, 0, SEEK_SET); + + do { + cBuf[0] = fgetc(myDisk->file); + if((cBuf[0] != 0x1a) && isVerbose) putchar(cBuf[0]); + } + while (cBuf[0] != 0x1a); + + myDisk->nsides = 1; + myDisk->ntracks = 0; + myDisk->flags = 0; /* Make sure all flags are clear. */ + + do { + DBG_PRINT(("start of track %d at file offset %d\n", myDisk->ntracks, ftell(myDisk->file))); + + fread(&imd, 1, 5, myDisk->file); + if(feof(myDisk->file)) break; + + sectorSize = (1 << imd.sectsize) * 128; + + DBG_PRINT(("Track %d:\n", myDisk->ntracks)); + DBG_PRINT(("\tMode=%d, Cyl=%d, Head=%d, #sectors=%d, sectsize=%d (%d bytes)\n", imd.mode, imd.cyl, imd.head, imd.nsects, imd.sectsize, sectorSize)); + + if((imd.head + 1) > myDisk->nsides) { + myDisk->nsides = imd.head + 1; + } + + myDisk->track[imd.cyl][imd.head].mode = imd.mode; + myDisk->track[imd.cyl][imd.head].nsects = imd.nsects; + myDisk->track[imd.cyl][imd.head].sectsize = sectorSize; + + fread(sectorMap, 1, imd.nsects, myDisk->file); + myDisk->track[imd.cyl][imd.head].start_sector = imd.nsects; + DBG_PRINT(("\tSector Map: ")); + for(i=0;itrack[imd.cyl][imd.head].start_sector) { + myDisk->track[imd.cyl][imd.head].start_sector = sectorMap[i]; + } + } + DBG_PRINT((", Start Sector=%d", myDisk->track[imd.cyl][imd.head].start_sector)); + + if(imd.head & IMD_FLAG_SECT_HEAD_MAP) { + fread(sectorHeadMap, 1, imd.nsects, myDisk->file); + DBG_PRINT(("\tSector Head Map: ")); + for(i=0;ifile); + DBG_PRINT(("\tSector Cyl Map: ")); + for(i=0;ifile))); + + /* Build the table with location 0 being the start sector. */ + start_sect = myDisk->track[imd.cyl][imd.head].start_sector; + + /* Now read each sector */ + for(i=0;ifile); + switch(sectRecordType) { + case SECT_RECORD_UNAVAILABLE: /* Data could not be read from the original media */ + myDisk->track[imd.cyl][imd.head].sectorOffsetMap[sectorMap[i]-start_sect] = 0xBADBAD; + break; + case SECT_RECORD_NORM: /* Normal Data */ + case SECT_RECORD_NORM_DAM: /* Normal Data with deleted address mark */ + case SECT_RECORD_NORM_ERR: /* Normal Data with read error */ + case SECT_RECORD_NORM_DAM_ERR: /* Normal Data with deleted address mark with read error */ +/* DBG_PRINT(("Uncompressed Data\n")); */ + myDisk->track[imd.cyl][imd.head].sectorOffsetMap[sectorMap[i]-start_sect] = ftell(myDisk->file); + fseek(myDisk->file, sectorSize, SEEK_CUR); + break; + case SECT_RECORD_NORM_COMP: /* Compressed Normal Data */ + case SECT_RECORD_NORM_DAM_COMP: /* Compressed Normal Data with deleted address mark */ + case SECT_RECORD_NORM_COMP_ERR: /* Compressed Normal Data */ + case SECT_RECORD_NORM_DAM_COMP_ERR: /* Compressed Normal Data with deleted address mark */ + myDisk->track[imd.cyl][imd.head].sectorOffsetMap[sectorMap[i]-start_sect] = ftell(myDisk->file); + myDisk->flags |= FD_FLAG_WRITELOCK; /* Write-protect the disk if any sectors are compressed. */ +#ifdef VERBOSE_DEBUG + DBG_PRINT(("Compressed Data = 0x%02x\n", fgetc(myDisk->file))); +#else + fgetc(myDisk->file); +#endif + break; + default: + printf("ERROR: unrecognized sector record type %d\n", sectRecordType); + break; + } + DBG_PRINT(("\n")); + } + + myDisk->ntracks++; + } + while (!feof(myDisk->file)); + + DBG_PRINT(("Processed %d sectors\n", TotalSectorCount)); + +#ifdef VERBOSE_DEBUG + for(i=0;intracks;i++) { + DBG_PRINT(("Track %02d: ", i)); + for(j=0;jtrack[i][0].sectorOffsetMap[j])); + } + DBG_PRINT(("\n")); + } +#endif + if(myDisk->flags & FD_FLAG_WRITELOCK) { + printf("Disk write-protected because the image contains compressed sectors. Use IMDU to uncompress.\n"); + } + + return myDisk; +} + +unsigned int diskClose(DISK_INFO *myDisk) +{ + unsigned int retval = 0; + + if(myDisk == NULL) { + return (-1); + } + + free(myDisk); + myDisk = NULL; + + return retval; +} + +unsigned int imdGetSides(DISK_INFO *myDisk) +{ + if(myDisk != NULL) { + return(myDisk->nsides); + } + + return (0); +} + +unsigned int imdIsWriteLocked(DISK_INFO *myDisk) +{ + if(myDisk != NULL) { + return((myDisk->flags & FD_FLAG_WRITELOCK) ? 1 : 0); + } + + return (0); +} + +/* Check that the given track/sector exists on the disk */ +int sectSeek(DISK_INFO *myDisk, unsigned int Cyl, unsigned int Head) +{ + if(myDisk->track[Cyl][Head].nsects == 0) { + DBG_PRINT(("%s: invalid track/head" NLP, __FUNCTION__)); + return(-1); + } + + return(0); +} + + +int sectRead(DISK_INFO *myDisk, unsigned int Cyl, unsigned int Head, unsigned int Sector, unsigned char *buf, unsigned int buflen, unsigned int *flags, unsigned int *readlen) +{ + unsigned int sectorFileOffset; + unsigned char sectRecordType; + unsigned char start_sect; + *readlen = 0; + *flags = 0; + + if(Sector > myDisk->track[Cyl][Head].nsects) { + DBG_PRINT(("%s: invalid sector" NLP, __FUNCTION__)); + return(-1); + } + + if(buflen < myDisk->track[Cyl][Head].sectsize) { + printf("%s: Reading C:%d/H:%d/S:%d, len=%d: user buffer too short, need %d" NLP, __FUNCTION__, Cyl, Head, Sector, buflen, myDisk->track[Cyl][Head].sectsize); + return(-1); + } + + start_sect = myDisk->track[Cyl][Head].start_sector; + + sectorFileOffset = myDisk->track[Cyl][Head].sectorOffsetMap[Sector-start_sect]; + + DBG_PRINT(("Reading C:%d/H:%d/S:%d, len=%d, offset=0x%08x" NLP, Cyl, Head, Sector, buflen, sectorFileOffset)); + + fseek(myDisk->file, sectorFileOffset-1, 0); + + sectRecordType = fgetc(myDisk->file); + switch(sectRecordType) { + case SECT_RECORD_UNAVAILABLE: /* Data could not be read from the original media */ + *flags |= IMD_DISK_IO_ERROR_GENERAL; + break; + case SECT_RECORD_NORM_ERR: /* Normal Data with read error */ + case SECT_RECORD_NORM_DAM_ERR: /* Normal Data with deleted address mark with read error */ + *flags |= IMD_DISK_IO_ERROR_CRC; + case SECT_RECORD_NORM: /* Normal Data */ + case SECT_RECORD_NORM_DAM: /* Normal Data with deleted address mark */ + +/* DBG_PRINT(("Uncompressed Data" NLP)); */ + fread(buf, 1, myDisk->track[Cyl][Head].sectsize, myDisk->file); + *readlen = myDisk->track[Cyl][Head].sectsize; + break; + case SECT_RECORD_NORM_COMP_ERR: /* Compressed Normal Data */ + case SECT_RECORD_NORM_DAM_COMP_ERR: /* Compressed Normal Data with deleted address mark */ + *flags |= IMD_DISK_IO_ERROR_CRC; + case SECT_RECORD_NORM_COMP: /* Compressed Normal Data */ + case SECT_RECORD_NORM_DAM_COMP: /* Compressed Normal Data with deleted address mark */ +/* DBG_PRINT(("Compressed Data" NLP)); */ + memset(buf, fgetc(myDisk->file), myDisk->track[Cyl][Head].sectsize); + *readlen = myDisk->track[Cyl][Head].sectsize; + *flags |= IMD_DISK_IO_COMPRESSED; + break; + default: + printf("ERROR: unrecognized sector record type %d" NLP, sectRecordType); + break; + } + + /* Set flags for deleted address mark. */ + switch(sectRecordType) { + case SECT_RECORD_NORM_DAM: /* Normal Data with deleted address mark */ + case SECT_RECORD_NORM_DAM_ERR: /* Normal Data with deleted address mark with read error */ + case SECT_RECORD_NORM_DAM_COMP: /* Compressed Normal Data with deleted address mark */ + case SECT_RECORD_NORM_DAM_COMP_ERR: /* Compressed Normal Data with deleted address mark */ + *flags |= IMD_DISK_IO_DELETED_ADDR_MARK; + default: + break; + } + + return(0); +} + + +int sectWrite(DISK_INFO *myDisk, unsigned int Cyl, unsigned int Head, unsigned int Sector, unsigned char *buf, unsigned int buflen, unsigned int *flags, unsigned int *writelen) +{ + unsigned int sectorFileOffset; + unsigned char sectRecordType; + unsigned char start_sect; + *writelen = 0; + *flags = 0; + + DBG_PRINT(("Writing C:%d/H:%d/S:%d, len=%d" NLP, Cyl, Head, Sector, buflen)); + + if(myDisk->flags & FD_FLAG_WRITELOCK) { + printf("Disk write-protected because the image contains compressed sectors. Use IMDU to uncompress." NLP); + } + + if(Sector > myDisk->track[Cyl][Head].nsects) { + printf("%s: invalid sector [sector %i > # of sectors %i]" NLP, + __FUNCTION__, Sector, myDisk->track[Cyl][Head].nsects); + return(-1); + } + + if(buflen < myDisk->track[Cyl][Head].sectsize) { + printf("%s: user buffer too short [buflen %i < sectsize %i]" NLP, + __FUNCTION__, buflen, myDisk->track[Cyl][Head].sectsize); + return(-1); + } + + start_sect = myDisk->track[Cyl][Head].start_sector; + + sectorFileOffset = myDisk->track[Cyl][Head].sectorOffsetMap[Sector-start_sect]; + + fseek(myDisk->file, sectorFileOffset-1, 0); + + if (*flags & IMD_DISK_IO_ERROR_GENERAL) { + sectRecordType = SECT_RECORD_UNAVAILABLE; + } else if (*flags & IMD_DISK_IO_ERROR_CRC) { + if (*flags & IMD_DISK_IO_DELETED_ADDR_MARK) + sectRecordType = SECT_RECORD_NORM_DAM_ERR; + else + sectRecordType = SECT_RECORD_NORM_ERR; + } else { + sectRecordType = SECT_RECORD_NORM; + } + + fputc(sectRecordType, myDisk->file); + fwrite(buf, 1, myDisk->track[Cyl][Head].sectsize, myDisk->file); + *writelen = myDisk->track[Cyl][Head].sectsize; + + return(0); +} diff --git a/AltairZ80/sim_imd.h b/AltairZ80/sim_imd.h new file mode 100644 index 00000000..eb70ef1a --- /dev/null +++ b/AltairZ80/sim_imd.h @@ -0,0 +1,110 @@ +/************************************************************************* + * * + * $Id: sim_imd.h 1904 2008-05-21 06:57:57Z hharte $ * + * * + * Copyright (c) 2007-2008 Howard M. Harte. * + * http://www.hartetec.com * + * * + * 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 HOWARD M. HARTE 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 Howard M. Harte shall * + * not be used in advertising or otherwise to promote the sale, use or * + * other dealings in this Software without prior written authorization * + * Howard M. Harte. * + * * + * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. * + * * + * Module Description: * + * ImageDisk Disk Image File access module for SIMH, definitions. * + * see : * + * for details on the ImageDisk format and other utilities. * + * * + * Environment: * + * User mode only * + * * + *************************************************************************/ + +typedef struct { + unsigned char mode; + unsigned char cyl; + unsigned char head; + unsigned char nsects; + unsigned char sectsize; +} IMD_HEADER; + + +#define IMD_FLAG_SECT_HEAD_MAP (1 << 6) +#define IMD_FLAG_SECT_CYL_MAP (1 << 7) + +#define SECT_RECORD_UNAVAILABLE 0 /* Data could not be read from the original media */ +#define SECT_RECORD_NORM 1 /* Normal Data */ +#define SECT_RECORD_NORM_COMP 2 /* Compressed Normal Data */ +#define SECT_RECORD_NORM_DAM 3 /* Normal Data with deleted address mark */ +#define SECT_RECORD_NORM_DAM_COMP 4 /* Compressed Normal Data with deleted address mark */ +#define SECT_RECORD_NORM_ERR 5 /* Normal Data */ +#define SECT_RECORD_NORM_COMP_ERR 6 /* Compressed Normal Data */ +#define SECT_RECORD_NORM_DAM_ERR 7 /* Normal Data with deleted address mark */ +#define SECT_RECORD_NORM_DAM_COMP_ERR 8 /* Compressed Normal Data with deleted address mark */ + +#define MAX_CYL 80 +#define MAX_HEAD 2 +#define MAX_SPT 26 + +#define FD_FLAG_WRITELOCK 1 + +#define IMD_DISK_IO_ERROR_GENERAL (1 << 0) /* General data error. */ +#define IMD_DISK_IO_ERROR_CRC (1 << 1) /* Data read/written, but got a CRC error. */ +#define IMD_DISK_IO_DELETED_ADDR_MARK (1 << 2) /* Sector had a deleted address mark */ +#define IMD_DISK_IO_COMPRESSED (1 << 3) /* Sector is compressed in the IMD file (Read Only) */ + +#define IMD_MODE_500K_FM 0 +#define IMD_MODE_300K_FM 1 +#define IMD_MODE_250K_FM 2 +#define IMD_MODE_500K_MFM 3 +#define IMD_MODE_300K_MFM 4 +#define IMD_MODE_250K_MFM 5 + +#define IMD_MODE_FM(x) (x <= IMD_MODE_250K_FM) +#define IMD_MODE_MFM(x) (x >= IMD_MODE_500K_MFM) + +typedef struct { + unsigned char mode; + unsigned char nsects; + unsigned int sectsize; + unsigned int sectorOffsetMap[MAX_SPT]; + unsigned char start_sector; +} TRACK_INFO; + +typedef struct { + FILE *file; + unsigned int ntracks; + unsigned char nsides; + unsigned char flags; + TRACK_INFO track[MAX_CYL][MAX_HEAD]; +} DISK_INFO; + +extern DISK_INFO *diskOpen(FILE *fileref, int isVerbose); /*char *filename); */ +extern unsigned int diskClose(DISK_INFO *myDisk); +extern unsigned int imdGetSides(DISK_INFO *myDisk); +extern unsigned int imdIsWriteLocked(DISK_INFO *myDisk); + +extern int sectSeek(DISK_INFO *myDisk, unsigned int Cyl, unsigned int Head); +extern int sectRead(DISK_INFO *myDisk, unsigned int Cyl, unsigned int Head, unsigned int Sector, unsigned char *buf, unsigned int buflen, unsigned int *flags, unsigned int *readlen); +extern int sectWrite(DISK_INFO *myDisk, unsigned int Cyl, unsigned int Head, unsigned int Sector, unsigned char *buf, unsigned int buflen, unsigned int *flags, unsigned int *writelen); diff --git a/AltairZ80/vfdhd.c b/AltairZ80/vfdhd.c new file mode 100644 index 00000000..84751531 --- /dev/null +++ b/AltairZ80/vfdhd.c @@ -0,0 +1,650 @@ +/************************************************************************* + * * + * $Id: vfdhd.c 1773 2008-01-11 05:46:19Z hharte $ * + * * + * Copyright (c) 2007-2008 Howard M. Harte. * + * http://www.hartetec.com * + * * + * 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 HOWARD M. HARTE 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 Howard M. Harte shall * + * not be used in advertising or otherwise to promote the sale, use or * + * other dealings in this Software without prior written authorization * + * Howard M. Harte. * + * * + * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. * + * * + * Module Description: * + * Micropolis FDC module for SIMH * + * * + * Environment: * + * User mode only * + * * + *************************************************************************/ + +/*#define DBG_MSG */ +#define USE_VGI /* Use 275-byte VGI-format sectors (includes all metadata) */ + +#include "altairz80_defs.h" + +#if defined (_WIN32) +#include +#endif + +#include "sim_imd.h" + +#ifdef DBG_MSG +#define DBG_PRINT(args) printf args +#else +#define DBG_PRINT(args) +#endif + +#define SEEK_MSG 0x01 +#define ORDERS_MSG 0x02 +#define CMD_MSG 0x04 +#define RD_DATA_MSG 0x08 +#define WR_DATA_MSG 0x10 +#define STATUS_MSG 0x20 + +static void VFDHD_Command(void); + +#define VFDHD_MAX_DRIVES 4 + +#define VFDHD_SECTOR_LEN 275 + +typedef union { + struct { + uint8 preamble[40]; /* Hard disk uses 30 bytes of preamble, floppy uses 40. */ + uint8 sync; + uint8 header[2]; + uint8 unused[10]; + uint8 data[256]; + uint8 checksum; + uint8 ecc[4]; + uint8 ecc_valid; /* 0xAA indicates ECC is being used. */ + uint8 postamble[128]; + } u; + uint8 raw[VFDHD_SECTOR_LEN]; + +} SECTOR_FORMAT; + +typedef struct { + UNIT *uptr; + DISK_INFO *imd; + uint16 ntracks; /* number of tracks */ + uint8 nheads; /* number of heads */ + uint8 nspt; /* number of sectors per track */ + uint8 npre_len; /* preamble length */ + uint32 sectsize; /* sector size, not including pre/postamble */ + uint16 track; + uint8 wp; /* Disk write protected */ + uint8 ready; /* Drive is ready */ + uint8 write_fault; + uint8 seek_complete; + uint8 sync_lost; + uint32 sector_wait_count; +} VFDHD_DRIVE_INFO; + +typedef struct { + PNP_INFO pnp; /* Plug and Play */ + uint8 xfr_flag; /* Indicates controller is ready to send/receive data */ + uint8 sel_drive; /* Currently selected drive */ + uint8 selected; /* 1 if drive is selected */ + uint8 track0; /* Set it selected drive is on track 0 */ + uint8 head; /* Currently selected head */ + uint8 wr_latch; /* Write enable latch */ + uint8 int_enable; /* Interrupt Enable */ + uint32 datacount; /* Number of data bytes transferred from controller for current sector */ + uint8 step; + uint8 direction; + uint8 rwc; + uint8 sector; + uint8 read; + uint8 ecc_enable; + uint8 precomp; + + uint8 floppy_sel; + uint8 controller_busy; + uint8 motor_on; + uint8 hdsk_type; + VFDHD_DRIVE_INFO drive[VFDHD_MAX_DRIVES]; +} VFDHD_INFO; + +static VFDHD_INFO vfdhd_info_data = { { 0x0, 0, 0xC0, 4 } }; +static VFDHD_INFO *vfdhd_info = &vfdhd_info_data; + +static SECTOR_FORMAT sdata; +extern uint32 PCX; +extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc); +extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, + int32 (*routine)(const int32, const int32, const int32), uint8 unmap); + +#define UNIT_V_VFDHD_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_VFDHD_WLK (1 << UNIT_V_VFDHD_WLK) +#define UNIT_V_VFDHD_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ +#define UNIT_VFDHD_VERBOSE (1 << UNIT_V_VFDHD_VERBOSE) +#define VFDHD_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */ +#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */ +#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */ +#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */ + +static t_stat vfdhd_reset(DEVICE *vfdhd_dev); +static t_stat vfdhd_attach(UNIT *uptr, char *cptr); +static t_stat vfdhd_detach(UNIT *uptr); + +static int32 vfdhddev(const int32 port, const int32 io, const int32 data); + +static uint8 VFDHD_Read(const uint32 Addr); +static uint8 VFDHD_Write(const uint32 Addr, uint8 cData); + +static int32 trace_level = FALSE; +static int32 hdSize = 5; + +static UNIT vfdhd_unit[] = { + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, VFDHD_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, VFDHD_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, VFDHD_CAPACITY) }, + { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, VFDHD_CAPACITY) } +}; + +static REG vfdhd_reg[] = { + { HRDATA (TRACELEVEL, trace_level, 16), }, + { DRDATA (HDSIZE, hdSize, 10), }, + { NULL } +}; + +static MTAB vfdhd_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL }, + { UNIT_VFDHD_WLK, 0, "WRTENB", "WRTENB", NULL }, + { UNIT_VFDHD_WLK, UNIT_VFDHD_WLK, "WRTLCK", "WRTLCK", NULL }, + /* quiet, no warning messages */ + { UNIT_VFDHD_VERBOSE, 0, "QUIET", "QUIET", NULL }, + /* verbose, show warning messages */ + { UNIT_VFDHD_VERBOSE, UNIT_VFDHD_VERBOSE, "VERBOSE", "VERBOSE", NULL }, + { 0 } +}; + +DEVICE vfdhd_dev = { + "VFDHD", vfdhd_unit, vfdhd_reg, vfdhd_mod, + VFDHD_MAX_DRIVES, 10, 31, 1, VFDHD_MAX_DRIVES, VFDHD_MAX_DRIVES, + NULL, NULL, &vfdhd_reset, + NULL, &vfdhd_attach, &vfdhd_detach, + &vfdhd_info_data, (DEV_DISABLE | DEV_DIS), 0, + NULL, NULL, NULL +}; + +/* Reset routine */ +static t_stat vfdhd_reset(DEVICE *dptr) +{ + PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; + + if(dptr->flags & DEV_DIS) { + sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &vfdhddev, TRUE); + } else { + /* Connect MFDC at base address */ + if(sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &vfdhddev, FALSE) != 0) { + printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->io_base); + return SCPE_ARG; + } + } + return SCPE_OK; +} + + +/* Attach routine */ +static t_stat vfdhd_attach(UNIT *uptr, char *cptr) +{ + char header[4]; + t_stat r; + unsigned int i = 0; + + r = attach_unit(uptr, cptr); /* attach unit */ + if ( r != SCPE_OK) /* error? */ + return r; + + /* Determine length of this disk */ + uptr->capac = sim_fsize(uptr->fileref); + + for(i = 0; i < VFDHD_MAX_DRIVES; i++) { + vfdhd_info->drive[i].uptr = &vfdhd_dev.units[i]; + } + + for(i = 0; i < VFDHD_MAX_DRIVES; i++) { + if(vfdhd_dev.units[i].fileref == uptr->fileref) { + break; + } + } + + if(uptr->capac > 0) { + fgets(header, 4, uptr->fileref); + if(!strcmp(header, "IMD")) { + uptr->u3 = IMAGE_TYPE_IMD; + } else if(!strcmp(header, "CPT")) { + printf("CPT images not yet supported\n"); + uptr->u3 = IMAGE_TYPE_CPT; + vfdhd_detach(uptr); + return SCPE_OPENERR; + } else { + uptr->u3 = IMAGE_TYPE_DSK; + } + } else { + /* creating file, must be DSK format. */ + uptr->u3 = IMAGE_TYPE_DSK; + } + + if (uptr->flags & UNIT_VFDHD_VERBOSE) + printf("VFDHD%d: attached to '%s', type=%s, len=%d\n", i, cptr, + uptr->u3 == IMAGE_TYPE_IMD ? "IMD" : uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK", + uptr->capac); + + if(uptr->u3 == IMAGE_TYPE_IMD) { + if(uptr->capac < 318000) { + printf("Cannot create IMD files with SIMH.\nCopy an existing file and format it with CP/M.\n"); + vfdhd_detach(uptr); + return SCPE_OPENERR; + } + + if (uptr->flags & UNIT_VFDHD_VERBOSE) + printf("--------------------------------------------------------\n"); + vfdhd_info->drive[i].imd = diskOpen((uptr->fileref), (uptr->flags & UNIT_VFDHD_VERBOSE)); + printf("\n"); + } else { + vfdhd_info->drive[i].imd = NULL; + } + + if(i>0) { /* Floppy Disk, Unit 1-3 */ + vfdhd_info->drive[i].ntracks = 77; /* number of tracks */ + vfdhd_info->drive[i].nheads = 2; /* number of heads */ + vfdhd_info->drive[i].nspt = 16; /* number of sectors per track */ + vfdhd_info->drive[i].npre_len = 40; /* preamble length */ + vfdhd_info->drive[i].sectsize = VFDHD_SECTOR_LEN; /* sector size, not including pre/postamble */ + } else { /* Hard Disk, Unit 0 */ + if(hdSize == 10) { + vfdhd_info->drive[i].ntracks = 153; /* number of tracks */ + vfdhd_info->drive[i].nheads = 6; /* number of heads */ + vfdhd_info->hdsk_type = 1; + printf("10MB\n"); + } else if (hdSize == 5) { + vfdhd_info->drive[i].ntracks = 153; /* number of tracks */ + vfdhd_info->drive[i].nheads = 4; /* number of heads */ + vfdhd_info->hdsk_type = 0; + printf("5MB\n"); + } else { + vfdhd_info->drive[i].ntracks = 512; /* number of tracks */ + vfdhd_info->drive[i].nheads = 8; /* number of heads */ + vfdhd_info->hdsk_type = 1; + printf("32MB\n"); + } + + vfdhd_info->drive[i].nheads = 4; /* number of heads */ + vfdhd_info->drive[i].nspt = 32; /* number of sectors per track */ + vfdhd_info->drive[i].npre_len = 30; /* preamble length */ + vfdhd_info->drive[i].sectsize = VFDHD_SECTOR_LEN; /* sector size, not including pre/postamble */ + vfdhd_info->drive[i].ready = 1; + vfdhd_info->drive[i].seek_complete = 1; + vfdhd_info->drive[i].sync_lost = 1; /* Active LOW */ + } + + vfdhd_info->motor_on = 1; + return SCPE_OK; +} + + +/* Detach routine */ +static t_stat vfdhd_detach(UNIT *uptr) +{ + t_stat r; + int8 i; + + for(i = 0; i < VFDHD_MAX_DRIVES; i++) { + if(vfdhd_dev.units[i].fileref == uptr->fileref) { + break; + } + } + + DBG_PRINT(("Detach VFDHD%d\n", i)); + diskClose(vfdhd_info->drive[i].imd); + + r = detach_unit(uptr); /* detach unit */ + if ( r != SCPE_OK) + return r; + + return SCPE_OK; +} + + +static uint8 cy; +static uint8 adc(uint8 sum, uint8 a1) +{ + uint32 total; + + total = sum + a1 + cy; + + if(total > 0xFF) { + cy = 1; + } else { + cy = 0; + } + + return(total & 0xFF); +} + +static int32 vfdhddev(const int32 port, const int32 io, const int32 data) +{ + DBG_PRINT(("VFDHD: " ADDRESS_FORMAT " IO %s, Port %02x" NLP, PCX, io ? "WR" : "RD", port)); + if(io) { + VFDHD_Write(port, data); + return 0; + } else { + return(VFDHD_Read(port)); + } +} + +#define FDHD_CTRL_STATUS0 0 /* R=Status Port 0, W=Control Port 0 */ +#define FDHD_CTRL_STATUS1 1 /* R=Status Port 1, W=Control Port 0 */ +#define FDHD_DATA 2 /* R/W=Data Port */ +#define FDHD_RESET_START 3 /* R=RESET, W=START */ + +static uint8 VFDHD_Read(const uint32 Addr) +{ + uint8 cData; + VFDHD_DRIVE_INFO *pDrive; + + pDrive = &vfdhd_info->drive[vfdhd_info->sel_drive]; + + cData = 0x00; + + switch(Addr & 0x3) { + case FDHD_CTRL_STATUS0: + cData = (pDrive->wp & 1); /* [0] Write Protect (FD) */ + cData |= (pDrive->ready & 1) << 1; /* [1] Drive ready (HD) */ + cData |= (pDrive->track == 0) ? 0x04 : 0; /* [2] TK0 (FD/HD) */ + cData |= (pDrive->write_fault & 1) << 3; /* [3] Write Fault (HD) */ + cData |= (pDrive->seek_complete & 1) << 4; /* [4] Seek Complete (HD) */ + cData |= (pDrive->sync_lost & 1) << 5; /* [5] Loss of Sync (HD) */ + cData |= 0xC0; /* [7:6] Reserved (pulled up) */ + TRACE_PRINT(STATUS_MSG, ("VFDHD: " ADDRESS_FORMAT " RD S0 = 0x%02x" NLP, PCX, cData)); + break; + case FDHD_CTRL_STATUS1: + vfdhd_info->floppy_sel = (vfdhd_info->sel_drive == 0) ? 0 : 1; + cData = (vfdhd_info->floppy_sel & 0x1); /* [0] Floppy Selected */ + cData |= (vfdhd_info->controller_busy & 0x1) << 1; /* [1] Controller busy */ + cData |= (vfdhd_info->motor_on & 0x1) << 2; /* [2] Motor On (FD) */ + cData |= (vfdhd_info->hdsk_type & 0x1) << 3; /* [3] Hard Disk Type (0=5MB, 1=10MB) */ + cData |= 0xF0; /* [7:4] Reserved (pulled up) */ + if(vfdhd_info->sel_drive == 0) { +/* cData &= 0xF0; */ + } + + vfdhd_info->controller_busy = 0; + + TRACE_PRINT(STATUS_MSG, ("VFDHD: " ADDRESS_FORMAT " RD S1 = 0x%02x" NLP, PCX, cData)); + break; + case FDHD_DATA: +/* DBG_PRINT(("VFDHD: " ADDRESS_FORMAT " RD Data" NLP, PCX)); */ + cData = sdata.raw[vfdhd_info->datacount+40]; + + vfdhd_info->datacount++; + +/* DBG_PRINT(("VFDHD: " ADDRESS_FORMAT " RD Data Sector %d[%03d]: 0x%02x" NLP, PCX, pDrive->sector, vfdhd_info->datacount, cData)); */ + break; + case FDHD_RESET_START: /* Reset */ + TRACE_PRINT(CMD_MSG, ("VFDHD: " ADDRESS_FORMAT " Reset" NLP, PCX)); + vfdhd_info->datacount = 0; + cData = 0xFF; /* Return High-Z data */ + break; + } + + return (cData); +} + +static uint8 VFDHD_Write(const uint32 Addr, uint8 cData) +{ + VFDHD_DRIVE_INFO *pDrive; + + pDrive = &vfdhd_info->drive[vfdhd_info->sel_drive]; + + switch(Addr & 0x3) { + case FDHD_CTRL_STATUS0: + vfdhd_info->sel_drive = cData & 3; + vfdhd_info->head = (cData >> 2) & 0x7; + vfdhd_info->step = (cData >> 5) & 1; + vfdhd_info->direction = (cData >> 6) & 1; + vfdhd_info->rwc = (cData >> 7) & 1; + + TRACE_PRINT(WR_DATA_MSG, ("VFDHD: " ADDRESS_FORMAT " WR C0=%02x: sel_drive=%d, head=%d, step=%d, dir=%d, rwc=%d" NLP, + PCX, + cData, + vfdhd_info->sel_drive, + vfdhd_info->head, + vfdhd_info->step, + vfdhd_info->direction, + vfdhd_info->rwc)); + + if(vfdhd_info->step == 1) { + if(vfdhd_info->direction == 1) { /* Step IN */ + pDrive->track++; + } else { /* Step OUT */ + if(pDrive->track != 0) { + pDrive->track--; + } + } + TRACE_PRINT(SEEK_MSG, ("VFDHD: " ADDRESS_FORMAT " Drive %d on track %d" NLP, + PCX, vfdhd_info->sel_drive, pDrive->track)); + } + + break; + case FDHD_CTRL_STATUS1: + vfdhd_info->sector = (cData & 0x1f); + vfdhd_info->read = (cData >> 5) & 1; + vfdhd_info->ecc_enable = (cData >> 6) & 1; + vfdhd_info->precomp = (cData >> 7) & 1; + if(cData == 0xFF) { + TRACE_PRINT(SEEK_MSG, ("VFDHD: " ADDRESS_FORMAT " Home Disk %d" NLP, + PCX, vfdhd_info->sel_drive)); + pDrive->track = 0; + } + DBG_PRINT(("VFDHD: " ADDRESS_FORMAT " WR C1=%02x: sector=%d, read=%d, ecc_en=%d, precomp=%d" NLP, + PCX, + cData, + vfdhd_info->sector, + vfdhd_info->read, + vfdhd_info->ecc_enable, + vfdhd_info->precomp)); + break; + case FDHD_DATA: /* Data Port */ + DBG_PRINT(("VFDHD: " ADDRESS_FORMAT " WR Data" NLP, PCX)); +#ifdef USE_VGI + if(vfdhd_info->sel_drive > 0) { /* Floppy */ + sdata.raw[vfdhd_info->datacount] = cData; + } else { /* Hard */ + sdata.raw[vfdhd_info->datacount+10] = cData; + } +#else + sdata.u.data[vfdhd_info->datacount-13] = cData; +#endif /* USE_VGI */ + + vfdhd_info->datacount ++; + + break; + case FDHD_RESET_START: + TRACE_PRINT(CMD_MSG, ("VFDHD: " ADDRESS_FORMAT " Start Command" NLP, PCX)); + VFDHD_Command(); + break; + } + + cData = 0x00; + + return (cData); +} + +static void VFDHD_Command(void) +{ + VFDHD_DRIVE_INFO *pDrive; + + uint32 bytesPerTrack; + uint32 bytesPerHead; + + uint32 sec_offset; + uint32 flags; + + pDrive = &(vfdhd_info->drive[vfdhd_info->sel_drive]); + + bytesPerTrack = pDrive->sectsize * pDrive->nspt; + bytesPerHead = bytesPerTrack * pDrive->ntracks; + + sec_offset = (pDrive->track * bytesPerTrack) + \ + (vfdhd_info->head * bytesPerHead) + \ + (vfdhd_info->sector * pDrive->sectsize); + + vfdhd_info->controller_busy = 1; + + if(vfdhd_info->read == 1) { /* Perform a Read operation */ + unsigned int i, checksum; + unsigned int readlen; + + TRACE_PRINT(RD_DATA_MSG, ("VFDHD: " ADDRESS_FORMAT " RD: Drive=%d, Track=%d, Head=%d, Sector=%d" NLP, + PCX, + vfdhd_info->sel_drive, + pDrive->track, + vfdhd_info->head, + vfdhd_info->sector)); + + /* Clear out unused portion of sector. */ + memset(&sdata.u.unused[0], 0x00, 10); + + sdata.u.sync = 0xFF; + sdata.u.header[0] = pDrive->track & 0xFF; + sdata.u.header[1] = vfdhd_info->sector; + + switch((pDrive->uptr)->u3) + { + case IMAGE_TYPE_IMD: + if(pDrive->imd == NULL) { + printf(".imd is NULL!" NLP); + } + printf("%s: Read: imd=%p" NLP, __FUNCTION__, pDrive->imd); + sectRead(pDrive->imd, + pDrive->track, + vfdhd_info->head, + vfdhd_info->sector, + sdata.u.data, + 256, + &flags, + &readlen); + + adc(0,0); /* clear Carry bit */ + checksum = 0; + + /* Checksum everything except the sync byte */ + for(i=1;i<269;i++) { + checksum = adc(checksum, sdata.raw[i]); + } + + sdata.u.checksum = checksum & 0xFF; + sdata.u.ecc_valid = 0xAA; + break; + case IMAGE_TYPE_DSK: + if(pDrive->uptr->fileref == NULL) { + printf(".fileref is NULL!" NLP); + } else { + fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET); + fread(&sdata.u.sync, 274, /*VFDHD_SECTOR_LEN,*/ 1, (pDrive->uptr)->fileref); + + memset(&sdata.u.preamble, 0, 40); + memset(&sdata.u.ecc, 0, 5); /* Clear out the ECC and ECC Valid bytes */ + sdata.u.ecc_valid = 0xAA; + for(vfdhd_info->datacount = 0; sdata.raw[vfdhd_info->datacount] == 0x00; vfdhd_info->datacount++) { + } + + DBG_PRINT(("VFDHD: " ADDRESS_FORMAT " READ: Sync found at offset %d" NLP, PCX, vfdhd_info->datacount)); + + } + break; + case IMAGE_TYPE_CPT: + printf("%s: CPT Format not supported" NLP, __FUNCTION__); + break; + default: + printf("%s: Unknown image Format" NLP, __FUNCTION__); + break; + } + + } else { /* Perform a Write operation */ + unsigned int writelen; + + TRACE_PRINT(WR_DATA_MSG, ("VFDHD: " ADDRESS_FORMAT " WR: Drive=%d, Track=%d, Head=%d, Sector=%d" NLP, + PCX, + vfdhd_info->sel_drive, + pDrive->track, + vfdhd_info->head, + vfdhd_info->sector)); + +#ifdef USE_VGI +#else + int data_index = vfdhd_info->datacount - 13; + + sec_offset = (pDrive->track * 4096) + \ + (vfdhd_info->head * 315392) + \ + (vfdhd_info->sector * 256); +#endif /* USE_VGI */ + + switch((pDrive->uptr)->u3) + { + case IMAGE_TYPE_IMD: + if(pDrive->imd == NULL) { + printf(".imd is NULL!" NLP); + } + sectWrite(pDrive->imd, + pDrive->track, + vfdhd_info->head, + vfdhd_info->sector, + sdata.u.data, + 256, + &flags, + &writelen); + break; + case IMAGE_TYPE_DSK: + if(pDrive->uptr->fileref == NULL) { + printf(".fileref is NULL!" NLP); + } else { + DBG_PRINT(("VFDHD: " ADDRESS_FORMAT " WR drive=%d, track=%d, head=%d, sector=%d" NLP, + PCX, + vfdhd_info->sel_drive, + pDrive->track, + vfdhd_info->head, + vfdhd_info->sector)); + fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET); +#ifdef USE_VGI + fwrite(&sdata.u.sync, VFDHD_SECTOR_LEN, 1, (pDrive->uptr)->fileref); +#else + fwrite(sdata.u.data, 256, 1, (pDrive->uptr)->fileref); +#endif /* USE_VGI */ + } + break; + case IMAGE_TYPE_CPT: + printf("%s: CPT Format not supported" NLP, __FUNCTION__); + break; + default: + printf("%s: Unknown image Format" NLP, __FUNCTION__); + break; + } + } +} diff --git a/AltairZ80/vfdhd.h b/AltairZ80/vfdhd.h new file mode 100644 index 00000000..7b5052c2 --- /dev/null +++ b/AltairZ80/vfdhd.h @@ -0,0 +1,43 @@ +/************************************************************************* + * * + * $Id: vfdhd.h 1694 2007-12-14 05:23:11Z hharte $ * + * * + * Copyright (c) 2007-2008 Howard M. Harte. * + * http://www.hartetec.com * + * * + * 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 HOWARD M. HARTE 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 Howard M. Harte shall * + * not be used in advertising or otherwise to promote the sale, use or * + * other dealings in this Software without prior written authorization * + * Howard M. Harte. * + * * + * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. * + * * + * Module Description: * + * Micropolis FDC module for SIMH definitions * + * * + * Environment: * + * User mode only * + * * + *************************************************************************/ + +extern int32 mfdhd_dev(const int32 port, const int32 io, const int32 data); + diff --git a/AltairZ80/wd179x.c b/AltairZ80/wd179x.c new file mode 100644 index 00000000..f7394462 --- /dev/null +++ b/AltairZ80/wd179x.c @@ -0,0 +1,864 @@ +/************************************************************************* + * * + * $Id: wd179x.c 1907 2008-05-21 07:04:17Z hharte $ * + * * + * Copyright (c) 2007-2008 Howard M. Harte. * + * http://www.hartetec.com * + * * + * 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 HOWARD M. HARTE 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 Howard M. Harte shall * + * not be used in advertising or otherwise to promote the sale, use or * + * other dealings in this Software without prior written authorization * + * Howard M. Harte. * + * * + * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. * + * * + * Module Description: * + * Generic WD179X Disk Controller module for SIMH. * + * * + * Environment: * + * User mode only * + * * + *************************************************************************/ + +/*#define DBG_MSG */ + +#include "altairz80_defs.h" + +#if defined (_WIN32) +#include +#endif + +#include "sim_imd.h" +#include "wd179x.h" + +#ifdef DBG_MSG +#define DBG_PRINT(args) printf args +#else +#define DBG_PRINT(args) +#endif + +#define SEEK_MSG 0x01 +#define CMD_MSG 0x04 +#define RD_DATA_MSG 0x08 +#define WR_DATA_MSG 0x10 +#define STATUS_MSG 0x20 +#define VERBOSE_MSG 0x80 + +#define WD179X_MAX_DRIVES 4 +#define WD179X_SECTOR_LEN 8192 + +#define CMD_PHASE 0 +#define EXEC_PHASE 1 +#define DATA_PHASE 2 + +/* Status Bits for Type I Commands */ +#define WD179X_STAT_NOT_READY (1 << 7) +#define WD179X_STAT_WPROT (1 << 6) +#define WD179X_STAT_HLD (1 << 5) +#define WD179X_STAT_SEEK_ERROR (1 << 4) +#define WD179X_STAT_CRC_ERROR (1 << 3) +#define WD179X_STAT_TRACK0 (1 << 2) +#define WD179X_STAT_INDEX (1 << 1) +#define WD179X_STAT_BUSY (1 << 0) + +/* Status Bits for Type II, III Commands */ +#define WD179X_STAT_REC_TYPE (1 << 5) +#define WD179X_STAT_NOT_FOUND (1 << 4) +#define WD179X_STAT_LOST_DATA (1 << 2) +#define WD179X_STAT_DRQ (1 << 1) + + +typedef union { + uint8 raw[WD179X_SECTOR_LEN]; +} SECTOR_FORMAT; + +typedef struct { + UNIT *uptr; + DISK_INFO *imd; + uint8 ntracks; /* number of tracks */ + uint8 nheads; /* number of heads */ + uint32 sectsize; /* sector size, not including pre/postamble */ + uint8 track; /* Current Track */ + uint8 ready; /* Is drive ready? */ +} WD179X_DRIVE_INFO; + +typedef struct { + PNP_INFO pnp; /* Plug-n-Play Information */ + uint8 intrq; /* WD179X Interrupt Request Output (EOJ) */ + uint8 hld; /* WD179X Head Load Output */ + uint8 drq; /* WD179X DMA Request Output */ + uint8 ddens; /* WD179X Double-Density Input */ + uint8 fdc_head; /* H Head Number */ + uint8 sel_drive; /* Currently selected drive */ + uint8 drivetype; /* 8 or 5 depending on disk type. */ + uint8 fdc_status; /* WD179X Status Register */ + uint8 verify; /* WD179X Type 1 command Verify flag */ + uint8 fdc_data; /* WD179X Data Register */ + uint8 fdc_read; /* TRUE when reading */ + uint8 fdc_write; /* TRUE when writing */ + uint8 fdc_read_addr; /* TRUE when READ ADDRESS command is in progress */ + uint8 fdc_multiple; /* TRUE for multi-sector read/write */ + uint16 fdc_datacount; /* Read or Write data remaining transfer length */ + uint16 fdc_dataindex; /* index of current byte in sector data */ + uint8 index_pulse_wait; /* TRUE if waiting for interrupt on next index pulse. */ + uint8 fdc_sector; /* R Record (Sector) */ + uint8 fdc_sec_len; /* N Sector Length */ + int8 step_dir; + WD179X_DRIVE_INFO drive[WD179X_MAX_DRIVES]; +} WD179X_INFO; + +static SECTOR_FORMAT sdata; +extern uint32 PCX; +extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc); +extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type, + int32 (*routine)(const int32, const int32, const int32), uint8 unmap); + +t_stat wd179x_svc (UNIT *uptr); + +/* These are needed for DMA. PIO Mode has not been implemented yet. */ +extern void PutBYTEWrapper(const uint32 Addr, const uint32 Value); +extern uint8 GetBYTEWrapper(const uint32 Addr); +static uint8 Do1793Command(uint8 cCommand); + +#define UNIT_V_WD179X_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_WD179X_WLK (1 << UNIT_V_WD179X_WLK) +#define UNIT_V_WD179X_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ +#define UNIT_WD179X_VERBOSE (1 << UNIT_V_WD179X_VERBOSE) +#define WD179X_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */ +#define WD179X_CAPACITY_SSSD (77*1*26*128) /* Single-sided Single Density IBM Diskette1 */ +#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */ +#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */ +#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */ + +/* WD179X Commands */ +#define WD179X_RESTORE 0x00 /* Type I */ +#define WD179X_SEEK 0x10 /* Type I */ +#define WD179X_STEP 0x20 /* Type I */ +#define WD179X_STEP_U 0x30 /* Type I */ +#define WD179X_STEP_IN 0x40 /* Type I */ +#define WD179X_STEP_IN_U 0x50 /* Type I */ +#define WD179X_STEP_OUT 0x60 /* Type I */ +#define WD179X_STEP_OUT_U 0x70 /* Type I */ +#define WD179X_READ_REC 0x80 /* Type II */ +#define WD179X_READ_RECS 0x90 /* Type II */ +#define WD179X_WRITE_REC 0xA0 /* Type II */ +#define WD179X_WRITE_RECS 0xB0 /* Type II */ +#define WD179X_READ_ADDR 0xC0 /* Type III */ +#define WD179X_FORCE_INTR 0xD0 /* Type IV */ +#define WD179X_READ_TRACK 0xE0 /* Type III */ +#define WD179X_WRITE_TRACK 0xF0 /* Type III */ + +static int32 trace_level = 0xff; /* Disable all tracing by default. */ +static int32 bootstrap = 0; + +static int32 wd179xdev(const int32 port, const int32 io, const int32 data); +static t_stat wd179x_reset(DEVICE *dptr); +int32 find_unit_index (UNIT *uptr); + +WD179X_INFO wd179x_info_data = { { 0x0, 0, 0x30, 4 } }; +WD179X_INFO *wd179x_info = &wd179x_info_data; + +static UNIT wd179x_unit[] = { + { UDATA (&wd179x_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, WD179X_CAPACITY), 58200 }, + { UDATA (&wd179x_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, WD179X_CAPACITY), 58200 }, + { UDATA (&wd179x_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, WD179X_CAPACITY), 58200 }, + { UDATA (&wd179x_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, WD179X_CAPACITY), 58200 } +}; + +static REG wd179x_reg[] = { + { HRDATA (TRACELEVEL, trace_level, 16), }, + { DRDATA (BOOTSTRAP, bootstrap, 10), }, + { NULL } +}; + +static MTAB wd179x_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL }, + { UNIT_WD179X_WLK, 0, "WRTENB", "WRTENB", NULL }, + { UNIT_WD179X_WLK, UNIT_WD179X_WLK, "WRTLCK", "WRTLCK", NULL }, + /* quiet, no warning messages */ + { UNIT_WD179X_VERBOSE, 0, "QUIET", "QUIET", NULL }, + /* verbose, show warning messages */ + { UNIT_WD179X_VERBOSE, UNIT_WD179X_VERBOSE, "VERBOSE", "VERBOSE", NULL }, + { 0 } +}; + +DEVICE wd179x_dev = { + "WD179X", wd179x_unit, wd179x_reg, wd179x_mod, + WD179X_MAX_DRIVES, 10, 31, 1, WD179X_MAX_DRIVES, WD179X_MAX_DRIVES, + NULL, NULL, &wd179x_reset, + NULL, &wd179x_attach, &wd179x_detach, + &wd179x_info_data, (DEV_DISABLE | DEV_DIS), 0, + NULL, NULL, NULL +}; + +/* Unit service routine */ +/* Used to generate INDEX pulses in response to a FORCE_INTR command */ +t_stat wd179x_svc (UNIT *uptr) +{ + + if(wd179x_info->index_pulse_wait == TRUE) { + wd179x_info->index_pulse_wait = FALSE; + wd179x_info->intrq = 1; + } + + return SCPE_OK; +} + + +/* Reset routine */ +static t_stat wd179x_reset(DEVICE *dptr) +{ + PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; + + if(dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */ + sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &wd179xdev, TRUE); + } else { + /* Connect I/O Ports at base address */ + if(sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &wd179xdev, FALSE) != 0) { + printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->io_base); + return SCPE_ARG; + } + } + return SCPE_OK; +} + +extern int32 find_unit_index (UNIT *uptr); + +void wd179x_external_restore(void) +{ + WD179X_DRIVE_INFO *pDrive; + pDrive = &wd179x_info->drive[wd179x_info->sel_drive]; + + if(pDrive->uptr == NULL) { + TRACE_PRINT(SEEK_MSG, + ("WD179X: " ADDRESS_FORMAT " No drive selected, cannot restore." NLP, PCX)) + return; + } + + TRACE_PRINT(SEEK_MSG, + ("WD179X[%d]: " ADDRESS_FORMAT " External Restore drive to track 0" NLP, wd179x_info->sel_drive, PCX)) + + pDrive->track = 0; + +} + +/* Attach routine */ +t_stat wd179x_attach(UNIT *uptr, char *cptr) +{ + char header[4]; + t_stat r; + int32 i = 0; + + r = attach_unit(uptr, cptr); /* attach unit */ + if ( r != SCPE_OK) /* error? */ + return r; + + /* Determine length of this disk */ + uptr->capac = sim_fsize(uptr->fileref); + + i = find_unit_index(uptr); + + if (i == -1) { + return (SCPE_IERR); + } + + DBG_PRINT(("Attach WD179X%d\n", i)); + wd179x_info->drive[i].uptr = uptr; + + /* Default to drive not ready */ + wd179x_info->drive[i].ready = 0; + + if(uptr->capac > 0) { + fgets(header, 4, uptr->fileref); + if(!strcmp(header, "IMD")) { + uptr->u3 = IMAGE_TYPE_IMD; + } else if(!strcmp(header, "CPT")) { + printf("CPT images not yet supported\n"); + uptr->u3 = IMAGE_TYPE_CPT; + wd179x_detach(uptr); + return SCPE_OPENERR; + } else { + printf("DSK images not yet supported\n"); + uptr->u3 = IMAGE_TYPE_DSK; + wd179x_detach(uptr); + return SCPE_OPENERR; + } + } else { + /* creating file, must be DSK format. */ + printf("Cannot create images, must start with a WD179X IMD image.\n"); + uptr->u3 = IMAGE_TYPE_DSK; + wd179x_detach(uptr); + return SCPE_OPENERR; + } + + if (uptr->flags & UNIT_WD179X_VERBOSE) + printf("WD179X%d: attached to '%s', type=%s, len=%d\n", i, cptr, + uptr->u3 == IMAGE_TYPE_IMD ? "IMD" : uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK", + uptr->capac); + + if(uptr->u3 == IMAGE_TYPE_IMD) { + if(uptr->capac < WD179X_CAPACITY_SSSD) { /*was 318000 but changed to allow 8inch SSSD disks*/ + printf("IMD file too small for use with SIMH.\nCopy an existing file and format it with CP/M.\n"); + } + + if (uptr->flags & UNIT_WD179X_VERBOSE) + printf("--------------------------------------------------------\n"); + wd179x_info->drive[i].imd = diskOpen((uptr->fileref), (uptr->flags & UNIT_WD179X_VERBOSE)); + wd179x_info->drive[i].ready = 1; + if (uptr->flags & UNIT_WD179X_VERBOSE) + printf("\n"); + } else { + wd179x_info->drive[i].imd = NULL; + } + + wd179x_info->fdc_sec_len = 0; /* 128 byte sectors, fixme */ + wd179x_info->sel_drive = 0; + + return SCPE_OK; +} + + +/* Detach routine */ +t_stat wd179x_detach(UNIT *uptr) +{ + t_stat r; + int8 i; + + i = find_unit_index(uptr); + + if (i == -1) { + return (SCPE_IERR); + } + + DBG_PRINT(("Detach WD179X%d\n", i)); + diskClose(wd179x_info->drive[i].imd); + wd179x_info->drive[i].ready = 0; + + r = detach_unit(uptr); /* detach unit */ + if ( r != SCPE_OK) + return r; + + return SCPE_OK; +} + + +static int32 wd179xdev(const int32 port, const int32 io, const int32 data) +{ + DBG_PRINT(("WD179X: " ADDRESS_FORMAT " %s, Port 0x%02x Data 0x%02x" NLP, + PCX, io ? "OUT" : " IN", port, data)); + if(io) { + WD179X_Write(port, data); + return 0; + } else { + return(WD179X_Read(port)); + } +} + +static uint8 floorlog2(unsigned int n) +{ + /* Compute log2(n) */ + uint8 r = 0; + if(n >= 1<<16) { n >>=16; r += 16; } + if(n >= 1<< 8) { n >>= 8; r += 8; } + if(n >= 1<< 4) { n >>= 4; r += 4; } + if(n >= 1<< 2) { n >>= 2; r += 2; } + if(n >= 1<< 1) { r += 1; } + return ((n == 0) ? (0xFF) : r); /* 0xFF is error return value */ +} + +uint8 WD179X_Read(const uint32 Addr) +{ + uint8 cData; + WD179X_DRIVE_INFO *pDrive; + unsigned int flags; + unsigned int readlen; + int status; + + pDrive = &wd179x_info->drive[wd179x_info->sel_drive]; + + if(pDrive->uptr == NULL) { + return 0xFF; + } + + cData = 0x00; + + switch(Addr & 0x3) { + case WD179X_STATUS: + cData = (pDrive->ready == 0) ? WD179X_STAT_NOT_READY : 0; + cData |= wd179x_info->fdc_status; /* Status Register */ + TRACE_PRINT(STATUS_MSG, + ("WD179X: " ADDRESS_FORMAT " RD STATUS = 0x%02x" NLP, PCX, cData)) + wd179x_info->intrq = 0; + break; + case WD179X_TRACK: + cData = pDrive->track; + TRACE_PRINT(STATUS_MSG, + ("WD179X: " ADDRESS_FORMAT " RD TRACK = 0x%02x" NLP, PCX, cData)) + break; + case WD179X_SECTOR: + cData = wd179x_info->fdc_sector; + TRACE_PRINT(STATUS_MSG, + ("WD179X: " ADDRESS_FORMAT " RD SECT = 0x%02x" NLP, PCX, cData)) + break; + case WD179X_DATA: + cData = 0xFF; /* Return High-Z data */ + if(wd179x_info->fdc_read == TRUE) { + if(wd179x_info->fdc_dataindex < wd179x_info->fdc_datacount) { + cData = sdata.raw[wd179x_info->fdc_dataindex]; + if(wd179x_info->fdc_read_addr == TRUE) { + TRACE_PRINT(STATUS_MSG, + ("WD179X[%d]: " ADDRESS_FORMAT " READ_ADDR[%d] = 0x%02x" NLP, wd179x_info->sel_drive, PCX, wd179x_info->fdc_dataindex, cData)) + } + + wd179x_info->fdc_dataindex++; + if(wd179x_info->fdc_dataindex == wd179x_info->fdc_datacount) { + if(wd179x_info->fdc_multiple == FALSE) { + wd179x_info->fdc_status &= ~(WD179X_STAT_DRQ | WD179X_STAT_BUSY); /* Clear DRQ, BUSY */ + wd179x_info->drq = 0; + wd179x_info->intrq = 1; + wd179x_info->fdc_read = FALSE; + wd179x_info->fdc_read_addr = FALSE; + } else { + + /* Compute Sector Size */ + wd179x_info->fdc_sec_len = floorlog2( + pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7; + if(wd179x_info->fdc_sec_len == 0xF8) { /*Error calculating N*/ + printf("Invalid sector size!\n"); + } + + wd179x_info->fdc_sector ++; + TRACE_PRINT(RD_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " MULTI_READ_REC, T:%d/S:%d/N:%d, %s, len=%d" NLP, + wd179x_info->sel_drive, + PCX, + pDrive->track, + wd179x_info->fdc_head, + wd179x_info->fdc_sector, + wd179x_info->ddens ? "DD" : "SD", + 128 << wd179x_info->fdc_sec_len)); + + status = sectRead(pDrive->imd, + pDrive->track, + wd179x_info->fdc_head, + wd179x_info->fdc_sector, + sdata.raw, + 128 << wd179x_info->fdc_sec_len, + &flags, + &readlen); + + if(status != -1) { + wd179x_info->fdc_status = (WD179X_STAT_DRQ | WD179X_STAT_BUSY); /* Set DRQ, BUSY */ + wd179x_info->drq = 1; + wd179x_info->fdc_datacount = 128 << wd179x_info->fdc_sec_len; + wd179x_info->fdc_dataindex = 0; + wd179x_info->fdc_read = TRUE; + wd179x_info->fdc_read_addr = FALSE; + } else { + wd179x_info->fdc_status = 0; /* Clear DRQ, BUSY */ + wd179x_info->fdc_status |= WD179X_STAT_NOT_FOUND; + wd179x_info->drq = 0; + wd179x_info->intrq = 1; + wd179x_info->fdc_read = FALSE; + wd179x_info->fdc_read_addr = FALSE; + } + } + } + } + } + break; + } + + return (cData); +} + +/* + * Command processing happens in three stages: + * 1. Flags and initial conditions are set up based on the Type of the command. + * 2. The execution phase takes place. + * 3. Status is updated based on the Type and outcome of the command execution. + * + * See the WD179x-02 Datasheet available on www.hartetechnologies.com/manuals/ + * + */ +static uint8 Do1793Command(uint8 cCommand) +{ + uint8 result = 0; + WD179X_DRIVE_INFO *pDrive; + unsigned int flags; + unsigned int readlen; + + pDrive = &wd179x_info->drive[wd179x_info->sel_drive]; + + if(pDrive->uptr == NULL) { + return 0xFF; + } + + if(wd179x_info->fdc_status & WD179X_STAT_BUSY) { + if((cCommand & 0xF0) != WD179X_FORCE_INTR) { + printf("WD179X[%d]: ERROR: Command 0x%02x ignored because controller is BUSY\n", wd179x_info->sel_drive, cCommand); + } + return 0xFF; + } + + /* Extract Type-specific command flags, and set initial conditions */ + switch(cCommand & 0xF0) { + /* Type I Commands */ + case WD179X_RESTORE: + case WD179X_SEEK: + case WD179X_STEP: + case WD179X_STEP_U: + case WD179X_STEP_IN: + case WD179X_STEP_IN_U: + case WD179X_STEP_OUT: + case WD179X_STEP_OUT_U: + wd179x_info->fdc_status |= WD179X_STAT_BUSY; /* Set BUSY */ + wd179x_info->fdc_status &= ~(WD179X_STAT_CRC_ERROR | WD179X_STAT_SEEK_ERROR | WD179X_STAT_DRQ); + wd179x_info->intrq = 0; + wd179x_info->hld = cCommand && 0x08; + wd179x_info->verify = cCommand & 0x04; + break; + /* Type II Commands */ + case WD179X_READ_REC: + case WD179X_READ_RECS: + case WD179X_WRITE_REC: + case WD179X_WRITE_RECS: + wd179x_info->fdc_status = WD179X_STAT_BUSY; /* Set BUSY, clear all others */ + wd179x_info->intrq = 0; + wd179x_info->hld = 1; /* Load the head immediately, E Flag not checked. */ + break; + /* Type III Commands */ + case WD179X_READ_ADDR: + case WD179X_READ_TRACK: + case WD179X_WRITE_TRACK: + /* Type IV Commands */ + case WD179X_FORCE_INTR: + default: + break; + } + + switch(cCommand & 0xF0) { + /* Type I Commands */ + case WD179X_RESTORE: + TRACE_PRINT(CMD_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=RESTORE" NLP, wd179x_info->sel_drive, PCX)); + pDrive->track = 0; + wd179x_info->intrq = 1; + break; + case WD179X_SEEK: + TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=SEEK, track=%d, new=%d" NLP, wd179x_info->sel_drive, PCX, pDrive->track, wd179x_info->fdc_data)); + pDrive->track = wd179x_info->fdc_data; + break; + case WD179X_STEP: + TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=STEP" NLP, wd179x_info->sel_drive, PCX)); + break; + case WD179X_STEP_U: + TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=STEP_U dir=%d" NLP, wd179x_info->sel_drive, PCX, wd179x_info->step_dir)); + if(wd179x_info->step_dir == 1) { + if(pDrive->track < 255) pDrive->track++; + } else if (wd179x_info->step_dir == -1) { + if(pDrive->track > 0) pDrive->track--; + } else { + printf("WD179X[%d]: Error, undefined direction for STEP\n", wd179x_info->sel_drive); + } + break; + case WD179X_STEP_IN: + TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=STEP_IN" NLP, wd179x_info->sel_drive, PCX)); + break; + case WD179X_STEP_IN_U: + if(pDrive->track < 255) pDrive->track++; + wd179x_info->step_dir = 1; + TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=STEP_IN_U, Track=%d" NLP, + wd179x_info->sel_drive, PCX, pDrive->track)); + break; + case WD179X_STEP_OUT: + TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=STEP_OUT" NLP, + wd179x_info->sel_drive, PCX)); + break; + case WD179X_STEP_OUT_U: + TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=STEP_OUT_U" NLP, + wd179x_info->sel_drive, PCX)); + if(pDrive->track > 0) pDrive->track--; + wd179x_info->step_dir = -1; + break; + /* Type II Commands */ + case WD179X_READ_REC: + case WD179X_READ_RECS: + /* Compute Sector Size */ + wd179x_info->fdc_sec_len = floorlog2( + pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7; + if(wd179x_info->fdc_sec_len == 0xF8) { /*Error calculating N*/ + printf("Invalid sector size!\n"); + } + + wd179x_info->fdc_multiple = (cCommand & 0x10) ? TRUE : FALSE; + TRACE_PRINT(RD_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=READ_REC, T:%d/S:%d/N:%d, %s, %s len=%d" NLP, + wd179x_info->sel_drive, + PCX, pDrive->track, + wd179x_info->fdc_head, + wd179x_info->fdc_sector, + wd179x_info->fdc_multiple ? "Multiple" : "Single", + wd179x_info->ddens ? "DD" : "SD", + 128 << wd179x_info->fdc_sec_len)); + + sectRead(pDrive->imd, + pDrive->track, + wd179x_info->fdc_head, + wd179x_info->fdc_sector, + sdata.raw, + 128 << wd179x_info->fdc_sec_len, + &flags, + &readlen); + + if(IMD_MODE_MFM(pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].mode) != (wd179x_info->ddens)) { + printf("Sector not found\n"); + wd179x_info->fdc_status |= WD179X_STAT_NOT_FOUND; /* Sector not found */ + wd179x_info->intrq = 1; + } else { + wd179x_info->fdc_status |= (WD179X_STAT_DRQ); /* Set DRQ */ + wd179x_info->drq = 1; + wd179x_info->fdc_datacount = 128 << wd179x_info->fdc_sec_len; + wd179x_info->fdc_dataindex = 0; + wd179x_info->fdc_write = FALSE; + wd179x_info->fdc_read = TRUE; + wd179x_info->fdc_read_addr = FALSE; + } + break; + case WD179X_WRITE_RECS: + printf("-->> Error: WRITE_RECS not implemented." NLP); + case WD179X_WRITE_REC: + /* Compute Sector Size */ + wd179x_info->fdc_sec_len = floorlog2( + pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7; + if(wd179x_info->fdc_sec_len == 0xF8) { /*Error calculating N*/ + printf("Invalid sector size!\n"); + } + + TRACE_PRINT(WR_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=WRITE_REC, T:%d/S:%d/N:%d, %s." NLP, + wd179x_info->sel_drive, + PCX, + pDrive->track, + cCommand&&0x08, + wd179x_info->fdc_sector, + (cCommand & 0x10) ? "Multiple" : "Single")); + wd179x_info->fdc_status |= (WD179X_STAT_DRQ); /* Set DRQ */ + wd179x_info->drq = 1; + wd179x_info->fdc_datacount = 128 << wd179x_info->fdc_sec_len; + wd179x_info->fdc_dataindex = 0; + wd179x_info->fdc_write = TRUE; + wd179x_info->fdc_read = FALSE; + wd179x_info->fdc_read_addr = FALSE; + + sdata.raw[wd179x_info->fdc_dataindex] = wd179x_info->fdc_data; + break; + /* Type III Commands */ + case WD179X_READ_ADDR: + TRACE_PRINT(RD_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=READ_ADDR, T:%d/S:%d, %s" NLP, + wd179x_info->sel_drive, + PCX, + pDrive->track, + wd179x_info->fdc_head, + wd179x_info->ddens ? "DD" : "SD")); + + /* Compute Sector Size */ + wd179x_info->fdc_sec_len = floorlog2( + pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7; + if(wd179x_info->fdc_sec_len == 0xF8) { /*Error calculating N*/ + printf("Invalid sector size!\n"); + } + + if(IMD_MODE_MFM(pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].mode) != (wd179x_info->ddens)) { + wd179x_info->fdc_status = WD179X_STAT_NOT_FOUND; /* Sector not found */ + wd179x_info->intrq = 1; + } else { + wd179x_info->fdc_status = (WD179X_STAT_DRQ | WD179X_STAT_BUSY); /* Set DRQ, BUSY */ + wd179x_info->drq = 1; + wd179x_info->fdc_datacount = 6; + wd179x_info->fdc_dataindex = 0; + wd179x_info->fdc_read = TRUE; + wd179x_info->fdc_read_addr = TRUE; + + sdata.raw[0] = pDrive->track; + sdata.raw[1] = wd179x_info->fdc_head; + sdata.raw[2] = wd179x_info->fdc_sector; + sdata.raw[3] = wd179x_info->fdc_sec_len; + sdata.raw[4] = 0xAA; /* CRC1 */ + sdata.raw[5] = 0x55; /* CRC2 */ + + wd179x_info->fdc_sector = pDrive->track; + wd179x_info->fdc_status &= ~(WD179X_STAT_BUSY); /* Clear BUSY */ + wd179x_info->intrq = 1; + } + break; + case WD179X_READ_TRACK: + TRACE_PRINT(RD_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=READ_TRACK" NLP, wd179x_info->sel_drive, PCX)); + printf("-->> Error: READ_TRACK not implemented." NLP); + break; + case WD179X_WRITE_TRACK: + TRACE_PRINT(WR_DATA_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=WRITE_TRACK" NLP, wd179x_info->sel_drive, PCX)); + printf("-->> Error: WRITE_TRACK not implemented." NLP); + break; + /* Type IV Commands */ + case WD179X_FORCE_INTR: + TRACE_PRINT(CMD_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " CMD=FORCE_INTR" NLP, wd179x_info->sel_drive, PCX)); + if((cCommand & 0x0F) == 0) { /* I0-I3 == 0, no intr, but clear BUSY and terminate command */ + wd179x_info->fdc_status &= ~(WD179X_STAT_DRQ | WD179X_STAT_BUSY); /* Clear DRQ, BUSY */ + wd179x_info->drq = 0; + wd179x_info->fdc_write = FALSE; + wd179x_info->fdc_read = FALSE; + wd179x_info->fdc_read_addr = FALSE; + wd179x_info->fdc_datacount = 0; + wd179x_info->fdc_dataindex = 0; + } else { + if(wd179x_info->fdc_status & WD179X_STAT_BUSY) { /* Force Interrupt when command is pending */ + } else { /* Command not pending, clear status */ + wd179x_info->fdc_status = 0; + } + + if(cCommand & 0x04) { + wd179x_info->index_pulse_wait = TRUE; + sim_activate (wd179x_unit, wd179x_info->drivetype == 8 ? 48500 : 58200); /* Generate INDEX pulse */ + } else { + wd179x_info->intrq = 1; + } + wd179x_info->fdc_status &= ~(WD179X_STAT_BUSY); /* Clear BUSY */ + } + break; + default: + printf("WD179X[%d]: Unknown WD179X command 0x%02x.\n", wd179x_info->sel_drive, cCommand); + break; + } + + /* Post processing of Type-specific command */ + switch(cCommand & 0xF0) { + /* Type I Commands */ + case WD179X_RESTORE: + case WD179X_SEEK: + case WD179X_STEP: + case WD179X_STEP_U: + case WD179X_STEP_IN: + case WD179X_STEP_IN_U: + case WD179X_STEP_OUT: + case WD179X_STEP_OUT_U: + if(wd179x_info->verify) { /* Verify the selected track/head is ok. */ + TRACE_PRINT(SEEK_MSG, ("WD179X[%d]: " ADDRESS_FORMAT " Verify ", wd179x_info->sel_drive, PCX)); + if(sectSeek(pDrive->imd, pDrive->track, wd179x_info->fdc_head) != 0) { + TRACE_PRINT(SEEK_MSG, ("FAILED" NLP)); + wd179x_info->fdc_status |= WD179X_STAT_NOT_FOUND; + } else { + TRACE_PRINT(SEEK_MSG, ("Ok" NLP)); + } + } + + if(pDrive->track == 0) { + wd179x_info->fdc_status |= WD179X_STAT_TRACK0; + } else { + wd179x_info->fdc_status &= ~(WD179X_STAT_TRACK0); + } + + wd179x_info->fdc_status &= ~(WD179X_STAT_BUSY); /* Clear BUSY */ + wd179x_info->intrq = 1; + break; + /* Type II Commands */ + case WD179X_READ_REC: + case WD179X_READ_RECS: + case WD179X_WRITE_REC: + case WD179X_WRITE_RECS: + /* Type III Commands */ + case WD179X_READ_ADDR: + case WD179X_READ_TRACK: + case WD179X_WRITE_TRACK: + /* Type IV Commands */ + case WD179X_FORCE_INTR: + default: + break; + } + + + return result; +} + +uint8 WD179X_Write(const uint32 Addr, uint8 cData) +{ + WD179X_DRIVE_INFO *pDrive; + unsigned int flags; + unsigned int writelen; + + pDrive = &wd179x_info->drive[wd179x_info->sel_drive]; + + if(pDrive->uptr == NULL) { + return 0xFF; + } + + switch(Addr & 0x3) { + case WD179X_STATUS: + TRACE_PRINT(STATUS_MSG, + ("WD179X: " ADDRESS_FORMAT " WR CMD = 0x%02x" NLP, PCX, cData)) + wd179x_info->fdc_read = FALSE; + wd179x_info->fdc_write = FALSE; + wd179x_info->fdc_datacount = 0; + wd179x_info->fdc_dataindex = 0; + + Do1793Command(cData); + break; + case WD179X_TRACK: + TRACE_PRINT(STATUS_MSG, + ("WD179X: " ADDRESS_FORMAT " WR TRACK = 0x%02x" NLP, PCX, cData)) + pDrive->track = cData; + break; + case WD179X_SECTOR: /* Sector Register */ + TRACE_PRINT(STATUS_MSG, + ("WD179X: " ADDRESS_FORMAT " WR SECT = 0x%02x" NLP, PCX, cData)) + wd179x_info->fdc_sector = cData; + break; + case WD179X_DATA: + TRACE_PRINT(STATUS_MSG, + ("WD179X: " ADDRESS_FORMAT " WR DATA = 0x%02x" NLP, PCX, cData)) + if(wd179x_info->fdc_write == TRUE) { + if(wd179x_info->fdc_dataindex < wd179x_info->fdc_datacount) { + sdata.raw[wd179x_info->fdc_dataindex] = cData; + + wd179x_info->fdc_dataindex++; + if(wd179x_info->fdc_dataindex == wd179x_info->fdc_datacount) { + wd179x_info->fdc_status &= ~(WD179X_STAT_DRQ | WD179X_STAT_BUSY); /* Clear DRQ, BUSY */ + wd179x_info->drq = 0; + wd179x_info->intrq = 1; + + sectWrite(pDrive->imd, + pDrive->track, + wd179x_info->fdc_head, + wd179x_info->fdc_sector, + sdata.raw, + 128 << wd179x_info->fdc_sec_len, + &flags, + &writelen); + + wd179x_info->fdc_write = FALSE; + } + } + } + wd179x_info->fdc_data = cData; + break; + } + + return 0; +} + diff --git a/AltairZ80/wd179x.h b/AltairZ80/wd179x.h new file mode 100644 index 00000000..1ac1f19f --- /dev/null +++ b/AltairZ80/wd179x.h @@ -0,0 +1,67 @@ +/************************************************************************* + * * + * $Id: wd179x.h 1907 2008-05-21 07:04:17Z hharte $ * + * * + * Copyright (c) 2007-2008 Howard M. Harte. * + * http://www.hartetec.com * + * * + * 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 HOWARD M. HARTE 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 Howard M. Harte shall * + * not be used in advertising or otherwise to promote the sale, use or * + * other dealings in this Software without prior written authorization * + * Howard M. Harte. * + * * + * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. * + * * + * Module Description: * + * Generic Intel 8272 Disk Controller module for SIMH. * + * * + * Environment: * + * User mode only * + * * + *************************************************************************/ + +extern t_stat wd179x_attach(UNIT *uptr, char *cptr); +extern t_stat wd179x_detach(UNIT *uptr); +extern uint8 WD179X_Set_DMA(const uint32 dma_addr); +extern uint8 WD179X_Read(const uint32 Addr); +extern uint8 WD179X_Write(const uint32 Addr, uint8 cData); + +extern void wd179x_external_restore(void); + +#define WD179X_FDC_MSR 0 /* R=FDC Main Status Register, W=Drive Select Register */ +#define WD179X_FDC_DATA 1 /* R/W FDC Data Register */ + +#define WD179X_STATUS 0 +#define WD179X_TRACK 1 +#define WD179X_SECTOR 2 +#define WD179X_DATA 3 + +typedef struct { + PNP_INFO pnp; /* Plug-n-Play Information */ + uint8 intrq; /* WD179X Interrupt Request Output (EOJ) */ + uint8 hld; /* WD179X Head Load Output */ + uint8 drq; /* WD179X DMA Request Output */ + uint8 ddens; /* WD179X Double-Density Input */ + uint8 fdc_head; /* H Head Number */ + uint8 sel_drive; /* Currently selected drive */ + uint8 drivetype; /* 8 or 5 depending on disk type. */ +} WD179X_INFO_PUB; diff --git a/GRI/gri_cpu.c b/GRI/gri_cpu.c index c854828d..8f86b9e8 100644 --- a/GRI/gri_cpu.c +++ b/GRI/gri_cpu.c @@ -1,6 +1,6 @@ /* gri_cpu.c: GRI-909 CPU simulator - Copyright (c) 2001-2007, Robert M. Supnik + Copyright (c) 2001-2008, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,24 +23,26 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - cpu GRI-909 CPU + cpu GRI-909/GRI-99 CPU + 14-Jan-08 RMS Added GRI-99 support 28-Apr-07 RMS Removed clock initialization 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) 18-Jul-04 RMS Fixed missing ao_update calls in AX, AY write 17-Jul-04 RMS Revised MSR, EAO based on additional documentation 14-Mar-03 RMS Fixed bug in SC queue tracking - The system state for the GRI-909 is: + The system state for the GRI-909/GRI-99 is: - AX<0:15> arithmetic input - AY<0:15> arithmetic input - BSW<0:15> byte swapper - BPK<0:15> byte packer - GR[0:5]<0:15> extended general registers - MSR<0:15> machine status register - TRP<0:15> trap register (subroutine return) - SC<0:14> sequence counter + AX<15:0> arithmetic input + AY<15:0> arithmetic input + BSW<15:0> byte swapper + BPK<15:0> byte packer + GR[0:5]<15:0> extended general registers + MSR<15:0> machine status register + TRP<15:0> trap register (subroutine return) + SC<14:0> sequence counter + XR<15:0> index register (GRI-99 only) The GRI-909 has, nominally, just one instruction format: move. @@ -149,10 +151,20 @@ #define SCQ_SIZE 64 /* must be 2**n */ #define SCQ_MASK (SCQ_SIZE - 1) #define SCQ_ENTRY scq[scq_p = (scq_p - 1) & SCQ_MASK] = SC -#define UNIT_V_NOEAO (UNIT_V_UF) /* EAO absent */ -#define UNIT_NOEAO (1 << UNIT_V_NOEAO) -#define UNIT_V_MSIZE (UNIT_V_UF + 1) /* dummy mask */ -#define UNIT_MSIZE (1 << UNIT_V_MSIZE) +#define UNIT_V_AO (UNIT_V_UF + 0) /* AO */ +#define UNIT_AO (1u << UNIT_V_AO) +#define UNIT_V_EAO (UNIT_V_UF + 1) /* EAO */ +#define UNIT_EAO (1u << UNIT_V_EAO) +#define UNIT_V_GPR (UNIT_V_UF + 2) /* GPR */ +#define UNIT_GPR (1u << UNIT_V_GPR) +#define UNIT_V_BSWPK (UNIT_V_UF + 3) /* BSW-BPK */ +#define UNIT_BSWPK (1u << UNIT_V_BSWPK) +#define UNIT_V_GRI99 (UNIT_V_UF + 4) /* GRI-99 */ +#define UNIT_GRI99 (1u << UNIT_V_GRI99) +#define UNIT_V_MSIZE (UNIT_V_UF + 5) /* dummy mask */ +#define UNIT_MSIZE (1u << UNIT_V_MSIZE) + +#define IDX_ADD(x) ((((cpu_unit.flags & UNIT_GRI99) && ((x) & INDEX))? ((x) + XR): (x)) & AMASK) uint16 M[MAXMEMSIZE] = { 0 }; /* memory */ uint32 SC; /* sequence cntr */ @@ -166,6 +178,7 @@ uint32 BSW, BPK; /* byte swap, pack */ uint32 GR[6]; /* extended general regs */ uint32 SWR; /* switch reg */ uint32 DR; /* display register */ +uint32 XR; /* index register */ uint32 thwh = 0; /* thumbwheel */ uint32 dev_done = 0; /* device flags */ uint32 bkp = 0; /* bkpt pending */ @@ -197,6 +210,9 @@ uint32 zero_sf (uint32 op); uint32 ir_rd (uint32 op); t_stat ir_fo (uint32 op); uint32 trp_rd (uint32 src); +t_stat trp_wr (uint32 dst, uint32 val); +uint32 atrp_rd (uint32 src); +t_stat atrp_wr (uint32 dst, uint32 val); uint32 isr_rd (uint32 src); t_stat isr_wr (uint32 dst, uint32 val); t_stat isr_fo (uint32 op); @@ -224,6 +240,8 @@ uint32 bpk_rd (uint32 src); t_stat bpk_wr (uint32 dst, uint32 val); uint32 gr_rd (uint32 src); t_stat gr_wr (uint32 dst, uint32 val); +uint32 xr_rd (uint32 src); +t_stat xr_wr (uint32 dst, uint32 val); extern t_stat rtc_fo (uint32 op); extern uint32 rtc_sf (uint32 op); @@ -240,9 +258,9 @@ struct gdev dev_tab[64] = { { &zero_rd, &zero_wr, &zero_fo, &zero_sf }, /* 00: zero */ { &ir_rd, &zero_wr, &ir_fo, &zero_sf }, /* ir */ { &no_rd, &no_wr, &no_fo, &no_sf }, /* fo/sf */ - { &trp_rd, &no_wr, &zero_fo, &zero_sf }, /* trp */ + { &trp_rd, &trp_wr, &zero_fo, &zero_sf }, /* trp */ { &isr_rd, &isr_wr, &isr_fo, &isr_sf }, /* isr */ - { &ma_rd, &no_wr, &no_fo, &no_sf }, /* MA */ + { &ma_rd, &no_wr, &no_fo, &no_sf }, /* ma */ { &mem_rd, &mem_wr, &zero_fo, &zero_sf }, /* memory */ { &sc_rd, &sc_wr, &zero_fo, &zero_sf }, /* sc */ { &swr_rd, &no_wr, &no_fo, &no_sf }, /* swr */ @@ -255,8 +273,8 @@ struct gdev dev_tab[64] = { { &msr_rd, &msr_wr, &zero_fo, &zero_sf }, /* msr */ { &no_rd, &no_wr, &no_fo, &no_sf }, /* 20 */ { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, + { &xr_rd, &xr_wr, &no_fo, &no_sf }, /* xr */ + { &atrp_rd, &atrp_wr, &no_fo, &no_sf }, { &bsw_rd, &bsw_wr, &no_fo, &no_sf }, /* bsw */ { &bpk_rd, &bpk_wr, &no_fo, &no_sf }, /* bpk */ { &no_rd, &no_wr, &no_fo, &no_sf }, @@ -318,7 +336,7 @@ static const int32 vec_map[16] = { cpu_mod CPU modifiers list */ -UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) }; +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX+UNIT_BINK+UNIT_AO+UNIT_EAO+UNIT_GPR, MAXMEMSIZE) }; REG cpu_reg[] = { { ORDATA (SC, SC, 15) }, @@ -336,9 +354,11 @@ REG cpu_reg[] = { { ORDATA (GR4, GR[3], 16) }, { ORDATA (GR5, GR[4], 16) }, { ORDATA (GR6, GR[5], 16) }, + { ORDATA (XR, XR, 16) }, { FLDATA (BOV, MSR, MSR_V_BOV) }, { FLDATA (L, MSR, MSR_V_L) }, { GRDATA (FOA, MSR, 8, 2, MSR_V_FOA) }, + { FLDATA (SOV, MSR, MSR_V_SOV) }, { FLDATA (AOV, MSR, MSR_V_AOV) }, { ORDATA (IR, IR, 16), REG_RO }, { ORDATA (MA, MA, 16), REG_RO }, @@ -357,8 +377,16 @@ REG cpu_reg[] = { }; MTAB cpu_mod[] = { - { UNIT_NOEAO, UNIT_NOEAO, "no EAO", "NOEAO", NULL }, - { UNIT_NOEAO, 0, "EAO", "EAO", NULL }, + { UNIT_GRI99, UNIT_GRI99, "GRI99", "GRI99", NULL }, + { UNIT_GRI99, 0, "GRI909", "GRI909", NULL }, + { UNIT_AO, UNIT_AO, "AO", "AO", NULL }, + { UNIT_AO, 0, "no AO", "NOAO", NULL }, + { UNIT_EAO, UNIT_EAO, "EAO", "EAO", NULL }, + { UNIT_EAO, 0, "no EAO", "NOEAO", NULL }, + { UNIT_GPR, UNIT_GPR, "GPR", "GPR", NULL }, + { UNIT_GPR, 0, "no GPR", "NOGPR", NULL }, + { UNIT_BSWPK, UNIT_BSWPK, "BSW-BPK", "BSW-BPK", NULL }, + { UNIT_BSWPK, 0, "no BSW-BPK", "NOBSW-BPK", NULL }, { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size }, { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size }, { UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size }, @@ -488,10 +516,11 @@ while (reason == 0) { /* loop until halted */ SCQ_ENTRY; /* save SC */ SC = (SC + 1) & AMASK; /* incr SC once */ MA = M[SC]; /* get jump addr */ + MA = IDX_ADD (MA); /* index? */ if (op & TRP_DEF) { /* defer? */ t = (M[MA] + 1) & DMASK; /* autoinc */ if (MEM_ADDR_OK (MA)) M[MA] = t; - MA = t & AMASK; /* ind addr */ + MA = IDX_ADD (t); /* index? */ } TRP = SC; /* save SC */ SC = MA; /* load new SC */ @@ -515,17 +544,19 @@ while (reason == 0) { /* loop until halted */ switch (op & MEM_MOD) { /* case on addr mode */ case MEM_DIR: /* direct */ - MA = M[SC] & AMASK; /* get address */ + MA = M[SC]; /* get address */ + MA = IDX_ADD (MA); /* index? */ SC = (SC + 1) & AMASK; /* incr SC again */ reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */ break; case MEM_DEF: /* defer */ - MA = M[SC] & AMASK; /* get ind addr */ + MA = M[SC]; /* get ind addr */ + MA = IDX_ADD (MA); /* index? */ SC = (SC + 1) & AMASK; /* incr SC again */ t = (M[MA] + 1) & DMASK; /* autoinc */ if (MEM_ADDR_OK (MA)) M[MA] = t; - MA = t & AMASK; /* ind addr */ + MA = IDX_ADD (t); /* index? */ reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */ break; @@ -539,7 +570,7 @@ while (reason == 0) { /* loop until halted */ MA = SC; /* get ind addr */ t = (M[MA] + 1) & DMASK; /* autoinc */ if (MEM_ADDR_OK (MA)) M[MA] = t; - MA = t & AMASK; /* ind addr */ + MA = IDX_ADD (t); /* index? */ SC = (SC + 1) & AMASK; /* incr SC again */ reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */ break; @@ -671,6 +702,12 @@ uint32 trp_rd (uint32 src) return TRP; } +t_stat trp_wr (uint32 dst, uint32 val) +{ +TRP = val; +return SCPE_OK; +} + /* Interrupt status register (04) */ uint32 isr_rd (uint32 src) @@ -727,7 +764,7 @@ return SC; t_stat sc_wr (uint32 dst, uint32 dat) { SCQ_ENTRY; -SC = dat & AMASK; +SC = IDX_ADD (dat); return SCPE_OK; } @@ -748,11 +785,11 @@ return MSR & MSR_RW; t_stat msr_wr (uint32 src, uint32 dat) { MSR = dat & MSR_RW; /* new MSR */ -ao_update (); /* update AOV */ +ao_update (); /* update SOV,AOV */ return SCPE_OK; } -/* Arithmetic operators (11:14) */ +/* Arithmetic operator (11:13) */ uint32 ao_update (void) { @@ -787,47 +824,70 @@ return AO; uint32 ax_rd (uint32 src) { -return AX; +if (cpu_unit.flags & UNIT_AO) return AX; +else return 0; } t_stat ax_wr (uint32 dst, uint32 dat) { -AX = dat; -ao_update (); -return SCPE_OK; +if (cpu_unit.flags & UNIT_AO) { + AX = dat; + ao_update (); + return SCPE_OK; + } +return stop_opr; } uint32 ay_rd (uint32 src) { -return AY; +if (cpu_unit.flags & UNIT_AO) return AY; +else return 0; } t_stat ay_wr (uint32 dst, uint32 dat) { -AY = dat; -ao_update (); -return SCPE_OK; +if (cpu_unit.flags & UNIT_AO) { + AY = dat; + ao_update (); + return SCPE_OK; + } +return stop_opr; } uint32 ao_rd (uint32 src) { -return ao_update (); +if (cpu_unit.flags & UNIT_AO) return ao_update (); +else return 0; } t_stat ao_fo (uint32 op) { -uint32 t = OP_GET_FOA (op); /* get func */ - -MSR = MSR_PUT_FOA (MSR, t); /* store in MSR */ -ao_update (); /* update AOV */ -return SCPE_OK; +if (cpu_unit.flags & UNIT_AO) { + uint32 t = OP_GET_FOA (op); /* get func */ + MSR = MSR_PUT_FOA (MSR, t); /* store in MSR */ + ao_update (); /* update AOV */ + return SCPE_OK; + } +return stop_opr; } +uint32 ao_sf (uint32 op) +{ +if (!(cpu_unit.flags & UNIT_AO)) /* not installed? */ + return (stop_opr << SF_V_REASON); +if (((op & 2) && (MSR & MSR_AOV)) || /* arith carry? */ + ((op & 4) && (MSR & MSR_SOV))) return 1; /* arith overflow? */ +return 0; +} + +/* Extended arithmetic operator (14) */ + t_stat eao_fo (uint32 op) { uint32 t; -if (cpu_unit.flags & UNIT_NOEAO) return stop_opr; /* EAO installed? */ +if (!(cpu_unit.flags & UNIT_EAO)) /* EAO installed? */ + return stop_opr; switch (op) { case EAO_MUL: /* mul? */ @@ -869,54 +929,94 @@ switch (op) { break; } +// MSR = MSR_PUT_FOA (MSR, AO_ADD); /* AO fnc is add */ ao_update (); return SCPE_OK; } -uint32 ao_sf (uint32 op) +/* Index register (GRI-99) (22) */ + +uint32 xr_rd (uint32 src) { -if (((op & 2) && (MSR & MSR_AOV)) || /* arith carry? */ - ((op & 4) && (MSR & MSR_SOV))) return 1; /* arith overflow? */ -return 0; +if (cpu_unit.flags & UNIT_GRI99) return XR; +else return 0; +} + +t_stat xr_wr (uint32 dst, uint32 val) +{ +if (cpu_unit.flags & UNIT_GRI99) { + XR = val; + return SCPE_OK; + } +return stop_opr; +} + +/* Alternate trap (GRI-99) (23) */ + +uint32 atrp_rd (uint32 src) +{ +if (cpu_unit.flags & UNIT_GRI99) return TRP; +else return 0; +} + +t_stat atrp_wr (uint32 dst, uint32 val) +{ +if (cpu_unit.flags & UNIT_GRI99) { + TRP = val; + return SCPE_OK; + } +return stop_opr; } /* Byte swapper (24) */ uint32 bsw_rd (uint32 src) { -return BSW; +if (cpu_unit.flags & UNIT_BSWPK) return BSW; +else return 0; } t_stat bsw_wr (uint32 dst, uint32 val) { -BSW = ((val >> 8) & 0377) | ((val & 0377) << 8); -return SCPE_OK; +if (cpu_unit.flags & UNIT_BSWPK) { + BSW = ((val >> 8) & 0377) | ((val & 0377) << 8); + return SCPE_OK; + } +return stop_opr; } /* Byte packer (25) */ uint32 bpk_rd (uint32 src) { -return BPK; +if (cpu_unit.flags & UNIT_BSWPK) return BPK; +else return 0; } t_stat bpk_wr (uint32 dst, uint32 val) { -BPK = ((BPK & 0377) << 8) | (val & 0377); -return SCPE_OK; +if (cpu_unit.flags & UNIT_BSWPK) { + BPK = ((BPK & 0377) << 8) | (val & 0377); + return SCPE_OK; + } +return stop_opr; } /* General registers (30:35) */ uint32 gr_rd (uint32 src) { -return GR[src - U_GR]; +if (cpu_unit.flags & UNIT_GPR) return GR[src - U_GR]; +else return 0; } t_stat gr_wr (uint32 dst, uint32 dat) { -GR[dst - U_GR] = dat; -return SCPE_OK; +if (cpu_unit.flags & UNIT_GPR) { + GR[dst - U_GR] = dat; + return SCPE_OK; + } +return stop_opr; } /* Reset routine */ @@ -926,6 +1026,7 @@ t_stat cpu_reset (DEVICE *dptr) int32 i; AX = AY = AO = 0; +XR = 0; TRP = 0; ISR = 0; MSR = 0; diff --git a/GRI/gri_defs.h b/GRI/gri_defs.h index dacc88f5..35eff8f4 100644 --- a/GRI/gri_defs.h +++ b/GRI/gri_defs.h @@ -1,6 +1,6 @@ /* gri_defs.h: GRI-909 simulator definitions - Copyright (c) 2001-2004, Robert M. Supnik + Copyright (c) 2001-2008, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 12-Jan-08 RMS Added GRI-99 support 25-Apr-03 RMS Revised for extended file support 19-Sep-02 RMS Fixed declarations in gdev structure @@ -37,17 +38,12 @@ (SOV). Answer: signed and unsigned. 3. Ref Manual documents a ROM-subroutine multiply operator and mentions but does not document a "fast multiply"; MITCS uses an extended - arithmetic operator with multiply, divide, and shift. The behavior - of the extended arithmetic operator can only be inferred partially; - the shift is never used, and there is no indication of how divide - overflow is handled. Answer: EAO is a package of ROM subroutines - with just four functions: multiply, divide, arithmetic right shift, - and normalize. + arithmetic operator with multiply, divide, and shift. Answer: EAO + is a package of ROM subroutines with just four functions: multiply, + divide, arithmetic right shift, and normalize. 4. Is SOV testable even if the FOA is not ADD? Answer: AOV and SOV are calculated regardless of the function. 5. How does the EAO handle divide overflow? Answer: set link. - 6. What are the other EAO functions beside multiply and divide? - Answer: arithmetic right shift, normalize. */ #include "sim_defs.h" /* simulator defns */ @@ -69,6 +65,7 @@ /* Architectural constants */ #define SIGN 0100000 /* sign */ +#define INDEX 0100000 /* indexed (GRI-99) */ #define DMASK 0177777 /* data mask */ #define CBIT (DMASK + 1) /* carry bit */ @@ -105,9 +102,20 @@ #define U_AO 013 /* arith out */ #define U_EAO 014 /* ext arith */ #define U_MSR 017 /* machine status */ +#define U_XR 022 /* GRI-99: idx reg */ +#define U_GTRP 023 /* GRI-99: alt trap */ #define U_BSW 024 /* byte swap */ #define U_BPK 025 /* byte pack */ +#define U_BCP1 026 /* byte compare 1 */ +#define U_BCP2 027 /* byte compare 2 */ #define U_GR 030 /* hex general regs */ +#define U_CDR 055 /* card reader */ +#define U_CADR 057 +#define U_DWC 066 /* disk */ +#define U_DCA 067 +#define U_DISK 070 +#define U_LPR 071 /* line printer */ +#define U_CAS 074 /* casette */ #define U_RTC 075 /* clock */ #define U_HS 076 /* paper tape */ #define U_TTY 077 /* console */ @@ -173,8 +181,8 @@ struct gdev { #define MSR_SOV (1u << MSR_V_SOV) #define MSR_AOV (1u << MSR_V_AOV) #define MSR_GET_FOA(x) (((x) >> MSR_V_FOA) & MSR_M_FOA) -#define MSR_PUT_FOA(x,n) (((x) & ~(MSR_M_FOA << MSR_V_FOA)) | \ - (((n) & MSR_M_FOA) << MSR_V_FOA)) +#define MSR_PUT_FOA(x,n) (((x) & ~(MSR_M_FOA << MSR_V_FOA)) | \ + (((n) & MSR_M_FOA) << MSR_V_FOA)) #define MSR_RW (MSR_BOV|MSR_L|MSR_FOA|MSR_SOV|MSR_AOV) /* Real time clock */ @@ -201,14 +209,24 @@ struct gdev { #define INT_V_TTI 1 /* console in */ #define INT_V_HSP 2 /* paper tape punch */ #define INT_V_HSR 3 /* paper tape reader */ +#define INT_V_LPR 5 /* line printer */ +#define INT_V_CDR 7 /* card reader */ +#define INT_V_CASW 9 /* casette */ +#define INT_V_CASR 10 #define INT_V_RTC 11 /* clock */ +#define INT_V_DISK 14 /* disk */ #define INT_V_NODEF 16 /* nodefer */ #define INT_V_ON 17 /* enable */ #define INT_TTO (1u << INT_V_TTO) #define INT_TTI (1u << INT_V_TTI) #define INT_HSP (1u << INT_V_HSP) #define INT_HSR (1u << INT_V_HSR) +#define INT_LPR (1u << INT_V_LPR) +#define INT_CDR (1u << INT_V_CDR) +#define INT_CASW (1u << INT_V_CAS1) +#define INT_CASR (1u << INT_V_CAS2) #define INT_RTC (1u << INT_V_RTC) +#define INT_DISK (1u << INT_V_DISK) #define INT_NODEF (1u << INT_V_NODEF) #define INT_ON (1u << INT_V_ON) #define INT_PENDING (INT_ON | INT_NODEF) @@ -220,4 +238,9 @@ struct gdev { #define VEC_TTI 0014 /* console in */ #define VEC_HSP 0017 /* paper tape punch */ #define VEC_HSR 0022 /* paper tape reader */ +#define VEC_LPR 0033 /* line printer */ +#define VEC_CDR 0033 /* card reader */ +#define VEC_CASW 0044 /* casette */ +#define VEC_CASR 0047 +#define VEC_DISK 0055 /* disk */ #define VEC_RTC 0100 /* clock */ diff --git a/GRI/gri_stddev.c b/GRI/gri_stddev.c index 493a1713..0d773160 100644 --- a/GRI/gri_stddev.c +++ b/GRI/gri_stddev.c @@ -1,6 +1,6 @@ /* gri_stddev.c: GRI-909 standard devices - Copyright (c) 2001-2006, Robert M Supnik + Copyright (c) 2001-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -29,6 +29,7 @@ hsp S42-006 high speed punch rtc real time clock + 31-May-08 RMS Fixed declarations (found by Peter Schorn) 30-Sep-06 RMS Fixed handling of non-printable characters in KSR mode 22-Nov-05 RMS Revised for new terminal processing routines 29-Dec-03 RMS Added support for console backpressure @@ -208,7 +209,7 @@ DEVICE rtc_dev = { /* Console terminal function processors */ -int32 tty_rd (int32 src, int32 ea) +uint32 tty_rd (int32 src, int32 ea) { return tti_unit.buf; /* return data */ } @@ -294,7 +295,7 @@ return SCPE_OK; /* High speed paper tape function processors */ -int32 hsrp_rd (int32 src, int32 ea) +uint32 hsrp_rd (int32 src, int32 ea) { return hsr_unit.buf; /* return data */ } @@ -386,7 +387,7 @@ if (op & RTC_OV) dev_done = dev_done & ~INT_RTC; /* clr ovflo? */ return SCPE_OK; } -int32 rtc_sf (int32 op) +uint32 rtc_sf (int32 op) { if ((op & RTC_OV) && (dev_done & INT_RTC)) return 1; return 0; diff --git a/GRI/gri_sys.c b/GRI/gri_sys.c index 2d7a89d5..afceb2e3 100644 --- a/GRI/gri_sys.c +++ b/GRI/gri_sys.c @@ -1,6 +1,6 @@ /* gri_sys.c: GRI-909 simulator interface - Copyright (c) 2001-2005, Robert M Supnik + Copyright (c) 2001-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 14-Jan-08 RMS Added GRI-99 support 18-Oct-02 RMS Fixed bug in symbolic decode (found by Hans Pufal) */ @@ -38,6 +39,8 @@ extern REG cpu_reg[]; extern uint16 M[]; extern int32 sim_switches; +void fprint_addr (FILE *of, uint32 val, uint32 mod, uint32 dst); + /* SCP data structures and interface routines sim_name simulator name string @@ -210,26 +213,26 @@ static const uint32 opc_val[] = { static const char *unsrc[64] = { "0", "IR", "2", "TRP", "ISR", "MA", "MB", "SC", /* 00 - 07 */ "SWR", "AX", "AY", "AO", "14", "15", "16", "MSR", /* 10 - 17 */ - "20", "21", "22", "23", "BSW", "BPK", "26", "27", /* 20 - 27 */ + "20", "21", "XR", "ATRP", "BSW", "BPK", "BCPA", "BCPB",/* 20 - 27 */ "GR1", "GR2", "GR3", "GR4", "GR5", "GR6", "36", "37", /* 30 - 37 */ "40", "41", "42", "43", "44", "45", "46", "47", - "50", "51", "52", "53", "54", "55", "56", "57", - "60", "61", "62", "63", "64", "65", "66", "67", - "70", "71", "72", "73", "74", "RTC", "HSR", "TTI" /* 70 - 77 */ + "50", "51", "52", "53", "54", "CDR", "56", "CADR", + "60", "61", "62", "63", "64", "65", "DWC", "DCA", + "DISK", "LPR", "72", "73", "CAS", "RTC", "HSR", "TTI" /* 70 - 77 */ }; static const char *undst[64] = { "0", "IR", "2", "TRP", "ISR", "5", "MB", "SC", /* 00 - 07 */ "SWR", "AX", "AY", "13", "EAO", "15", "16", "MSR", /* 10 - 17 */ - "20", "21", "22", "23", "BSW", "BPK", "26", "27", /* 20 - 27 */ + "20", "21", "XR", "ATRP", "BSW", "BPK", "BCPA", "BCPB",/* 20 - 27 */ "GR1", "GR2", "GR3", "GR4", "GR5", "GR6", "36", "37", /* 30 - 37 */ "40", "41", "42", "43", "44", "45", "46", "47", - "50", "51", "52", "53", "54", "55", "56", "57", - "60", "61", "62", "63", "64", "65", "66", "67", - "70", "71", "72", "73", "74", "RTC", "HSP", "TTO" /* 70 - 77 */ + "50", "51", "52", "53", "54", "CDR", "56", "CADR", + "60", "61", "62", "63", "64", "65", "DWC", "DCA", + "DISK", "LPR", "72", "73", "CAS", "RTC", "HSP", "TTO" /* 70 - 77 */ }; - /* Operators */ +/* Operators */ static const char *opname[4] = { NULL, "P1", "L1", "R1" @@ -299,6 +302,17 @@ if (op) fprintf (of, " %o", op); return; } +/* Print address field with potential indexing */ + +void fprint_addr (FILE *of, uint32 val, uint32 mode, uint32 dst) +{ +if ((val & INDEX) && + ((dst == U_SC) || (mode != MEM_IMM))) + fprintf (of, "#%o", val & AMASK); +else fprintf (of, "%o", val); +return; +} + /* Symbolic decode Inputs: @@ -387,36 +401,40 @@ for (i = 0; opcode[i] != NULL; i++) { /* loop thru ops */ break; case F_V_JC: /* jump cond */ - fprintf (of, "%s %s,%s,%o", opcode[i], - unsrc[src], cdname[op >> 1], val[1]); + fprintf (of, "%s %s,%s,", + opcode[i], unsrc[src], cdname[op >> 1]); + fprint_addr (of, val[1], 0, U_SC); break; case F_V_JU: /* jump uncond */ - fprintf (of, "%s %o", opcode[i], val[1]); + fprintf (of, "%s ", opcode[i]); + fprint_addr (of, val[1], 0, U_SC); break; case F_V_RM: /* reg mem */ - if (bop) fprintf (of, "%s %s,%s,%o", opcode[i], - unsrc[src], opname[bop], val[1]); - else fprintf (of, "%s %s,%o", opcode[i], unsrc[src], val[1]); + if (bop) fprintf (of, "%s %s,%s,", + opcode[i], unsrc[src], opname[bop]); + else fprintf (of, "%s %s,", opcode[i], unsrc[src]); + fprint_addr (of, val[1], op & MEM_MOD, dst); break; case F_V_ZM: /* zero mem */ - if (bop) fprintf (of, "%s %s,%o", opcode[i], - opname[bop], val[1]); - else fprintf (of, "%s %o", opcode[i], val[1]); + if (bop) fprintf (of, "%s %s,", opcode[i], opname[bop]); + else fprintf (of, "%s ", opcode[i]); + fprint_addr (of, val[1], op & MEM_MOD, dst); break; case F_V_MR: /* mem reg */ - if (bop) fprintf (of, "%s %o,%s,%s", opcode[i], - val[1], opname[bop], undst[dst]); - else fprintf (of, "%s %o,%s", opcode[i], val[1], undst[dst]); + fprintf (of, "%s ", opcode[i]); + fprint_addr (of, val[1], op & MEM_MOD, dst); + if (bop) fprintf (of, ",%s,%s", opname[bop], undst[dst]); + else fprintf (of, ",%s", undst[dst]); break; case F_V_MS: /* mem self */ - if (bop) fprintf (of, "%s %o,%s", opcode[i], - val[1], opname[bop]); - else fprintf (of, "%s %o", opcode[i], val[1]); + fprintf (of, "%s ", opcode[i]); + fprint_addr (of, val[1], op & MEM_MOD, dst); + if (bop) fprintf (of, ",%s", opname[bop]); break; } /* end case */ @@ -475,7 +493,9 @@ t_value d; t_stat r; cptr = get_glyph (cptr, gbuf, term); /* get glyph */ -d = get_uint (gbuf, 8, DMASK, &r); /* [0,177777] */ +if (gbuf[0] == '#') /* indexed? */ + d = get_uint (gbuf + 1, 8, AMASK, &r) | INDEX; /* [0, 77777] */ +else d = get_uint (gbuf, 8, DMASK, &r); /* [0,177777] */ if (r != SCPE_OK) return NULL; val[1] = d; /* second wd */ return cptr; diff --git a/HP2100/hp2100_baci.c b/HP2100/hp2100_baci.c new file mode 100644 index 00000000..13a7fd58 --- /dev/null +++ b/HP2100/hp2100_baci.c @@ -0,0 +1,1585 @@ +/* hp2100_baci.c: HP 12966A buffered asynchronous communications interface simulator + + Copyright (c) 2007-2008, 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. + + BACI 12966A BACI card + + 13-Jun-08 JDB Cleaned up debug reporting for sim_activate calls + 16-Apr-08 JDB Separated terminal I/O and Telnet poll for idle compatibility + 07-Dec-07 JDB Created BACI device + + References: + - HP 12966A Buffered Asynchronous Data Communications Interface Installation + and Reference Manual (12966-90001, Jul-1982) + - Western Digital Communications Products Handbook (Jun-1984) + + + The 12966A BACI card supplanted the 12531C Teletype and 12880A CRT interfaces + as the primary terminal connection for HP 1000 systems. The main advantage + of this card over the others was its 128-character FIFO memory. While this + allowed more efficient I/O than its interrupt-per-character predecessors, the + most significant advantage was that block input from the 264x-series of CRT + terminals was supported. The 264x were the first HP-supported terminals to + provide local editing and character storage, as well as mass storage via dual + DC-100 minicartridge drives. This support meant that input from the terminal + could come in bursts at the full baud rate, which would overrun the older + cards that needed a small intercharacter handling time. Also, the older + cards placed a substantial load on the CPU in high-baud-rate output + applications. Indeed, block output under RTE on a 1000 M-Series with a + 12880A CRT card would saturate the CPU at about 5700 baud. + + For a while, the BACI and the earlier cards were both supported as the system + console interface, and RTE primary systems were generated with drivers for + both cards. The boot-time I/O reconfigurator would detect the presence of + the BACI card and would dynamically select the correct driver (DVR05 vs. + DVR00). However, the 12880A card faded quickly as the 264x and later 262x + terminals gained in popularity, and support for the 12880A was dropped in + favor of the BACI. This meant that later RTE primary systems could only be + run on CPUs containing a BACI card. + + The simulation supports terminal and diagnostic modes. The latter simulates + the installation of the 12966-60003 diagnostic loopback connector on the + card. + + Fifteen programmable baud rates were supported by the BACI. We simulate + these "realistic" rates by scheduling I/O service based on the appropriate + number of 1000 E-Series instructions for the rate selected. We also provide + an "external rate" that is equivalent to 9600 baud, as most terminals were + set to their maximum speeds. + + We support the 12966A connected to an HP terminal emulator via Telnet. + Internally, we model the BACI as a terminal multiplexer with one line. The + simulation is complicated by the half-duplex nature of the card (there is + only one FIFO, used selectively either for transmission or reception) and the + double-buffered UART (a Western Digital TR1863A), which has holding registers + as well as a shift registers for transmission and reception. We model both + sets of device registers. + + During an output operation, the first character output to the card passes + through the FIFO and into the transmitter holding register. Subsequent + characters remain in the FIFO. If the FIFO is then turned around by a mode + switch from transmission to reception, the second character output becomes + the first character input to the CPU, as the first character output remains + in the THR. Also, the FIFO counter reflects the combined state of the FIFO + and the THR: it is incremented by a "shift in" to the FIFO and decremented by + the "transmit complete" signal from the UART. This has two implications: + + 1. If the FIFO is turned around before the character in the THR is + transmitted, the counter will not decrement when transmission is + complete, so the FIFO will show as "empty" when the counter reads "1". + + 2. The FIFO counter will indicate "half full" and "full" one character + before the FIFO itself reaches those stages. + + The diagnostic hood connects the UART clock to a spare output register. This + allows the diagnostic to supply programmed clock pulses to the UART. The + serial transmit and receive lines from the UART are also available to the + diagnostic. Functional operation is checked by supplying or testing serial + data while clocking the UART sixteen times for each bit. This meant that we + had to model the UART shift registers for faithful hardware simulation. + + The simulation provides both the "realistic timing" described above, as well + as an "optimized (fast) timing" option. Optimization makes three + improvements: + + 1. On output, characters in the FIFO are emptied into the Telnet buffer as a + block, rather than one character per service call, and on input, all of + the characters available in the Telnet buffer are loaded into the FIFO as + a block. + + 2. The ENQ/ACK handshake is done locally, without involving the Telnet + client. + + 3. Input occurring during an output operation is delayed until the second or + third consecutive ENQ/ACK handshake. + + During development, it was noted that a comparatively long time elapsed + (approximately 30 milliseconds on a 3 GHz system) between the transmission of + an ENQ and the reception of the ACK. As the RTE BACI driver, DVR05, does + three ENQ/ACKs at the end of each line, plus an additional ENQ/ACK every 33 + characters within a line, maximum throughput was about ten lines per second. + The source of this delay is not understood but apparently lies within the + terminal emulator, as it was observed with two emulators from two different + companies. Absorbing the ENQ and generating the ACK locally provided a + dramatic improvement in output speed. + + However, as a result, RTE break-mode became effectively impossible, i.e., + striking a key during output no longer produced the break-mode prompt. This + was traced to the RTE driver. DVR05 only checks for an input character + during ENQ/ACK processing, and then only during the second and third + end-of-line handshakes. When the ENQ/ACKs were eliminated, break-mode also + disappeared. + + The workaround is to save a character received during output and supply it + during the second or third consecutive handshake. This ensures that + break-mode is recognized. Because the driver tries to "cheat" the card by + selecting receive mode before the ENQ has actually been transmitted (in order + to save an interrupt), the FIFO counter becomes "off by one" and is reset + with a master clear at the end of each handshake. This would normally clear + the UART receiving register, thereby losing the deferred character. We work + around this by skipping the register clear in "fast timing" mode. +*/ + +#include + +#include "hp2100_defs.h" +#include "sim_sock.h" +#include "sim_tmxr.h" + + +/* Program limits */ + +#define FIFO_SIZE 128 /* read/write buffer size */ + + +/* Character constants */ + +#define ENQ '\005' +#define ACK '\006' + + +/* Unit flags */ + +#define UNIT_V_DIAG (UNIT_V_UF + 0) /* diagnostic mode */ +#define UNIT_V_FASTTIME (UNIT_V_UF + 1) /* fast timing mode */ +#define UNIT_V_CAPSLOCK (UNIT_V_UF + 2) /* caps lock mode */ + +#define UNIT_DIAG (1 << UNIT_V_DIAG) +#define UNIT_FASTTIME (1 << UNIT_V_FASTTIME) +#define UNIT_CAPSLOCK (1 << UNIT_V_CAPSLOCK) + + +/* Debug flags */ + +#define DEB_CMDS (1 << 0) /* commands and status */ +#define DEB_CPU (1 << 1) /* CPU I/O */ +#define DEB_BUF (1 << 2) /* buffer gets and puts */ +#define DEB_XFER (1 << 3) /* character reads and writes */ + + +/* Bit flags */ + +#define OUT_MR 0100000 /* common master reset */ + +#define OUT_ENCM 0000040 /* ID1: enable character mode */ +#define OUT_ENCB 0000020 /* ID1: enable CB */ +#define OUT_ENCC 0000010 /* ID1: enable CC */ +#define OUT_ENCE 0000004 /* ID1: enable CE */ +#define OUT_ENCF 0000002 /* ID1: enable CF */ +#define OUT_ENSXX 0000001 /* ID1: enable SBB/SCF */ + +#define OUT_DIAG 0000040 /* ID2: diagnostic output */ +#define OUT_REFCB 0000020 /* ID2: reference CB */ +#define OUT_REFCC 0000010 /* ID2: reference CC */ +#define OUT_REFCE 0000004 /* ID2: reference CE */ +#define OUT_REFCF 0000002 /* ID2: reference CF */ +#define OUT_REFSXX 0000001 /* ID2: reference SBB/SCF */ + +#define OUT_STBITS 0000040 /* ID3: number of stop bits */ +#define OUT_ECHO 0000020 /* ID3: enable echo */ +#define OUT_PARITY 0000010 /* ID3: enable parity */ +#define OUT_PAREVEN 0000004 /* ID3: even parity or odd */ + +#define OUT_XMIT 0000400 /* ID4: transmit or receive */ +#define OUT_CA 0000200 /* ID4: CA on */ +#define OUT_CD 0000100 /* ID4: CD on */ +#define OUT_SXX 0000040 /* ID4: SBA/SCA on */ +#define OUT_DCPC 0000020 /* ID4: DCPC on */ + +#define OUT_CSC 0000040 /* ID5: clear special char interrupt */ +#define OUT_CBH 0000020 /* ID5: clear buffer half-full interrupt */ +#define OUT_CBF 0000010 /* ID5: clear buffer full interrupt */ +#define OUT_CBE 0000004 /* ID5: clear buffer empty interrupt */ +#define OUT_CBRK 0000002 /* ID5: clear break interrupt */ +#define OUT_COVR 0000001 /* ID5: clear overrun/parity interrupt */ + +#define OUT_SPFLAG 0000400 /* ID6: special character */ + +#define OUT_IRQCLR (OUT_CBH | OUT_CBF | OUT_CBE | OUT_CBRK | OUT_COVR) + + +#define IN_VALID 0100000 /* received data: character valid */ +#define IN_SPFLAG 0040000 /* received data: is special character */ + +#define IN_DEVINT 0100000 /* status: device interrupt */ +#define IN_SPCHAR 0040000 /* status: special char has been recd */ +#define IN_SPARE 0010000 /* status: spare receiver state */ +#define IN_TEST 0004000 /* status: unprocessed serial data line */ +#define IN_BUFHALF 0001000 /* status: buffer is half full */ +#define IN_BUFFULL 0000400 /* status: buffer is full */ +#define IN_BUFEMPTY 0000200 /* status: buffer is empty */ +#define IN_BREAK 0000100 /* status: break detected */ +#define IN_OVRUNPE 0000040 /* status: overrun or parity error */ +#define IN_CB 0000020 /* status: CB is on */ +#define IN_CC 0000010 /* status: CC is on */ +#define IN_CE 0000004 /* status: CE is on */ +#define IN_CF 0000002 /* status: CF is on */ +#define IN_SXX 0000001 /* status: SBB/SCF is on */ + +#define IN_MODEM (IN_CB | IN_CC | IN_CE | IN_CF | IN_SXX) +#define IN_LOOPBACK (IN_DEVINT | IN_SPARE | IN_TEST | IN_MODEM) +#define IN_STDIRQ (IN_DEVINT | IN_SPCHAR | IN_BREAK | IN_OVRUNPE) +#define IN_FIFOIRQ (IN_BUFEMPTY | IN_BUFHALF | IN_BUFFULL) + + +/* Packed starting bit numbers */ + +#define OUT_V_ID 12 /* common output word ID */ +#define OUT_V_DATA 0 /* ID 0: output data character */ +#define OUT_V_CHARSIZE 0 /* ID 3: character size */ +#define OUT_V_BAUDRATE 0 /* ID 4: baud rate */ +#define OUT_V_SPCHAR 0 /* ID 6: special character */ + +#define IN_V_CHARCNT 8 /* data: char count in buffer */ +#define IN_V_DATA 0 /* data: input character */ +#define IN_V_IRQCLR 5 /* status: interrupt status clear */ + + +/* Packed bit widths */ + +#define OUT_W_ID 3 +#define OUT_W_DATA 8 +#define OUT_W_CHARSIZE 2 +#define OUT_W_BAUDRATE 4 +#define OUT_W_SPCHAR 8 + +#define IN_W_CHARCNT 6 +#define IN_W_DATA 8 + +/* Packed bit masks */ + +#define OUT_M_ID ((1 << OUT_W_ID) - 1) +#define OUT_M_DATA ((1 << OUT_W_DATA) - 1) +#define OUT_M_CHARSIZE ((1 << OUT_W_CHARSIZE) - 1) +#define OUT_M_BAUDRATE ((1 << OUT_W_BAUDRATE) - 1) +#define OUT_M_SPCHAR ((1 << OUT_W_SPCHAR) - 1) + +#define IN_M_CHARCNT ((1 << IN_W_CHARCNT) - 1) +#define IN_M_DATA ((1 << IN_W_DATA) - 1) + +/* Packed field masks */ + +#define OUT_ID (OUT_M_ID << OUT_V_ID) +#define OUT_DATA (OUT_M_DATA << OUT_V_DATA) +#define OUT_CHARSIZE (OUT_M_CHARSIZE << OUT_V_CHARSIZE) +#define OUT_BAUDRATE (OUT_M_BAUDRATE << OUT_V_BAUDRATE) +#define OUT_SPCHAR (OUT_M_SPCHAR << OUT_V_SPCHAR) + +#define IN_CHARCNT (IN_M_CHARCNT << IN_V_CHARCNT) +#define IN_DATA (IN_M_DATA << IN_V_DATA) + + +/* Command helpers */ + +#define TO_CHARCNT(c) (((c) << IN_V_CHARCNT) & IN_CHARCNT) + +#define GET_ID(i) (((i) & OUT_ID) >> OUT_V_ID) +#define GET_BAUDRATE(b) (((b) & OUT_BAUDRATE) >> OUT_V_BAUDRATE) + +#define IO_MODE (baci_icw & OUT_XMIT) +#define XMIT OUT_XMIT +#define RECV 0 + +#define CLEAR_HR 0 /* UART holding register clear value */ +#define CLEAR_R -1 /* UART register clear value */ + + +/* Unit references */ + +#define baci_term baci_unit[0] /* terminal I/O unit */ +#define baci_poll baci_unit[1] /* Telnet polling unit */ + + +/* External variables */ + +extern uint32 PC; +extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2]; +extern FILE *sim_deb; + + +/* BACI state variables */ + +uint16 baci_ibuf = 0; /* status/data in */ +uint16 baci_obuf = 0; /* command/data out */ +uint16 baci_status = 0; /* current status */ + +uint16 baci_edsiw = 0; /* enable device status word */ +uint16 baci_dsrw = 0; /* device status reference word */ +uint16 baci_cfcw = 0; /* character frame control word */ +uint16 baci_icw = 0; /* interface control word */ +uint16 baci_isrw = 0; /* interrupt status reset word */ + +uint32 baci_fput = 0; /* FIFO buffer add index */ +uint32 baci_fget = 0; /* FIFO buffer remove index */ +uint32 baci_fcount = 0; /* FIFO buffer counter */ +uint32 baci_bcount = 0; /* break counter */ + +uint8 baci_fifo [FIFO_SIZE]; /* read/write buffer FIFO */ +uint8 baci_spchar [256]; /* special character RAM */ + +uint16 baci_uart_thr = CLEAR_HR; /* UART transmitter holding register */ +uint16 baci_uart_rhr = CLEAR_HR; /* UART receiver holding register */ + int32 baci_uart_tr = CLEAR_R; /* UART transmitter register */ + int32 baci_uart_rr = CLEAR_R; /* UART receiver register */ +uint32 baci_uart_clk = 0; /* UART transmit/receive clock */ + +t_bool baci_enq_seen = FALSE; /* ENQ seen flag */ +uint32 baci_enq_cntr = 0; /* ENQ seen counter */ + + +/* Terminal multiplexer library interface */ + +TMLN baci_ldsc = { 0 }; /* line descriptor */ +TMXR baci_desc = { 1, 0, 0, &baci_ldsc }; /* device descriptor */ + + +/* BACI local routines */ + +static int32 service_time (uint32 control_word); +static const char *fmt_char (uint8 ch); +static void update_status (void); +static void master_reset (uint32 selcode); + +static uint32 fifo_get (void); +static void fifo_put (uint8 ch); +static void clock_uart (void); + +/* BACI global routines */ + + int32 baci_io (int32 inst, int32 IR, int32 dat); +t_stat baci_term_svc (UNIT *uptr); +t_stat baci_poll_svc (UNIT *uptr); +t_stat baci_reset (DEVICE *dptr); +t_stat baci_attach (UNIT *uptr, char *cptr); +t_stat baci_detach (UNIT *uptr); +t_stat baci_show (FILE *st, UNIT *uptr, int32 val, void *desc); + + +/* BACI data structures + + baci_dib BACI device information block + baci_dev BACI device descriptor + baci_unit BACI unit list + baci_reg BACI register list + baci_mod BACI modifier list + baci_deb BACI debug list + + Two units are used: one to handle character I/O via the Telnet library, and + another to poll for connections and input. The character I/O service routine + runs only when there are characters to read or write. It operates at the + approximate baud rate of the terminal (in CPU instructions per second) in + order to be compatible with the OS drivers. The Telnet poll must run + continuously, but it can operate much more slowly, as the only requirement is + that it must not present a perceptible lag to human input. To be compatible + with CPU idling, it is co-scheduled with the master poll timer, which uses a + ten millisecond period. +*/ + +DIB baci_dib = { BACI, 0, 0, 0, 0, 0, &baci_io }; + +DEVICE baci_dev; + +UNIT baci_unit[] = + { { UDATA (&baci_term_svc, UNIT_ATTABLE | UNIT_FASTTIME, 0) }, /* terminal I/O unit */ + { UDATA (&baci_poll_svc, UNIT_DIS, POLL_WAIT) } }; /* Telnet poll unit */ + +REG baci_reg[] = { + { ORDATA (IBUF, baci_ibuf, 16) }, + { ORDATA (OBUF, baci_obuf, 16) }, + { ORDATA (STATUS, baci_status, 16) }, + + { ORDATA (EDSIW, baci_edsiw, 16) }, + { ORDATA (DSRW, baci_dsrw, 16) }, + { ORDATA (CFCW, baci_cfcw, 16) }, + { ORDATA (ICW, baci_icw, 16) }, + { ORDATA (ISRW, baci_isrw, 16) }, + + { DRDATA (FIFOPUT, baci_fput, 8) }, + { DRDATA (FIFOGET, baci_fget, 8) }, + { DRDATA (FIFOCNTR, baci_fcount, 8) }, + { DRDATA (BRKCNTR, baci_bcount, 16) }, + + { BRDATA (FIFO, baci_fifo, 8, 8, FIFO_SIZE) }, + { BRDATA (SPCHAR, baci_spchar, 8, 1, 256) }, + + { ORDATA (UARTTHR, baci_uart_thr, 16) }, + { ORDATA (UARTTR, baci_uart_tr, 16), REG_NZ }, + { ORDATA (UARTRHR, baci_uart_rhr, 16) }, + { ORDATA (UARTRR, baci_uart_rr, 16), REG_NZ }, + { DRDATA (UARTCLK, baci_uart_clk, 16) }, + + { DRDATA (CTIME, baci_term.wait, 19), REG_RO }, + + { FLDATA (ENQFLAG, baci_enq_seen, 0), REG_HRO }, + { DRDATA (ENQCNTR, baci_enq_cntr, 16), REG_HRO }, + + { FLDATA (LKO, baci_dib.cmd, 0) }, + { FLDATA (CTL, baci_dib.ctl, 0) }, + { FLDATA (FLG, baci_dib.flg, 0) }, + { FLDATA (FBF, baci_dib.fbf, 0) }, + { FLDATA (SRQ, baci_dib.srq, 0) }, + { ORDATA (DEVNO, baci_dib.devno, 6), REG_HRO }, + { NULL } + }; + +MTAB baci_mod[] = { + { UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", NULL, NULL, NULL }, + { UNIT_DIAG, 0, "terminal mode", "TERMINAL", NULL, NULL, NULL }, + + { UNIT_FASTTIME, UNIT_FASTTIME, "fast timing", "FASTTIME", NULL, NULL, NULL }, + { UNIT_FASTTIME, 0, "realistic timing", "REALTIME", NULL, NULL, NULL }, + + { UNIT_CAPSLOCK, UNIT_CAPSLOCK, "CAPS LOCK down", "CAPSLOCK", NULL, NULL, NULL }, + { UNIT_CAPSLOCK, 0, "CAPS LOCK up", "NOCAPSLOCK", NULL, NULL, NULL }, + + { MTAB_XTD | MTAB_VDV | MTAB_NC, 0, "LOG", "LOG", &tmxr_set_log, &tmxr_show_log, &baci_desc }, + { MTAB_XTD | MTAB_VDV | MTAB_NC, 0, NULL, "NOLOG", &tmxr_set_nolog, NULL, &baci_desc }, + + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTION", NULL, NULL, &baci_show, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, NULL, &baci_show, NULL }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "DISCONNECT", &tmxr_dscln, NULL, &baci_desc }, + + { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &baci_dev }, + { 0 } + }; + +DEBTAB baci_deb[] = { + { "CMDS", DEB_CMDS }, + { "CPU", DEB_CPU }, + { "BUF", DEB_BUF }, + { "XFER", DEB_XFER }, + { NULL, 0 } + }; + +DEVICE baci_dev = { + "BACI", /* device name */ + baci_unit, /* unit array */ + baci_reg, /* register array */ + baci_mod, /* modifier array */ + 2, /* number of units */ + 10, /* address radix */ + 31, /* address width */ + 1, /* address increment */ + 8, /* data radix */ + 8, /* data width */ + &tmxr_ex, /* examine routine */ + &tmxr_dep, /* deposit routine */ + &baci_reset, /* reset routine */ + NULL, /* boot routine */ + &baci_attach, /* attach routine */ + &baci_detach, /* detach routine */ + &baci_dib, /* device information block */ + DEV_NET | DEV_DEBUG | DEV_DISABLE, /* device flags */ + 0, /* debug control flags */ + baci_deb, /* debug flag name table */ + NULL, /* memory size change routine */ + NULL }; /* logical device name */ + + + +/* I/O instruction processor. + + The BACI processes seven types of output words and supplies two types of + input words. Output word type is identified by an ID code in bits 14-12. + Input word type is determined by the state of the control flip-flop. + + The card has the usual control, flag buffer, flag, and SRQ flip-flops. + However, they have the following unusual characteristics: + + - STC is not required to transfer a character. + - Flag is not set after character transfer completes. + - FLAG and SRQ are decoupled. + + An interrupt lockout flip-flop is used to prevent the generation of multiple + interrupts until the cause of the first interrupt is identified and cleared. + CMD is used to model the lockout flip-flop. +*/ + +int32 baci_io (int32 inst, int32 IR, int32 dat) +{ +uint8 ch; +uint32 mask; +uint32 dev = IR & I_DEVMASK; + +switch (inst) { /* dispatch by instruction */ + + case ioFLG: /* set or clear flag */ + if ((IR & I_HC) == 0) { /* STF? */ + setFSR (dev); /* set flag, flag buffer, and SRQ */ + setCMD (dev); /* set lockout */ + + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fputs (">>BACI cmds: [STF] Flag, SRQ, and lockout set\n", sim_deb); + } + break; /* CLF handled by H/C below */ + + + case ioSFC: /* skip if flag clear */ + if (FLG (dev) == 0) /* flag clear? */ + PC = (PC + 1) & VAMASK; /* skip next instruction */ + break; + + + case ioSFS: /* skip if flag set */ + if (FLG (dev) != 0) /* flag set? */ + PC = (PC + 1) & VAMASK; /* skip next instruction */ + break; + + + case ioCRS: /* control reset */ + master_reset (dev); /* issue master reset */ + + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fputs (">>BACI cmds: [CRS] Master reset\n", sim_deb); + break; + + + case ioOTX: /* output word */ + if (DEBUG_PRI (baci_dev, DEB_CPU)) + fprintf (sim_deb, ">>BACI cpu: [OTx] Command = %06o\n", dat); + + baci_obuf = dat; + + if (baci_obuf & OUT_MR) { /* master reset? */ + master_reset (dev); /* do before processing */ + + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fputs (">>BACI cmds: [OTx] Master reset\n", sim_deb); + } + + switch (GET_ID (baci_obuf)) { /* isolate ID code */ + + case 0: /* transmit data */ + if (IO_MODE == XMIT) { /* transmitting? */ + ch = baci_obuf & OUT_DATA; /* mask to character */ + fifo_put (ch); /* queue character */ + + if (baci_term.flags & UNIT_ATT) { /* attached to network? */ + if (DEBUG_PRI (baci_dev, DEB_CMDS) && /* debugging? */ + (sim_is_active (&baci_term) == 0)) /* service stopped? */ + fprintf (sim_deb, ">>BACI cmds: [OTx] Terminal service scheduled, " + "time = %d\n", baci_term.wait); + + if (baci_fcount == 1) /* first char to xmit? */ + sim_activate_abs (&baci_term, /* start service with full char time */ + baci_term.wait); + else + sim_activate (&baci_term, /* start service if not running */ + baci_term.wait); + } + } + break; + + case 1: /* enable device status interrupt */ + baci_edsiw = baci_obuf; /* load new enable word */ + update_status (); /* may have enabled an interrupt */ + break; + + case 2: /* device status reference */ + if ((baci_term.flags & UNIT_DIAG) && /* diagnostic mode? */ + (baci_dsrw & OUT_DIAG) && /* and last DIAG was high? */ + !(baci_obuf & OUT_DIAG) && /* and new DIAG is low? */ + !(baci_icw & OUT_BAUDRATE)) /* and clock is external? */ + clock_uart (); /* pulse UART clock */ + + baci_dsrw = baci_obuf; /* load new reference word */ + update_status (); /* clocking UART may interrupt */ + break; + + case 3: /* character frame control */ + baci_cfcw = baci_obuf; /* load new frame word */ + break; + + case 4: /* interface control */ + if ((baci_icw ^ baci_obuf) & OUT_BAUDRATE) { /* baud rate change? */ + baci_term.wait = service_time (baci_obuf); /* set service time to match rate */ + + if (baci_term.flags & UNIT_DIAG) /* diagnostic mode? */ + if (baci_obuf & OUT_BAUDRATE) { /* internal baud rate requested? */ + sim_activate (&baci_term, /* activate I/O service */ + baci_term.wait); + + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fprintf (sim_deb, ">>BACI cmds: [OTx] Terminal service scheduled, " + "time = %d\n", baci_term.wait); + } + + else { /* external rate */ + sim_cancel (&baci_term); /* stop I/O service */ + + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fputs (">>BACI cmds: [OTx] Terminal service stopped\n", sim_deb); + } + } + + baci_icw = baci_obuf; /* load new reference word */ + update_status (); /* loopback may change status */ + break; + + case 5: /* interrupt status reset */ + baci_isrw = baci_obuf; /* load new reset word */ + + mask = (baci_isrw & OUT_IRQCLR) << /* form reset mask */ + IN_V_IRQCLR; /* for common irqs */ + + if (baci_isrw & OUT_CSC) /* add special char mask bit */ + mask = mask | IN_SPCHAR; /* if requested */ + + baci_status = baci_status & ~mask; /* clear specified status bits */ + break; + + case 6: /* special character */ + baci_spchar [baci_obuf & OUT_SPCHAR] = /* set special character entry */ + ((baci_obuf & OUT_SPFLAG) != 0); + break; + } + + break; + + + case ioLIX: /* load word */ + dat = 0; + + case ioMIX: /* merge word */ + if (CTL (dev)) { /* control set? */ + baci_ibuf = TO_CHARCNT (baci_fcount); /* get FIFO count */ + + if (IO_MODE == RECV) /* receiving? */ + baci_ibuf = baci_ibuf | fifo_get (); /* add char and validity flag */ + + dat = dat | baci_ibuf; /* return received data */ + + if (DEBUG_PRI (baci_dev, DEB_CPU)) + fprintf (sim_deb, ">>BACI cpu: [LIx] Received data = %06o\n", dat); + } + + else { /* control clear? */ + dat = dat | baci_status; /* return status */ + + if (DEBUG_PRI (baci_dev, DEB_CPU)) + fprintf (sim_deb, ">>BACI cpu: [LIx] Status = %06o\n", dat); + } + break; + + + case ioCTL: /* control set/clear */ + if (IR & I_CTL) { /* CLC */ + clrCTL (dev); /* clear control */ + + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fputs (">>BACI cmds: [CLC] Control cleared\n", sim_deb); + } + + else { /* STC */ + setCTL (dev); /* set control */ + clrCMD (dev); /* clear lockout */ + + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fputs (">>BACI cmds: [STC] Control set and lockout cleared\n", sim_deb); + + update_status (); /* clearing lockout might interrupt */ + } + break; + + + default: /* all others */ + break; /* do nothing */ + } + + +if (IR & I_HC) { /* H/C option */ + clrFSR (dev); /* clear flag and SRQ */ + + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fprintf (sim_deb, ">>BACI cmds: [%s] Flag and SRQ cleared\n", + (inst == ioFLG ? "CLF" : "x,C")); + + update_status (); /* FLG might set when SRQ clears */ + } + +return dat; +} + + +/* BACI terminal service. + + The terminal service routine is used to transmit and receive characters. + + In terminal mode, it is started when a character is ready for output or when + the Telnet poll routine determines that there are characters ready for input + and stopped when there are no more characters to output or input. When the + terminal is quiescent, this routine does not run. + + In diagnostic mode, it is started whenever an internal baud rate is set and + stopped when the external clock is requested. In this mode, the routine will + be called without an attached socket, so character I/O will be skipped. + + Because there is only one FIFO, the card is half-duplex and must be + configured for transmit or receive mode. The UART, though, is double- + buffered, so it may transmit and receive simultaneously. We implement both + the UART shift and holding registers for each mode. + + If a character is received by the UART while the card is in transmit mode, it + will remain in the receiver holding register (RHR). When the mode is + reversed, the RHR contents will be unloaded into the FIFO. Conversely, + transmit mode enables the output of the FIFO to be unloaded into the + transmitter holding register (THR). Characters received or transmitted pass + through the receiver register (RR) or transmitter register (TR), + respectively. They are not strictly necessary in terminal (Telnet) + transactions but are critical to diagnostic operations. + + The UART signals an overrun if a complete character is received while the RHR + still contains the previous character. The BACI does not use this signal, + though; an overrun is only indicated if the FIFO is full, and another + character is received. + + In "fast timing" mode, we defer the recognition of a received character until + the card is put into receive mode for the second or third consecutive ENQ/ACK + handshake. This improves RTE break-mode recognition. "Realistic timing" + mode behaves as the hardware does: a character present in the RHR is unloaded + into the FIFO as soon as receive mode is set. + + Fast timing mode also enables internal ENQ/ACK handshaking. We allow one + character time for the RTE driver to turn the card around, as otherwise the + ACK may not be seen by the driver. Also, the local ACK is supplied after any + received characters, as the driver detects operator attention only when the + first character after an ENQ is not an ACK. + + Finally, fast timing enables buffer combining. For output, all characters + present in the FIFO are unloaded into the Telnet buffer before initiating a + packet send. For input, all characters present in the Telnet buffer are + loaded into the FIFO. This reduces network traffic and decreases simulator + overhead (there is only one service routine entry per block, rather than one + per character). + + In fast output mode, it is imperative that not less than 1500 instructions + elapse between the first character load to the FIFO and the initiation of + transmission. The RTE driver must have enough time to output the maximum + number of contiguous characters (33) and reset the interrupt status flags + before the service routine is entered. Because all of the characters are + transmitted as a block, the FIFO empty flag will be set by the service + routine. If the driver has not yet exited at that time, the buffer-empty + interrupt will be cleared when the interrupt status reset is done. The + symptom will be a 3.8-second pause in output until the driver times out. + + To avoid this, the OTx output character handler does an absolute schedule for + the first character to ensure that a full character time is used. +*/ + +t_stat baci_term_svc (UNIT *uptr) +{ +uint32 data_bits, data_mask; +const t_bool fast_timing = (baci_term.flags & UNIT_FASTTIME) != 0; +const t_bool is_attached = (baci_term.flags & UNIT_ATT) != 0; +t_stat status = SCPE_OK; +t_bool xmit_loop = TRUE; +t_bool recv_loop = TRUE; + + +/* Transmission */ + +while (xmit_loop && (baci_uart_thr & IN_VALID)) { /* valid character in UART? */ + data_bits = 5 + (baci_cfcw & OUT_CHARSIZE); /* calculate number of data bits */ + data_mask = (1 << data_bits) - 1; /* generate mask for data bits */ + baci_uart_tr = baci_uart_thr & data_mask; /* mask data into transmitter register */ + + if ((baci_uart_tr == ENQ) && fast_timing) { /* char is ENQ and fast timing? */ + baci_enq_seen = TRUE; /* set flag instead of transmitting */ + baci_enq_cntr = baci_enq_cntr + 1; /* bump ENQ counter */ + recv_loop = FALSE; /* skip recv to allow time before ACK */ + + if (DEBUG_PRI (baci_dev, DEB_XFER)) + fprintf (sim_deb, ">>BACI xfer: Character ENQ absorbed internally, " + "ENQ count = %d\n", baci_enq_cntr); + } + + else { /* character is not an ENQ */ + baci_enq_cntr = 0; /* reset ENQ counter */ + + if (is_attached) { /* attached to network? */ + status = tmxr_putc_ln (&baci_ldsc, /* transmit the character */ + baci_uart_tr); + + if ((status == SCPE_OK) && /* transmitted OK? */ + DEBUG_PRI (baci_dev, DEB_XFER)) + fprintf (sim_deb, ">>BACI xfer: Character %s " + "transmitted from UART\n", fmt_char (baci_uart_tr)); + } + } + + if (status == SCPE_OK) { /* transmitted OK? */ + baci_uart_tr = CLEAR_R; /* clear transmitter register */ + + if (IO_MODE == XMIT) { /* transmit mode? */ + baci_fcount = baci_fcount - 1; /* decrement occupancy counter */ + baci_uart_thr = fifo_get (); /* get next char into UART */ + update_status (); /* update FIFO status */ + } + + else /* receive mode */ + baci_uart_thr = CLEAR_HR; /* clear holding register */ + + xmit_loop = fast_timing && !baci_enq_seen; /* loop if fast mode and char not ENQ */ + } + + else + xmit_loop = FALSE; + } + + +/* Deferred reception */ + +if (recv_loop && /* ok to process? */ + baci_uart_rhr && (IO_MODE == RECV) && /* and deferred char in RHR in recv mode? */ + (!baci_enq_seen || (baci_enq_cntr >= 2))) { /* and either no ENQ or at least 2nd ENQ? */ + + baci_uart_rhr = baci_uart_rhr & ~IN_VALID; /* clear valid bit */ + + if (DEBUG_PRI (baci_dev, DEB_XFER)) + fprintf (sim_deb, ">>BACI xfer: Deferred character %s processed\n", + fmt_char ((uint8) baci_uart_rhr)); + + fifo_put ((uint8) baci_uart_rhr); /* move deferred character to FIFO */ + baci_uart_rhr = CLEAR_HR; /* clear RHR */ + update_status (); /* update FIFO status */ + } + + +/* Reception */ + +while (recv_loop && /* OK to process? */ + (baci_uart_rr = tmxr_getc_ln (&baci_ldsc))) { /* and new character available? */ + + if (baci_uart_rr & SCPE_BREAK) /* break detected? */ + baci_status = baci_status | IN_BREAK; /* set break status */ + + data_bits = 5 + (baci_cfcw & OUT_CHARSIZE); /* calculate number of data bits */ + data_mask = (1 << data_bits) - 1; /* generate mask for data bits */ + baci_uart_rhr = baci_uart_rr & data_mask; /* mask data into holding register */ + baci_uart_rr = CLEAR_R; /* clear receiver register */ + + if (DEBUG_PRI (baci_dev, DEB_XFER)) + fprintf (sim_deb, ">>BACI xfer: Character %s received by UART\n", + fmt_char ((uint8) baci_uart_rhr)); + + if (baci_term.flags & UNIT_CAPSLOCK) /* caps lock mode? */ + baci_uart_rhr = toupper (baci_uart_rhr); /* convert to upper case if lower */ + + if (baci_cfcw & OUT_ECHO) /* echo wanted? */ + tmxr_putc_ln (&baci_ldsc, baci_uart_rhr); /* send it back */ + + if ((IO_MODE == RECV) && !baci_enq_seen) { /* receive mode and not ENQ/ACK? */ + fifo_put ((uint8) baci_uart_rhr); /* put data in FIFO */ + baci_uart_rhr = CLEAR_HR; /* clear RHR */ + update_status (); /* update FIFO status (may set flag) */ + + recv_loop = fast_timing && !FLG (baci_dib.devno); /* loop if fast mode and no IRQ */ + } + + else { /* xmit or ENQ/ACK, leave char in RHR */ + baci_uart_rhr = baci_uart_rhr | IN_VALID; /* set character valid bit */ + recv_loop = FALSE; /* terminate loop */ + } + } + + +/* Housekeeping */ + +if (recv_loop && baci_enq_seen) { /* OK to process and ENQ seen? */ + baci_enq_seen = FALSE; /* reset flag */ + + if (DEBUG_PRI (baci_dev, DEB_XFER)) + fputs (">>BACI xfer: Character ACK generated internally\n", sim_deb); + + fifo_put (ACK); /* fake ACK from terminal */ + update_status (); /* update FIFO status */ + } + +if (is_attached) /* attached to network? */ + tmxr_poll_tx (&baci_desc); /* output any accumulated chars */ + +if ((baci_uart_thr & IN_VALID) || baci_enq_seen || /* more to transmit? */ + tmxr_rqln (&baci_ldsc)) /* or more to receive? */ + sim_activate (uptr, uptr->wait); /* reschedule service */ +else + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fputs (">>BACI cmds: Terminal service stopped\n", sim_deb); + +return status; +} + + +/* BACI Telnet poll service. + + This service routine is used to poll for Telnet connections and incoming + characters. If characters are available, the terminal I/O service routine is + scheduled. It starts when the socket is attached and stops when the socket + is detached. +*/ + +t_stat baci_poll_svc (UNIT *uptr) +{ +if (baci_term.flags & UNIT_ATT) { /* attached to network? */ + if (tmxr_poll_conn (&baci_desc) >= 0) /* new connection established? */ + baci_ldsc.rcve = 1; /* enable line to receive */ + + tmxr_poll_rx (&baci_desc); /* poll for input */ + + if (tmxr_rqln (&baci_ldsc)) /* chars available? */ + sim_activate (&baci_term, baci_term.wait); /* activate I/O service */ + } + +uptr->wait = sync_poll (SERVICE); /* synchronize poll */ +sim_activate (uptr, uptr->wait); /* continue polling */ + +return SCPE_OK; +} + + +/* Simulator reset routine */ + +t_stat baci_reset (DEVICE *dptr) +{ +master_reset (0); /* do master reset */ + +baci_dib.ctl = 0; /* clear control */ +baci_dib.flg = 1; /* set flag */ +baci_dib.fbf = 1; /* set flag buffer */ +baci_dib.srq = 1; /* set SRQ */ +baci_dib.cmd = 1; /* set lockout */ + +baci_ibuf = 0; /* clear input buffer */ +baci_obuf = 0; /* clear output buffer */ + +baci_enq_seen = FALSE; /* reset ENQ seen flag */ +baci_enq_cntr = 0; /* clear ENQ counter */ + +baci_term.wait = service_time (baci_icw); /* set terminal I/O time */ + +if (baci_term.flags & UNIT_ATT) { /* device attached? */ + baci_poll.wait = sync_poll (INITIAL); /* synchronize poll */ + sim_activate (&baci_poll, baci_poll.wait); /* start Telnet poll */ + } +else + sim_cancel (&baci_poll); /* else stop Telnet poll */ + +return SCPE_OK; +} + + +/* Attach controller */ + +t_stat baci_attach (UNIT *uptr, char *cptr) +{ +t_stat status = SCPE_OK; + +status = tmxr_attach (&baci_desc, uptr, cptr); /* attach to socket */ + +if (status == SCPE_OK) { + baci_poll.wait = sync_poll (INITIAL); /* synchronize poll */ + sim_activate (&baci_poll, baci_poll.wait); /* start Telnet poll */ + } +return status; +} + +/* Detach controller */ + +t_stat baci_detach (UNIT *uptr) +{ +t_stat status; + +status = tmxr_detach (&baci_desc, uptr); /* detach socket */ +baci_ldsc.rcve = 0; /* disable line reception */ +sim_cancel (&baci_poll); /* stop Telnet poll */ +return status; +} + +/* Show connection status and statistics */ + +t_stat baci_show (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +if (baci_ldsc.conn) + if (val) + tmxr_fconns (st, &baci_ldsc, -1); + else + tmxr_fstats (st, &baci_ldsc, -1); +else + fprintf (st, "terminal disconnected\n"); + +return SCPE_OK; +} + + +/* Local routines */ + + +/* Master reset. + + This is the programmed card master reset, not the simulator reset routine. + It is called from the simulator reset routine with "selcode" = 0; the latter + routine will take care of setting the card flip-flops appropriately. + + Master reset normally clears the UART registers. However, if we are in "fast + timing" mode, the receiver holding register may hold a deferred character. + In this case, we do not clear the RHR, unless we are called from the + simulator reset routine. + + The HP BACI manual states that master reset "Clears Service Request (SRQ)." + An examination of the schematic, though, shows that it sets SRQ instead. +*/ + +static void master_reset (uint32 selcode) +{ +baci_fput = baci_fget = 0; /* clear FIFO indexes */ +baci_fcount = 0; /* clear FIFO counter */ +memset (baci_fifo, 0, sizeof (baci_fifo)); /* clear FIFO data */ + +baci_uart_thr = CLEAR_HR; /* clear transmitter holding register */ + +if (!(baci_term.flags & UNIT_FASTTIME) || !selcode) /* real time mode or power-on init? */ + baci_uart_rhr = CLEAR_HR; /* clear receiver holding register */ + +baci_uart_tr = CLEAR_R; /* clear transmitter register */ +baci_uart_rr = CLEAR_R; /* clear receiver register */ + +baci_uart_clk = 0; /* clear UART clock */ +baci_bcount = 0; /* clear break counter */ + +if (selcode) { + clrCTL (selcode); /* clear control */ + setFLG (selcode); /* set flag and flag buffer */ + setSRQ (selcode); /* set SRQ */ + setCMD (selcode); /* set lockout flip-flop */ + } + +baci_edsiw = 0; /* clear interrupt enables */ +baci_dsrw = 0; /* clear status reference */ +baci_cfcw = baci_cfcw & ~OUT_ECHO; /* clear echo flag */ +baci_icw = baci_icw & OUT_BAUDRATE; /* clear interface control */ + +if (baci_term.flags & UNIT_DIAG) /* diagnostic mode? */ + baci_status = baci_status & ~IN_MODEM | IN_SPARE; /* clear loopback status, set BA */ + +return; +} + + +/* Update status. + + In diagnostic mode, several of the modem output lines are looped back to the + input lines. Also, CD is tied to BB (received data), which is presented on + the TEST status bit via an inversion. Echo mode couples BB to BA + (transmitted data), which is presented on the SPARE status bit. + + If a modem line interrupt condition is present and enabled, the DEVINT status + bit is set. Other potential "standard" interrupt sources are the special + character, break detected, and overrun/parity error bits. If DCPC transfers + are not selected, then the FIFO interrupts (buffer empty, half-full, and + full) and the "data ready" condition (i.e., receive and character modes + enabled and FIFO not empty) also produces an interrupt request. + + An interrupt request will set the card flag unless either the lockout or SRQ + flip-flops are set. SRQ will set if DCPC mode is enabled and there is room + (transmit mode) or data (receive mode) in the FIFO. +*/ + +static void update_status (void) +{ +if (baci_term.flags & UNIT_DIAG) { /* diagnostic mode? */ + baci_status = baci_status & ~IN_LOOPBACK; /* prepare loopback flags */ + + if (baci_icw & OUT_SXX) /* SCA to SCF and CF */ + baci_status = baci_status | IN_SXX | IN_CF; + if ((baci_icw & OUT_CA) && (baci_fcount < 128)) /* CA to CC and CE */ + baci_status = baci_status | IN_CC | IN_CE; + if (baci_icw & OUT_CD) /* CD to CB */ + baci_status = baci_status | IN_CB; + else { + baci_status = baci_status | IN_TEST; /* BB is inversion of CD */ + if (baci_cfcw & OUT_ECHO) + baci_status = baci_status | IN_SPARE; /* BB couples to BA with echo */ + } + + if (!(baci_cfcw & OUT_ECHO) && (baci_uart_tr & 1)) /* no echo and UART TR set? */ + baci_status = baci_status | IN_SPARE; /* BA to SPARE */ + } + +if (baci_edsiw & (baci_status ^ baci_dsrw) & IN_MODEM) /* device interrupt? */ + baci_status = baci_status | IN_DEVINT; /* set flag */ + +if ((baci_status & IN_STDIRQ) || /* standard interrupt? */ + !(baci_icw & OUT_DCPC) && /* or under program control */ + (baci_status & IN_FIFOIRQ) || /* and FIFO interrupt? */ + (IO_MODE == RECV) && /* or receiving */ + (baci_edsiw & OUT_ENCM) && /* and char mode */ + (baci_fget != baci_fput)) { /* and FIFO not empty? */ + + if (CMD (baci_dib.devno)) { /* interrupt lockout? */ + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fputs (">>BACI cmds: Lockout prevents flag set", sim_deb); + } + + else if (SRQ (baci_dib.devno)) { /* SRQ? */ + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fputs (">>BACI cmds: SRQ prevents flag set", sim_deb); + } + + else { + setFLG (baci_dib.devno); /* set device flag and flag buffer */ + setCMD (baci_dib.devno); /* set lockout */ + + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fputs (">>BACI cmds: Flag and lockout set", sim_deb); + } + + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fprintf (sim_deb, ", status = %06o\n", baci_status); + } + +if ((baci_icw & OUT_DCPC) && /* DCPC enabled? */ + ((IO_MODE == XMIT) && (baci_fcount < 128) || /* and xmit and room in FIFO */ + (IO_MODE == RECV) && (baci_fcount > 0))) { /* or recv and data in FIFO? */ + + if (CMD (baci_dib.devno)) { /* interrupt lockout? */ + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fputs (">>BACI cmds: Lockout prevents SRQ set", sim_deb); + } + + else { + setSRQ (baci_dib.devno); /* set SRQ */ + + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fputs (">>BACI cmds: SRQ set", sim_deb); + } + + if (DEBUG_PRI (baci_dev, DEB_CMDS)) + fprintf (sim_deb, ", status = %06o\n", baci_status); + } + +return; +} + + +/* Calculate service time from baud rate. + + Service times are based on 1580 instructions per second, which is the 1000 + E-Series execution speed. The "external clock" rate uses the 9600 baud rate, + as most real terminals were set to their maximum rate. + + Note that the RTE driver has a race condition that will trip if the service + time is less than 1500 instructions. Therefore, these times cannot be + shortened arbitrarily. +*/ + +static int32 service_time (uint32 control_word) +{ +static const int32 ticks [] = { 1646, 316000, 210667, 143636, 117472, 105333, 52667, 26333, + 17556, 13667, 8778, 6583, 4389, 3292, 2194, 1646 }; + +return ticks [GET_BAUDRATE (control_word)]; /* return service time for indicated rate */ +} + + +/* Format a character into a printable string. + + Control characters are translated to readable strings. Printable characters + retain their original form but are enclosed in single quotes. Characters + outside of the ASCII range are represented as escaped octal values. +*/ + +static const char *fmt_char (uint8 ch) +{ +static const char *const ctl[] = { "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", + "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI", + "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", + "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US" }; +static char rep[5]; + +if (ch <= '\037') /* ASCII control character? */ + return ctl [ch]; /* return string representation */ + +else if (ch == '\177') /* ASCII delete? */ + return "DEL"; /* return string representation */ + +else if (ch > '\177') { /* beyond printable range? */ + sprintf (rep, "\\%03o", ch); /* format value */ + return rep; /* return escaped octal code */ + } + +else { /* printable character */ + rep[0] = '\''; /* form string */ + rep[1] = ch; /* containing character */ + rep[2] = '\''; + rep[3] = '\0'; + return rep; /* return quoted character */ + } +} + + +/* FIFO manipulation routines. + + The BACI is a half-duplex device that has a single 128-byte FIFO that is used + for both transmitting and receiving. Whether the FIFO is connected to the + input or output of the UART is determined by the XMIT bit in word 4. A + separate 8-bit FIFO up/down counter is used to track the number of bytes + available. FIFO operations are complicated slightly by the UART, which is + double-buffered. + + The FIFO is modeled as a circular 128-byte array. Separate get and put + indexes track the current data extent. A FIFO character counter is used to + derive empty, half-full, and full status indications, and counts greater than + 128 are possible. + + In the transmit mode, an OTA/B with word type 0 generates SI (shift in) to + load the FIFO and increment the FIFO counter. When the UART is ready for a + character, THRE (UART transmitter holding register empty) and OR (FIFO output + ready) generate THRL (transmitter holding register load) and SO (FIFO shift + out) to unload the FIFO into the UART. When transmission of the character + over the serial line is complete, TRE (UART transmitter register empty) + decrements the FIFO counter. + + In the receive mode, the UART sets DR (data received) when has obtained a + character, which generates SI (FIFO shift in) to load the FIFO and increment + the FIFO counter. This also clocks PE (UART parity error) and IR (FIFO input + ready) into the overrun/parity error flip-flop. An LIA/B with control set + and with OR (FIFO output ready) set, indicating valid data is available, + generates SO (FIFO shift out) to unload the FIFO and decrement the FIFO + counter. + + Presuming an empty FIFO and UART, double-buffering in the transmit mode means + that the first byte deposited into the FIFO is removed and loaded into the + UART transmitter holding register. Even though the FIFO is actually empty, + the FIFO counter remains at 1, because FIFO decrement does not occur until + the UART actually transmits the data byte. The intended mode of operation is + to wait until the buffer-empty interrupt occurs, which will happen when the + final character is transmitted from the UART, before switching the BACI into + receive mode. The counter will match the FIFO contents properly, i.e., will + be zero, when the UART transmission completes. + + However, during diagnostic operation, FIFO testing will take this "extra" + count into consideration. For example, after a master reset, if ten bytes + are written to the FIFO in transmit mode, the first byte will pass through to + the UART transmitter holding register, and the next nine bytes will fill the + FIFO. The first byte read in receive mode will be byte 2, not byte 1; the + latter remains in the UART. After the ninth byte is read, OR (FIFO output + ready) will drop, resetting the valid data flip-flop and inhibiting any + further FIFO counter decrement pulses. The counter will remain at 1 until + another master reset is done. + + The same situation occurs in the RTE driver during ENQ/ACK handshakes. The + driver sets the card to transmit mode, sends an ENQ, waits for a short time + for the character to "bubble through" the FIFO and into the UART transmitter + holding register, and then switches the card to receive mode to await the + interrupt from the reception of the ACK. This is done to avoid the overhead + of the interrupt after the ENQ is transmitted. However, switching the card + into receive mode before the ENQ is actually transmitted means that the FIFO + counter will not decrement when that occurs, leaving the counter in an "off + by one" configuration. To remedy this, the driver does a master reset after + the ACK is received. + + Therefore, for proper operation, we must simulate both the UART + double-buffering and the decoupling of the FIFO and FIFO character counter. +*/ + + +/* Get a character from the FIFO. + + In receive mode, getting a character from the FIFO decrements the character + counter concurrently. In transmit mode, the counter must not be decremented + until the character is actually sent; in this latter case, the caller is + responsible for decrementing. Attempting to get a character when the FIFO is + empty returns the last valid data and does not alter the FIFO indexes. + + Because the FIFO counter may indicate more characters than are actually in + the FIFO, the count is not an accurate indicator of FIFO fill status. We + account for this by examining the get and put indexes. If these are equal, + then the FIFO is either empty or exactly full. We differentiate by examining + the FIFO counter and seeing if it is >= 128, indicating an (over)full + condition. If it is < 128, then the FIFO is empty, even if the counter is + not 0. +*/ + +static uint32 fifo_get (void) +{ +uint32 data; + +data = baci_fifo [baci_fget]; /* get character */ + +if ((baci_fget != baci_fput) || (baci_fcount >= 128)) { /* FIFO occupied? */ + if (IO_MODE == RECV) /* receive mode? */ + baci_fcount = baci_fcount - 1; /* decrement occupancy counter */ + + if (DEBUG_PRI (baci_dev, DEB_BUF)) + fprintf (sim_deb, ">>BACI buf: Character %s get from FIFO [%d], " + "character counter = %d\n", fmt_char (data), baci_fget, baci_fcount); + + baci_fget = (baci_fget + 1) % FIFO_SIZE; /* bump index modulo array size */ + + if (baci_spchar [data]) /* is it a special character? */ + data = data | IN_SPFLAG; /* set flag */ + + data = data | IN_VALID; /* set valid flag in return */ + } + +else /* FIFO empty */ + if (DEBUG_PRI (baci_dev, DEB_BUF)) + fprintf (sim_deb, ">>BACI buf: Attempted get on empty FIFO, " + "character count = %d\n", baci_fcount); + +if (baci_fcount == 0) /* count now zero? */ + baci_status = baci_status | IN_BUFEMPTY; /* set buffer empty flag */ + +update_status (); /* update FIFO status */ + +return data; /* return character */ +} + + +/* Put a character into the FIFO. + + In transmit mode, available characters are unloaded from the FIFO into the + UART transmitter holding register as soon as the THR is empty. That is, + given an empty FIFO and THR, a stored character will pass through the FIFO + and into the THR immediately. Otherwise, the character will remain in the + FIFO. In either case, the FIFO character counter is incremented. + + In receive mode, characters are only unloaded from the FIFO explicitly, so + stores always load the FIFO and increment the counter. +*/ + +static void fifo_put (uint8 ch) +{ +uint32 index = 0; +t_bool pass_thru; + +pass_thru = (IO_MODE == XMIT) && /* pass thru if XMIT and THR empty */ + !(baci_uart_thr & IN_VALID); + +if (pass_thru) /* pass char thru to UART */ + baci_uart_thr = ch | IN_VALID; /* and set valid character flag */ + +else { /* RECV or THR occupied */ + index = baci_fput; /* save current index */ + baci_fifo [baci_fput] = ch; /* put char in FIFO */ + baci_fput = (baci_fput + 1) % FIFO_SIZE; /* bump index modulo array size */ + } + +baci_fcount = baci_fcount + 1; /* increment occupancy counter */ + +if (DEBUG_PRI (baci_dev, DEB_BUF)) + if (pass_thru) + fprintf (sim_deb, ">>BACI buf: Character %s put to UART transmitter holding register, " + "character counter = 1\n", fmt_char (ch)); + else + fprintf (sim_deb, ">>BACI buf: Character %s put to FIFO [%d], " + "character counter = %d\n", fmt_char (ch), index, baci_fcount); + +if ((IO_MODE == RECV) && (baci_spchar [ch])) /* receive mode and special character? */ + baci_status = baci_status | IN_SPCHAR; /* set special char seen flag */ + +if (baci_fcount == 64) /* FIFO half full? */ + baci_status = baci_status | IN_BUFHALF; + +else if (baci_fcount == 128) /* FIFO completely full? */ + baci_status = baci_status | IN_BUFFULL; + +else if (baci_fcount > 128) /* FIFO overrun? */ + baci_status = baci_status | IN_OVRUNPE; + +update_status (); /* update FIFO status */ + +return; +} + + +/* Clock the UART. + + In the diagnostic mode, the DIAG output is connected to the EXT CLK input. + If the baud rate of the Interface Control Word is set to "external clock," + then raising and lowering the DIAG output will pulse the UART transmitter and + receiver clock lines, initiating transmission or reception of serial data. + Sixteen pulses are needed to shift one bit through the UART. + + The diagnostic hood ties CD to BB (received data), so bits presented to CD + via the Interface Control Word can be clocked into the UART receiver register + (RR). Similarly, the UART transmitter register (TR) shifts data onto BA + (transmitted data), and the hood ties BA to SPARE, so transmitted bits are + presented to the SPARE bit in the status word. + + "baci_uart_clk" contains the number of clock pulses remaining for the current + character transfer. Calling this routine with "baci_uart_clk" = 0 initiates + a transfer. The value will be a multiple of 16 and will account for the + start bit, the data bits, the optional parity bit, and the stop bits. The + transfer terminates when the count reaches zero (or eight, if 1.5 stop bits + is selected during transmission). + + Every sixteen pulses when the lower four bits of the clock count are zero, + the transmitter or receiver register will be shifted to present or receive a + new serial bit. The registers are initialized to all ones for proper + handling of the stop bits. + + A break counter is maintained and incremented whenever a space (0) condition + is seen on the serial line. After 160 clock times (10 bits) of continuous + zero data, the "break seen" status is set. + + This routine is not used in terminal mode. +*/ + +static void clock_uart (void) +{ +uint32 uart_bits, data_bits, data_mask, parity, bit_low, i; + +if (baci_uart_clk > 0) { /* transfer in progress? */ + bit_low = (baci_icw & OUT_CD); /* get current receive bit */ + + if ((baci_uart_clk & 017) == 0) /* end of a bit? */ + if (IO_MODE == XMIT) /* transmit? */ + baci_uart_tr = baci_uart_tr >> 1; /* shift new bit onto line */ + else /* receive? */ + baci_uart_rr = (baci_uart_rr >> 1) & /* shift new bit in */ + (bit_low ? ~SIGN : -1); /* (inverted sense) */ + + if (bit_low) { /* another low bit? */ + baci_bcount = baci_bcount + 1; /* update break counter */ + + if (baci_bcount == 160) { /* break held long enough? */ + baci_status = baci_status | IN_BREAK; /* set break flag */ + + if (DEBUG_PRI (baci_dev, DEB_XFER)) + fputs (">>BACI xfer: Break detected\n", sim_deb); + } + } + + else /* high bit? */ + baci_bcount = 0; /* reset break counter */ + + baci_uart_clk = baci_uart_clk - 1; /* decrement clocks remaining */ + + if ((IO_MODE == XMIT) && /* transmit mode? */ + ((baci_uart_clk == 0) || /* and end of character? */ + (baci_uart_clk == 8) && /* or last stop bit */ + (baci_cfcw & OUT_STBITS) && /* and extra stop bit requested */ + ((baci_cfcw & OUT_CHARSIZE) == 0))) { /* and 1.5 stop bits used? */ + + baci_uart_clk = 0; /* clear clock count */ + + baci_fcount = baci_fcount - 1; /* decrement occupancy counter */ + baci_uart_thr = fifo_get (); /* get next char into THR */ + update_status (); /* update FIFO status */ + + if (DEBUG_PRI (baci_dev, DEB_XFER)) + fprintf (sim_deb, ">>BACI xfer: UART transmitter empty, " + "holding register = %06o\n", baci_uart_thr); + } + + else if ((IO_MODE == RECV) && /* receive mode? */ + (baci_uart_clk == 0)) { /* and end of character? */ + + data_bits = 5 + (baci_cfcw & OUT_CHARSIZE); /* calculate number of data bits */ + data_mask = (1 << data_bits) - 1; /* generate mask for data bits */ + + uart_bits = data_bits + /* calculate UART bits as data bits */ + ((baci_cfcw & OUT_PARITY) != 0) + /* plus parity bit if used */ + ((baci_cfcw & OUT_STBITS) != 0); /* plus extra stop bit if used */ + + baci_uart_rhr = baci_uart_rr >> (16 - uart_bits); /* position data to right align */ + baci_uart_rr = CLEAR_R; /* clear receiver register */ + + if (DEBUG_PRI (baci_dev, DEB_XFER)) + fprintf (sim_deb, ">>BACI xfer: UART receiver = %06o (%s)\n", + baci_uart_rhr, fmt_char (baci_uart_rhr & data_mask)); + + fifo_put (baci_uart_rhr & data_mask); /* put data in FIFO */ + update_status (); /* update FIFO status */ + + if (baci_cfcw & OUT_PARITY) { /* parity present? */ + data_mask = data_mask << 1 | 1; /* widen mask to encompass parity */ + uart_bits = baci_uart_rhr & data_mask; /* get data plus parity */ + + parity = (baci_cfcw & OUT_PAREVEN) == 0; /* preset for even/odd parity */ + + for (i = 0; i < data_bits + 1; i++) { /* calc parity of data + parity bit */ + parity = parity ^ uart_bits; /* parity calculated in LSB */ + uart_bits = uart_bits >> 1; + } + + if (parity & 1) { /* parity error? */ + baci_status = baci_status | IN_OVRUNPE; /* report it */ + + if (DEBUG_PRI (baci_dev, DEB_XFER)) + fputs (">>BACI xfer: Parity error detected\n", sim_deb); + } + } + } + } + +if ((baci_uart_clk == 0) && /* start of transfer? */ + ((IO_MODE == RECV) || /* and receive mode */ + (baci_uart_thr & IN_VALID))) { /* or character ready to transmit? */ + + data_bits = 5 + (baci_cfcw & OUT_CHARSIZE); /* calculate number of data bits */ + + uart_bits = data_bits + /* calculate UART bits as data bits */ + ((baci_cfcw & OUT_PARITY) != 0) + /* plus parity bit if used */ + 2 + ((baci_cfcw & OUT_STBITS) != 0); /* plus start/stop and extra stop if used */ + + baci_uart_clk = 16 * uart_bits; /* calculate clocks pulses expected */ + + if (IO_MODE == XMIT) { /* transmit mode? */ + data_mask = (1 << data_bits) - 1; /* generate mask for data bits */ + baci_uart_tr = baci_uart_thr & data_mask; /* mask data into holding register */ + + if (baci_cfcw & OUT_PARITY) { /* add parity to this transmission? */ + uart_bits = baci_uart_tr; /* copy data bits */ + parity = (baci_cfcw & OUT_PAREVEN) == 0; /* preset for even/odd parity */ + + for (i = 0; i < data_bits; i++) { /* calculate parity of data */ + parity = parity ^ uart_bits; /* parity calculated in LSB */ + uart_bits = uart_bits >> 1; + } + + data_mask = data_mask << 1 | 1; /* extend mask for the parity bit */ + baci_uart_tr = baci_uart_tr | /* include parity in transmission register */ + (parity & 1) << data_bits; /* (mask to parity bit and position it) */ + } + + baci_uart_tr = (~data_mask | baci_uart_tr) << 2 | 1; /* form serial data stream */ + + if (DEBUG_PRI (baci_dev, DEB_XFER)) + fprintf (sim_deb, ">>BACI xfer: UART transmitter = %06o (%s), " + "clock count = %d\n", baci_uart_tr & DMASK, + fmt_char (baci_uart_thr & data_mask), baci_uart_clk); + } + + else { + baci_uart_rr = CLEAR_R; /* clear receiver register */ + + if (DEBUG_PRI (baci_dev, DEB_XFER)) + fprintf (sim_deb, ">>BACI xfer: UART receiver empty, " + "clock count = %d\n", baci_uart_clk); + } + } + +return; +} diff --git a/HP2100/hp2100_cpu.c b/HP2100/hp2100_cpu.c index 8cca1782..9c139043 100644 --- a/HP2100/hp2100_cpu.c +++ b/HP2100/hp2100_cpu.c @@ -1,6 +1,6 @@ /* hp2100_cpu.c: HP 21xx CPU simulator - Copyright (c) 1993-2007, Robert M. Supnik + Copyright (c) 1993-2008, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -28,6 +28,14 @@ DMA0,DMA1 12607B/12578A/12895A direct memory access controller DCPC0,DCPC1 12897B dual channel port controller + 30-Apr-08 JDB Enabled SIGNAL instructions, SIG debug flag + 24-Apr-08 JDB Fixed single stepping through interrupts + 20-Apr-08 JDB Enabled EMA and VIS, added EMA, VIS, and SIGNAL debug flags + 03-Dec-07 JDB Memory ex/dep and bkpt type default to current map mode + 26-Nov-07 JDB Added SET CPU DEBUG and OS/VMA flags, enabled OS/VMA + 15-Nov-07 JDB Corrected MP W5 (JSB) jumper action, SET/SHOW reversal, + mp_mevff clear on interrupt with I/O instruction in trap cell + 04-Nov-07 JDB Removed DBI support from 1000-M (was temporary for RTE-6/VM) 28-Apr-07 RMS Removed clock initialization 02-Mar-07 JDB EDT passes input flag and DMA channel in dat parameter 11-Jan-07 JDB Added 12578A DMA byte packing @@ -120,14 +128,17 @@ References: - 2100A Computer Reference Manual (02100-90001, Dec-1971) + - Model 2100A Computer Installation and Maintenance Manual + (02100-90002, Aug-1972) - HP 1000 M/E/F-Series Computers Technical Reference Handbook (5955-0282, Mar-1980) - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation - (92851-90001, Mar-1981) + (92851-90001, Mar-1981) - 12607A Direct Memory Access Operating and Service Manual - (12607-90002, Jan-1970) + (12607-90002, Jan-1970) - 12578A/12578A-01 Direct Memory Access Operating and Service Manual - (12578-9001, Mar-1972) + (12578-9001, Mar-1972) + - 12892B Memory Protect Installation Manual (12892-90007, Jun-1978) The register state for the HP 2116 CPU is: @@ -358,13 +369,16 @@ timer is not called). 6. Interrupt deferral. At instruction fetch time, a pending interrupt - request may be deferred if the previous instruction was a JMP indirect, - JSB indirect, STC, CLC, STF, CLF, SFS (1000 only), or SFC (1000 only), or - was executing from an interrupt trap cell. If the CPU is a 1000, then the - request is always deferred until after the current instruction completes. - If the CPU is a 21xx, then the request is deferred unless the current - instruction is an MRG instruction other than JMP or JMP,I or JSB,I. Note - that for the 21xx, SFS and SFC are not included in the deferral criteria. + request will be deferred if the previous instruction was a JMP indirect, + JSB indirect, STC, CLC, STF, CLF, or was executing from an interrupt trap + cell. In addition, the following instructions will cause deferral on the + 1000 series: SFS, SFC, JRS, DJP, DJS, SJP, SJS, UJP, and UJS. + + On the HP 1000, the request is always deferred until after the current + instruction completes. On the 21xx, the request is deferred unless the + current instruction is an MRG instruction other than JMP or JMP,I or + JSB,I. Note that for the 21xx, SFS and SFC are not included in the + deferral criteria. */ #include "hp2100_defs.h" @@ -373,12 +387,12 @@ /* Memory protect constants */ -#define UNIT_V_MP_JSB (UNIT_V_UF + 0) /* MP jumper W5 out */ -#define UNIT_V_MP_INT (UNIT_V_UF + 1) /* MP jumper W6 out */ -#define UNIT_V_MP_SEL1 (UNIT_V_UF + 2) /* MP jumper W7 out */ -#define UNIT_MP_JSB (1 << UNIT_V_MP_JSB) -#define UNIT_MP_INT (1 << UNIT_V_MP_INT) -#define UNIT_MP_SEL1 (1 << UNIT_V_MP_SEL1) +#define UNIT_V_MP_JSB (UNIT_V_UF + 0) /* MP jumper W5 */ +#define UNIT_V_MP_INT (UNIT_V_UF + 1) /* MP jumper W6 */ +#define UNIT_V_MP_SEL1 (UNIT_V_UF + 2) /* MP jumper W7 */ +#define UNIT_MP_JSB (1 << UNIT_V_MP_JSB) /* 1 = W5 is out */ +#define UNIT_MP_INT (1 << UNIT_V_MP_INT) /* 1 = W6 is out */ +#define UNIT_MP_SEL1 (1 << UNIT_V_MP_SEL1) /* 1 = W7 is out */ #define ABORT(val) longjmp (save_env, (val)) @@ -386,6 +400,7 @@ #define DMAR1 2 #define ALL_BKPTS (SWMASK('E')|SWMASK('N')|SWMASK('S')|SWMASK('U')) +#define ALL_MAPMODES (SWMASK('S')|SWMASK('U')|SWMASK('P')|SWMASK('Q')) uint16 *M = NULL; /* memory */ uint32 saved_AR = 0; /* A register */ @@ -467,8 +482,8 @@ static struct FEATURE_TABLE cpu_features[] = { /* features in UNIT_xxxx { 0, 0, 0 }, { 0, 0, 0 }, { UNIT_MP | UNIT_DMA | UNIT_EAU | UNIT_FP | UNIT_DMS, /* UNIT_1000_M */ - UNIT_PFAIL | UNIT_DMA | UNIT_MP | UNIT_DMS | - UNIT_IOP | UNIT_FFP | UNIT_DBI | UNIT_DS, + UNIT_PFAIL | UNIT_DMA | UNIT_MP | UNIT_DMS | + UNIT_IOP | UNIT_FFP | UNIT_DS, 1048576 }, { UNIT_MP | UNIT_DMA | UNIT_EAU | UNIT_FP | UNIT_DMS, /* UNIT_1000_E */ UNIT_PFAIL | UNIT_DMA | UNIT_MP | UNIT_DMS | @@ -476,7 +491,7 @@ static struct FEATURE_TABLE cpu_features[] = { /* features in UNIT_xxxx 1048576 }, { UNIT_MP | UNIT_DMA | UNIT_EAU | UNIT_FP | /* UNIT_1000_F */ UNIT_FFP | UNIT_DBI | UNIT_DMS, - UNIT_PFAIL | UNIT_DMA | UNIT_MP | + UNIT_PFAIL | UNIT_DMA | UNIT_MP | UNIT_VIS | UNIT_IOP | UNIT_DS | UNIT_SIGNAL | UNIT_EMA_VMA, 1048576 } }; @@ -503,6 +518,7 @@ uint32 shift (uint32 inval, uint32 flag, uint32 oper); void dma_cycle (uint32 chan, uint32 map); uint32 calc_dma (void); uint32 calc_int (void); +uint32 calc_defer (void); t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_reset (DEVICE *dptr); @@ -530,6 +546,7 @@ extern void (*sim_vm_post) (t_bool from_scp); cpu_unit CPU unit descriptor cpu_reg CPU register list cpu_mod CPU modifiers list + cpu_deb CPU debug flags */ UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, 0) }; @@ -623,7 +640,6 @@ MTAB cpu_mod[] = { { UNIT_DBI, 0, "no DBI", NULL, NULL, NULL, NULL }, { MTAB_XTD | MTAB_VDV, UNIT_DBI, NULL, "NODBI", &cpu_clr_opt, NULL, NULL }, -/* Future microcode support. { UNIT_EMA_VMA, UNIT_EMA, "EMA", "EMA", &cpu_set_opt, NULL, NULL }, { MTAB_XTD | MTAB_VDV, UNIT_EMA, NULL, "NOEMA", &cpu_clr_opt, NULL, NULL }, @@ -632,17 +648,20 @@ MTAB cpu_mod[] = { { UNIT_EMA_VMA, 0, "no EMA/VMA", NULL, &cpu_set_opt, NULL, NULL }, +#if defined (HAVE_INT64) { UNIT_VIS, UNIT_VIS, "VIS", "VIS", &cpu_set_opt, NULL, NULL }, { UNIT_VIS, 0, "no VIS", NULL, NULL, NULL, NULL }, { MTAB_XTD | MTAB_VDV, UNIT_VIS, NULL, "NOVIS", &cpu_clr_opt, NULL, NULL }, - { UNIT_DS, UNIT_DS, "DS", "DS", &cpu_set_opt, NULL, NULL }, - { UNIT_DS, 0, "no DS", NULL, NULL, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, UNIT_DS, NULL, "NODS", &cpu_clr_opt, NULL, NULL }, - { UNIT_SIGNAL, UNIT_SIGNAL,"SIGNAL", "SIGNAL", &cpu_set_opt, NULL, NULL }, { UNIT_SIGNAL, 0, "no SIGNAL", NULL, NULL, NULL, NULL }, { MTAB_XTD | MTAB_VDV, UNIT_SIGNAL, NULL, "NOSIGNAL", &cpu_clr_opt, NULL, NULL }, +#endif + +/* Future microcode support. + { UNIT_DS, UNIT_DS, "DS", "DS", &cpu_set_opt, NULL, NULL }, + { UNIT_DS, 0, "no DS", NULL, NULL, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, UNIT_DS, NULL, "NODS", &cpu_clr_opt, NULL, NULL }, */ { MTAB_XTD | MTAB_VDV, 4096, NULL, "4K", &cpu_set_size, NULL, NULL }, @@ -659,11 +678,23 @@ MTAB cpu_mod[] = { { 0 } }; +DEBTAB cpu_deb[] = { + { "OS", DEB_OS }, + { "OSTBG", DEB_OSTBG }, + { "VMA", DEB_VMA }, + { "EMA", DEB_EMA }, + { "VIS", DEB_VIS }, + { "SIG", DEB_SIG }, + { NULL, 0 } + }; + DEVICE cpu_dev = { "CPU", &cpu_unit, cpu_reg, cpu_mod, 1, 8, PA_N_SIZE, 1, 8, 16, &cpu_ex, &cpu_dep, &cpu_reset, - &cpu_boot, NULL, NULL + &cpu_boot, NULL, NULL, + NULL, DEV_DEBUG, + 0, cpu_deb, NULL, NULL }; /* Memory protect data structures @@ -674,7 +705,7 @@ DEVICE cpu_dev = { mp_mod MP modifiers list */ -UNIT mp_unit = { UDATA (NULL, UNIT_MP_SEL1, 0) }; +UNIT mp_unit = { UDATA (NULL, UNIT_MP_SEL1, 0) }; /* default is JSB in, INT in, SEL1 out */ REG mp_reg[] = { { FLDATA (CTL, dev_ctl[PRO/32], INT_V (PRO)) }, @@ -688,12 +719,12 @@ REG mp_reg[] = { }; MTAB mp_mod[] = { - { UNIT_MP_JSB, UNIT_MP_JSB, "JSB (W5) in", "JSBIN", NULL }, - { UNIT_MP_JSB, 0, "JSB (W5) out", "JSBOUT", NULL }, - { UNIT_MP_INT, UNIT_MP_INT, "INT (W6) in", "INTIN", NULL }, - { UNIT_MP_INT, 0, "INT (W6) out", "INTOUT", NULL }, - { UNIT_MP_SEL1, UNIT_MP_SEL1, "SEL1 (W7) in", "SEL1IN", NULL }, - { UNIT_MP_SEL1, 0, "SEL1 (W7) out", "SEL1OUT", NULL }, + { UNIT_MP_JSB, UNIT_MP_JSB, "JSB (W5) out", "JSBOUT", NULL }, + { UNIT_MP_JSB, 0, "JSB (W5) in", "JSBIN", NULL }, + { UNIT_MP_INT, UNIT_MP_INT, "INT (W6) out", "INTOUT", NULL }, + { UNIT_MP_INT, 0, "INT (W6) in", "INTIN", NULL }, + { UNIT_MP_SEL1, UNIT_MP_SEL1, "SEL1 (W7) out", "SEL1OUT", NULL }, + { UNIT_MP_SEL1, 0, "SEL1 (W7) in", "SEL1IN", NULL }, { 0 } }; @@ -883,23 +914,9 @@ while (reason == 0) { /* loop until halted */ intrq = calc_int (); /* recalc interrupts */ } -/* Interrupt deferral rules differ on the 21xx vs. the 1000. The 1000 always - defers until the completion of the instruction following a deferring - instruction. The 21xx defers unless the current instruction is an MRG - instruction other than JMP or JMP,I or JSB,I. See the "Set Phase Logic - Flowchart" in the 2100A Computer Reference Manual for details. -*/ - - if (intrq && /* interrupt pending? */ - ion_defer && /* deferring instruction? */ - (UNIT_CPU_FAMILY == UNIT_FAMILY_21XX)) { /* 21xx series? */ - IR = ReadW (PC); /* prefetch next instr */ - if (((IR & 0070000) != 0000000) && /* MRG instruction? */ - ((IR & 0174000) != 0114000) && /* JSB,I? */ - ((IR & 0074000) != 0024000)) /* JMP or JMP,I? */ - ion_defer = 0; /* no, so clear deferral */ - } - + if (intrq && ion_defer) /* interrupt pending but deferred? */ + ion_defer = calc_defer (); /* confirm deferral */ + /* (From Dave Bryan) Unlike most other I/O devices, the MP flag flip-flop is cleared automatically when the interrupt is acknowledged and not by a programmed @@ -930,6 +947,8 @@ while (reason == 0) { /* loop until halted */ if (((IR & I_NMRMASK) != I_IO) || /* if not I/O or */ (I_GETIOOP (IR) == ioHLT)) /* if halt, */ clrCTL (PRO); /* protection off */ + else /* I/O instr leaves MP on */ + mp_mevff = 0; /* but clears MEV flip-flop */ } else { /* normal instruction */ @@ -945,10 +964,11 @@ while (reason == 0) { /* loop until halted */ if (mp_evrff) mp_viol = PC; /* if ok, upd mp_viol */ IR = ReadW (PC); /* fetch instr */ PC = (PC + 1) & VAMASK; - sim_interval = sim_interval - 1; ion_defer = 0; } + sim_interval = sim_interval - 1; /* count instruction */ + /* Instruction decode. The 21MX does a 256-way decode on IR<15:8> 15 14 13 12 11 10 09 08 instruction @@ -977,6 +997,27 @@ while (reason == 0) { /* loop until halted */ AR = AR & ReadW (MA); break; +/* JSB is a little tricky. It is possible to generate both an MP and a DM + violation simultaneously. Consider a JSB to a location under the MP fence + and on a write-protected page. This situation must be reported as a DM + violation, because it has priority (SFS 5 and SFC 5 check only the MEVFF, + which sets independently of the MP fence violation). + + Under simulation, this means that DM violations must be checked, and the + MEVFF must be set, before an MP abort is taken. This is done for JSB by the + WriteW call to store the return PC. However, WriteW only checks for fence + violations above location 2, as normally JSBs to locations 0 and 1 (i.e., the + A and B register) are allowed. However, if the W5 (JSB) jumper is out, then + JSB 0 and JSB 1 are MP violations as well and must be caught. We do this + with an explicit check before calling WriteW. + + This would seem to violate the above requirement for DM checks before MP + checks. However, a DM abort cannot occur on a write to 0/1, even if logical + page 0 is write-protected, because writes to 0/1 do not attempt to access + memory; they are intercepted and affect the A/B registers instead (micro- + order TAB is used in the Store field), so no MEV signal is generated. +*/ + case 0230:case 0231:case 0232:case 0233: case 0234:case 0235:case 0236:case 0237: ion_defer = 1; /* defer if JSB,I */ @@ -984,9 +1025,11 @@ while (reason == 0) { /* loop until halted */ case 0030:case 0031:case 0032:case 0033: case 0034:case 0035:case 0036:case 0037: if (reason = Ea (IR, &MA, intrq)) break; /* JSB */ - if ((mp_unit.flags & UNIT_MP_JSB) && /* MP if W7 (JSB) out */ - CTL (PRO) && (MA < mp_fence)) - ABORT (ABORT_PRO); + + if ((mp_unit.flags & UNIT_MP_JSB) && /* if W5 (JSB) out */ + CTL (PRO) && (MA <= 1)) /* and MP on and JSB 0 or JSB 1 */ + ABORT (ABORT_PRO); /* MP violation */ + WriteW (MA, PC); /* store PC */ PCQ_ENTRY; PC = (MA + 1) & VAMASK; /* jump */ @@ -1224,6 +1267,10 @@ for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru dev */ } } pcq_r->qptr = pcq_p; /* update pc q ptr */ +if (dms_enb) /* default breakpoint type */ + if (dms_ump) sim_brk_dflt = SWMASK ('U'); /* to current map mode */ + else sim_brk_dflt = SWMASK ('S'); +else sim_brk_dflt = SWMASK ('N'); return reason; } @@ -1316,7 +1363,17 @@ if (op == 06) E = (t >> 15) & 1; /* disabled ext lft rot return t; /* input unchanged */ } -/* IO instruction decode */ +/* I/O instruction decode. + + If memory protect is enabled, and the instruction is not in a trap cell, then + HLT instructions are illegal and will cause a memory protect violation. If + jumper W7 (SEL1) is in, then all other I/O instructions are legal; if W7 is + out, then only I/O instructions to select code 1 are legal. + + We return NOTE_IOG for normal status instead of SCPE_OK to request that + interrupts be recalculated at the end of the instruction (execution of the + I/O group instructions can change the interrupt priority chain). +*/ t_stat iogrp (uint32 ir, uint32 iotrap) { @@ -1327,7 +1384,7 @@ dev = ir & I_DEVMASK; /* get device */ sop = I_GETIOOP (ir); /* get subopcode */ if (!iotrap && CTL (PRO) && /* protected? */ ((sop == ioHLT) || /* halt or !ovf? */ - ((dev != OVF) && (mp_unit.flags & UNIT_MP_SEL1)))) { + ((dev != OVF) && (mp_unit.flags & UNIT_MP_SEL1)))) { /* sel code OK? */ if (sop == ioLIX) ABREG[ab] = 0; /* A/B writes anyway */ ABORT (ABORT_PRO); } @@ -1366,6 +1423,41 @@ if (CMD (DMA1) && SRQ (dmac[1].cw1 & I_DEVMASK)) /* check DMA1 cycle */ return r; } +/* Determine whether a pending interrupt deferral should be inhibited. + + Execution of certain instructions generally causes a pending interrupt to be + deferred until the succeeding instruction completes. However, the interrupt + deferral rules differ on the 21xx vs. the 1000. + + The 1000 always defers until the completion of the instruction following a + deferring instruction. The 21xx defers unless the following instruction is + an MRG instruction other than JMP or JMP,I or JSB,I. If it is, then the + deferral is inhibited, i.e., the pending interrupt will be serviced. + + See the "Set Phase Logic Flowchart," transition from phase 1A to phase 1B, + and the "Theory of Operation," "Control Section Detailed Theory," "Phase + Control Logic," "Phase 1B" paragraph in the Model 2100A Computer Installation + and Maintenance Manual for details. +*/ + +uint32 calc_defer (void) +{ +uint16 IR; + +if (UNIT_CPU_FAMILY == UNIT_FAMILY_21XX) { /* 21xx series? */ + IR = ReadW (PC); /* prefetch next instr */ + + if (((IR & I_MRG & ~I_AB) != 0000000) && /* is MRG instruction? */ + ((IR & I_MRG_I) != I_JSB_I) && /* but not JSB,I? */ + ((IR & I_MRG) != I_JMP)) /* and not JMP or JMP,I? */ + return 0; /* yes, so inhibit deferral */ + else + return 1; /* no, so allow deferral */ + } +else + return 1; /* 1000 always allows deferral */ +} + /* Calculate interrupt requests This routine takes into account all the relevant state of the @@ -1621,12 +1713,14 @@ uint32 dms_cons (uint32 va, int32 sw) { uint32 map_sel; -if (sw & SWMASK ('V')) map_sel = dms_ump; /* switch? select map */ +if ((dms_enb == 0) || /* DMS off? */ + (sw & (SWMASK ('N') | SIM_SW_REST))) /* no mapping rqst or save/rest? */ + return va; /* use physical address */ else if (sw & SWMASK ('S')) map_sel = SMAP; else if (sw & SWMASK ('U')) map_sel = UMAP; else if (sw & SWMASK ('P')) map_sel = PAMAP; else if (sw & SWMASK ('Q')) map_sel = PBMAP; -else return va; /* no switch, physical */ +else map_sel = dms_ump; /* dflt to log addr, cur map */ if (va >= VASIZE) return MEMSIZE; /* virtual, must be 15b */ else if (dms_enb) return dms_io (va, map_sel); /* DMS on? go thru map */ else return va; /* else return virtual */ @@ -1824,6 +1918,11 @@ return dat; From Dave Bryan: Examination of the schematics for the MP card in the engineering documentation shows that the SFS and SFC I/O backplane signals gate the output of the MEVFF onto the SKF line unconditionally. + + The MEVFF records memory expansion (a.k.a. dynamic mapping) violations. It + is set when an DM violation is encountered. It is cleared on POPIO, STC 5, + and -HLT * IOGSP * INTPT. The latter occurs when an interrupt causes + execution of a non-halt I/O instruction in the interrupt trap cell. */ int32 proio (int32 inst, int32 IR, int32 dat) @@ -2153,7 +2252,7 @@ dms_sr = 0; dms_vr = 0; pcq_r = find_reg ("PCQ", NULL, dptr); sim_brk_types = ALL_BKPTS; -sim_brk_dflt = SWMASK ('E'); +sim_brk_dflt = SWMASK ('N'); /* type is nomap as DMS is off */ if (M == NULL) { /* initial call? */ M = calloc (PASIZE, sizeof (uint16)); /* alloc mem */ @@ -2224,6 +2323,8 @@ t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) { int32 d; +if ((sw & ALL_MAPMODES) && (dms_enb == 0)) /* req map with DMS off? */ + return SCPE_NOFNC; /* command not allowed */ addr = dms_cons (addr, sw); if (addr >= MEMSIZE) return SCPE_NXM; if (!(sw & SIM_SW_REST) && (addr == 0)) d = saved_AR; @@ -2237,6 +2338,8 @@ return SCPE_OK; t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) { +if ((sw & ALL_MAPMODES) && (dms_enb == 0)) /* req map with DMS off? */ + return SCPE_NOFNC; /* command not allowed */ addr = dms_cons (addr, sw); if (addr >= MEMSIZE) return SCPE_NXM; if (!(sw & SIM_SW_REST) && (addr == 0)) saved_AR = val & DMASK; @@ -2379,7 +2482,7 @@ if (!(sim_switches & SWMASK ('F'))) { /* force truncation? */ for (i = new_size; i < MEMSIZE; i++) mc = mc | M[i]; if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) return SCPE_INCOMP; - } + } if (UNIT_CPU_FAMILY == UNIT_FAMILY_21XX) { /* 21xx CPU? */ cpu_set_ldr (uptr, FALSE, NULL, NULL); /* save loader to shadow RAM */ diff --git a/HP2100/hp2100_cpu.h b/HP2100/hp2100_cpu.h index 40012a48..60eaa550 100644 --- a/HP2100/hp2100_cpu.h +++ b/HP2100/hp2100_cpu.h @@ -1,6 +1,6 @@ /* hp2100_cpu.h: HP 2100 CPU definitions - Copyright (c) 2005-2006, Robert M. Supnik + Copyright (c) 2005-2008, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,11 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 24-Apr-08 JDB Added calc_defer() prototype + 20-Apr-08 JDB Added DEB_VIS and DEB_SIG debug flags + 26-Nov-07 JDB Added extern sim_deb, cpu_dev, DEB flags for debug printouts + 05-Nov-07 JDB Added extern intaddr, mp_viol, mp_mevff, calc_int, dev_ctl, + ReadIO, WriteIO for RTE-6/VM microcode support 16-Dec-06 JDB Added UNIT_2115 and UNIT_2114 16-Oct-06 JDB Moved ReadF to hp2100_cpu1.c 26-Sep-06 JDB Added CPU externs for microcode simulators @@ -78,10 +83,10 @@ #define UNIT_V_DBI (UNIT_V_UF + 9) /* DBI installed */ #define UNIT_V_EMA (UNIT_V_UF + 10) /* RTE-4 EMA installed */ #define UNIT_V_VMAOS (UNIT_V_UF + 11) /* RTE-6 VMA/OS installed */ -/* Future microcode expansion; reuse flags bottom-up if needed */ #define UNIT_V_VIS (UNIT_V_UF + 12) /* VIS installed */ -#define UNIT_V_DS (UNIT_V_UF + 13) /* DS installed */ -#define UNIT_V_SIGNAL (UNIT_V_UF + 14) /* SIGNAL/1000 installed */ +#define UNIT_V_SIGNAL (UNIT_V_UF + 13) /* SIGNAL/1000 installed */ +/* Future microcode expansion; reuse flags bottom-up if needed */ +#define UNIT_V_DS (UNIT_V_UF + 14) /* DS installed */ /* Unit models */ @@ -151,6 +156,14 @@ #define UNIT_NONE 0 /* no options */ +/* Debug flags */ + +#define DEB_OS (1 << 0) /* RTE-6/VM OS firmware non-TBG processing */ +#define DEB_OSTBG (1 << 1) /* RTE-6/VM OS firmware TBG processing */ +#define DEB_VMA (1 << 2) /* RTE-6/VM VMA firmware instructions */ +#define DEB_EMA (1 << 3) /* RTE-6/VM EMA firmware instructions */ +#define DEB_VIS (1 << 4) /* E/F-Series VIS firmware instructions */ +#define DEB_SIG (1 << 5) /* F-Series SIGNAL/1000 firmware instructions */ /* PC queue. */ @@ -158,6 +171,10 @@ #define PCQ_MASK (PCQ_SIZE - 1) #define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = err_PC +/* simulator state */ + +extern FILE *sim_deb; + /* CPU registers */ extern uint16 ABREG[2]; /* A/B regs (use AR/BR) */ @@ -169,6 +186,7 @@ extern uint32 XR; /* X register */ extern uint32 YR; /* Y register */ extern uint32 E; /* E register */ extern uint32 O; /* O register */ +extern uint32 dev_ctl[2]; /* device control */ /* CPU state */ @@ -178,12 +196,16 @@ extern uint32 dms_ump; extern uint32 dms_sr; extern uint32 dms_vr; extern uint32 mp_fence; +extern uint32 mp_viol; +extern uint32 mp_mevff; extern uint32 iop_sp; extern uint32 ion_defer; +extern uint32 intaddr; extern uint16 pcq[PCQ_SIZE]; extern uint32 pcq_p; extern uint32 stop_inst; extern UNIT cpu_unit; +extern DEVICE cpu_dev; /* CPU functions */ @@ -192,11 +214,15 @@ uint8 ReadB (uint32 addr); uint8 ReadBA (uint32 addr); uint16 ReadW (uint32 addr); uint16 ReadWA (uint32 addr); +uint16 ReadIO (uint32 addr, uint32 map); void WriteB (uint32 addr, uint32 dat); void WriteBA (uint32 addr, uint32 dat); void WriteW (uint32 addr, uint32 dat); void WriteWA (uint32 addr, uint32 dat); +void WriteIO (uint32 addr, uint32 dat, uint32 map); t_stat iogrp (uint32 ir, uint32 iotrap); +uint32 calc_int (void); +uint32 calc_defer (void); void mp_dms_jmp (uint32 va); uint16 dms_rmap (uint32 mapi); void dms_wmap (uint32 mapi, uint32 dat); diff --git a/HP2100/hp2100_cpu0.c b/HP2100/hp2100_cpu0.c index f537f4da..ad1dc33c 100644 --- a/HP2100/hp2100_cpu0.c +++ b/HP2100/hp2100_cpu0.c @@ -1,6 +1,6 @@ /* hp2100_cpu0.c: HP 1000 unimplemented instruction set stubs - Copyright (c) 2006, J. David Bryan + Copyright (c) 2006-2008, 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"), @@ -25,6 +25,9 @@ CPU0 Unimplemented firmware option instructions + 26-Feb-08 HV Removed and implemented "cpu_vis" and "cpu_signal" + 22-Nov-07 JDB Removed and implemented "cpu_rte_ema" + 12-Nov-07 JDB Removed and implemented "cpu_rte_vma" and "cpu_rte_os" 01-Dec-06 JDB Removed and implemented "cpu_sis". 26-Sep-06 JDB Created @@ -50,261 +53,7 @@ #include "hp2100_cpu1.h" -t_stat cpu_rte_ema (uint32 IR, uint32 intrq); /* RTE-4 EMA */ -t_stat cpu_rte_vma (uint32 IR, uint32 intrq); /* RTE-6 VMA */ -t_stat cpu_rte_os (uint32 IR, uint32 intrq, uint32 iotrap); /* RTE-6 OS */ -t_stat cpu_ds (uint32 IR, uint32 intrq); /* Distributed System */ -t_stat cpu_vis (uint32 IR, uint32 intrq); /* Vector Instruction Set */ -t_stat cpu_signal (uint32 IR, uint32 intrq); /* SIGNAL/1000 Instructions */ - - -/* RTE-IV Extended Memory Area Instructions - - The RTE-IV operating system (HP product number 92067A) introduced the - Extended Memory Area (EMA) instructions. EMA provided a mappable data area - up to one megaword in size. These three instructions accelerated data - accesses to variables stored in EMA partitions. Support was limited to - E/F-Series machines; M-Series machines used software equivalents. - - Option implementation by CPU was as follows: - - 2114 2115 2116 2100 1000-M 1000-E 1000-F - ------ ------ ------ ------ ------ ------ ------ - N/A N/A N/A N/A N/A 92067A 92067A - - The routines are mapped to instruction codes as follows: - - Instr. 1000-E/F Description - ------ -------- ---------------------------------------------- - .EMIO 105240 EMA I/O - MMAP 105241 Map physical to logical memory - [test] 105242 [self test] - .EMAP 105257 Resolve array element address - - Notes: - - 1. RTE-IV EMA and RTE-6 VMA instructions share the same address space, so a - given machine can run one or the other, but not both. - - Additional references: - - RTE-IVB Programmer's Reference Manual (92068-90004, Dec-1983). - - RTE-IVB Technical Specifications (92068-90013, Jan-1980). -*/ - -static const OP_PAT op_ema[16] = { - OP_A, OP_AKK, OP_N, OP_N, /* .EMIO MMAP [test] --- */ - OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ - OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ - OP_N, OP_N, OP_N, OP_A /* --- --- --- .EMAP */ - }; - -t_stat cpu_rte_ema (uint32 IR, uint32 intrq) -{ -t_stat reason = SCPE_OK; -OPS op; -uint32 entry; - -if ((cpu_unit.flags & UNIT_EMA) == 0) /* EMA option installed? */ - return stop_inst; - -entry = IR & 017; /* mask to entry point */ - -if (op_ema[entry] != OP_N) - if (reason = cpu_ops (op_ema[entry], op, intrq)) /* get instruction operands */ - return reason; - -switch (entry) { /* decode IR<3:0> */ - - default: /* others undefined */ - reason = stop_inst; - } - -return reason; -} - - -/* RTE-6/VM Virtual Memory Area Instructions - - RTE-6/VM (product number 92084A) introduced Virtual Memory Area (VMA) - instructions -- a superset of the RTE-IV EMA instructions. Different - microcode was supplied with the operating system that replaced the microcode - used with RTE-IV. Microcode was limited to the E/F-Series, and the M-Series - used software equivalents. - - Option implementation by CPU was as follows: - - 2114 2115 2116 2100 1000-M 1000-E 1000-F - ------ ------ ------ ------ ------ ------ ------ - N/A N/A N/A N/A N/A 92084A 92084A - - The routines are mapped to instruction codes as follows: - - Instr. 1000-E/F Description - ------ -------- ---------------------------------------------- - .PMAP 105240 Map VMA page into map register - $LOC 105241 Load on call - [test] 105242 [self test] - .SWP 105243 [Swap A and B registers] - .STAS 105244 [STA B; LDA SP] - .LDAS 105245 [LDA SP] - .MYAD 105246 [NOP in microcode] - .UMPY 105247 [Unsigned multiply and add] - - .IMAP 105250 Integer element resolve address and map - .IMAR 105251 Integer element resolve address - .JMAP 105252 Double integer element resolve address and map - .JMAR 105253 Double integer element resolve address - .LPXR 105254 Map pointer in P+1 plus offset in P+2 - .LPX 105255 Map pointer in A/B plus offset in P+1 - .LBPR 105256 Map pointer in P+1 - .LBP 105257 Map pointer in A/B registers - - Notes: - - 1. The opcodes 105243-247 are undocumented and do not appear to be used in - any HP software. - - 2. The opcode list in the CE Handbook incorrectly shows 105246 as ".MYAD - - multiply 2 signed integers." The microcode listing shows that this - instruction was deleted, and the opcode is now a NOP. - - 3. RTE-IV EMA and RTE-6 VMA instructions shared the same address space, so - a given machine could run one or the other, but not both. - - Additional references: - - RTE-6/VM VMA/EMA Microcode Source (92084-18828, revision 3). - - RTE-6/VM Technical Specifications (92084-90015, Apr-1983). - - M/E/F-Series Computer Systems CE Handbook (5950-3767, Jul-1984). -*/ - -static const OP_PAT op_vma[16] = { - OP_N, OP_KKKAKK, OP_N, OP_N, /* .PMAP $LOC [test] .SWAP */ - OP_N, OP_N, OP_N, OP_K, /* .STAS .LDAS .MYAD .UMPY */ - OP_A, OP_A, OP_A, OP_A, /* .IMAP .IMAR .JMAP .JMAR */ - OP_FF, OP_F, OP_F, OP_N /* .LPXR .LPX .LBPR .LBP */ - }; - -t_stat cpu_rte_vma (uint32 IR, uint32 intrq) -{ -t_stat reason = SCPE_OK; -OPS op; -uint32 entry; - -if ((cpu_unit.flags & UNIT_VMAOS) == 0) /* VMA/OS option installed? */ - return cpu_rte_ema (IR, intrq); /* try EMA */ - -entry = IR & 017; /* mask to entry point */ - -if (op_vma[entry] != OP_N) - if (reason = cpu_ops (op_vma[entry], op, intrq)) /* get instruction operands */ - return reason; - -switch (entry) { /* decode IR<3:0> */ - - default: /* others undefined */ - reason = stop_inst; - } - -return reason; -} - - -/* RTE-6/VM Operating System Instructions - - The OS instructions were added to acccelerate certain time-consuming - operations of the RTE-6/VM operating system, HP product number 92084A. - Microcode was available for the E- and F-Series; the M-Series used software - equivalents. - - Option implementation by CPU was as follows: - - 2114 2115 2116 2100 1000-M 1000-E 1000-F - ------ ------ ------ ------ ------ ------ ------ - N/A N/A N/A N/A N/A 92084A 92084A - - The routines are mapped to instruction codes as follows: - - Instr. 1000-E/F Description - ------ -------- ---------------------------------------------- - $LIBR 105340 Enter privileged/reentrant library routine - $LIBX 105341 Exit privileged/reentrant library routine - .TICK 105342 TBG tick interrupt handler - .TNAM 105343 Find ID segment that matches name - .STIO 105344 Configure I/O instructions - .FNW 105345 Find word with user increment - .IRT 105346 Interrupt return processing - .LLS 105347 Linked list search - - .SIP 105350 Skip if interrupt pending - .YLD 105351 .SIP completion return point - .CPM 105352 Compare words LT/EQ/GT - .ETEQ 105353 Set up EQT pointers in base page - .ENTN 105354 Transfer parameter addresses (utility) - [test] 105355 [self test] - .ENTC 105356 Transfer parameter addresses (priv/reent) - .DSPI 105357 Set display indicator - - Opcodes 105354-105357 are "dual use" instructions that take different - actions, depending on whether they are executed from a trap cell during an - interrupt. When executed from a trap cell, they have these actions: - - Instr. 1000-E/F Description - ------ -------- ---------------------------------------------- - [dma] 105354 DCPC channel interrupt processing - [dms] 105355 DMS/MP/PE interrupt processing - [dev] 105356 Standard device interrupt processing - [tbg] 105357 TBG interrupt processing - - Notes: - - 1. The microcode differentiates between interrupt processing and normal - execution of the "dual use" instructions by testing the CPU flag. - Interrupt vectoring sets the flag; a normal instruction fetch clears it. - Under simulation, interrupt vectoring is indicated by the value of the - "iotrap" parameter. - - 2. The operand patterns for .ENTN and .ENTC normally would be coded as - "OP_A", as each takes a single address as a parameter. However, because - they might also be executed from a trap cell, we cannot assume that P+1 - is an address, or we might cause a DM abort when trying to access - memory. Therefore, "OP_A" handling is done within each routine, once - the type of use is determined. - - Additional references: - - RTE-6/VM O/S Microcode Source (92084-18831, revision 6). - - RTE-6/VM Technical Specifications (92084-90015, Apr-1983). -*/ - -static const OP_PAT op_os[16] = { - OP_A, OP_A, OP_N, OP_N, /* $LIBR $LIBX .TICK .TNAM */ - OP_A, OP_K, OP_A, OP_KK, /* .STIO .FNW .IRT .LLS */ - OP_N, OP_CC, OP_KK, OP_N, /* .SIP .YLD .CPM .ETEQ */ - OP_N, OP_N, OP_N, OP_N /* .ENTN [test] .ENTC .DSPI */ - }; - -t_stat cpu_rte_os (uint32 IR, uint32 intrq, uint32 iotrap) -{ -t_stat reason = SCPE_OK; -OPS op; -uint32 entry; - -if ((cpu_unit.flags & UNIT_VMAOS) == 0) /* VMA/OS option installed? */ - return stop_inst; - -entry = IR & 017; /* mask to entry point */ - -if (op_os[entry] != OP_N) - if (reason = cpu_ops (op_os[entry], op, intrq)) /* get instruction operands */ - return reason; - -switch (entry) { /* decode IR<3:0> */ - - default: /* others undefined */ - reason = stop_inst; - } - -return reason; -} +t_stat cpu_ds (uint32 IR, uint32 intrq); /* Distributed System */ /* Distributed System @@ -386,172 +135,3 @@ switch (entry) { /* decode IR<3:0> */ return reason; } - - -/* Vector Instruction Set - - The VIS provides instructions that operate on one-dimensional arrays of - floating-point values. Both single- and double-precision operations are - supported. - - Option implementation by CPU was as follows: - - 2114 2115 2116 2100 1000-M 1000-E 1000-F - ------ ------ ------ ------ ------ ------ ------ - N/A N/A N/A N/A N/A N/A 12824A - - The routines are mapped to instruction codes as follows: - - Single-Precision Double-Precision - Instr. Opcode Subcod Instr. Opcode Subcod Description - ------ ------ ------ ------ ------ ------ ----------------------------- - VADD 101460 000000 DVADD 105460 004002 Vector add - VSUB 101460 000020 DVSUB 105460 004022 Vector subtract - VMPY 101460 000040 DVMPY 105460 004042 Vector multiply - VDIV 101460 000060 DVDIV 105460 004062 Vector divide - VSAD 101460 000400 DVSAD 105460 004402 Scalar-vector add - VSSB 101460 000420 DVSSB 105460 004422 Scalar-vector subtract - VSMY 101460 000440 DVSMY 105460 004442 Scalar-vector multiply - VSDV 101460 000460 DVSDV 105460 004462 Scalar-vector divide - VPIV 101461 0xxxxx DVPIV 105461 0xxxxx Vector pivot - VABS 101462 0xxxxx DVABS 105462 0xxxxx Vector absolute value - VSUM 101463 0xxxxx DVSUM 105463 0xxxxx Vector sum - VNRM 101464 0xxxxx DVNRM 105464 0xxxxx Vector norm - VDOT 101465 0xxxxx DVDOT 105465 0xxxxx Vector dot product - VMAX 101466 0xxxxx DVMAX 105466 0xxxxx Vector maximum value - VMAB 101467 0xxxxx DVMAB 105467 0xxxxx Vector maximum absolute value - VMIN 101470 0xxxxx DVMIN 105470 0xxxxx Vector minimum value - VMIB 101471 0xxxxx DVMIB 105471 0xxxxx Vector minimum absolute value - VMOV 101472 0xxxxx DVMOV 105472 0xxxxx Vector move - VSWP 101473 0xxxxx DVSWP 105473 0xxxxx Vector swap - .ERES 101474 -- -- -- -- Resolve array element address - .ESEG 101475 -- -- -- -- Load MSEG maps - .VSET 101476 -- -- -- -- Vector setup - [test] -- -- -- 105477 -- [self test] - - Instructions use IR bit 11 to select single- or double-precision format. The - double-precision instruction names begin with "D" (e.g., DVADD vs. VADD). - Most VIS instructions are two words in length, with a sub-opcode immediately - following the primary opcode. - - Notes: - - 1. The .VECT (101460) and .DVCT (105460) opcodes preface a single- or - double-precision arithmetic operation that is determined by the - sub-opcode value. The remainder of the dual-precision sub-opcode values - are "don't care," except for requiring a zero in bit 15. - - 2. The VIS uses the hardware FPP of the F-Series. FPP malfunctions are - detected by the VIS firmware and are indicated by a memory-protect - violation and setting the overflow flag. Under simulation, - malfunctions cannot occur. - - 3. VIS ROM data are available from Bitsavers. - - Additional references: - - 12824A Vector Instruction Set User's Manual (12824-90001, Jun-1979). -*/ - -static const OP_PAT op_vis[16] = { - OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ - OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ - OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ - OP_N, OP_N, OP_N, OP_N /* --- --- --- --- */ - }; - -t_stat cpu_vis (uint32 IR, uint32 intrq) -{ -t_stat reason = SCPE_OK; -OPS op; -uint32 entry; - -if ((cpu_unit.flags & UNIT_VIS) == 0) /* VIS option installed? */ - return stop_inst; - -entry = IR & 017; /* mask to entry point */ - -if (op_vis[entry] != OP_N) - if (reason = cpu_ops (op_vis[entry], op, intrq)) /* get instruction operands */ - return reason; - -switch (entry) { /* decode IR<3:0> */ - - default: /* others undefined */ - reason = stop_inst; - } - -return reason; -} - - -/* SIGNAL/1000 Instructions - - The SIGNAL/1000 instructions provide fast Fourier transforms and complex - arithmetic. They utilize the F-Series floating-point processor and the - Vector Instruction Set. - - Option implementation by CPU was as follows: - - 2114 2115 2116 2100 1000-M 1000-E 1000-F - ------ ------ ------ ------ ------ ------ ------ - N/A N/A N/A N/A N/A N/A 92835A - - The routines are mapped to instruction codes as follows: - - Instr. 1000-F Description - ------ ------ ---------------------------------------------- - BITRV 105600 Bit reversal - BTRFY 105601 Butterfly algorithm - UNSCR 105602 Unscramble for phasor MPY - PRSCR 105603 Unscramble for phasor MPY - BITR1 105604 Swap two elements in array (alternate format) - BTRF1 105605 Butterfly algorithm (alternate format) - .CADD 105606 Complex number addition - .CSUB 105607 Complex number subtraction - .CMPY 105610 Complex number multiplication - .CDIV 105611 Complex number division - CONJG 105612 Complex conjugate - ..CCM 105613 Complex complement - AIMAG 105614 Return imaginary part - CMPLX 105615 Form complex number - [nop] 105616 [no operation] - [test] 105617 [self test] - - Notes: - - 1. SIGNAL/1000 ROM data are available from Bitsavers. - - Additional references (documents unavailable): - - HP Signal/1000 User Reference and Installation Manual (92835-90002). -*/ - -static const OP_PAT op_signal[16] = { - OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ - OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ - OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ - OP_N, OP_N, OP_N, OP_N /* --- --- --- --- */ - }; - -t_stat cpu_signal (uint32 IR, uint32 intrq) -{ -t_stat reason = SCPE_OK; -OPS op; -uint32 entry; - -if ((cpu_unit.flags & UNIT_SIGNAL) == 0) /* SIGNAL option installed? */ - return stop_inst; - -entry = IR & 017; /* mask to entry point */ - -if (op_signal[entry] != OP_N) - if (reason = cpu_ops (op_signal[entry], op, intrq)) /* get instruction operands */ - return reason; - -switch (entry) { /* decode IR<3:0> */ - - default: /* others undefined */ - reason = stop_inst; - } - -return reason; -} diff --git a/HP2100/hp2100_cpu1.c b/HP2100/hp2100_cpu1.c index 091e18c0..e4eb4d6f 100644 --- a/HP2100/hp2100_cpu1.c +++ b/HP2100/hp2100_cpu1.c @@ -1,6 +1,6 @@ /* hp2100_cpu1.c: HP 2100/1000 EAU simulator and UIG dispatcher - Copyright (c) 2005-2007, Robert M. Supnik + Copyright (c) 2005-2008, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,9 @@ CPU1 Extended arithmetic and optional microcode dispatchers + 20-Apr-08 JDB Fixed VIS and SIGNAL to depend on the FPP and HAVE_INT64 + 28-Nov-07 JDB Added fprint_ops, fprint_regs for debug printouts + 17-Nov-07 JDB Enabled DIAG as NOP on 1000 F-Series 04-Jan-07 JDB Added special DBI dispatcher for non-INT64 diagnostic 29-Dec-06 JDB Allows RRR as NOP if 2114 (diag config test) 01-Dec-06 JDB Substitutes FPP for firmware FP if HAVE_INT64 @@ -101,19 +104,19 @@ #if defined (HAVE_INT64) /* int64 support available */ extern t_stat cpu_fpp (uint32 IR, uint32 intrq); /* Floating Point Processor */ -extern t_stat cpu_sis (uint32 IR, uint32 intrq); /* Scientific Instruction */ +extern t_stat cpu_sis (uint32 IR, uint32 intrq); /* Scientific Instruction Set */ +extern t_stat cpu_vis (uint32 IR, uint32 intrq); /* Vector Instruction Set */ +extern t_stat cpu_signal (uint32 IR, uint32 intrq); /* SIGNAL/1000 */ #else /* int64 support unavailable */ -extern t_stat cpu_fp (uint32 IR, uint32 intrq); /* Firmware Floating Point */ +extern t_stat cpu_fp (uint32 IR, uint32 intrq); /* Firmware Floating Point */ #endif /* end of int64 support */ extern t_stat cpu_ffp (uint32 IR, uint32 intrq); /* Fast FORTRAN Processor */ -extern t_stat cpu_ds (uint32 IR, uint32 intrq); /* Distributed Systems */ -extern t_stat cpu_vis (uint32 IR, uint32 intrq); /* Vector Instruction */ +extern t_stat cpu_ds (uint32 IR, uint32 intrq); /* Distributed Systems */ extern t_stat cpu_dbi (uint32 IR, uint32 intrq); /* Double integer */ extern t_stat cpu_rte_vma (uint32 IR, uint32 intrq); /* RTE-4/6 EMA/VMA */ extern t_stat cpu_rte_os (uint32 IR, uint32 intrq, uint32 iotrap); /* RTE-6 OS */ extern t_stat cpu_iop (uint32 IR, uint32 intrq); /* 2000 I/O Processor */ -extern t_stat cpu_signal (uint32 IR, uint32 intrq); /* SIGNAL/1000 Instructions */ extern t_stat cpu_dms (uint32 IR, uint32 intrq); /* Dynamic mapping system */ extern t_stat cpu_eig (uint32 IR, uint32 intrq); /* Extended instruction group */ @@ -198,7 +201,8 @@ switch ((IR >> 8) & 0377) { /* decode IR<15:8> */ switch ((IR >> 4) & 017) { /* decode IR<7:4> */ case 000: /* DIAG 100000 */ - if (UNIT_CPU_MODEL != UNIT_1000_E) /* must be 1000-E */ + if ((UNIT_CPU_MODEL != UNIT_1000_E) && /* must be 1000 E-series */ + (UNIT_CPU_MODEL != UNIT_1000_F)) /* or 1000 F-series */ return stop_inst; /* trap if not */ break; /* DIAG is NOP unless halted */ @@ -509,17 +513,21 @@ switch ((IR >> 4) & 017) { /* decode IR<7:4> */ return cpu_iop (IR, intrq); /* 2000 I/O Processor */ case 003: /* 105460-105477 */ +#if defined (HAVE_INT64) /* int64 support available */ if (UNIT_CPU_MODEL == UNIT_1000_F) /* F-series? */ return cpu_vis (IR, intrq); /* Vector Instruction Set */ else /* M/E-series */ +#endif /* end of int64 support */ return cpu_iop (IR, intrq); /* 2000 I/O Processor */ case 005: /* 105520-105537 */ IR = IR ^ 0000620; /* remap to 105300-105317 */ return cpu_ds (IR, intrq); /* Distributed System */ +#if defined (HAVE_INT64) /* int64 support available */ case 010: /* 105600-105617 */ return cpu_signal (IR, intrq); /* SIGNAL/1000 Instructions */ +#endif /* end of int64 support */ case 014: /* 105700-105717 */ case 015: /* 105720-105737 */ @@ -744,3 +752,119 @@ for (i = 0; i < OP_N_F; i++) { } return reason; } + + +/* Print operands to the debug device. + + The values of an operand array are printed to the debug device. The types of + the operands are specified by an operand pattern. Typically, the operand + pattern is the same one that was used to fill the array originally. +*/ + +void fprint_ops (OP_PAT pattern, OPS op) +{ +OP_PAT flags; +uint32 i; + +for (i = 0; i < OP_N_F; i++) { + flags = pattern & OP_M_FLAGS; /* get operand pattern */ + + switch (flags) { + case OP_NUL: /* null operand */ + return; /* no more, so quit */ + + case OP_IAR: /* int in A */ + case OP_CON: /* inline constant operand */ + case OP_VAR: /* inline variable operand */ + case OP_ADR: /* inline address operand */ + case OP_ADK: /* address of int constant */ + fprintf (sim_deb, + ", op[%d] = %06o", + i, op[i].word); + break; + + case OP_JAB: /* dbl-int in A/B */ + case OP_ADD: /* address of dbl-int constant */ + fprintf (sim_deb, + ", op[%d] = %011o", + i, op[i].dword); + break; + + case OP_FAB: /* 2-word FP in A/B */ + case OP_ADF: /* address of 2-word FP const */ + fprintf (sim_deb, + ", op[%d] = (%06o, %06o)", + i, op[i].fpk[0], op[i].fpk[1]); + break; + + case OP_ADX: /* address of 3-word FP const */ + fprintf (sim_deb, + ", op[%d] = (%06o, %06o, %06o)", + i, op[i].fpk[0], op[i].fpk[1], + op[i].fpk[2]); + break; + + case OP_ADT: /* address of 4-word FP const */ + fprintf (sim_deb, + ", op[%d] = (%06o, %06o, %06o, %06o)", + i, op[i].fpk[0], op[i].fpk[1], + op[i].fpk[2], op[i].fpk[3]); + break; + + case OP_ADE: /* address of 5-word FP const */ + fprintf (sim_deb, + ", op[%d] = (%06o, %06o, %06o, %06o, %06o)", + i, op[i].fpk[0], op[i].fpk[1], + op[i].fpk[2], op[i].fpk[3], op[i].fpk[4]); + break; + + default: + fprintf (sim_deb, "UNKNOWN OPERAND TYPE"); /* not implemented */ + } + + pattern = pattern >> OP_N_FLAGS; /* move next pattern into place */ + } +} + + +/* Print CPU registers to the debug device. + + One or more CPU registers may be printed to the debug output device, which + must be valid before calling. +*/ + +void fprint_regs (char *caption, uint32 regs, uint32 base) +{ +static uint32 ARX, BRX, PRL; /* static so addresses are constant */ + +static const char *reg_names[] = { "CIR", "A", "B", "E", "X", "Y", "O", "P", "return" }; +static const uint32 *reg_ptrs[] = { &intaddr, &ARX, &BRX, &E, &XR, &YR, &O, &PC, &PRL }; +static const char *formats[] = { "%02o", "%06o", "%06o", "%01o", "%06o", "%06o", "%01o", "%06o", "P+%d" }; + +static char format[20] = " %s = "; /* base format string */ +static const int eos = 6; /* length of base format string */ + +uint32 i; +t_bool first = TRUE; /* first-time through flag */ + +ARX = AR; /* copy 16-bit value to static variable */ +BRX = BR; /* copy 16-bit value to static variable */ +PRL = PC - base; /* compute value in static variable */ + +for (i = 0; i < REG_COUNT; i++) { + if (regs & 1) { /* register requested? */ + if (first) /* first time? */ + fputs (caption, sim_deb); /* print caption */ + else + fputc (',', sim_deb); /* print separator */ + + strcpy (&format[eos], formats[i]); /* copy format specifier */ + fprintf (sim_deb, format, reg_names[i], *reg_ptrs[i]); + + first = FALSE; + } + + regs = regs >> 1; /* align next register flag */ + } +return; +} diff --git a/HP2100/hp2100_cpu1.h b/HP2100/hp2100_cpu1.h index e61d1d2a..e563443c 100644 --- a/HP2100/hp2100_cpu1.h +++ b/HP2100/hp2100_cpu1.h @@ -1,6 +1,6 @@ /* hp2100_cpu1.h: HP 2100/1000 firmware dispatcher definitions - Copyright (c) 2006, J. David Bryan + Copyright (c) 2006-2008, 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"), @@ -23,6 +23,11 @@ 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-Apr-08 JDB Corrected OP_AFF to OP_AAFF for SIGNAL/1000 + Removed unused operand patterns + 23-Feb-08 HV Added more OP_* for SIGNAL/1000 and VIS + 28-Nov-07 JDB Added fprint_ops, fprint_regs for debug printouts + 19-Oct-07 JDB Revised OP_KKKAKK operand profile to OP_CCCACC for $LOC 16-Oct-06 JDB Generalized operands for F-Series FP types 26-Sep-06 JDB Split from hp2100_cpu1.c */ @@ -31,6 +36,21 @@ #define _HP2100_CPU1_H_ +/* Register print encoding. */ + +#define REG_COUNT 9 /* count of print flags */ + +#define REG_CIR (1 << 0) /* print central interrupt register */ +#define REG_A (1 << 1) /* print A register */ +#define REG_B (1 << 2) /* print B register */ +#define REG_E (1 << 3) /* print E register */ +#define REG_X (1 << 4) /* print X register */ +#define REG_Y (1 << 5) /* print Y register */ +#define REG_O (1 << 6) /* print O register */ +#define REG_P (1 << 7) /* print P register */ +#define REG_P_REL (1 << 8) /* print P register as relative */ + + /* Operand processing encoding. */ /* Base operand types. Note that all address encodings must be grouped together @@ -76,7 +96,6 @@ #define OP_A (OP_ADR << OP_V_F1) #define OP_K (OP_ADK << OP_V_F1) #define OP_D (OP_ADD << OP_V_F1) -#define OP_F (OP_ADF << OP_V_F1) #define OP_X (OP_ADX << OP_V_F1) #define OP_T (OP_ADT << OP_V_F1) #define OP_E (OP_ADE << OP_V_F1) @@ -87,7 +106,6 @@ #define OP_RC ((OP_FAB << OP_V_F1) | (OP_CON << OP_V_F2)) #define OP_RK ((OP_FAB << OP_V_F1) | (OP_ADK << OP_V_F2)) #define OP_RF ((OP_FAB << OP_V_F1) | (OP_ADF << OP_V_F2)) -#define OP_CC ((OP_CON << OP_V_F1) | (OP_CON << OP_V_F2)) #define OP_CV ((OP_CON << OP_V_F1) | (OP_VAR << OP_V_F2)) #define OP_AC ((OP_ADR << OP_V_F1) | (OP_CON << OP_V_F2)) #define OP_AA ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2)) @@ -97,7 +115,6 @@ #define OP_KV ((OP_ADK << OP_V_F1) | (OP_VAR << OP_V_F2)) #define OP_KA ((OP_ADK << OP_V_F1) | (OP_ADR << OP_V_F2)) #define OP_KK ((OP_ADK << OP_V_F1) | (OP_ADK << OP_V_F2)) -#define OP_FF ((OP_ADF << OP_V_F1) | (OP_ADF << OP_V_F2)) #define OP_IIF ((OP_IAR << OP_V_F1) | (OP_IAR << OP_V_F2) | \ (OP_ADF << OP_V_F3)) @@ -108,6 +125,9 @@ #define OP_CVA ((OP_CON << OP_V_F1) | (OP_VAR << OP_V_F2) | \ (OP_ADR << OP_V_F3)) +#define OP_AAA ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADR << OP_V_F3)) + #define OP_AAF ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ (OP_ADF << OP_V_F3)) @@ -117,6 +137,9 @@ #define OP_AAT ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ (OP_ADT << OP_V_F3)) +#define OP_AKA ((OP_ADR << OP_V_F1) | (OP_ADK << OP_V_F2) | \ + (OP_ADR << OP_V_F3)) + #define OP_AKK ((OP_ADR << OP_V_F1) | (OP_ADK << OP_V_F2) | \ (OP_ADK << OP_V_F3)) @@ -132,16 +155,57 @@ #define OP_AAXX ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ (OP_ADX << OP_V_F3) | (OP_ADX << OP_V_F4)) +#define OP_AAFF ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADF << OP_V_F3) | (OP_ADF << OP_V_F4)) + +#define OP_AAKK ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADK << OP_V_F3) | (OP_ADK << OP_V_F4)) + #define OP_KKKK ((OP_ADK << OP_V_F1) | (OP_ADK << OP_V_F2) | \ (OP_ADK << OP_V_F3) | (OP_ADK << OP_V_F4)) +#define OP_AAAKK ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADR << OP_V_F3) | (OP_ADK << OP_V_F4) | \ + (OP_ADK << OP_V_F5)) + +#define OP_AKAKK ((OP_ADR << OP_V_F1) | (OP_ADK << OP_V_F2) | \ + (OP_ADR << OP_V_F3) | (OP_ADK << OP_V_F4) | \ + (OP_ADK << OP_V_F5)) + +#define OP_AAACCC ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADR << OP_V_F3) | (OP_CON << OP_V_F4) | \ + (OP_CON << OP_V_F5) | (OP_CON << OP_V_F6)) + +#define OP_AAFFKK ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADF << OP_V_F3) | (OP_ADF << OP_V_F4) | \ + (OP_ADK << OP_V_F5) | (OP_ADK << OP_V_F6)) + +#define OP_AAKAKK ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADK << OP_V_F3) | (OP_ADR << OP_V_F4) | \ + (OP_ADK << OP_V_F5) | (OP_ADK << OP_V_F6)) + #define OP_CATAKK ((OP_CON << OP_V_F1) | (OP_ADR << OP_V_F2) | \ (OP_ADT << OP_V_F3) | (OP_ADR << OP_V_F4) | \ (OP_ADK << OP_V_F5) | (OP_ADK << OP_V_F6)) -#define OP_KKKAKK ((OP_ADK << OP_V_F1) | (OP_ADK << OP_V_F2) | \ +#define OP_CCCACC ((OP_CON << OP_V_F1) | (OP_CON << OP_V_F2) | \ + (OP_CON << OP_V_F3) | (OP_ADR << OP_V_F4) | \ + (OP_CON << OP_V_F5) | (OP_CON << OP_V_F6)) + +#define OP_AAAFFKK ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADR << OP_V_F3) | (OP_ADF << OP_V_F4) | \ + (OP_ADF << OP_V_F5) | (OP_ADK << OP_V_F6) | \ + (OP_ADK << OP_V_F7)) + +#define OP_AKAKAKK ((OP_ADR << OP_V_F1) | (OP_ADK << OP_V_F2) | \ + (OP_ADR << OP_V_F3) | (OP_ADK << OP_V_F4) | \ + (OP_ADR << OP_V_F5) | (OP_ADK << OP_V_F6) | \ + (OP_ADK << OP_V_F7)) + +#define OP_AAKAKAKK ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ (OP_ADK << OP_V_F3) | (OP_ADR << OP_V_F4) | \ - (OP_ADK << OP_V_F5) | (OP_ADK << OP_V_F6)) + (OP_ADK << OP_V_F5) | (OP_ADR << OP_V_F6) | \ + (OP_ADK << OP_V_F7) | (OP_ADK << OP_V_F8)) #define OP_CCACACCA ((OP_CON << OP_V_F1) | (OP_CON << OP_V_F2) | \ (OP_ADR << OP_V_F3) | (OP_CON << OP_V_F4) | \ @@ -171,7 +235,7 @@ typedef enum { in_s, in_d, fp_f, fp_x, fp_t, fp_e, fp_a } OPSIZE; /* Conversion from operand size to word count. */ -#define TO_COUNT(s) ((s == fp_a) ? 0 : s + (s < fp_f)) +#define TO_COUNT(s) ((s == fp_a) ? 0 : (uint32) (s + (s < fp_f))) /* HP in-memory representation of a packed floating-point number. @@ -212,4 +276,7 @@ OP ReadOp (uint32 va, OPSIZE precision); /* generalized opera void WriteOp (uint32 va, OP operand, OPSIZE precision); /* generalized operand write */ t_stat cpu_ops (OP_PAT pattern, OPS op, uint32 irq); /* operand processor */ +void fprint_ops (OP_PAT pattern, OPS op); /* debug print operands */ +void fprint_regs (char *caption, uint32 regs, uint32 base); /* debug print CPU registers */ + #endif diff --git a/HP2100/hp2100_cpu2.c b/HP2100/hp2100_cpu2.c index 014c88bf..d9ba58de 100644 --- a/HP2100/hp2100_cpu2.c +++ b/HP2100/hp2100_cpu2.c @@ -785,7 +785,7 @@ switch (entry) { /* decode IR<4:0> */ if (t == v2) { /* term match? */ PC = (PC + 1) & VAMASK; break; - } + } if (intrq) { /* int pending? */ PC = err_PC; /* back up PC */ break; diff --git a/HP2100/hp2100_cpu3.c b/HP2100/hp2100_cpu3.c index c49b615b..9f6585a0 100644 --- a/HP2100/hp2100_cpu3.c +++ b/HP2100/hp2100_cpu3.c @@ -1,6 +1,6 @@ /* hp2100_cpu3.c: HP 2100/1000 FFP/DBI instructions - Copyright (c) 2005-2006, J. David Bryan + Copyright (c) 2005-2008, 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"), @@ -25,6 +25,9 @@ CPU3 Fast FORTRAN and Double Integer instructions + 27-Feb-08 JDB Added DBI self-test instruction + 23-Oct-07 JDB Fixed unsigned-divide bug in .DDI + 17-Oct-07 JDB Fixed unsigned-multiply bug in .DMP 16-Oct-06 JDB Calls FPP for extended-precision math 12-Oct-06 JDB Altered DBLE, DDINT for F-Series FFP compatibility 26-Sep-06 JDB Moved from hp2100_cpu1.c to simplify extensions @@ -575,18 +578,14 @@ return reason; savings to allow programs to load in E-Series systems, in addition to accelerating these common operations. - M-Series microcode was never offered by HP. However, it costs us nothing to - enable double-integer instructions for M-Series simulations. This has the - concomitant advantage that it allows RTE-6/VM to run under SIMH (for - simulation, we must SET CPU 1000-M, because RTE-6/VM looks for the OS and VM - microcode -- which we do not implement yet -- if it detects an E- or F-Series - machine). + There was no equivalent M-Series microcode, due to the limited micromachine + address space on that system. Option implementation by CPU was as follows: 2114 2115 2116 2100 1000-M 1000-E 1000-F ------ ------ ------ ------ ------ ------ ------ - N/A N/A N/A N/A N/A 93575A std + N/A N/A N/A N/A N/A 93585A std The routines are mapped to instruction codes as follows: @@ -612,15 +611,12 @@ return reason; Notes: - 1. The E-Series opcodes are listed in Appendix C of the Macro/1000 manual. - These should be the same opcodes as given in the 93585A manual listed - below, but no copy of the reference below has been located to confirm - the proper opcodes. This module should be corrected if needed when such - documentation is found. + 1. Opcodes 105335-105337 are NOPs in the microcode. They generate + unimplemented instructions stops under simulation. - 2. The action of the self-test instruction (105320) is unknown. At the - moment, we take an unimplemented instruction trap for this. When - documentation explaining the action is located, it will be implemented. + 2. This is an implementation of Revision 2 of the microcode, which was + released as ROM part numbers 93585-80003, 93585-80005, and 93585-80001 + (Revision 1 substituted -80002 for -80005). 3. The F-Series firmware executes .DMP and .DDI/.DDIR by floating the 32-bit double integer to a 48-bit extended-precision number, calling the @@ -629,8 +625,9 @@ return reason; 64- or 32-bit integer arithmetic. Additional references: - - 93575A Double Integer Instructions Installation and Reference Manual - (93575-90007) + - 93585A Microcode Source (93585-18002 Rev. 2005) + - 93585A Double Integer Instructions Installation and Reference Manual + (93585-90007) */ static const OP_PAT op_dbi[16] = { @@ -659,8 +656,11 @@ if (op_dbi[entry] != OP_N) switch (entry) { /* decode IR<3:0> */ case 000: /* [test] 105320 (OP_N) */ - t = (AR << 16) | BR; /* set t for nop */ - reason = stop_inst; /* function unknown; not impl. */ + XR = 2; /* set revision */ + BR = 0377; /* side effect of microcode */ + SR = 0102077; /* set "pass" code */ + PC = (PC + 1) & VAMASK; /* return to P+1 */ + t = (AR << 16) | BR; /* set t for return */ break; case 001: /* .DAD 105321 (OP_JD) */ @@ -677,8 +677,8 @@ switch (entry) { /* decode IR<3:0> */ t_int64 t64; - t64 = (t_int64) op[0].dword * /* multiply values */ - (t_int64) op[1].dword; + t64 = (t_int64) INT32 (op[0].dword) * /* multiply signed values */ + (t_int64) INT32 (op[1].dword); O = ((t64 < -(t_int64) 0x80000000) || /* overflow if out of range */ (t64 > (t_int64) 0x7FFFFFFF)); if (O) @@ -752,7 +752,8 @@ switch (entry) { /* decode IR<3:0> */ if (O) t = ~SIGN32; /* rtn max pos for ovf */ else - t = op[0].dword / op[1].dword; /* else return quotient */ + t = (uint32) (INT32 (op[0].dword) / /* else return quotient */ + INT32 (op[1].dword)); break; case 006: /* .DDIR 105326 (OP_JD) */ @@ -806,7 +807,7 @@ switch (entry) { /* decode IR<3:0> */ goto DSB; /* continue at .DSB */ default: /* others undefined */ - t = (AR << 16) | BR; /* set t for nop */ + t = (AR << 16) | BR; /* set t for NOP */ reason = stop_inst; } diff --git a/HP2100/hp2100_cpu4.c b/HP2100/hp2100_cpu4.c index 3f253553..126da35e 100644 --- a/HP2100/hp2100_cpu4.c +++ b/HP2100/hp2100_cpu4.c @@ -1,6 +1,6 @@ /* hp2100_cpu4.c: HP 1000 FPP/SIS - Copyright (c) 2006, J. David Bryan + Copyright (c) 2006-2008, 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"), @@ -25,6 +25,7 @@ CPU4 Floating Point Processor and Scientific Instruction Set + 18-Mar-08 JDB Fixed B register return bug in /CMRT 01-Dec-06 JDB Substitutes FPP for firmware FP if HAVE_INT64 Primary references: @@ -978,7 +979,7 @@ switch (entry) { /* decode IR<3:0> */ if ((int16) count.word >= 0) /* nearest even integer */ count.word = count.word + 1; - BR = count.word = count.word & ~1; + BR = count.word = count.word & ~1; /* save LSBs of N */ O = O | fp_exec (0122, ACCUM, count, NOP); /* acc = FLT (count) */ @@ -996,6 +997,7 @@ switch (entry) { /* decode IR<3:0> */ (exponent - rsltexp < 5)) { /* bits lost < 5? */ WriteOp (op[0].word, result, fp_t); /* write result */ PC = (PC + 1) & VAMASK; /* P+2 return for good result */ + op[0].fpk[1] = BR; /* return LSBs of N in B */ break; /* all done! */ } } @@ -1024,6 +1026,7 @@ switch (entry) { /* decode IR<3:0> */ if ((int32) op[6].dword >= 0) /* nearest even integer */ op[6].dword = op[6].dword + 1; op[6].dword = op[6].dword & ~1; + BR = op[6].dword & DMASK; /* save LSBs of N */ O = fp_exec (0126, ACCUM, op[6], NOP); /* acc = flt (op6) */ @@ -1046,6 +1049,7 @@ switch (entry) { /* decode IR<3:0> */ WriteOp (op[0].word, result, fp_t); /* write result */ PC = (PC + 1) & VAMASK; /* P+2 return for good result */ + op[0].fpk[1] = BR; /* return LSBs of N in B */ break; diff --git a/HP2100/hp2100_cpu5.c b/HP2100/hp2100_cpu5.c new file mode 100644 index 00000000..ea9ce3bb --- /dev/null +++ b/HP2100/hp2100_cpu5.c @@ -0,0 +1,1426 @@ +/* hp2100_cpu5.c: HP 1000 RTE-6/VM VMA and RTE-IV EMA instructions + + Copyright (c) 2006, J. David Bryan + Copyright (c) 2007-2008, Holger Veit + + 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 AUTHORS 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 authors 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 authors. + + CPU5 RTE-6/VM and RTE-IV firmware option instructions + + 01-May-08 HV Fixed mapping bug in "cpu_ema_emap" + 21-Apr-08 JDB Added EMA support from Holger + 25-Nov-07 JDB Added TF fix from Holger + 07-Nov-07 HV VMACK diagnostic tests 1...32 passed + 19-Oct-07 JDB Corrected $LOC operand profile to OP_CCCACC + 03-Oct-07 HV Moved RTE-6/VM instrs from hp2100_cpu0.c + 26-Sep-06 JDB Created + + Primary references: + - HP 1000 M/E/F-Series Computers Technical Reference Handbook + (5955-0282, Mar-1980) + - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation + (92851-90001, Mar-1981) + - Macro/1000 Reference Manual (92059-90001, Dec-1992) + + Additional references are listed with the associated firmware + implementations, as are the HP option model numbers pertaining to the + applicable CPUs. +*/ + +#include +#include "hp2100_defs.h" +#include "hp2100_cpu.h" +#include "hp2100_cpu1.h" + + +t_stat cpu_rte_vma (uint32 IR, uint32 intrq); /* RTE-6 VMA */ +t_stat cpu_rte_ema (uint32 IR, uint32 intrq); /* RTE-IV EMA */ + + +/* RTE-6/VM Virtual Memory Area Instructions + + RTE-6/VM (product number 92084A) introduced Virtual Memory Area (VMA) + instructions -- a superset of the RTE-IV EMA instructions. Different + microcode was supplied with the operating system that replaced the microcode + used with RTE-IV. Microcode was limited to the E/F-Series, and the M-Series + used software equivalents. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A N/A 92084A 92084A + + The routines are mapped to instruction codes as follows: + + Instr. 1000-E/F Description + ------ -------- ---------------------------------------------- + .PMAP 105240 Map VMA page into map register + $LOC 105241 Load on call + [test] 105242 [self test] + .SWP 105243 [Swap A and B registers] + .STAS 105244 [STA B; LDA SP] + .LDAS 105245 [LDA SP] + .MYAD 105246 [NOP in microcode] + .UMPY 105247 [Unsigned multiply and add] + + .IMAP 105250 Integer element resolve address and map + .IMAR 105251 Integer element resolve address + .JMAP 105252 Double integer element resolve address and map + .JMAR 105253 Double integer element resolve address + .LPXR 105254 Map pointer in P+1 plus offset in P+2 + .LPX 105255 Map pointer in A/B plus offset in P+1 + .LBPR 105256 Map pointer in P+1 + .LBP 105257 Map pointer in A/B registers + + Notes: + + 1. The opcodes 105243-247 are undocumented and do not appear to be used in + any HP software. + + 2. The opcode list in the CE Handbook incorrectly shows 105246 as ".MYAD - + multiply 2 signed integers." The microcode listing shows that this + instruction was deleted, and the opcode is now a NOP. + + 3. RTE-IV EMA and RTE-6 VMA instructions shared the same address space, so + a given machine could run one or the other, but not both. + + Additional references: + - RTE-6/VM VMA/EMA Microcode Source (92084-18828, revision 3). + - RTE-6/VM Technical Specifications (92084-90015, Apr-1983). + - M/E/F-Series Computer Systems CE Handbook (5950-3767, Jul-1984). +*/ + +static const OP_PAT op_vma[16] = { + OP_N, OP_CCCACC, OP_N, OP_N, /* .PMAP $LOC [test] .SWAP */ + OP_N, OP_N, OP_N, OP_K, /* .STAS .LDAS .MYAD .UMPY */ + OP_A, OP_A, OP_A, OP_A, /* .IMAP .IMAR .JMAP .JMAR */ + OP_AA, OP_A, OP_A, OP_N /* .LPXR .LPX .LBPR .LBP */ + }; + +/* some addresses in page0 of RTE-6/VM */ +static const uint32 idx = 0001645; +static const uint32 xmata = 0001646; +static const uint32 xi = 0001647; +static const uint32 xeqt = 0001717; +static const uint32 vswp = 0001776; +static const uint32 umaps = 0003740; +static const uint32 page30 = 0074000; +static const uint32 page31 = 0076000; +static const uint32 ptemiss = 0176000; + +/* frequent constants in paging */ +#define SUITMASK 0176000 +#define NILPAGE 0176000 +#define PAGEIDX 0001777 +#define MSEGMASK 0076000 +#define RWPROT 0141777 + +/* from scp.c */ +extern int32 sim_step; +extern FILE* sim_log; + +/* MP abort handler */ +extern jmp_buf save_env; +#define ABORT(val) longjmp (save_env, (val)) + +/* microcode version of resolve(): allows a much higher # of indirection levels. Used for + instance for LBP microcode diagnostics which will check > 100 levels. + */ +#define VMA_INDMAX 200 + +static t_stat vma_resolve (uint32 MA, uint32 *addr, t_bool debug) +{ +uint32 i; +uint32 faultma = MA; + +for (i = 0; (i < VMA_INDMAX) && (MA & I_IA); i++) { /* resolve multilevel */ + MA = ReadW (MA & VAMASK); /* follow address chain */ + } + +if (MA & I_IA) { + if (debug) + fprintf(sim_deb,">>CPU VMA: vma_resolve indirect loop addr=%06o\n",faultma); + return STOP_IND; /* indirect loop */ + } + +*addr = MA; +return SCPE_OK; +} + +/* $LOC + ASSEMBLER CALLING SEQUENCE: + + $MTHK NOP RETURN ADDRESS OF CALL (REDONE AFTER THIS ROUTINE) + JSB $LOC + .DTAB OCT LGPG# LOGICAL PAGE # AT WHICH THE NODE TO + * BE MAPPED IN BELONGS (0-31) + OCT RELPG RELATIVE PAGE OFFSET FROM BEGINING + * OF PARTITION OF WHERE THAT NODE RESIDES. + * (0 - 1023) + OCT RELBP RELATIVE PAGE OFFSET FROM BEGINING OF + * PARTITION OF WHERE BASE PAGE RESIDES + * (0 - 1023) + CNODE DEF .CNOD THIS IS THE ADDRESS OF CURRENT PATH # WORD + .ORD OCT XXXXX THIS NODE'S LEAF # (IE PATH #) + .NOD# OCT XXXXX THIS NODE'S ORDINAL # +*/ + +static t_stat cpu_vma_loc(OPS op,uint32 intrq,t_bool debug) +{ +uint32 eqt,mls,pnod,lstpg,fstpg,rotsz,lgpg,relpg,relbp,matloc,ptnpg,physpg,cnt,pgs,umapr; + +eqt = ReadIO(xeqt,UMAP); /* get ID segment */ +mls = ReadIO(eqt+33,SMAP); /* get word33 of alternate map */ +if ((mls & 0x8000) == 0) { /* this is not an MLS prog! */ + PC = err_PC; + if (debug) + fprintf(sim_deb,">>CPU VMA: cpu_vma_loc at P=%06o: not an MLS program\n", PC); + if (CTL (PRO)) ABORT (ABORT_PRO); /* allow an MP abort */ + return STOP_HALT; /* FATAL error! */ + } + +pnod = mls & 01777; /* get #pages of mem res nodes */ +if (pnod == 0) { /* no pages? FATAL! */ + PC = err_PC; + if (debug) + fprintf(sim_deb,">>CPU VMA: cpu_vma_loc at P=%06o: no mem resident pages\n", PC); + if (CTL (PRO)) ABORT (ABORT_PRO); /* allow an MP abort */ + return STOP_HALT; + } + +lstpg = (ReadIO(eqt+29,SMAP) >> 10) - 1; /* last page# of code */ +fstpg = ReadIO(eqt+23,SMAP) >> 10; /* index to 1st addr + mem nodes */ +rotsz = fstpg - (ReadIO(eqt+22,SMAP) >> 10); /* #pages in root */ +lgpg = op[0].word; + +/* lets do some consistency checks, CPU halt if they fail */ +if (lstpg < lgpg || lgpg < fstpg) { /* assert LSTPG >= LGPG# >= FSTPG */ + PC = err_PC; + if (debug) + fprintf(sim_deb, + ">>CPU VMA: $LOC at P=%06o: failed check LSTPG >= LGPG# >= FSTPG\n",PC); + if (CTL (PRO)) ABORT (ABORT_PRO); /* allow an MP abort */ + return STOP_HALT; + } + +relpg = op[1].word; +if (pnod < relpg || relpg < (rotsz+1)) { /* assert #PNOD >= RELPG >= ROTSZ+1 */ + PC = err_PC; + if (debug) + fprintf(sim_deb, + ">>CPU VMA: $LOC at %06o: failed check #PNOD >= RELPG >= ROTSZ+1\n",PC); + if (CTL (PRO)) ABORT (ABORT_PRO); /* allow an MP abort */ + return STOP_HALT; + } + +relbp = op[2].word; +if (relbp != 0) /* assert RELBP == 0 OR */ + if (pnod < relbp || relbp < (rotsz+1)) { /* #PNOD >= RELBP >= ROTSZ+1 */ + PC = err_PC; + if (debug) + fprintf(sim_deb, + ">>CPU VMA: $LOC at P=%06o: failed check: #PNOD >= RELBP >= ROTSZ+1\n",PC); + if (CTL (PRO)) ABORT (ABORT_PRO); /* allow an MP abort */ + return STOP_HALT; + } + +cnt = lstpg - lgpg + 1; /* #pages to map */ +pgs = pnod - relpg + 1; /* #pages from start node to end of code */ +if (pgs < cnt) cnt = pgs; /* ensure minimum, so not to map into EMA */ + +matloc = ReadIO(xmata,UMAP); /* get MAT $LOC address */ +ptnpg = ReadIO(matloc+3,SMAP) & 01777; /* index to start phys pg */ +physpg = ptnpg + relpg; /* phys pg # of node */ +umapr = 32 + lgpg; /* map register to start */ + +/* do an XMS with AR=umapr,BR=physpg,XR=cnt */ +if (debug) + fprintf(sim_deb, + ">>CPU VMA: $LOC map %d pgs from phys=%06o to mapr=%d\n", + cnt,physpg,umapr); +while (cnt != 0) { + dms_wmap (umapr, physpg); /* map pages of new overlay segment */ + cnt = (cnt - 1) & DMASK; + umapr = (umapr + 1) & DMASK; + physpg = (physpg + 1) & DMASK; + } + +dms_wmap(32,relbp+ptnpg); /* map base page again */ +WriteW(op[3].word,op[4].word); /* path# we are going to */ + +PC = (PC - 8) & DMASK; /* adjust PC to return address */ + /* word before the $LOC microinstr. */ +PC = (ReadW(PC) - 1) & DMASK; /* but the call has to be rerun, */ + /* so must skip back to the original call */ + /* which will now lead to the real routine */ +if (debug) + fprintf(sim_deb,">>CPU VMA: $LOC done: path#=%06o, P=%06o\n",op[4].word,PC); +return SCPE_OK; +} + +/* map pte into last page + return FALSE if page fault, nil flag in PTE or suit mismatch + return TRUE if suit match, physpg = physical page + or page=0 -> last+1 page +*/ +static t_bool cpu_vma_ptevl(uint32 pagid,uint32* physpg) +{ +uint32 suit; +uint32 pteidx = pagid & 0001777; /* build index */ +uint32 reqst = pagid & SUITMASK; /* required suit */ +uint32 pteval = ReadW(page31 | pteidx); /* get PTE entry */ +*physpg = pteval & 0001777; /* store physical page number */ +suit = pteval & SUITMASK; /* suit number seen */ +if (pteval == NILPAGE) return FALSE; /* NIL value in PTE */ +return suit == reqst || !*physpg; /* good page or last+1 */ +} + +/* handle page fault */ +static t_stat cpu_vma_fault(uint32 x,uint32 y,int32 mapr, + uint32 ptepg,uint32 ptr,uint32 faultpc, t_bool debug) +{ +uint32 pre = ReadIO(xi,UMAP); /* get program preamble */ +uint32 ema = ReadIO(pre+2,UMAP); /* get address of $EMA$/$VMA$ */ +WriteIO(ema,faultpc,UMAP); /* write addr of fault instr */ +XR = x; /* X = faulting page */ +YR = y; /* Y = faulting address for page */ + +if (mapr>0) + dms_wmap(mapr+UMAP,ptepg); /* map PTE into specified user dmsmap */ + +/* do a safety check: first instr of $EMA$/$VMA$ must be a DST instr */ +if (ReadIO(ema+1,UMAP) != 0104400) { + if (debug) + fprintf(sim_deb, ">>CPU VMA: pg fault: no EMA/VMA user code present\n"); + if (CTL (PRO)) ABORT (ABORT_PRO); /* allow an MP abort */ + return STOP_HALT; /* FATAL: no EMA/VMA! */ + } + +PC = (ema+1) & VAMASK; /* restart $EMA$ user code, */ + /* will return to fault instruction */ + +AR = (ptr >> 16) & DMASK; /* restore A, B */ +BR = ptr & DMASK; +E = 0; /* enforce E = 0 */ +if (debug) + fprintf(sim_deb, + ">>CPU VMA: Call pg fault OS exit, AR=%06o BR=%06o P=%06o\n", + AR, BR, PC); +return SCPE_OK; +} + +/* map in PTE into last page, return false, if page fault */ +static t_bool cpu_vma_mapte(uint32* ptepg) +{ +uint32 idext,idext2; +uint32 dispatch = ReadIO(vswp,UMAP) & 01777; /* get fresh dispatch flag */ +t_bool swapflag = TRUE; + +if (dispatch == 0) { /* not yet set */ + idext = ReadIO(idx,UMAP); /* go into IDsegment extent */ + if (idext != 0) { /* is ema/vma program? */ + dispatch = ReadWA(idext+1) & 01777; /* get 1st ema page: new vswp */ + WriteIO(vswp,dispatch,UMAP); /* move into $VSWP */ + idext2 = ReadWA(idext+2); /* get swap bit */ + swapflag = (idext2 & 020000) != 0; /* bit 13 = swap bit */ + } + } + +if (dispatch) { /* some page is defined */ + dms_wmap(31 + UMAP,dispatch); /* map $VSWP to register 31 */ + *ptepg = dispatch; /* return PTEPG# for later */ + } + +return swapflag; /* true for swap bit set */ +} + +/* .LBP + ASSEMBLER CALLING SEQUENCE: + + DLD PONTR TRANSLATE 32 BIT POINTER TO 15 + JSB .LBP BIT POINTER. + + + 32 bit pointer: + ----------AR------------ -----BR----- + 15 14....10 9....4 3...0 15.10 9....0 + L<----------------------------------- L=1 local reference bit + XXXXXXXX<------------------------- 5 bit unused + PPPPPP PPPPP PPPPP<------ 16 bit PAGEID + SSSSSS<------------------ SUIT# within PAGEID + PPPPP PPPPP<------ 10 bit PAGEID index into PTE + OOOOOO 10 bit OFFSET +*/ + +static t_stat cpu_vma_lbp(uint32 ptr,uint32 aoffset,uint32 faultpc,uint32 intrq,t_bool debug) +{ +uint32 pagid,offset,ptrl,pgidx,ptepg; +uint16 p30,p31,suit; +t_stat reason = SCPE_OK; +uint32 faultab = ptr; /* remember A,B for page fault */ +ptr += aoffset; /* add the offset e.g. for .LPX */ + +if (debug) + fprintf(sim_deb,">>CPU VMA: cpu_vma_lbp: ptr=%o/%o\n", + (ptr>>16) & DMASK,ptr & DMASK); + +O = 0; /* clear overflow */ +if (ptr & 0x80000000) { /* is it a local reference? */ + ptrl = ptr & VAMASK; + if ((ptr&I_IA) && (reason = vma_resolve (ReadW (ptrl), &ptrl, debug))) + return reason; /* yes, resolve indirect ref */ + BR = ptrl & VAMASK; /* address is local */ + AR = (ptr >> 16) & DMASK; + if (debug) + fprintf(sim_deb,">>CPU VMA: cpu_vma_lbp: local ref AR=%06o BR=%06o\n",AR,BR); + return SCPE_OK; + } + +pagid = (ptr >> 10) & DMASK; /* extract page id (16 bit idx, incl suit*/ +offset = ptr & 01777; /* and offset */ +suit = pagid & SUITMASK; /* suit of page */ +pgidx = pagid & PAGEIDX; /* index into PTE */ + +if (!cpu_vma_mapte(&ptepg)) /* map in PTE */ + return cpu_vma_fault(65535,ptemiss,-1,ptepg,faultab,faultpc, debug); /* oops, must init PTE */ + +/* ok, we have the PTE mapped to page31 */ +/* the microcode tries to reads two consecutive data pages into page30 and page31 */ + +/* read the 1st page value from PTE */ +p30 = ReadW(page31 | pgidx) ^ suit; +if (!p30) /* matched suit for 1st page */ + return cpu_vma_fault(pagid,page30,30,ptepg,faultab,faultpc,debug); + +/* suit switch situation: 1st page is in last idx of PTE, then following page + * must be in idx 0 of PTE */ +if (pgidx==01777) { /* suit switch situation */ + pgidx = 0; /* select correct idx 0 */ + suit = pagid+1; /* suit needs increment */ + if (suit==0) { /* is it page 65536? */ + offset += 02000; /* adjust to 2nd page */ + suit = NILPAGE; + pgidx = 01777; + } +} else + pgidx++; /* select next page */ + +p31 = ReadW(page31 | pgidx) ^ suit; +if (!p31) { /* matched suit for 2nd page */ + dms_wmap(31+UMAP,p30); + if (p30 & SUITMASK) + return cpu_vma_fault(pagid,page30,30,ptepg,faultab,faultpc,debug); + if (!(p31 ^ NILPAGE)) /* suit is 63: fault */ + return cpu_vma_fault(pagid+1,page31,31,ptepg,faultab,faultpc,debug); + + offset += 02000; /* adjust offset to last user map because */ + /* the address requested page 76xxx */ + } +else { + dms_wmap(30+UMAP,p30); + if (p30 & SUITMASK) + return cpu_vma_fault(pagid,page30,30,ptepg,faultab,faultpc,debug); + dms_wmap(31+UMAP,p31); + if (p31 & SUITMASK) + return cpu_vma_fault(pagid+1,page31,31,ptepg,faultab,faultpc,debug); + } + +AR = pagid; /* return pagid in A */ +BR = page30+offset; /* mapped address in B */ +if (debug) + fprintf(sim_deb,">>CPU VMA: cpu_vma_lbp: map done AR=%06o BR=%o6o\n",AR,BR); +return SCPE_OK; +} + +/* .PMAP + ASSEMBLER CALLING SEQUENCE: + + LDA UMAPR (MSEG - 31) + LDB PAGID (0-65535) + JSB .PMAP GO MAP IT IN + A-REG = REASON, NOTE 1 + > SEE NOTE 2> + + NOTE 1 : IF BIT 15 OF A-REG SET, THEN ALL NORMAL BRANCHES TO THE + $EMA$/$VMA$ CODE WILL BE CHANGED TO P+1 EXIT. THE A-REG + WILL BE THE REASON THE MAPPING WAS NOT SUCCESSFUL IF BIT 15 + OF THE A-REG WAS NOT SET. + THIS WAS DONE SO THAT A ROUTINE ($VMA$) CAN DO A MAPPING + WITHOUT THE POSSIBILITY OF BEING RE-CURRED. IT IS USED + BY $VMA$ AND PSTVM IN THE PRIVLEDGED MODE. + NOTE 2: E-REG WILL = 1 IF THE LAST+1 PAGE IS REQUESTED AND + MAPPED READ/WRITE PROTECTED ON A GOOD P+2 RETURN. +*/ +static t_stat cpu_vma_pmap(uint32 umapr,uint32 pagid, t_bool debug) +{ +uint32 physpg, ptr, pgpte; +uint32 mapnm = umapr & 0x7fff; /* strip off bit 15 */ + +if (debug) + fprintf(sim_deb, ">>CPU VMA: .PMAP AR=%06o(umapr) BR=%06o(pagid)\n",umapr,pagid); + +if (mapnm > 31) { /* check for invalid map register */ + AR = 80; /* error: corrupt EMA/VMA system */ + if (debug) + fprintf(sim_deb, ">>CPU VMA: .PMAP invalid mapr: AR=80, exit P+1\n"); + return SCPE_OK; /* return exit PC+1 */ + } + +ptr = (umapr << 16) | (pagid & DMASK); /* build the ptr argument for vma_fault */ +if (!cpu_vma_mapte(&pgpte)) { /* map the PTE */ + if (umapr & 0x8000) { + XR = 65535; + YR = ptemiss; + if (debug) + fprintf(sim_deb, + ">>CPU VMA: .PMAP pg fault&bit15: XR=%06o YR=%06o, exit P+1\n", + XR, YR); + return SCPE_OK; /* use PC+1 error exit */ + } + return cpu_vma_fault(65535,ptemiss,-1,pgpte,ptr,PC-1,debug); /* oops: fix PTE */ + } + +/* PTE is successfully mapped to page31 and dmsmap[63] */ +if (!cpu_vma_ptevl(pagid,&physpg)) { + if (umapr & 0x8000) { + XR = pagid; + YR = page31; + if (debug) + fprintf(sim_deb, + ">>CPU VMA: .PMAP pg map&bit15: XR=%06o YR=%06o, exit P+1\n", + XR, YR); + return SCPE_OK; /* use PC+1 error exit*/ + } + return cpu_vma_fault(pagid,page31,31,pgpte,ptr,PC-1,debug); /* page not present */ + } + +E = 1; +if (physpg == 0) /* last+1 page ? */ + physpg = RWPROT; /* yes, use page 1023 RW/Protected */ +else E = 0; /* normal page to map */ + +dms_wmap(mapnm+UMAP,physpg); /* map page to user page reg */ +if (mapnm != 31) /* unless already unmapped, */ + dms_wmap(31+UMAP,RWPROT); /* unmap PTE */ + +AR = (umapr + 1) & DMASK; /* increment mapr for next call */ +BR = (pagid + 1) & DMASK; /* increment pagid for next call */ +O = 0; /* clear overflow */ +PC = (PC + 1) & VAMASK; /* normal PC+2 return */ +if (debug) + fprintf(sim_deb,">>CPU VMA: .PMAP map done: AR=%06o BR=%o6o exit P+2\n",AR,BR); +return SCPE_OK; +} + +/* array calc helper for .imar, .jmar, .imap, .jmap + ij=in_s: 16 bit descriptors + ij=in_d: 32 bit descriptors + + This helper expects mainly the following arguments: + dtbl: pointer to an array descriptor table + atbl: pointer to the table of actual subscripts + + where subscript table is the following: + atbl-> DEF last_subscript,I (point to single or double integer) + ... + DEF first subscript,I (point to single or double integer) + + where Descriptor_table is the following table: + dtbl-> DEC #dimensions + DEC/DIN next-to-last dimension (single or double integer) + ... + DEC/DIN first dimension (single or double integer) + DEC elementsize in words + DEC high,low offset from start of EMA to element(0,0...0) + + Note that subscripts are counting from 0 +*/ +static t_stat cpu_vma_ijmar(OPSIZE ij,uint32 dtbl,uint32 atbl,uint32* dimret, + uint32 intrq,t_bool debug) +{ +t_stat reason = SCPE_OK; +uint32 ndim,MA,i,ws; +int32 accu,ax,dx; +OP din; +int opsz = ij==in_d ? 2 : 1; + +ndim = ReadW(dtbl++); /* get #dimensions itself */ +if (debug) { + fprintf(sim_deb, ">>CPU VMA array calc #dim=%d, size=%d\n",ndim,opsz); + fprintf(sim_deb, ">>CPU VMA: array actual subscripts ("); + for (i=0; i0) fputc(',',sim_deb); + fprintf(sim_deb,"%d",ij==in_d?INT32(din.dword) : INT16(din.word)); + } + + fprintf(sim_deb,")\n>>CPU VMA: array descriptor table ("); + if (ndim) { + for (i=0; i0) fputc(',',sim_deb); + fprintf(sim_deb,"%d",ij==in_d?INT32(din.dword) : INT16(din.word)); + } + i = dtbl+1+(ndim-1)*opsz; + ws = ReadW(i-1); + } + else { + i = dtbl; + ws = 1; + } + fprintf(sim_deb,")\n>>CPU VMA: array elemsz=%d base=%o/%o\n", + ws,ReadW(i),ReadW(i+1)); + } + +if (dimret) *dimret = ndim; /* return dimensions */ +if (ndim == 0) { /* no dimensions: */ + AR = ReadW(dtbl++); /* return the array base itself */ + BR = ReadW(dtbl); + if (debug) + fprintf(sim_deb,">>CPU VMA: #dim=0, AR=%06o, BR=%06o\n",AR,BR); + return SCPE_OK; + } + +/* calculate + * (...(An*Dn-1)+An-1)*Dn-2)+An-2....)+A2)*D1)+A1)*#words + Array base + * Depending on ij, Ax and Dx can be 16 or 32 bit + */ +accu = 0; +while (ndim-- > 0) { + MA = ReadW(atbl++); /* get addr of subscript */ + if ((reason = resolve (MA, &MA, intrq))) /* and resolve it */ + return reason; + din = ReadOp(MA,ij); /* get actual subscript value */ + ax = ij==in_d ? INT32(din.dword) : INT16(din.word); + accu += ax; /* add to accu */ + + if (ndim==0) ij = in_s; /* #words is single */ + din = ReadOp(dtbl,ij); /* get dimension from descriptor table */ + if (ij==in_d) { + dx = INT32(din.dword); /* either get double or single dimension */ + dtbl += 2; + } else { + dx = INT16(din.word); + dtbl++; + } + accu *= dx; /* multiply */ + } + +din = ReadOp(dtbl,in_d); /* add base address */ +accu += din.dword; + +AR = (accu >> 16) & DMASK; /* transfer to AB */ +BR = accu & DMASK; +if (debug) + fprintf(sim_deb,">>CPU VMA: resulting virt addr=%o (AR=%06o, BR=%06o)\n",accu,AR,BR); +return reason; +} + +/* + * This is the main handler for the RTE6/VMA microcodes */ +t_stat cpu_rte_vma (uint32 IR, uint32 intrq) +{ +t_stat reason = SCPE_OK; +OPS op; +OP_PAT pattern; +uint32 entry,t32,ndim; +uint32 dtbl,atbl; /* descriptor table ptr, actual args ptr */ +OP dop0,dop1; +uint32 pcsave = (PC+1) & VAMASK; /* save PC to check for redo in imap/jmap */ +t_bool debug = DEBUG_PRI (cpu_dev, DEB_VMA); + +if ((cpu_unit.flags & UNIT_VMAOS) == 0) /* VMA/OS option installed? */ + return cpu_rte_ema (IR, intrq); /* try EMA */ + +entry = IR & 017; /* mask to entry point */ +pattern = op_vma[entry]; /* get operand pattern */ + +if (pattern != OP_N) + if (reason = cpu_ops (pattern, op, intrq)) /* get instruction operands */ + return reason; + +if (debug) { /* debugging? */ + fprintf (sim_deb, ">>CPU VMA: IR = %06o (", IR); /* print preamble and IR */ + fprint_sym (sim_deb, err_PC, (t_value *) &IR, /* print instruction mnemonic */ + NULL, SWMASK('M')); + fprintf (sim_deb, "), P = %06o, XEQT = %06o", /* print location and program ID */ + err_PC, ReadW (xeqt)); + + fprint_ops (pattern, op); /* print operands */ + fputc ('\n', sim_deb); /* terminate line */ + } + +switch (entry) { /* decode IR<3:0> */ + + case 000: /* .PMAP 105240 (OP_N) */ + reason = cpu_vma_pmap(AR,BR,debug); /* map pages */ + break; + + case 001: /* $LOC 105241 (OP_CCCACC) */ + reason = cpu_vma_loc(op,intrq,debug); /* handle the coroutine switch */ + break; + + case 002: /* [test] 105242 (OP_N) */ + XR = 3; /* refer to src code 92084-18828 rev 3 */ + SR = 0102077; /* HLT 77 instruction */ + YR = 1; /* ROMs correctly installed */ + PC = (PC+1) & VAMASK; /* skip instr if VMA/EMA ROM installed */ + break; + + case 003: /* [swap] 105243 (OP_N) */ + t32 = AR; /* swap A and B registers */ + AR = BR; + BR = t32; + break; + + case 004: /* [---] 105244 (OP_N) */ + reason = stop_inst; /* fragment of dead code */ + break; /* in microrom */ + + case 005: /* [---] 105245 (OP_N) */ + reason = stop_inst; /* fragment of dead code */ + break; /* in microrom */ + + case 006: /* [nop] 105246 (OP_N) */ + break; /* do nothing */ + + case 007: /* [umpy] 105247 (OP_K) */ + t32 = AR * op[0].word; /* get multiplier */ + t32 += BR; /* add B */ + AR = (t32 >> 16) & DMASK; /* move result back to AB */ + BR = t32 & DMASK; + O = 0; /* instr clears OV */ + break; + + case 010: /* .IMAP 105250 (OP_A) */ + dtbl = op[0].word; + atbl = PC; + if ((reason = cpu_vma_ijmar(in_s,dtbl,atbl,&ndim,intrq,debug))) /* calc the virt address to AB */ + return reason; + t32 = (AR << 16) | (BR & DMASK); + if ((reason = cpu_vma_lbp(t32,0,PC-2,intrq,debug))) + return reason; + if (PC==pcsave) + PC = (PC+ndim) & VAMASK; /* adjust PC: skip ndim subscript words */ + break; + + case 011: /* .IMAR 105251 (OP_A) */ + dtbl = ReadW(op[0].word); + atbl = (op[0].word+1) & VAMASK; + reason = cpu_vma_ijmar(in_s,dtbl,atbl,0,intrq,debug); /* calc the virt address to AB */ + break; + + case 012: /* .JMAP 105252 (OP_A) */ + dtbl = op[0].word; + atbl = PC; + if ((reason = cpu_vma_ijmar(in_d,dtbl,atbl,&ndim,intrq,debug))) /* calc the virtual address to AB */ + return reason; + t32 = (AR << 16) | (BR & DMASK); + if ((reason = cpu_vma_lbp(t32,0,PC-2,intrq,debug))) + return reason; + if (PC==pcsave) + PC = (PC + ndim) & VAMASK; /* adjust PC: skip ndim subscript dword ptr */ + break; + + case 013: /* .JMAR 105253 (OP_A) */ + dtbl = ReadW(op[0].word); + atbl = (op[0].word+1) & VAMASK; + reason = cpu_vma_ijmar(in_d,dtbl,atbl,0,intrq,debug); /* calc the virt address to AB */ + break; + + case 014: /* .LPXR 105254 (OP_AA) */ + dop0 = ReadOp(op[0].word,in_d); /* get pointer from arg */ + dop1 = ReadOp(op[1].word,in_d); + t32 = dop0.dword + dop1.dword; /* add offset to it */ + reason = cpu_vma_lbp(t32,0,PC-3,intrq,debug); + break; + + case 015: /* .LPX 105255 (OP_A) */ + t32 = (AR << 16) | (BR & DMASK); /* pointer in AB */ + dop0 = ReadOp(op[0].word,in_d); + reason = cpu_vma_lbp(t32,dop0.dword,PC-2,intrq,debug); + break; + + case 016: /* .LBPR 105256 (OP_A) */ + dop0 = ReadOp(op[0].word,in_d); /* get the pointer */ + reason = cpu_vma_lbp(dop0.dword,0,PC-2,intrq,debug); + break; + + case 017: /* .LBP 105257 (OP_N) */ + t32 = (AR << 16) | (BR & DMASK); + reason = cpu_vma_lbp(t32,0,PC-1,intrq,debug); + break; + } + +return reason; +} + + +/* RTE-IV Extended Memory Area Instructions + + The RTE-IV operating system (HP product number 92067A) introduced the + Extended Memory Area (EMA) instructions. EMA provided a mappable data area + up to one megaword in size. These three instructions accelerated data + accesses to variables stored in EMA partitions. Support was limited to + E/F-Series machines; M-Series machines used software equivalents. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A N/A 92067A 92067A + + The routines are mapped to instruction codes as follows: + + Instr. 1000-E/F Description + ------ -------- ---------------------------------------------- + .EMIO 105240 EMA I/O + MMAP 105241 Map physical to logical memory + [test] 105242 [self test] + .EMAP 105257 Resolve array element address + + Notes: + + 1. RTE-IV EMA and RTE-6 VMA instructions share the same address space, so a + given machine can run one or the other, but not both. + + Additional references: + - RTE-IVB Programmer's Reference Manual (92068-90004, Dec-1983). + - RTE-IVB Technical Specifications (92068-90013, Jan-1980). +*/ + +static const OP_PAT op_ema[16] = { + OP_AKA, OP_AKK, OP_N, OP_N, /* .EMIO MMAP [test] --- */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_AAA /* --- --- --- .EMAP */ + }; + +/* calculate the 32 bit EMA subscript for an array */ +static t_bool cpu_ema_resolve(uint32 dtbl,uint32 atbl,uint32* sum) +{ +int32 sub, act, low, sz; +uint32 MA, base; + +int32 ndim = ReadW(dtbl++); /* # dimensions */ +if (ndim < 0) return FALSE; /* invalid? */ + +*sum = 0; /* accu for index calc */ +while (ndim > 0) { + MA = ReadW(atbl++); /* get address of A(N) */ + resolve (MA, &MA, 0); + act = ReadW(MA); /* A(N) */ + low = ReadW(dtbl++); /* -L(N) */ + sub = SEXT(act) + SEXT(low); /* subscript */ + if (sub & 0xffff8000) return FALSE; /* overflow? */ + *sum += sub; /* accumulate */ + sz = ReadW(dtbl++); + sz = SEXT(sz); + if (sz < 0) return FALSE; + *sum *= sz; + if (*sum > (512*1024)) return FALSE; /* overflow? */ + ndim--; +} +base = (ReadW(dtbl+1)<<16) | (ReadW(dtbl) & 0xffff); /* base of array in EMA */ +if (base & 0x8000000) return FALSE; +*sum += base; /* calculate address into EMA */ +if (*sum & 0xf8000000) return FALSE; /* overflow? */ +return TRUE; +} + +/* implementation of VIS RTE-IVB EMA support + * .ERES microcode routine, resolves only EMA addresses + * Call: + * .OCT 101474B + * DEF RTN error return (rtn), good return is rtn+1 + * DEF DUMMY dummy argument for compatibility with .EMAP + * DEF TABLE[,I] array declaration (dtbl) + * DEF A(N)[,I] actual subscripts (atbl) + * DEF A(N-1)[,I] + * ... + * DEF A(2)[,I] + * DEF A(1)[,I] + * RTN EQU * error return A="20", B="EM" + * RTN+1 EQU *+1 good return B=logical address + * + * TABLE DEC # # dimensions + * DEC -L(N) + * DEC D(N-1) + * DEC -L(N-1) lower bound (n-1)st dim + * DEC D(N-2) (n-2)st dim + * ... + * DEC D(1) 1st dim + * DEC -L(1) lower bound 1st dim + * DEC # # words/element + * OFFSET 1 EMA Low + * OFFSET 2 EMA High + */ +t_stat cpu_ema_eres(uint32 *rtn,uint32 dtbl,uint32 atbl,t_bool debug) +{ +uint32 sum; +if (cpu_ema_resolve(dtbl,atbl,&sum)) { /* calculate subscript */ + AR = sum & 0xffff; + BR = sum >> 16; + if (!(BR & SIGN)) { /* no overflow? */ + (*rtn)++; /* return via good exit */ + return SCPE_OK; + } +} +AR = 0x3230; /* error condition: */ +BR = 0x454d; /* AR = '20', BR = 'EM' */ +return SCPE_OK; /* return via unmodified rtn */ +} + +/* implementation of VIS RTE-IVB EMA support + * .ESEG microcode routine + * Call: + * LDA FIRST first map to set + * LDB N # of maps to set + * .OCT 101475B/105475B + * DEF RTN ptr to return + * DEF TABLE map table + * RTN EQU * error return A="21", B="EM" + * RTN+1 EQU *+1 good return B=logical address + * + * load maps FIRST to FIRST+N from TABLE, with FIRST = FIRST + LOG_START MSEG + * update map table in base page. Set LOG_START MSEG=0 if opcode==105475 + */ +t_stat cpu_ema_eseg(uint32* rtn, uint32 IR, uint32 tbl, t_bool debug) +{ +uint32 xidex,eqt,idext0,idext1; +uint32 msegsz,phys,msegn,last,emasz,pg0,pg1,pg,i,lp; + +if ((BR & SIGN) || BR==0) goto em21; /* #maps not positive? */ +xidex = ReadIO(idx,UMAP); /* read ID extension */ +if (xidex==0) goto em21; +idext0 = ReadWA(xidex+0); /* get 1st word idext */ +msegsz = idext0 & 037; /* S7 MSEG size */ +WriteIO(xidex+0, idext0 | 0100000, SMAP); /* enforce nonstd MSEG */ +idext1 = ReadWA(xidex+1); /* get 2nd word idext */ +phys = idext1 & 01777; /* S5 phys start of EMA */ +msegn = (idext1 >> 11) & 037; /* S9 get logical start MSEG# */ +if (IR & 04000) { /* opcode == 105475? (.VPRG) */ + msegn = 0; /* log start = 0 */ + msegsz = 32; /* size = full range */ +} +last = AR-1 + BR; /* last page */ +if (last > msegsz) goto em21; /* too many? error */ +eqt = ReadIO(xeqt,UMAP); +emasz = (ReadWA(eqt+28) & 01777) - 1; /* S6 EMA size in pages */ + +/* locations 1740...1777 of user base page contain the map entries we need. + * They are normally hidden by BP fence, therefore they have to be accessed by + * another fence-less map register. uCode uses #1 temporarily */ +pg0 = dms_rmap(UMAP+0); /* read map #0 */ +pg1 = dms_rmap(UMAP+1); /* save map #1 */ +dms_wmap(UMAP+1,pg0); /* copy #0 into reg #1 */ +lp = AR + msegn; /* first */ +for (i=0; i emasz) pg |= 0140000; /* write protect if outside */ + pg += phys; /* adjust into EMA page range */ + WriteIO(umaps+lp+i, pg, UMAP); /* copy pg to user map */ +//printf("MAP val %oB to reg %d (addr=%oB)\n",pg,lp+i,umaps+lp+i); + dms_wmap(UMAP+lp+i, pg); /* set DMS reg */ +} +dms_wmap(UMAP+1,pg1); /* restore map #1 */ +O = 0; /* clear overflow */ +(*rtn)++; /* return via good exit */ +return SCPE_OK; + +em21: +AR = 0x3231; /* error condition: */ +BR = 0x454d; /* AR = '21', BR = 'EM' */ +return SCPE_OK; /* return via unmodified rtn */ +} + +/* implementation of VIS RTE-IVB EMA support + * .VSET microcode routine + * Call: + * .OCT 101476B + * DEF RTN return address + * DEF VIN input vector + * DEF VOUT output vector + * DEF MAPS + * OCT #SCALARS + * OCT #VECTORS + * OCT K 1024/(#words/element) + * RTN EQU * error return (B,A) = "VI22" + * RTN+1 EQU *+1 hard return, A = K/IMAX + * RTN+2 EQU *+2 easy return, A = 0, B = 2* #VCTRS + */ +t_stat cpu_ema_vset(uint32* rtn, OPS op, t_bool debug) +{ +uint32 vin = op[0].word; /* S1 */ +uint32 vout = op[1].word; /* S2 */ +uint32 maps = op[2].word; /* S3 */ +uint32 scalars = op[3].word; /* S4 */ +uint32 vectors = op[4].word; /* S5 */ +uint32 k = op[5].word; /* S6 */ +uint32 imax = 0; /* imax S11*/ +uint32 xidex,idext1,mseg,phys, addr, i, MA; +t_bool negflag = FALSE; + +for (i=0; i> 1) & MSEGMASK; /* S9 get logical start MSEG */ +phys = idext1 & 01777; /* phys start of EMA */ + +for (i=0; i> 10) & 0xffff; /* get page */ + WriteW(maps++, addr); /* save page# */ + WriteW(maps++, addr+1); /* save next page# as well */ + MA = ReadW(vin++); /* get index into Y */ + resolve(MA, &MA, 0); + YR = ReadW(MA); /* get index value */ + WriteW(vout++, MA); /* copy address of index */ + if (YR & SIGN) { /* index is negative */ + negflag = TRUE; /* mark a negative index (HARD) */ + YR = (~YR + 1) & DMASK; /* make index positive */ + } + if (imax < YR) imax = YR; /* set maximum index */ + mseg += 04000; /* incr mseg address by 2 more pages */ +} +MA = ReadW(vin); /* get N index into Y */ +resolve(MA, &MA, 0); +YR = ReadW(MA); +WriteW(vout++, MA); vin++; /* copy address of N */ + +if (imax==0) goto easy; /* easy case */ +AR = k / imax; AR++; /* calculate K/IMAX */ +if (negflag) goto hard; /* had a negative index? */ +if (YR > AR) goto hard; + +easy: +(*rtn)++; /* return via exit 2 */ +AR = 0; + +hard: +(*rtn)++; /* return via exit 1 */ +BR = 2 * op[4].word; /* B = 2* vectors */ +return SCPE_OK; + +vi22: /* error condition */ + AR=0x3232; /* AR = '22' */ + BR=0x5649; /* BR = 'VI' */ + return SCPE_OK; /* return via unmodified e->rtn */ +} + +typedef struct ema4 { + uint32 mseg; /* logical start of MSEG */ + uint32 msegsz; /* size of std mseg in pgs */ + uint32 pgoff; /* pg # in EMA containing element */ + uint32 offs; /* offset into page of element */ + uint32 msoff; /* total offset to element in MSEG */ + uint32 emasz; /* size of ema in pgs */ + uint32 msegno; /* # of std mseg */ + uint32 ipgs; /* # of pgs to start of MSEG */ + uint32 npgs; /* # of pgs needed */ + uint32 spmseg; /* first phys pg of MSEG */ +} EMA4; + +static t_bool cpu_ema_emas(uint32 dtbl,uint32 atbl,EMA4* e) +{ +uint32 xidex, eqt; +uint32 sum, msegsz,pgoff,offs,emasz,msegno,msoff,ipgs; + +if (!cpu_ema_resolve(dtbl,atbl,&sum)) return FALSE; /* calculate 32 bit index */ + +xidex = ReadIO(idx,UMAP); /* read ID extension */ +msegsz = ReadWA(xidex+0) & 037; /* S5 # pgs for std MSEG */ +pgoff = sum >> 10; /* S2 page containing element */ +offs = sum & 01777; /* S6 offset in page to element */ +if (pgoff > 1023) return FALSE; /* overflow? */ +eqt = ReadIO(xeqt,UMAP); +emasz = ReadWA(eqt+28) & 01777; /* S EMA size in pages */ +if (pgoff > emasz) return FALSE; /* outside EMA? */ +msegno = pgoff / msegsz; /* S4 # of MSEG */ +msoff = pgoff % msegsz; /* offset within MSEG in pgs */ +ipgs = pgoff - msoff; /* S7 # pgs to start of MSEG */ +msoff = msoff << 10; /* offset within MSEG in words */ +msoff += offs; /* S1 offset to element in words */ + +e->msegsz = msegsz; /* return calculated data */ +e->pgoff = pgoff; +e->offs = offs; +e->emasz = emasz; +e->msegno = msegno; +e->ipgs = ipgs; +e->msoff = msoff; +return TRUE; +} + +static t_bool cpu_ema_mmap01(EMA4* e) +{ +uint32 xidex,idext0, pg, pg0, pg1, i; + +uint32 base = e->mseg >> 10; /* get the # of first MSEG DMS reg */ +xidex = ReadIO(idx,UMAP); /* get ID extension */ +idext0 = ReadWA(xidex+1); + +if (e->npgs==0) return FALSE; /* no pages to map? */ +if ((e->npgs+1+e->ipgs) <= e->emasz) e->npgs++; /* actually map npgs+1 pgs */ + +/* locations 1740...1777 of user base page contain the map entries we need. + * They are normally hidden by BP fence, therefore they have to be accessed by + * another fence-less map register. uCode uses #1, macro code uses $DVCT (==2) + */ +pg0 = dms_rmap(UMAP+0); /* read base page map# */ +pg1 = dms_rmap(UMAP+1); /* save map# 1 */ +dms_wmap(UMAP+1,pg0); /* map #0 into reg #1 */ +for (i=0; (base+i)<32; i++) { + pg = inpgs ? e->spmseg : 0140000; /* write protect if outside */ + WriteIO(umaps+base+i, pg, UMAP); /* copy pg to user map */ +//printf("MAP val %d to reg %d (addr=%o)\n",pg,base+i,umaps+base+i); + dms_wmap(UMAP+base+i, pg); /* set DMS reg */ + e->spmseg++; +} +dms_wmap(UMAP+1,pg1); /* restore map #1 */ + +xidex = ReadIO(idx,UMAP); /* get ID extension */ +idext0 = ReadWA(xidex+0); +if (e->msegno == 0xffff) /* non std mseg */ + idext0 |= 0x8000; /* set nonstd marker */ +else + idext0 = (idext0 & 037) | (e->msegno<<5); /* set new current mseg# */ +WriteIO(xidex, idext0, SMAP); /* save back value */ +AR = 0; /* was successful */ +return TRUE; +} + +static t_bool cpu_ema_mmap02(EMA4* e) +{ +uint32 xidex, eqt, idext1; +uint32 mseg,phys,spmseg,emasz,msegsz,msegno; + +xidex = ReadIO(idx,UMAP); /* get ID extension */ +msegsz = ReadWA(xidex+0) & 037; /* P size of std MSEG */ +idext1 = ReadWA(xidex+1); +mseg = (idext1 >> 1) & MSEGMASK; /* S9 get logical start MSEG */ +phys = idext1 & 01777; /* S phys start of EMA */ +spmseg = phys + e->ipgs; /* S7 phys pg# of MSEG */ +msegno = e->ipgs / msegsz; +if ((e->ipgs % msegsz) != 0) /* non std MSEG? */ + msegno = 0xffff; /* S4 yes, set marker */ +if (e->npgs > msegsz) return FALSE; /* map more pages than MSEG sz? */ +eqt = ReadIO(xeqt,UMAP); +emasz = ReadWA(eqt+28) & 01777; /* B EMA size in pages */ +if ((e->ipgs+e->npgs) > emasz) return FALSE; /* outside EMA? */ +if ((e->ipgs+msegsz) > emasz) /* if MSEG overlaps end of EMA */ + e->npgs = emasz - e->ipgs; /* only map until end of EMA */ + +e->emasz = emasz; /* copy arguments */ +e->msegsz = msegsz; +e->msegno = msegno; +e->spmseg = spmseg; +e->mseg = mseg; +return cpu_ema_mmap01(e); +} + +static t_stat cpu_ema_mmap(uint32 ipage,uint32 npgs, t_bool debug) +{ +uint32 xidex; +EMA4 ema4, *e = &ema4; + +e->ipgs = ipage; /* S6 set the arguments */ +e->npgs = npgs; /* S5 */ + +AR = 0; +xidex = ReadIO(idx,UMAP); +if ((ipage & SIGN) || /* negative page displacement? */ + (npgs & SIGN) || /* negative # of pages? */ + xidex == 0 || /* no EMA? */ + !cpu_ema_mmap02(e)) /* mapping failed? */ + AR = 0177777; /* return with error */ +return SCPE_OK; /* leave */ +} + +static t_bool cpu_ema_emat(EMA4* e) +{ +uint32 xidex,idext0; +uint32 curmseg,phys,msnum,lastpgs; + +xidex = ReadIO(idx,UMAP); /* read ID extension */ +idext0 = ReadWA(xidex+0); /* get current segment */ +curmseg = idext0 >> 5; +if ((idext0 & 0100000) || /* was nonstd MSEG? */ + curmseg != e->msegno) { /* or different MSEG last time? */ + phys = ReadWA(xidex+1) & 01777; /* physical start pg of EMA */ + e->spmseg = phys + e->ipgs; /* physical start pg of MSEG */ + msnum = e->emasz / e->msegsz; /* find last MSEG# */ + lastpgs = e->emasz % e->msegsz; /* #pgs in last MSEG */ + if (lastpgs==0) msnum--; /* adjust # of last MSEG */ + e->npgs = msnum==e->msegno ? lastpgs : e->msegsz; /* for last MSEG, only map available pgs */ + if (!cpu_ema_mmap01(e)) return FALSE; /* map npgs pages at ipgs */ +} +BR = e->mseg + e->msoff; /* return address of element */ +return TRUE; /* and everything done */ +} + +/* .EMIO microcode routine, resolves element addr for EMA array + * and maps the appropriate map segment + * + * Call: + * OCT 105250B + * DEF RTN error return (rtn), good return is rtn+1 + * DEF BUFLEN length of buffer in words (bufl) + * DEF TABLE[,I] array declaration (dtbl) + * DEF A(N)[,I] actual subscripts (atbl) + * DEF A(N-1)[,I] + * ... + * DEF A(2)[,I] + * DEF A(1)[,I] + * RTN EQU * error return A="15", B="EM" + * RTN+1 EQU *+1 good return B=logical address + * + * TABLE DEC # # dimensions + * DEC -L(N) + * DEC D(N-1) + * DEC -L(N-1) lower bound (n-1)st dim + * DEC D(N-2) (n-2)st dim + * ... + * DEC D(1) 1st dim + * DEC -L(1) lower bound 1st dim + * DEC # # words/element + * OFFSET 1 EMA Low + * OFFSET 2 EMA High + */ +static t_stat cpu_ema_emio(uint32* rtn,uint32 bufl,uint32 dtbl,uint32 atbl,t_bool debug) +{ +uint32 xidex, idext1; +uint32 mseg, bufpgs, npgs; +EMA4 ema4, *e = &ema4; + +xidex = ReadIO(idx,UMAP); /* read ID extension */ +if (bufl & SIGN || /* buffer length negative? */ + xidex==0) goto em16; /* no EMA declared? */ + +idext1 = ReadWA(xidex+1); /* |logstrt mseg|d|physstrt ema| */ +mseg = (idext1 >> 1) & MSEGMASK; /* get logical start MSEG */ +if (!cpu_ema_emas(dtbl,atbl,e)) goto em16; /* resolve address */ +bufpgs = (bufl + e->offs) >> 10; /* # of pgs reqd for buffer */ +if ((bufl + e->offs) & 01777) bufpgs++; /* S11 add 1 if not at pg boundary */ +if ((bufpgs + e->pgoff) > e->emasz) goto em16; /* exceeds EMA limit? */ +npgs = (e->msoff + bufl) >> 10; /* # of pgs reqd for MSEG */ +if ((e->msoff + bufl) & 01777) npgs++; /* add 1 if not at pg boundary */ +if (npgs < e->msegsz) { + e->mseg = mseg; /* logical stat of MSEG */ + if (!cpu_ema_emat(e)) goto em16; /* do a std mapping */ +} else { + BR = mseg + e->offs; /* logical start of buffer */ + e->npgs = bufpgs; /* S5 # pgs required */ + e->ipgs = e->pgoff; /* S6 page offset to reqd pg */ + if (!cpu_ema_mmap02(e)) goto em16; /* do nonstd mapping */ +} +(*rtn)++; /* return via good exit */ +return SCPE_OK; + +em16: /* error condition */ +AR=0x3136; /* AR = '16' */ +BR=0x454d; /* BR = 'EM' */ +return SCPE_OK; /* return via unmodified rtn */ +} + +/* .EMAP microcode routine, resolves both EMA/non-EMA calls + * Call: + * OCT 105257B + * DEF RTN error return (rtn), good return is rtn+1 + * DEF ARRAY[,I] array base (abase) + * DEF TABLE[,I] array declaration (dtbl) + * DEF A(N)[,I] actual subscripts (atbl) + * DEF A(N-1)[,I] + * ... + * DEF A(2)[,I] + * DEF A(1)[,I] + * RTN EQU * error return A="15", B="EM" + * RTN+1 EQU *+1 good return B=logical address + * + * TABLE DEC # # dimensions + * DEC -L(N) + * DEC D(N-1) + * DEC -L(N-1) lower bound (n-1)st dim + * DEC D(N-2) (n-2)st dim + * ... + * DEC D(1) 1st dim + * DEC -L(1) lower bound 1st dim + * DEC # # words/element + * OFFSET 1 EMA Low + * OFFSET 2 EMA High + */ +static t_stat cpu_ema_emap(uint32* rtn,uint32 abase,uint32 dtbl,uint32 atbl,t_bool debug) +{ +uint32 xidex, eqt, idext0, idext1; +int32 sub, act, low, ndim, sz; +uint32 offs, pgoff, emasz, phys, msgn, mseg, sum, MA, pg0, pg1; + +xidex = ReadIO(idx,UMAP); /* read ID Extension */ +if (xidex) { /* is EMA declared? */ + idext1 = ReadWA(xidex+1); /* get word 1 of idext */ + mseg = (idext1 >> 1) & MSEGMASK; /* get logical start MSEG */ + if (abase >= mseg) { /* EMA reference? */ + if (!cpu_ema_resolve(dtbl,atbl,&sum)) /* calculate subscript */ + goto em15; + offs = sum & 01777; /* address offset within page */ + pgoff = sum >> 10; /* ema offset in pages */ + if (pgoff > 1023) goto em15; /* overflow? */ + eqt = ReadIO(xeqt,UMAP); + emasz = ReadWA(eqt+28) & 01777; /* EMA size in pages */ + phys = idext1 & 01777; /* physical start pg of EMA */ + if (pgoff > emasz) goto em15; /* outside EMA range? */ + + msgn = mseg >> 10; /* get # of 1st MSEG reg */ + phys += pgoff; + + pg0 = dms_rmap(UMAP+0); /* read base page map# */ + pg1 = dms_rmap(UMAP+1); /* save map# 1 */ + dms_wmap(UMAP+1,pg0); /* map #0 into reg #1 */ + + WriteIO(umaps+msgn, phys, UMAP); /* store 1st mapped pg in user map */ + dms_wmap(UMAP+msgn, phys); /* and set the map register */ + phys = (pgoff+1)==emasz ? 0140000 : phys+1; /* protect 2nd map if end of EMA */ + WriteIO(umaps+msgn+1, phys, UMAP); /* store 2nd mapped pg in user map */ + dms_wmap(UMAP+msgn+1, phys); /* and set the map register */ + + dms_wmap(UMAP+1,pg1); /* restore map #1 */ + + idext0 = ReadWA(xidex+0) | 0100000; /* set NS flag in id extension */ + WriteIO(xidex+0, idext0, SMAP); /* save back value */ + AR = 0; /* was successful */ + BR = mseg + offs; /* calculate log address */ + (*rtn)++; /* return via good exit */ + return SCPE_OK; + } +} /* not EMA reference */ +ndim = ReadW(dtbl++); +if (ndim<0) goto em15; /* negative ´dimensions */ +sum = 0; /* accu for index calc */ +while (ndim > 0) { + MA = ReadW(atbl++); /* get address of A(N) */ + resolve (MA, &MA, 0); + act = ReadW(MA); /* A(N) */ + low = ReadW(dtbl++); /* -L(N) */ + sub = SEXT(act) + SEXT(low); /* subscript */ + if (sub & 0xffff8000) goto em15; /* overflow? */ + sum += sub; /* accumulate */ + sz = ReadW(dtbl++); + sz = SEXT(sz); + if (sz < 0) goto em15; + sum *= sz; /* and multiply with sz of dimension */ + if (sum & 0xffff8000) goto em15; /* overflow? */ + ndim--; +} +BR = abase + sum; /* add displacement */ +(*rtn)++; /* return via good exit */ +return SCPE_OK; + +em15: /* error condition */ + AR=0x3135; /* AR = '15' */ + BR=0x454d; /* BR = 'EM' */ + return SCPE_OK; /* return via unmodified e->rtn */ +} + +t_stat cpu_rte_ema (uint32 IR, uint32 intrq) +{ +t_stat reason = SCPE_OK; +OPS op; +OP_PAT pattern; +uint32 entry, rtn; +t_bool debug = DEBUG_PRI (cpu_dev, DEB_EMA); + +if ((cpu_unit.flags & UNIT_EMA) == 0) /* EMA option installed? */ + return stop_inst; + +entry = IR & 017; /* mask to entry point */ +pattern = op_ema[entry]; /* get operand pattern */ + +if (pattern != OP_N) + if (reason = cpu_ops (pattern, op, intrq)) /* get instruction operands */ + return reason; + +if (debug) { /* debugging? */ + fprintf (sim_deb, ">>CPU EMA: PC = %06o, IR = %06o (", err_PC,IR); /* print preamble and IR */ + fprint_sym (sim_deb, err_PC, (t_value *) &IR, /* print instruction mnemonic */ + NULL, SWMASK('M')); + fputc (')', sim_deb); + + fprint_ops (pattern, op); /* print operands */ + fputc ('\n', sim_deb); /* terminate line */ + } + +switch (entry) { /* decode IR<3:0> */ + case 000: /* .EMIO 105240 (OP_A) */ + rtn = op[0].word; + reason = cpu_ema_emio(&rtn, op[1].word, + op[2].word, PC, debug); /* handle the EMIO instruction */ + PC = rtn; + if (debug) + fprintf (sim_deb, ">>CPU EMA: return .EMIO: AR = %06o, BR = %06o, rtn=%s\n", + AR, BR, PC==op[0].word?"error":"good"); + break; + + case 001: /* .MMAP 105241 (OP_AKK) */ + reason = cpu_ema_mmap(op[1].word, + op[2].word, debug); /* handle the MMAP instruction */ + if (debug) + fprintf (sim_deb, ">>CPU EMA: return .MMAP: AR = %06o\n",AR); + break; + + case 002: /* [test] 105242 (OP_N) */ + /* effectively, this code just returns without error: + * real microcode will set S register to 102077B when in single step mode */ + if (sim_step==1) { + if (debug) + fprintf(sim_deb, ">>CPU EMA: EMA option 92067 correctly installed: S=102077\n"); + SR = 0102077; + } + break; + + case 017: /* .EMAP 105247 (OP_A) */ + rtn = op[0].word; /* error return */ + reason = cpu_ema_emap(&rtn, op[1].word, + op[2].word, PC, debug); /* handle the EMAP instruction */ + PC = rtn; + if (debug) { + fprintf (sim_deb, ">>CPU EMA: return .EMAP: AR = %06o, BR = %06o, rtn=%s\n", + AR, BR, PC==op[0].word?"error":"good"); + } + break; + + default: /* others undefined */ + reason = stop_inst; + } + +return reason; +} diff --git a/HP2100/hp2100_cpu6.c b/HP2100/hp2100_cpu6.c new file mode 100644 index 00000000..88827eaf --- /dev/null +++ b/HP2100/hp2100_cpu6.c @@ -0,0 +1,811 @@ +/* hp2100_cpu6.c: HP 1000 RTE-6/VM OS instructions + + Copyright (c) 2006-2007, 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. + + CPU6 RTE-6/VM OS instructions + + 27-Nov-07 JDB Implemented OS instructions + 26-Sep-06 JDB Created + + Primary references: + - HP 1000 M/E/F-Series Computers Technical Reference Handbook + (5955-0282, Mar-1980) + - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation + (92851-90001, Mar-1981) + - Macro/1000 Reference Manual (92059-90001, Dec-1992) + + Additional references are listed with the associated firmware + implementations, as are the HP option model numbers pertaining to the + applicable CPUs. +*/ + + +#include +#include "hp2100_defs.h" +#include "hp2100_cpu.h" +#include "hp2100_cpu1.h" + + +/* external variables */ + +extern jmp_buf save_env; /* MP abort handler */ + + +/* Offsets to data and addresses within RTE. */ + +static const uint32 xi = 0001647; /* XI address */ +static const uint32 intba = 0001654; /* INTBA address */ +static const uint32 intlg = 0001655; /* INTLG address */ +static const uint32 eqt1 = 0001660; /* EQT1 address */ +static const uint32 eqt11 = 0001672; /* EQT11 address */ +static const uint32 pvcn = 0001712; /* PVCN address */ +static const uint32 xsusp = 0001730; /* XSUSP address */ +static const uint32 dummy = 0001737; /* DUMMY address */ +static const uint32 mptfl = 0001770; /* MPTFL address */ +static const uint32 eqt12 = 0001771; /* EQT12 address */ +static const uint32 eqt15 = 0001774; /* EQT15 address */ +static const uint32 vctr = 0002000; /* VCTR address */ + +static const uint32 CLC_0 = 0004700; /* CLC 0 instruction */ +static const uint32 STC_0 = 0000700; /* STC 0 instruction */ +static const uint32 CLF_0 = 0001100; /* CLF 0 instruction */ +static const uint32 STF_0 = 0000100; /* STF 0 instruction */ +static const uint32 SFS_0_C = 0003300; /* SFS 0,C instruction */ + +enum vctr_offsets { dms_offset = 0, /* DMS status */ + int_offset, /* interrupt system status */ + sc_offset, /* select code */ + clck_offset, /* TBG IRQ handler */ + cic4_offset, /* illegal IRQ handler */ + cic2_offset, /* device IRQ handler */ + sked_offset, /* prog sched IRQ handler */ + rqst_offset, /* EXEC request handler */ + cic_offset, /* IRQ location */ + perr_offset, /* parity error IRQ handler */ + mper_offset, /* memory protect IRQ handler */ + lxnd_offset }; /* $LIBR return */ + + +/* RTE-6/VM Operating System Instructions + + The OS instructions were added to acccelerate certain time-consuming + operations of the RTE-6/VM operating system, HP product number 92084A. + Microcode was available for the E- and F-Series; the M-Series used software + equivalents. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A N/A 92084A 92084A + + The routines are mapped to instruction codes as follows: + + Instr. 1000-E/F Description + ------ -------- ---------------------------------------------- + $LIBR 105340 Enter privileged/reentrant library routine + $LIBX 105341 Exit privileged/reentrant library routine + .TICK 105342 TBG tick interrupt handler + .TNAM 105343 Find ID segment that matches name + .STIO 105344 Configure I/O instructions + .FNW 105345 Find word with user increment + .IRT 105346 Interrupt return processing + .LLS 105347 Linked list search + + .SIP 105350 Skip if interrupt pending + .YLD 105351 .SIP completion return point + .CPM 105352 Compare words LT/EQ/GT + .ETEQ 105353 Set up EQT pointers in base page + .ENTN 105354 Transfer parameter addresses (utility) + $OTST * 105355 OS firmware self test + .ENTC 105356 Transfer parameter addresses (priv/reent) + .DSPI 105357 Set display indicator + + Opcodes 105354-105357 are "dual use" instructions that take different + actions, depending on whether they are executed from a trap cell during an + interrupt. When executed from a trap cell, they have these actions: + + Instr. 1000-E/F Description + ------ -------- ---------------------------------------------- + $DCPC * 105354 DCPC channel interrupt processing + $MPV * 105355 MP/DMS/PE interrupt processing + $DEV * 105356 Standard device interrupt processing + $TBG * 105357 TBG interrupt processing + + * These mnemonics are recognized by symbolic examine/deposit but are not + official HP mnemonics. + + Notes: + + 1. The microcode differentiates between interrupt processing and normal + execution of the "dual use" instructions by testing the CPU flag. + Interrupt vectoring sets the flag; a normal instruction fetch clears it. + Under simulation, interrupt vectoring is indicated by the value of the + "iotrap" parameter (0 = normal instruction, 1 = trap cell instruction). + + 2. The operand patterns for .ENTN and .ENTC normally would be coded as + "OP_A", as each takes a single address as a parameter. However, because + they might also be executed from a trap cell, we cannot assume that P+1 + is an address, or we might cause a DM abort when trying to resolve + indirects. Therefore, "OP_A" handling is done within each routine, once + the type of use is determined. + + 3. The microcode for .ENTC, .ENTN, .FNW, .LLS, .TICK, and .TNAM explicitly + checks for interrupts during instruction execution. In addition, the + .STIO, .CPM, and .LLS instructions implicitly check for interrupts + during parameter indirect resolution. Because the simulator calculates + interrupt requests only between instructions, this behavior is not + simulated. + + 4. The microcode executes certain I/O instructions (e.g., CLF 0) by + building the instruction in the IR and executing an IOG micro-order. We + simulate this behavior by calling the "iogrp" handler with the + appropriate instruction, rather than manipulating the I/O system + directly, so that we will remain unaffected by any future changes to the + underlying I/O simulation structure. + + 5. The $OTST and .DSPI microcode uses features (reading the RPL switches + and boot loader ROM data, loading the display register) that are not + simulated. The remaining functions of the $OTST instruction are + provided. The .DSPI instruction is a NOP or unimplemented instruction + stop. + + 6. The microcode detects a privileged system and takes some additional + actions if one is found. We provide simulations of these actions. + However, at the current time, the simulator does not provide a + privileged interrupt fence card, so this code is untested. + + 7. Because of the volume of calls to the OS firmware, debug printouts + attempt to write only one line per instruction invocation. This means + that calling and returned register values are printed separately, with a + newline added at the end of execution. However, many instructions can + MP or DM abort, either intentionally or due to improper use. That would + leave debug lines without the required trailing newlines. + + There are two ways to address this: either we could replace the CPU's + setjmp buffer with one that points to a routine that adds the missing + newline, or we can add a semaphore that is tested on entry to see if it + is already set, implying a longjmp occurred, and then add the newline if + so. The latter would add the newline when the MP trap cell instruction + was entered or when the next user-level instruction was executed. + However, the merged-line problem would still exist if some other module + generated intervening debug printouts. So we do the former. This does + mean that this routine must be changed if the MP abort mechanism is + changed. + + 8. The $LIBX instruction is executed to complete either a privileged or + reentrant execution. In the former case, the privileged nest counter + ($PVCN) is decremented. In the latter, $PVCN decrement is attempted but + the write will trap with an MP violation, as reentrant routines execute + with the interrupt system on. RTE will then complete the release of + memory allocated for the original $LIBR call. + + Additional references: + - RTE-6/VM OS Microcode Source (92084-18831, revision 8). + - RTE-6/VM Technical Specifications (92084-90015, Apr-1983). +*/ + + +/* Save the CPU registers. + + The CPU registers are saved in the current ID segment in preparation for + interrupt handling. Although the RTE base page has separate pointers for the + P, A, B, and E/O registers, they are always contiguous, and the microcode + simply increments the P-register pointer (XSUSP) to store the remaining + values. + + This routine is called from the trap cell interrupt handlers and from the + $LIBX processor. In the latter case, the privileged system interrupt + handling is not required, so it is bypassed. In either case, the current map + will be the system map when we are called. +*/ + +static t_stat cpu_save_regs (uint32 iotrap) +{ +uint16 save_area, priv_fence; +t_stat reason = SCPE_OK; + +save_area = ReadW (xsusp); /* addr of PABEO save area */ + +WriteW (save_area + 0, PC); /* save P */ +WriteW (save_area + 1, AR); /* save A */ +WriteW (save_area + 2, BR); /* save B */ +WriteW (save_area + 3, (E << 15) & SIGN | O & 1); /* save E and O */ + +save_area = ReadW (xi); /* addr of XY save area */ +WriteWA (save_area + 0, XR); /* save X (in user map) */ +WriteWA (save_area + 1, YR); /* save Y (in user map) */ + +if (iotrap) { /* do priv setup only if IRQ */ + priv_fence = ReadW (dummy); /* get priv fence select code */ + + if (priv_fence) { /* privileged system? */ + reason = iogrp (STC_0 + priv_fence, iotrap); /* STC SC on priv fence */ + reason = iogrp (CLC_0 + DMA0, iotrap); /* CLC 6 to inh IRQ on DCPC 0 */ + reason = iogrp (CLC_0 + DMA1, iotrap); /* CLC 7 to inh IRQ on DCPC 1 */ + reason = iogrp (STF_0, iotrap); /* turn interrupt system back on */ + } + } + +return reason; +} + + +/* Save the machine state at interrupt. + + This routine is called from each of the trap cell instructions. Its purpose + is to save the complete state of the machine in preparation for interrupt + handling. + + For the MP/DMS/PE interrupt, the interrupting device must not be cleared and + the CPU registers must not be saved until it is established that the + interrupt is not caused by a parity error. Parity errors cannot be + inhibited, so the interrupt may have occurred while in RTE. Saving the + registers would overwrite the user's registers that were saved at RTE entry. + + Note that the trap cell instructions are dual-use and invoke this routine + only when they are executed during interrupts. Therefore, the current map + will always be the system map when we are called. +*/ + +static t_stat cpu_save_state (uint32 iotrap) +{ +uint16 vectors; +uint32 saved_PC, int_sys_off; +t_stat reason; + +saved_PC = PC; /* save current PC */ +reason = iogrp (SFS_0_C, iotrap); /* turn interrupt system off */ +int_sys_off = (PC == saved_PC); /* set flag if already off */ +PC = saved_PC; /* restore PC in case it bumped */ + +vectors = ReadW (vctr); /* get address of vectors (in SMAP) */ + +WriteW (vectors + dms_offset, dms_upd_sr ()); /* save DMS status (SSM) */ +WriteW (vectors + int_offset, int_sys_off); /* save int status */ +WriteW (vectors + sc_offset, intaddr); /* save select code */ + +WriteW (mptfl, 1); /* show MP is off */ + +if (intaddr != 5) { /* only if not MP interrupt */ + reason = iogrp (CLF_0 + intaddr, iotrap); /* issue CLF to device */ + cpu_save_regs (iotrap); /* save CPU registers */ + } + +return reason; +} + + +/* Get the interrupt table entry corresponding to a select code. + + Return the word in the RTE interrupt table that corresponds to the + interrupting select code. Return 0 if the select code is beyond the end of + the table. +*/ + +uint32 cpu_get_intbl (uint32 select_code) +{ +uint16 interrupt_table; /* interrupt table (starts with SC 06) */ +uint16 table_length; /* length of interrupt table */ + +interrupt_table = ReadW (intba); /* get int table address */ +table_length = ReadW (intlg); /* get int table length */ + +if (select_code - 6 > table_length) /* SC beyond end of table? */ + return 0; /* return 0 for illegal interrupt */ +else + return ReadW (interrupt_table + select_code - 6); /* else return table entry */ +} + + +/* RTE-6/VM OS instruction dispatcher. + + Debugging printouts are provided with the OS and OSTBG debug flags. The OS + flag enables tracing for all instructions except for the three-instruction + sequence executed for the time-base generator interrupt ($TBG, .TICK, and + .IRT). The OSTBG flag enables tracing for just the TBG sequence. The flags + are separate, as the TBG generates 100 interrupts per second. Use caution + when specifying the OSTBG flag, as the debug output file will grow rapidly. + Note that the OS flag enables the .IRT instruction trace for all cases except + a TBG interrupt. + + The firmware self-test instruction (105355) is always allowed, regardless of + the UNIT_VMAOS setting. This is because RTE-6/VM will always test for the + presence of OS and VMA firmware on E/F-Series machines. If the firmware is + not present, then these instructions are NOPs and return to P+1. RTE will + then HLT 21. This means that RTE-6/VM will not run on an E/F-Series machine + without the OS and VMA firmware. + + Howwever, RTE allows the firmware instructions to be disabled for debugging + purposes. If the firmware is present and returns to P+2 but sets the X + register to 0, then RTE will use software equivalents. We enable this + condition when the OS firmware is enabled (SET CPU VMA), the OS debug flag is + set (SET CPU DEBUG=OS), but debug output has been disabled (SET CONSOLE + NODEBUG). That is: + + OS Debug + Firmware Flag Output Tracing Self-Test Instruction + ======== ===== ====== ======= ===================== + disabled x x off NOP + enabled clear x off X = revision code + enabled set off off X = 0 + enabled set on on X = revision code +*/ + +static const OP_PAT op_os[16] = { + OP_A, OP_A, OP_N, OP_N, /* $LIBR $LIBX .TICK .TNAM */ + OP_A, OP_K, OP_A, OP_KK, /* .STIO .FNW .IRT .LLS */ + OP_N, OP_C, OP_KK, OP_N, /* .SIP .YLD .CPM .ETEQ */ + OP_N, OP_N, OP_N, OP_N /* .ENTN $OTST .ENTC .DSPI */ + }; + +t_stat cpu_rte_os (uint32 IR, uint32 intrq, uint32 iotrap) +{ +t_stat reason = SCPE_OK; +OPS op; +OP_PAT pattern; +uint32 entry, count, cp, sa, da, i, ma; +uint16 vectors, save_area, priv_fence, eoreg, eqt, key; +char test[6], target[6]; +jmp_buf mp_handler; +int abortval; +t_bool debug_print; +static t_bool tbg_tick = FALSE; /* set if processing TBG interrupt */ + +if ((IR != 0105355) && /* allow self-test with OS disabled */ + (cpu_unit.flags & UNIT_VMAOS) == 0) /* VMA/OS option installed? */ + return stop_inst; + +entry = IR & 017; /* mask to entry point */ +pattern = op_os[entry]; /* get operand pattern */ + +if (pattern != OP_N) + if (reason = cpu_ops (pattern, op, intrq)) /* get instruction operands */ + return reason; + +tbg_tick = tbg_tick || (IR == 0105357) && iotrap; /* set TBG interrupting flag */ + +debug_print = (DEBUG_PRI (cpu_dev, DEB_OS) && !tbg_tick) || + (DEBUG_PRI (cpu_dev, DEB_OSTBG) && tbg_tick); + +if (debug_print) { + fprintf (sim_deb, ">>CPU OS: IR = %06o (", IR); /* print preamble and IR */ + fprint_sym (sim_deb, (iotrap ? intaddr : err_PC), /* print instruction mnemonic */ + (t_value *) &IR, NULL, SWMASK('M')); + fputc (')', sim_deb); + + fprint_ops (pattern, op); /* print operands */ + + memcpy (mp_handler, save_env, sizeof (jmp_buf)); /* save original MP handler */ + abortval = setjmp (save_env); /* set new MP abort handler */ + + if (abortval != 0) { /* MP abort? */ + fputs ("...MP abort\n", sim_deb); /* report it and terminate line */ + memcpy (save_env, mp_handler, sizeof (jmp_buf)); /* restore original MP handler */ + longjmp (save_env, abortval); /* transfer to MP handler */ + } + } + +switch (entry) { /* decode IR<3:0> */ + + case 000: /* $LIBR 105340 (OP_A) */ + if ((op[0].word != 0) || /* reentrant call? */ + (CTL (PRO) && (ReadW (dummy) != 0))) { /* or priv call + MP on + priv sys? */ + if (dms_ump) { /* called from user map? */ + dms_viol (err_PC, MVI_PRV); /* privilege violation */ + } + dms_ump = SMAP; /* set system map */ + + vectors = ReadW (vctr); /* get address of vectors (in SMAP) */ + PC = ReadW (vectors + mper_offset); /* vector to $MPER for processing */ + } + + else { /* privileged call */ + if (CTL (PRO)) { /* memory protect on? */ + clrCTL (PRO); /* turn it off */ + reason = iogrp (CLF_0, iotrap); /* turn interrupt system off */ + WriteW (mptfl, 1); /* show MP is off */ + save_area = ReadW (xsusp); /* get addr of P save area */ + + if (dms_ump) /* user map current? */ + WriteWA (save_area, (PC - 2) & VAMASK); /* set point of suspension */ + else /* system map current */ + WriteW (save_area, (PC - 2) & VAMASK); /* set point of suspension */ + } + + WriteW (pvcn, (ReadW (pvcn) + 1) & DMASK); /* increment priv nest counter */ + } + break; + + case 001: /* $LIBX 105341 (OP_A) */ + PC = ReadW (op[0].word); /* set P to return point */ + count = (ReadW (pvcn) - 1) & DMASK; /* decrement priv nest counter */ + WriteW (pvcn, count); /* write it back */ + + if (count == 0) { /* end of priv mode? */ + dms_ump = SMAP; /* set system map */ + reason = cpu_save_regs (iotrap); /* save registers */ + vectors = ReadW (vctr); /* get address of vectors */ + PC = ReadW (vectors + lxnd_offset); /* vector to $LXND for processing */ + } + break; + + case 002: /* .TICK 105342 (OP_N) */ + if (debug_print) /* debugging? */ + fprint_regs (",", REG_A | REG_B, 0); /* print entry registers */ + + do { + eqt = (ReadW (AR) + 1) & DMASK; /* bump timeout from EQT15 */ + + if (eqt != 1) { /* was timeout active? */ + WriteW (AR, eqt); /* yes, write it back */ + + if (eqt == 0) /* did timeout expire? */ + break; /* P+0 return for timeout */ + } + + AR = (AR + 15) & DMASK; /* point at next EQT15 */ + BR = (BR - 1) & DMASK; /* decrement count of EQTs */ + } while ((BR > 0) && (eqt != 0)); /* loop until timeout or done */ + + if (BR == 0) /* which termination condition? */ + PC = (PC + 1) & VAMASK; /* P+1 return for no timeout */ + + if (debug_print) /* debugging? */ + fprint_regs ("; result:", /* print return registers */ + REG_A | REG_B | REG_P_REL, + err_PC + 1); + break; + + case 003: /* .TNAM 105343 (OP_N) */ + if (debug_print) /* debugging? */ + fprint_regs (",", REG_A | REG_B, 0); /* print entry registers */ + + E = 1; /* preset flag for not found */ + cp = (BR << 1) & DMASK; /* form char addr (B is direct) */ + + for (i = 0; i < 5; i++) { /* copy target name */ + target[i] = (char) ReadB (cp); /* name is only 5 chars */ + cp = (cp + 1) & DMASK; + } + + if ((target[0] == '\0') && (target[1] == '\0')) /* if name is null, */ + break; /* return immed to P+0 */ + + key = ReadW (AR); /* get first keyword addr */ + + while (key != 0) { /* end of keywords? */ + cp = ((key + 12) << 1) & DMASK; /* form char addr of name */ + + for (i = 0; i < 6; i++) { /* copy test name */ + test[i] = (char) ReadB (cp); /* name is only 5 chars */ + cp = (cp + 1) & DMASK; /* but copy 6 to get flags */ + } + + if (strncmp (target, test, 5) == 0) { /* names match? */ + AR = (key + 15) & DMASK; /* A = addr of IDSEG [15] */ + BR = key; /* B = addr of IDSEG [0] */ + E = (uint32) ((test[5] >> 4) & 1); /* E = short ID segment bit */ + PC = (PC + 1) & VAMASK; /* P+1 for found return */ + break; + } + + AR = (AR + 1) & DMASK; /* bump to next keyword */ + key = ReadW (AR); /* get next keyword */ + }; + + if (debug_print) /* debugging? */ + fprint_regs ("; result:", /* print return registers */ + REG_A | REG_B | REG_E | REG_P_REL, + err_PC + 1); + break; + + case 004: /* .STIO 105344 (OP_A) */ + count = op[0].word - PC; /* get count of operands */ + + if (debug_print) /* debugging? */ + fprintf (sim_deb, /* print registers on entry */ + ", A = %06o, count = %d", AR, count); + + for (i = 0; i < count; i++) { + ma = ReadW (PC); /* get operand address */ + + if (reason = resolve (ma, &ma, intrq)) { /* resolve indirect */ + PC = err_PC; /* IRQ restarts instruction */ + break; + } + + WriteW (ma, ReadW (ma) & ~I_DEVMASK | AR); /* set SC into instruction */ + PC = (PC + 1) & VAMASK; /* bump to next */ + } + break; + + case 005: /* .FNW 105345 (OP_K) */ + if (debug_print) /* debugging? */ + fprint_regs (",", REG_A | REG_B | REG_X, 0); /* print entry registers */ + + while (XR != 0) { /* all comparisons done? */ + key = ReadW (BR); /* read a buffer word */ + + if (key == AR) { /* does it match? */ + PC = (PC + 1) & VAMASK; /* P+1 found return */ + break; + } + + BR = (BR + op[0].word) & DMASK; /* increment buffer ptr */ + XR = (XR - 1) & DMASK; /* decrement remaining count */ + } + /* P+0 not found return */ + if (debug_print) /* debugging? */ + fprint_regs ("; result:", /* print return registers */ + REG_A | REG_B | REG_X | REG_P_REL, + err_PC + 2); + break; + + case 006: /* .IRT 105346 (OP_A) */ + save_area = ReadW (xsusp); /* addr of PABEO save area */ + + WriteW (op[0].word, ReadW (save_area + 0)); /* restore P to DEF RTN */ + + AR = ReadW (save_area + 1); /* restore A */ + BR = ReadW (save_area + 2); /* restore B */ + + eoreg = ReadW (save_area + 3); /* get combined E and O */ + E = (eoreg >> 15) & 1; /* restore E */ + O = eoreg & 1; /* restore O */ + + save_area = ReadW (xi); /* addr of XY save area */ + XR = ReadWA (save_area + 0); /* restore X (from user map) */ + YR = ReadWA (save_area + 1); /* restore Y (from user map) */ + + reason = iogrp (CLF_0, iotrap); /* turn interrupt system off */ + WriteW (mptfl, 0); /* show MP is on */ + + priv_fence = ReadW (dummy); /* get priv fence select code */ + + if (priv_fence) { /* privileged system? */ + reason = iogrp (CLC_0 + priv_fence, iotrap); /* CLC SC on priv fence */ + reason = iogrp (STF_0 + priv_fence, iotrap); /* STF SC on priv fence */ + + if (cpu_get_intbl (DMA0) & SIGN) /* DCPC 0 active? */ + reason = iogrp (STC_0 + DMA0, iotrap); /* STC 6 to enable IRQ on DCPC 0 */ + + if (cpu_get_intbl (DMA1) & SIGN) /* DCPC 1 active? */ + reason = iogrp (STC_0 + DMA1, iotrap); /* STC 7 to enable IRQ on DCPC 1 */ + } + + tbg_tick = 0; /* .IRT terminates TBG servicing */ + break; + + case 007: /* .LLS 105347 (OP_KK) */ + if (debug_print) /* debugging? */ + fprint_regs (",", REG_A | REG_B | REG_E, 0); /* print entry registers */ + + AR = AR & ~SIGN; /* clear sign bit of A */ + + while ((AR != 0) && ((AR & SIGN) == 0)) { /* end of list or bad list? */ + key = ReadW ((AR + op[1].word) & VAMASK); /* get key value */ + + if ((E == 0) && (key == op[0].word) || /* for E = 0, key = arg? */ + (E != 0) && (key > op[0].word)) /* for E = 1, key > arg? */ + break; /* search is done */ + + BR = AR; /* B = last link */ + AR = ReadW (AR); /* A = next link */ + } + + if (AR == 0) /* exhausted list? */ + PC = (PC + 1) & VAMASK; /* P+1 arg not found */ + else if ((AR & SIGN) == 0) /* good link? */ + PC = (PC + 2) & VAMASK; /* P+2 arg found */ + /* P+0 bad link */ + if (debug_print) /* debugging? */ + fprint_regs ("; result:", /* print return registers */ + REG_A | REG_B | REG_P_REL, + err_PC + 3); + break; + + case 010: /* .SIP 105350 (OP_N) */ + reason = iogrp (STF_0, iotrap); /* turn interrupt system on */ + intrq = calc_int (); /* check for interrupt requests */ + reason = iogrp (CLF_0, iotrap); /* turn interrupt system off */ + + if (intrq) /* was interrupt pending? */ + PC = (PC + 1) & VAMASK; /* P+1 return for pending IRQ */ + /* P+0 return for no pending IRQ */ + if (debug_print) /* debugging? */ + fprintf (sim_deb, /* print return registers */ + "CIR = %02o, return = P+%d", + intrq, PC - (err_PC + 1)); + break; + + case 011: /* .YLD 105351 (OP_C) */ + PC = op[0].word; /* pick up point of resumption */ + reason = iogrp (STF_0, iotrap); /* turn interrupt system on */ + ion_defer = 0; /* kill defer so irq occurs immed */ + break; + + case 012: /* .CPM 105352 (OP_KK) */ + if (INT16 (op[0].word) > INT16 (op[1].word)) + PC = (PC + 2) & VAMASK; /* P+2 arg1 > arg2 */ + else if (INT16 (op[0].word) < INT16 (op[1].word)) + PC = (PC + 1) & VAMASK; /* P+1 arg1 < arg2 */ + /* P+0 arg1 = arg2 */ + if (debug_print) /* debugging? */ + fprint_regs (",", REG_P_REL, err_PC + 3); /* print return registers */ + break; + + case 013: /* .ETEQ 105353 (OP_N) */ + eqt = ReadW (eqt1); /* get addr of EQT1 */ + + if (AR != eqt) { /* already set up? */ + for (eqt = eqt1; eqt <= eqt11; eqt++) /* init EQT1-EQT11 */ + WriteW (eqt & VAMASK, (AR++ & DMASK)); + for (eqt = eqt12; eqt <= eqt15; eqt++) /* init EQT12-EQT15 */ + WriteW (eqt & VAMASK, (AR++ & DMASK)); /* (not contig with EQT1-11) */ + } + + if (debug_print) /* debugging? */ + fprintf (sim_deb, /* print return registers */ + ", A = %06o, EQT1 = %06o", AR, eqt); + break; + + case 014: /* .ENTN/$DCPC 105354 (OP_N) */ + if (iotrap) { /* in trap cell? */ + reason = cpu_save_state (iotrap); /* DMA interrupt */ + AR = cpu_get_intbl (intaddr) & ~SIGN; /* get intbl value and strip sign */ + goto DEVINT; /* vector by intbl value */ + } + + else { /* .ENTN instruction */ + ma = (PC - 2) & VAMASK; /* get addr of entry point */ + + ENTX: /* enter here from .ENTC */ + reason = cpu_ops (OP_A, op, intrq); /* get instruction operand */ + da = op[0].word; /* get addr of 1st formal */ + count = ma - da; /* get count of formals */ + sa = ReadW (ma); /* get addr of 1st actual */ + WriteW (ma, (sa + count) & VAMASK); /* adjust return point to skip actuals */ + + if (debug_print) /* debugging? */ + fprintf (sim_deb, /* print entry registers */ + ", op [0] = %06o, pcount = %d", + da, count); + + for (i = 0; i < count; i++) { /* parameter loop */ + ma = ReadW (sa); /* get addr of actual */ + sa = (sa + 1) & VAMASK; /* increment address */ + + if (reason = resolve (ma, &ma, intrq)) { /* resolve indirect */ + PC = err_PC; /* irq restarts instruction */ + break; + } + + WriteW (da, ma); /* put addr into formal */ + da = (da + 1) & VAMASK; /* increment address */ + } + + if (entry == 016) /* call was .ENTC? */ + AR = sa; /* set A to return address */ + } + break; + + case 015: /* $OTST/$MPV 105355 (OP_N) */ + if (iotrap) { /* in trap cell? */ + reason = cpu_save_state (iotrap); /* MP/DMS/PE interrupt */ + vectors = ReadW (vctr); /* get address of vectors (in SMAP) */ + + if (mp_viol & SIGN) { /* parity error? */ + WriteW (vectors + cic_offset, PC); /* save point of suspension in $CIC */ + PC = ReadW (vectors + perr_offset); /* vector to $PERR for processing */ + } + + else { /* MP/DMS violation */ + cpu_save_regs (iotrap); /* save CPU registers */ + PC = ReadW (vectors + rqst_offset); /* vector to $RQST for processing */ + } + + if (debug_print) { /* debugging? */ + fprint_regs (",", REG_CIR, 0); /* print interrupt source */ + /* and cause */ + if (mp_viol & SIGN) + fputs (", parity error", sim_deb); + else if (mp_mevff) + fputs (", DM violation", sim_deb); + else + fputs (", MP violation", sim_deb); + } + } + + else { /* self-test instruction */ + if (cpu_unit.flags & UNIT_VMAOS) { /* VMA/OS option installed? */ + YR = 0000000; /* RPL switch (not implemented) */ + AR = 0000000; /* LDR [B] (not implemented) */ + SR = 0102077; /* test passed code */ + PC = (PC + 1) & VAMASK; /* P+1 return for firmware OK */ + + if ((cpu_dev.dctrl & DEB_OS) && /* OS debug flag set, */ + (sim_deb == NULL)) /* but debugging disabled? */ + XR = 0; /* rev = 0 means RTE won't use ucode */ + else + XR = 010; /* firmware revision 10B = 8 */ + } + + if (debug_print) /* debugging? */ + fprint_regs (",", REG_X | REG_P_REL, /* print return registers */ + err_PC + 1); + } + + break; /* self-test is NOP if no firmware */ + + case 016: /* .ENTC/$DEV 105356 (OP_N) */ + if (iotrap) { /* in trap cell? */ + reason = cpu_save_state (iotrap); /* device interrupt */ + AR = cpu_get_intbl (intaddr); /* get interrupt table value */ + + DEVINT: + vectors = ReadW (vctr); /* get address of vectors (in SMAP) */ + + if (INT16 (AR) < 0) /* negative (program ID)? */ + PC = ReadW (vectors + sked_offset); /* vector to $SKED for processing */ + else if (AR > 0) /* positive (EQT address)? */ + PC = ReadW (vectors + cic2_offset); /* vector to $CIC2 for processing */ + else /* zero (illegal interrupt) */ + PC = ReadW (vectors + cic4_offset); /* vector to $CIC4 for processing */ + + if (debug_print) /* debugging? */ + fprintf (sim_deb, /* print return registers */ + ", CIR = %02o, INTBL = %06o", + intaddr, AR); + } + + else { /* .ENTC instruction */ + ma = (PC - 4) & VAMASK; /* get addr of entry point */ + goto ENTX; /* continue with common processing */ + } + break; + + case 017: /* .DSPI/$TBG 105357 (OP_N) */ + if (iotrap) { /* in trap cell? */ + reason = cpu_save_state (iotrap); /* TBG interrupt */ + vectors = ReadW (vctr); /* get address of vectors (in SMAP) */ + PC = ReadW (vectors + clck_offset); /* vector to $CLCK for processing */ + + if (debug_print) /* debugging? */ + fprint_regs (",", REG_CIR, 0); /* print interrupt source */ + } + + else /* .DSPI instruction */ + reason = stop_inst; /* not implemented yet */ + + break; + } + +if (debug_print) { /* debugging? */ + fputc ('\n', sim_deb); /* terminate line */ + memcpy (save_env, mp_handler, sizeof (jmp_buf)); /* restore original MP handler */ + } + +return reason; +} diff --git a/HP2100/hp2100_cpu7.c b/HP2100/hp2100_cpu7.c new file mode 100644 index 00000000..5b0e3d0c --- /dev/null +++ b/HP2100/hp2100_cpu7.c @@ -0,0 +1,945 @@ +/* hp2100_cpu7.c: HP 1000 VIS and SIGNAL/1000 microcode + + Copyright (c) 2006, J. David Bryan + Copyright (c) 2008, Holger Veit + + 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 AUTHORS 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 authors 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 authors. + + CPU7 Vector Instruction Set and SIGNAL firmware + + 30-Apr-08 JDB Updated SIGNAL code from Holger + 24-Apr-08 HV Implemented SIGNAL + 20-Apr-08 JDB Updated comments + 26-Feb-08 HV Implemented VIS + + Primary references: + - HP 1000 M/E/F-Series Computers Technical Reference Handbook + (5955-0282, Mar-1980) + - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation + (92851-90001, Mar-1981) + - Macro/1000 Reference Manual (92059-90001, Dec-1992) + + Additional references are listed with the associated firmware + implementations, as are the HP option model numbers pertaining to the + applicable CPUs. +*/ + +#include "hp2100_defs.h" +#include "hp2100_cpu.h" +#include "hp2100_cpu1.h" + +#if defined (HAVE_INT64) /* int64 support available */ + +#include "hp2100_fp1.h" + + +t_stat cpu_vis (uint32 IR, uint32 intrq); /* Vector Instruction Set */ +t_stat cpu_signal (uint32 IR, uint32 intrq); /* SIGNAL/1000 Instructions */ + +static const OP zero = { { 0, 0, 0, 0, 0 } }; /* DEC 0.0D0 */ + + +/* Vector Instruction Set + + The VIS provides instructions that operate on one-dimensional arrays of + floating-point values. Both single- and double-precision operations are + supported. VIS uses the F-Series floating-point processor to handle the + floating-point math. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A N/A N/A 12824A + + The routines are mapped to instruction codes as follows: + + Single-Precision Double-Precision + Instr. Opcode Subcod Instr. Opcode Subcod Description + ------ ------ ------ ------ ------ ------ ----------------------------- + VADD 101460 000000 DVADD 105460 004002 Vector add + VSUB 101460 000020 DVSUB 105460 004022 Vector subtract + VMPY 101460 000040 DVMPY 105460 004042 Vector multiply + VDIV 101460 000060 DVDIV 105460 004062 Vector divide + VSAD 101460 000400 DVSAD 105460 004402 Scalar-vector add + VSSB 101460 000420 DVSSB 105460 004422 Scalar-vector subtract + VSMY 101460 000440 DVSMY 105460 004442 Scalar-vector multiply + VSDV 101460 000460 DVSDV 105460 004462 Scalar-vector divide + VPIV 101461 0xxxxx DVPIV 105461 0xxxxx Vector pivot + VABS 101462 0xxxxx DVABS 105462 0xxxxx Vector absolute value + VSUM 101463 0xxxxx DVSUM 105463 0xxxxx Vector sum + VNRM 101464 0xxxxx DVNRM 105464 0xxxxx Vector norm + VDOT 101465 0xxxxx DVDOT 105465 0xxxxx Vector dot product + VMAX 101466 0xxxxx DVMAX 105466 0xxxxx Vector maximum value + VMAB 101467 0xxxxx DVMAB 105467 0xxxxx Vector maximum absolute value + VMIN 101470 0xxxxx DVMIN 105470 0xxxxx Vector minimum value + VMIB 101471 0xxxxx DVMIB 105471 0xxxxx Vector minimum absolute value + VMOV 101472 0xxxxx DVMOV 105472 0xxxxx Vector move + VSWP 101473 0xxxxx DVSWP 105473 0xxxxx Vector swap + .ERES 101474 -- -- -- -- Resolve array element address + .ESEG 101475 -- -- -- -- Load MSEG maps + .VSET 101476 -- -- -- -- Vector setup + [test] -- -- -- 105477 -- [self test] + + Instructions use IR bit 11 to select single- or double-precision format. The + double-precision instruction names begin with "D" (e.g., DVADD vs. VADD). + Most VIS instructions are two words in length, with a sub-opcode immediately + following the primary opcode. + + Notes: + + 1. The .VECT (101460) and .DVCT (105460) opcodes preface a single- or + double-precision arithmetic operation that is determined by the + sub-opcode value. The remainder of the dual-precision sub-opcode values + are "don't care," except for requiring a zero in bit 15. + + 2. The VIS uses the hardware FPP of the F-Series. FPP malfunctions are + detected by the VIS firmware and are indicated by a memory-protect + violation and setting the overflow flag. Under simulation, + malfunctions cannot occur. + + Additional references: + - 12824A Vector Instruction Set User's Manual (12824-90001, Jun-1979). + - VIS Microcode Source (12824-18059, revision 3). +*/ + +/* implemented in hp2100_cpu5.c (RTE-IV EMA functions) */ +extern t_stat cpu_ema_eres(uint32* rtn,uint32 dtbl,uint32 atbl, t_bool debug); +extern t_stat cpu_ema_eseg(uint32* rtn,uint32 ir,uint32 tbl, t_bool debug); +extern t_stat cpu_ema_vset(uint32* rtn,OPS op, t_bool debug); + +static const OP_PAT op_vis[16] = { + OP_N, OP_AAKAKAKK,OP_AKAKK, OP_AAKK, /* .VECT VPIV VABS VSUM */ + OP_AAKK, OP_AAKAKK, OP_AAKK, OP_AAKK, /* VNRM VDOT VMAX VMAB */ + OP_AAKK, OP_AAKK, OP_AKAKK, OP_AKAKK, /* VMIN VMIB VMOV VSWP */ + OP_AA, OP_A, OP_AAACCC,OP_N /* .ERES .ESEG .VSET [test] */ + }; + +static const t_bool op_ftnret[16] = { + FALSE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, + FALSE, TRUE, TRUE, FALSE, + }; + + +/* handle the scalar/vector base ops */ +static void vis_svop(uint32 subcode, OPS op, OPSIZE opsize) +{ +OP v1,v2; +int16 delta = opsize==fp_f ? 2 : 4; +OP s = ReadOp(op[0].word,opsize); +uint32 v1addr = op[1].word; +int16 ix1 = INT16(op[2].word) * delta; +uint32 v2addr = op[3].word; +int16 ix2 = INT16(op[4].word) * delta; +int16 i, n = INT16(op[5].word); +uint32 fpuop = (subcode & 060) | (opsize==fp_f ? 0 : 2); + +if (n <= 0) return; +for (i=0; ifpk[0] & 0100000) + +static void vis_abs(OP* in, uint32 opsize) +{ +uint32 sign = GET_MSIGN(in); /* get sign */ +if (sign) (void)fp_pcom(in, opsize); /* if negative, make positive */ +} + +static void vis_minmax(OPS op,OPSIZE opsize,t_bool domax,t_bool doabs) +{ +OP v1,vmxmn,res; +int16 delta = opsize==fp_f ? 2 : 4; +uint32 mxmnaddr = op[0].word; +uint32 v1addr = op[1].word; +int16 ix1 = INT16(op[2].word) * delta; +int16 n = INT16(op[3].word); +int16 i,mxmn,sign; +int32 subop = 020 | (opsize==fp_f ? 0 : 2); + +if (n <= 0) return; +mxmn = 0; /* index of maxmin element */ +vmxmn = ReadOp(v1addr,opsize); /* initialize with first element */ +if (doabs) vis_abs(&vmxmn,opsize); /* ABS(v[1]) if requested */ + +for (i = 0; ifpk[0] = in.fpk[0]; +out->fpk[1] = (in.fpk[1] & 0177400) | (in.fpk[3] & 0377); +} + +static void vis_vsmnm(OPS op,OPSIZE opsize,t_bool doabs) +{ +uint32 fpuop; +OP v1,sumnrm = zero; +int16 delta = opsize==fp_f ? 2 : 4; +uint32 saddr = op[0].word; +uint32 v1addr = op[1].word; +int16 ix1 = INT16(op[2].word) * delta; +int16 i,n = INT16(op[3].word); + +if (n <= 0) return; +/* calculates sumnrm = sumnrm + DBLE(v1[i]) resp DBLE(ABS(v1[i])) for incrementing i */ +for (i=0; i>CPU VIS: IR = %06o/%06o (", /* print preamble and IR */ + IR, subcode); + fprint_sym (sim_deb, err_PC, (t_value *) &IR, /* print instruction mnemonic */ + NULL, SWMASK('M')); + fprintf (sim_deb, "), P = %06o", err_PC); /* print location */ + fprint_ops (pattern, op); /* print operands */ + fputc ('\n', sim_deb); /* terminate line */ + } + +switch (entry) { /* decode IR<3:0> */ + case 000: /* .VECT (OP_special) */ + if (subcode & 0400) + vis_svop(subcode,op,opsize); /* scalar/vector op */ + else + vis_vvop(subcode,op,opsize); /* vector/vector op */ + break; + case 001: /* VPIV (OP_(A)AAKAKAKK) */ + vis_vpiv(op,opsize); + break; + case 002: /* VABS (OP_(A)AKAKK) */ + vis_vabs(op,opsize); + break; + case 003: /* VSUM (OP_(A)AAKK) */ + vis_vsmnm(op,opsize,FALSE); + break; + case 004: /* VNRM (OP_(A)AAKK) */ + vis_vsmnm(op,opsize,TRUE); + break; + case 005: /* VDOT (OP_(A)AAKAKK) */ + vis_vdot(op,opsize); + break; + case 006: /* VMAX (OP_(A)AAKK) */ + vis_minmax(op,opsize,TRUE,FALSE); + break; + case 007: /* VMAB (OP_(A)AAKK) */ + vis_minmax(op,opsize,TRUE,TRUE); + break; + case 010: /* VMIN (OP_(A)AAKK) */ + vis_minmax(op,opsize,FALSE,FALSE); + break; + case 011: /* VMIB (OP_(A)AAKK) */ + vis_minmax(op,opsize,FALSE,TRUE); + break; + case 012: /* VMOV (OP_(A)AKAKK) */ + vis_movswp(op,opsize,FALSE); + break; + case 013: /* VSWP (OP_(A)AKAKK) */ + vis_movswp(op,opsize,TRUE); + break; + case 014: /* .ERES (OP_(A)AA) */ + reason = cpu_ema_eres(&rtn,op[2].word,PC,debug); /* handle the ERES instruction */ + PC = rtn; + if (debug) + fprintf (sim_deb, + ">>CPU VIS: return .ERES: AR = %06o, BR = %06o, rtn=%s\n", + AR, BR, PC==op[0].word ? "error" : "good"); + break; + + case 015: /* .ESEG (OP_(A)A) */ + reason = cpu_ema_eseg(&rtn,IR,op[0].word,debug); /* handle the ESEG instruction */ + PC = rtn; + if (debug) + fprintf (sim_deb, + ">>CPU VIS: return .ESEG: AR = %06o , BR = %06o, rtn=%s\n", + AR, BR, rtn==rtn1 ? "error" : "good"); + break; + + case 016: /* .VSET (OP_(A)AAACCC) */ + reason = cpu_ema_vset(&rtn,op,debug); + PC = rtn; + if (debug) + fprintf (sim_deb, ">>CPU VIS: return .VSET: AR = %06o BR = %06o, rtn=%s\n", + AR, BR, + rtn==rtn1 ? "error" : (rtn==(rtn1+1) ? "hard" : "easy") ); + break; + + case 017: /* [test] (OP_N) */ + XR = 3; /* firmware revision */ + SR = 0102077; /* test passed code */ + PC = (PC + 1) & VAMASK; /* P+2 return for firmware w/VIS */ + break; + default: /* others undefined */ + reason = stop_inst; + } + +return reason; +} + + +/* SIGNAL/1000 Instructions + + The SIGNAL/1000 instructions provide fast Fourier transforms and complex + arithmetic. They utilize the F-Series floating-point processor and the + Vector Instruction Set. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A N/A N/A 92835A + + The routines are mapped to instruction codes as follows: + + Instr. 1000-F Description + ------ ------ ---------------------------------------------- + BITRV 105600 Bit reversal + BTRFY 105601 Butterfly algorithm + UNSCR 105602 Unscramble for phasor MPY + PRSCR 105603 Unscramble for phasor MPY + BITR1 105604 Swap two elements in array (alternate format) + BTRF1 105605 Butterfly algorithm (alternate format) + .CADD 105606 Complex number addition + .CSUB 105607 Complex number subtraction + .CMPY 105610 Complex number multiplication + .CDIV 105611 Complex number division + CONJG 105612 Complex conjugate + ..CCM 105613 Complex complement + AIMAG 105614 Return imaginary part + CMPLX 105615 Form complex number + [nop] 105616 [no operation] + [test] 105617 [self test] + + Notes: + + 1. SIGNAL/1000 ROM data are available from Bitsavers. + + Additional references (documents unavailable): + - HP Signal/1000 User Reference and Installation Manual (92835-90002). + - SIGNAL/1000 Microcode Source (92835-18075, revision 2). +*/ + +#define RE(x) (x+0) +#define IM(x) (x+2) + +static const OP_PAT op_signal[16] = { + OP_AAKK, OP_AAFFKK, OP_AAFFKK,OP_AAFFKK, /* BITRV BTRFY UNSCR PRSCR */ + OP_AAAKK, OP_AAAFFKK,OP_AAA, OP_AAA, /* BITR1 BTRF1 .CADD .CSUB */ + OP_AAA, OP_AAA, OP_AAA, OP_A, /* .CMPY .CDIV CONJG ..CCM */ + OP_AA, OP_AAFF, OP_N, OP_N /* AIMAG CMPLX --- [test]*/ + }; + +/* complex addition helper */ +static void sig_caddsub(uint32 addsub,OPS op) +{ +OP a,b,c,d,p1,p2; + +a = ReadOp(RE(op[1].word), fp_f); /* read 1st op */ +b = ReadOp(IM(op[1].word), fp_f); +c = ReadOp(RE(op[2].word), fp_f); /* read 2nd op */ +d = ReadOp(IM(op[2].word), fp_f); +(void)fp_exec(addsub,&p1, a, c); /* add real */ +(void)fp_exec(addsub,&p2, b, d); /* add imag */ +WriteOp(RE(op[0].word), p1, fp_f); /* write result */ +WriteOp(IM(op[0].word), p2, fp_f); /* write result */ +} + +/* butterfly operation helper */ +static void sig_btrfy(uint32 re,uint32 im,OP wr,OP wi,uint32 k, uint32 n2) +{ +/* + * v(k)-------->o-->o----> v(k) + * \ / + * x + * / \ + * v(k+N/2)---->o-->o----> v(k+N/2) + * Wn -1 + * + */ + +OP p1,p2,p3,p4; +OP v1r = ReadOp(re+k, fp_f); /* read v1 */ +OP v1i = ReadOp(im+k, fp_f); +OP v2r = ReadOp(re+k+n2, fp_f); /* read v2 */ +OP v2i = ReadOp(im+k+n2, fp_f); + +/* (p1,p2) := cmul(w,v2) */ +(void)fp_exec(040, &p1, wr, v2r); /* S7,8 p1 := wr*v2r */ +(void)fp_exec(040, ACCUM, wi, v2i); /* ACCUM := wi*v2i */ +(void)fp_exec(024, &p1, p1, NOP); /* S7,S8 p1 := wr*v2r-wi*v2i ==real(w*v2) */ +(void)fp_exec(040, &p2, wi, v2r); /* S9,10 p2 := wi*v2r */ +(void)fp_exec(040, ACCUM, wr, v2i); /* ACCUM := wr*v2i */ +(void)fp_exec(004, &p2, p2, NOP); /* S9,10 p2 := wi*v2r+wr*v2i ==imag(w*v2) */ +/* v2 := v1 - (p1,p2) */ +(void)fp_exec(020, &p3, v1r, p1); /* v2r := v1r-real(w*v2) */ +(void)fp_exec(020, &p4, v1i, p2); /* v2i := v1i-imag(w*v2) */ +WriteOp(re+k+n2, p3, fp_f); /* write v2r */ +WriteOp(im+k+n2, p4, fp_f); /* write v2i */ +/* v1 := v1 + (p1,p2) */ +(void)fp_exec(0, &p3, v1r, p1); /* v1r := v1r+real(w*v2) */ +(void)fp_exec(0, &p4, v1i, p2); /* v1i := v1i+imag(w*v2) */ +WriteOp(re+k, p3, fp_f); /* write v1r */ +WriteOp(im+k, p4, fp_f); /* write v1i */ +O = 0; +} + +/* helper for bit reversal + * idx is 0-based already */ +static void sig_bitrev(uint32 re,uint32 im, uint32 idx, uint32 log2n, int sz) +{ +uint32 i, org=idx, rev = 0; +OP v1r,v1i,v2r,v2i; + +for (i=0; i>= 1; +} + +if (rev < idx) return; /* avoid swapping same pair twice in loop */ + +idx *= sz; /* adjust for element size */ +rev *= sz; /* (REAL*4 vs COMPLEX*8) */ + +v1r = ReadOp(re+idx, fp_f); /* read 1st element */ +v1i = ReadOp(im+idx, fp_f); +v2r = ReadOp(re+rev, fp_f); /* read 2nd element */ +v2i = ReadOp(im+rev, fp_f); +WriteOp(re+idx, v2r, fp_f); /* swap elements */ +WriteOp(im+idx, v2i, fp_f); +WriteOp(re+rev, v1r, fp_f); +WriteOp(im+rev, v1i, fp_f); +} + +/* helper for PRSCR/UNSCR */ +static OP sig_scadd(uint32 oper,t_bool addh, OP a, OP b) +{ +OP r; +static const OP plus_half = { { 0040000, 0000000 } }; /* DEC +0.5 */ + +(void)fp_exec(oper,&r,a,b); /* calculate r := a +/- b */ +if (addh) (void)fp_exec(044,&r,plus_half,NOP); /* if addh set, multiply by 0.5 */ +return r; +} + +/* complex multiply helper */ +static void sig_cmul(OP *r, OP *i, OP a, OP b, OP c, OP d) +{ +OP p; +(void)fp_exec(040, &p , a, c); /* p := ac */ +(void)fp_exec(040, ACCUM, b, d); /* ACCUM := bd */ +(void)fp_exec(024, r, p , NOP); /* real := ac-bd */ +(void)fp_exec(040, &p, a, d); /* p := ad */ +(void)fp_exec(040, ACCUM, b, c); /* ACCUM := bc */ +(void)fp_exec(004, i, p, NOP); /* imag := ad+bc */ +} + +t_stat cpu_signal (uint32 IR, uint32 intrq) +{ +t_stat reason = SCPE_OK; +OPS op; +OP a,b,c,d,p1,p2,p3,p4,m1,m2,wr,wi; +uint32 entry, v, idx1, idx2; +int32 exc, exd; + +t_bool debug = DEBUG_PRI (cpu_dev, DEB_SIG); +if ((cpu_unit.flags & UNIT_SIGNAL) == 0) /* SIGNAL option installed? */ + return stop_inst; + +entry = IR & 017; /* mask to entry point */ + +if (op_signal[entry] != OP_N) + if (reason = cpu_ops (op_signal[entry], op, intrq)) /* get instruction operands */ + return reason; + +if (debug) { /* debugging? */ + fprintf (sim_deb, ">>CPU SIG: IR = %06o (", IR); /* print preamble and IR */ + fprint_sym (sim_deb, err_PC, (t_value *) &IR, /* print instruction mnemonic */ + NULL, SWMASK('M')); + fprintf (sim_deb, "), P = %06o", err_PC); /* print location */ + fprint_ops (op_signal[entry], op); /* print operands */ + fputc ('\n', sim_deb); /* terminate line */ + } + +switch (entry) { /* decode IR<3:0> */ + case 000: /* BITRV (OP_AAKK) */ + /* BITRV + * bit reversal for FFT + * JSB BITRV + * DEF ret(,I) return address + * DEF vect,I base address of array + * DEF idx,I index bitmap to be reversed (one-based) + * DEF nbits,I number of bits of index + * + * Given a complex*8 vector of nbits (power of 2), this calculates: + * swap( vect[idx], vect[rev(idx)]) where rev(i) is the bitreversed value of i */ + sig_bitrev(op[1].word, op[1].word+2, op[2].word-1, op[3].word, 4); + PC = op[0].word & VAMASK; + break; + + case 001: /* BTRFY (OP_AAFFKK) */ + /* BTRFY - butterfly operation + * JSB BTRFY + * DEF ret(,I) return address + * DEF vect(,I) complex*8 vector + * DEF wr,I real part of W + * DEF wi,I imag part of W + * DEF node,I index of 1st op (1 based) + * DEF lmax,I offset to 2nd op (0 based) */ + sig_btrfy(op[1].word, op[1].word+2, + op[2], op[3], + 2*(op[4].word-1), 2*op[5].word); + PC = op[0].word & VAMASK; + break; + + case 002: /* UNSCR (OP_AAFFKK) */ + /* UNSCR unscramble for phasor MPY + * JSB UNSCR + * DEF ret(,I) + * DEF vector,I + * DEF WR + * DEF WI + * DEF idx1,I + * DEF idx2,I */ + v = op[1].word; + idx1 = 2 * (op[4].word - 1); + idx2 = 2 * (op[5].word - 1); + wr = op[2]; /* read WR */ + wi = op[3]; /* read WI */ + p1 = ReadOp(RE(v + idx1), fp_f); /* S1 VR[idx1] */ + p2 = ReadOp(RE(v + idx2), fp_f); /* S2 VR[idx2] */ + p3 = ReadOp(IM(v + idx1), fp_f); /* S9 VI[idx1] */ + p4 = ReadOp(IM(v + idx2), fp_f); /* S10 VI[idx2] */ + c = sig_scadd(000, TRUE, p3, p4); /* S5,6 0.5*(p3+p4) */ + d = sig_scadd(020, TRUE, p2, p1); /* S7,8 0.5*(p2-p1) */ + sig_cmul(&m1, &m2, wr, wi, c, d); /* (WR,WI) * (c,d) */ + c = sig_scadd(000, TRUE, p1, p2); /* 0.5*(p1+p2) */ + d = sig_scadd(020, TRUE, p3, p4); /* 0.5*(p3-p4) */ + (void)fp_exec(000, &p1, c, m1); /* VR[idx1] := 0.5*(p1+p2) + real(W*(c,d)) */ + WriteOp(RE(v + idx1), p1, fp_f); + (void)fp_exec(000, &p2, d, m2); /* VI[idx1] := 0.5*(p3-p4) + imag(W*(c,d)) */ + WriteOp(IM(v + idx1), p2, fp_f); + (void)fp_exec(020, &p1, c, m1); /* VR[idx2] := 0.5*(p1+p2) - imag(W*(c,d)) */ + WriteOp(RE(v + idx2), p1, fp_f); + (void)fp_exec(020, &p2, d, m2); /* VI[idx2] := 0.5*(p3-p4) - imag(W*(c,d)) */ + WriteOp(IM(v + idx2), p2, fp_f); + PC = op[0].word & VAMASK; + break; + + case 003: /* PRSCR (OP_AAFFKK) */ + /* PRSCR unscramble for phasor MPY + * JSB PRSCR + * DEF ret(,I) + * DEF vector,I + * DEF WR + * DEF WI + * DEF idx1,I + * DEF idx2,I */ + v = op[1].word; + idx1 = 2 * (op[4].word - 1); + idx2 = 2 * (op[5].word - 1); + wr = op[2]; /* read WR */ + wi = op[3]; /* read WI */ + p1 = ReadOp(RE(v + idx1), fp_f); /* VR[idx1] */ + p2 = ReadOp(RE(v + idx2), fp_f); /* VR[idx2] */ + p3 = ReadOp(IM(v + idx1), fp_f); /* VI[idx1] */ + p4 = ReadOp(IM(v + idx2), fp_f); /* VI[idx2] */ + c = sig_scadd(020, FALSE, p1, p2); /* p1-p2 */ + d = sig_scadd(000, FALSE, p3, p4); /* p3+p4 */ + sig_cmul(&m1,&m2, wr, wi, c, d); /* (WR,WI) * (c,d) */ + c = sig_scadd(000, FALSE, p1, p2); /* p1+p2 */ + d = sig_scadd(020, FALSE, p3,p4); /* p3-p4 */ + (void)fp_exec(020, &p1, c, m2); /* VR[idx1] := (p1-p2) - imag(W*(c,d)) */ + WriteOp(RE(v + idx1), p1, fp_f); + (void)fp_exec(000, &p2, d, m1); /* VI[idx1] := (p3-p4) + real(W*(c,d)) */ + WriteOp(IM(v + idx1), p2, fp_f); + (void)fp_exec(000, &p1, c, m2); /* VR[idx2] := (p1+p2) + imag(W*(c,d)) */ + WriteOp(RE(v + idx2), p1, fp_f); + (void)fp_exec(020, &p2, m1, d); /* VI[idx2] := imag(W*(c,d)) - (p3-p4) */ + WriteOp(IM(v + idx2), p2, fp_f); + PC = op[0].word & VAMASK; + break; + + case 004: /* BITR1 (OP_AAAKK) */ + /* BITR1 + * bit reversal for FFT, alternative version + * JSB BITR1 + * DEF ret(,I) return address if already swapped + * DEF revect,I base address of real vect + * DEF imvect,I base address of imag vect + * DEF idx,I index bitmap to be reversed (one-based) + * DEF nbits,I number of bits of index + * + * Given a complex*8 vector of nbits (power of 2), this calculates: + * swap( vect[idx], vect[rev(idx)]) where rev(i) is the bitreversed value of i + * + * difference to BITRV is that BITRV uses complex*8, and BITR1 uses separate real*4 + * vectors for Real and Imag parts */ + sig_bitrev(op[1].word, op[2].word, op[3].word-1, op[4].word, 2); + PC = op[0].word & VAMASK; + break; + + + case 005: /* BTRF1 (OP_AAAFFKK) */ + /* BTRF1 - butterfly operation with real*4 vectors + * JSB BTRF1 + * DEF ret(,I) return address + * DEF rvect,I real part of vector + * DEF ivect,I imag part of vector + * DEF wr,I real part of W + * DEF wi,I imag part of W + * DEF node,I index (1 based) + * DEF lmax,I index (0 based) */ + sig_btrfy(op[1].word, op[2].word, + op[3], op[4], + op[5].word-1, op[6].word); + PC = op[0].word & VAMASK; + break; + + case 006: /* .CADD (OP_AAA) */ + /* .CADD Complex addition + * JSB .CADD + * DEF result,I + * DEF oprd1,I + * DEF oprd2,I + * complex addition is: (a+bi) + (c+di) => (a+c) + (b+d)i */ + sig_caddsub(000,op); + break; + + case 007: /* .CSUB (OP_AAA) */ + /* .CSUB Complex subtraction + * JSB .CSUB + * DEF result,I + * DEF oprd1,I + * DEF oprd2,I + * complex subtraction is: (a+bi) - (c+di) => (a - c) + (b - d)i */ + sig_caddsub(020,op); + break; + + case 010: /* .CMUL (OP_AAA) */ + /* .CMPY Complex multiplication + * call: + * JSB .CMPY + * DEF result,I + * DEF oprd1,I + * DEF oprd2,I + * complex multiply is: (a+bi)*(c+di) => (ac-bd) + (ad+bc)i */ + a = ReadOp(RE(op[1].word), fp_f); /* read 1st op */ + b = ReadOp(IM(op[1].word), fp_f); + c = ReadOp(RE(op[2].word), fp_f); /* read 2nd op */ + d = ReadOp(IM(op[2].word), fp_f); + sig_cmul(&p1, &p2, a, b, c, d); + WriteOp(RE(op[0].word), p1, fp_f); /* write real result */ + WriteOp(IM(op[0].word), p2, fp_f); /* write imag result */ + break; + + case 011: /* .CDIV (OP_AAA) */ + /* .CDIV Complex division + * call: + * JSB .CDIV + * DEF result,I + * DEF oprd1,I + * DEF oprd2,I + * complex division is: (a+bi)/(c+di) => ((ac+bd) + (bc-ad)i)/(c^2+d^2) */ + a = ReadOp(RE(op[1].word), fp_f); /* read 1st op */ + b = ReadOp(IM(op[1].word), fp_f); + c = ReadOp(RE(op[2].word), fp_f); /* read 2nd op */ + d = ReadOp(IM(op[2].word), fp_f); + (void)fp_unpack (NULL, &exc, c, fp_f); /* get exponents */ + (void)fp_unpack (NULL, &exd, d, fp_f); + if (exc < exd) { /* ensure c/d < 1 */ + p1 = a; a = c; c = p1; /* swap dividend and divisor */ + p1 = b; b = d; d = p1; + } + (void)fp_exec(060, &p1, d, c); /* p1,accu := d/c */ + (void)fp_exec(044, ACCUM, d, NOP); /* ACCUM := dd/c */ + (void)fp_exec(004, &p2, c, NOP); /* p2 := c + dd/c */ + (void)fp_exec(040, ACCUM, b, p1); /* ACCUM := bd/c */ + (void)fp_exec(004, ACCUM, a, NOP); /* ACCUM := a + bd/c */ + (void)fp_exec(070, &p3, NOP, p2); /* p3 := (a+bd/c)/(c+dd/c) == (ac+bd)/(cc+dd) */ + WriteOp(RE(op[0].word), p3, fp_f); /* Write real result */ + (void)fp_exec(040, ACCUM, a, p1); /* ACCUM := ad/c */ + (void)fp_exec(030, ACCUM, NOP, b); /* ACCUM := ad/c - b */ + if (exd < exc) { /* was not swapped? */ + (void)fp_exec(024, ACCUM, zero, NOP); /* ACCUM := -ACCUM */ + } + (void)fp_exec(070, &p3, NOP, p2); /* p3 := (b-ad/c)/(c+dd/c) == (bc-ad)/cc+dd) */ + WriteOp(IM(op[0].word), p3, fp_f); /* Write imag result */ + break; + + case 012: /* CONJG (OP_AAA) */ + /* CONJG build A-Bi from A+Bi + * call: + * JSB CONJG + * DEF RTN + * DEF res,I result + * DEF arg,I input argument */ + a = ReadOp(RE(op[2].word), fp_f); /* read real */ + b = ReadOp(IM(op[2].word), fp_f); /* read imag */ + (void)fp_pcom(&b, fp_f); /* negate imag */ + WriteOp(RE(op[1].word), a, fp_f); /* write real */ + WriteOp(IM(op[1].word), b, fp_f); /* write imag */ + break; + + case 013: /* ..CCM (OP_A) */ + /* ..CCM complement complex + * call + * JSB ..CCM + * DEF arg + * build (-RE,-IM) + */ + v = op[0].word; + a = ReadOp(RE(v), fp_f); /* read real */ + b = ReadOp(IM(v), fp_f); /* read imag */ + (void)fp_pcom(&a, fp_f); /* negate real */ + (void)fp_pcom(&b, fp_f); /* negate imag */ + WriteOp(RE(v), a, fp_f); /* write real */ + WriteOp(IM(v), b, fp_f); /* write imag */ + break; + + case 014: /* AIMAG (OP_AA) */ + /* AIMAG return the imaginary part in AB + * JSB AIMAG + * DEF *+2 + * DEF cplx(,I) + * returns: AB imaginary part of complex number */ + a = ReadOp(IM(op[1].word), fp_f); /* read imag */ + AR = a.fpk[0]; /* move MSB to A */ + BR = a.fpk[1]; /* move LSB to B */ + break; + + case 015: /* CMPLX (OP_AFF) */ + /* CMPLX form a complex number + * JSB CMPLX + * DEF *+4 + * DEF result,I complex number + * DEF repart,I real value + * DEF impart,I imaginary value */ + WriteOp(RE(op[1].word), op[2], fp_f); /* write real part */ + WriteOp(IM(op[1].word), op[3], fp_f); /* write imag part */ + break; + + case 017: /* [slftst] (OP_N) */ + XR = 2; /* firmware revision */ + SR = 0102077; /* test passed code */ + PC = (PC + 1) & VAMASK; /* P+2 return for firmware w/SIGNAL1000 */ + break; + + case 016: /* invalid */ + default: /* others undefined */ + reason = stop_inst; + } + +return reason; +} + +#endif /* end of int64 support */ diff --git a/HP2100/hp2100_defs.h b/HP2100/hp2100_defs.h index 0d0d94d0..f5b935fd 100644 --- a/HP2100/hp2100_defs.h +++ b/HP2100/hp2100_defs.h @@ -1,6 +1,6 @@ /* hp2100_defs.h: HP 2100 simulator definitions - Copyright (c) 1993-2007, Robert M. Supnik + Copyright (c) 1993-2008, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,12 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 24-Apr-08 JDB Added I_MRG_I, I_JSB, I_JSB_I, and I_JMP instruction masks + 14-Apr-08 JDB Changed TMR_MUX to TMR_POLL for idle support + Added POLLMODE, sync_poll() declaration + Added I_MRG, I_ISZ, I_IOG, I_STF, and I_SFS instruction masks + 07-Dec-07 JDB Added BACI device + 10-Nov-07 JDB Added 16/32-bit unsigned-to-signed conversions 11-Jan-07 JDB Added 12578A DMA byte packing to DMA structure 28-Dec-06 JDB Added CRS backplane signal as I/O pseudo-opcode Added DMASK32 32-bit mask value @@ -80,14 +86,22 @@ /* Architectural constants */ #define SIGN32 020000000000 /* 32b sign */ -#define DMASK32 037777777777 /* 32b data mask */ +#define DMASK32 037777777777 /* 32b data mask/maximum value */ +#define DMAX32 017777777777 /* 32b maximum signed value */ #define SIGN 0100000 /* 16b sign */ -#define DMASK 0177777 /* 16b data mask */ -#define DMASK8 0377 /* 8b data mask */ +#define DMASK 0177777 /* 16b data mask/maximum value */ +#define DMAX 0077777 /* 16b maximum signed value */ +#define DMASK8 0377 /* 8b data mask/maximum value */ #define AR ABREG[0] /* A = reg 0 */ #define BR ABREG[1] /* B = reg 1 */ + +/* Portable conversions (sign-extension, unsigned-to-signed) */ + #define SEXT(x) ((int32) (((x) & SIGN)? ((x) | ~DMASK): ((x) & DMASK))) +#define INT16(u) ((u) > DMAX ? (-(int16) (DMASK - (u)) - 1) : (int16) (u)) +#define INT32(u) ((u) > DMAX32 ? (-(int32) (DMASK32 - (u)) - 1) : (int32) (u)) + /* Memory reference instructions */ #define I_IA 0100000 /* indirect address */ @@ -108,6 +122,19 @@ #define I_DEVMASK 0000077 /* device mask */ #define I_GETIOOP(x) (((x) >> 6) & 07) /* I/O sub op */ +/* Instruction masks */ + +#define I_MRG 0074000 /* MRG instructions */ +#define I_MRG_I (I_MRG | I_IA) /* MRG indirect instruction group */ +#define I_JSB 0014000 /* JSB instruction */ +#define I_JSB_I (I_JSB | I_IA) /* JSB,I instruction */ +#define I_JMP 0024000 /* JMP instruction */ +#define I_ISZ 0034000 /* ISZ instruction */ + +#define I_IOG 0107700 /* I/O group instruction */ +#define I_SFS 0102300 /* SFS instruction */ +#define I_STF 0102100 /* STF instruction */ + /* DMA channels */ #define DMA_OE 020000000000 /* byte packing odd/even flag */ @@ -182,7 +209,12 @@ struct DMA { /* DMA channel */ /* Timers */ #define TMR_CLK 0 /* clock */ -#define TMR_MUX 1 /* multiplexor */ +#define TMR_POLL 1 /* input polling */ + +#define POLL_RATE 100 /* poll 100 times per second */ +#define POLL_WAIT 15800 /* initial poll ~ 10 msec. */ + +typedef enum { INITIAL, SERVICE } POLLMODE; /* poll synchronization modes */ /* I/O sub-opcodes */ @@ -209,9 +241,9 @@ struct DMA { /* DMA channel */ #define DMA1 007 /* DMA channel 1 */ #define VARDEV (DMA1 + 1) /* start of var assign */ #define M_NXDEV (INT_M (CPU) | INT_M (OVF) | \ - INT_M (DMALT0) | INT_M (DMALT1)) + INT_M (DMALT0) | INT_M (DMALT1)) #define M_FXDEV (M_NXDEV | INT_M (PWR) | INT_M (PRO) | \ - INT_M (DMA0) | INT_M (DMA1)) + INT_M (DMA0) | INT_M (DMA1)) /* I/O devices - variable assignment defaults */ @@ -234,6 +266,7 @@ struct DMA { /* DMA channel */ #define IPLI 032 /* 12566B link in */ #define IPLO 033 /* 12566B link out */ #define DS 034 /* 13037A control */ +#define BACI 035 /* 12966A Buffered Async Comm Interface */ #define MUXL 040 /* 12920A lower data */ #define MUXU 041 /* 12920A upper data */ #define MUXC 042 /* 12920A control */ @@ -300,9 +333,11 @@ typedef struct { /* Function prototypes */ +int32 sync_poll (POLLMODE poll_mode); t_stat ibl_copy (const uint16 pboot[IBL_LNT], int32 dev); t_stat hp_setdev (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat hp_showdev (FILE *st, UNIT *uptr, int32 val, void *desc); void hp_enbdis_pair (DEVICE *ccp, DEVICE *dcp); +t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, UNIT *uptr, int32 sw); #endif diff --git a/HP2100/hp2100_diag.txt b/HP2100/hp2100_diag.txt index a518d4af..27db3549 100644 --- a/HP2100/hp2100_diag.txt +++ b/HP2100/hp2100_diag.txt @@ -1,11 +1,11 @@ SIMH/HP 21XX DIAGNOSTICS PERFORMANCE ==================================== - Last update: 2007-03-05 + Last update: 2008-05-10 The HP 24396 diagnostic suite has been run against the SIMH HP 21xx simulation. Diagnostic programs were obtained from two magnetic tapes, HP 24396-13601 Rev. -1713 and Rev. 2326, plus a few standalone paper tapes. For each diagnostic, the +1713 and Rev. 2326, plus a few standalone paper tapes. For each diagnostic, the recommended standard tests were selected, plus any available optional tests that broadened the test coverage. @@ -18,8 +18,8 @@ configuration is the default SIMH configuration with these alterations: Detailed diagnostic configuration, operation, and results are given after the summary table. These may be used to duplicate the diagnostic results. -The results of the diagnostic runs are summarized below: +The results of the diagnostic runs are summarized below: Date SIMH DSN Diagnostic Name Code Vers. Result @@ -39,7 +39,7 @@ The results of the diagnostic runs are summarized below: 102305 Memory Protect/Parity Error 1705 3.3-0 Partial 101206 Power Fail/Auto Restart 1635 - No simulation -141103 I/O Instruction Group 1810 3.2-3 Passed +141203 I/O Instruction Group - I/O Extender 2326 3.2-3 Passed 143300 General Purpose Register 1813 3.2-3 Passed 101105 Direct Memory Access (2114/15/16) 1502 3.7-0 Passed 101220 Direct Memory Access (2100/21MX) 1705 3.2-3 Passed @@ -61,13 +61,13 @@ The results of the diagnostic runs are summarized below: 103207 12889 Hardwired Serial Interface 1717 - No simulation 103122 59310 Interface Bus Interface 1728 - No simulation -103003 12587 Asynchronous Data Set Interface 1553 - No simulation +103003 12587 Asynchronous Data Set Interface 1552 - No simulation 103110 12920 Asynchronous Multiplexer (Data) 1805 3.7-1 Passed 103011 12920 Asynchronous Multiplexer (Cntl) 1444 3.7-1 Passed 103012 12621 Synchronous Data Set (Receive) 1532 - No simulation -103013 12621 Synchronous Data Set (Send) 1532 - No simulation +103013 12622 Synchronous Data Set (Send) 1532 - No simulation 103116 12967 Synchronous Interface 1438 - No simulation -103017 12966 Asynchronous Data Set 1519 - No simulation +103017 12966 Asynchronous Data Set 1519 3.8-0 Passed 103121 12968 Asynchronous Comm. Interface 1602 - No simulation 103024 12821 ICD Disc Interface 1928 - No simulation @@ -88,7 +88,6 @@ The results of the diagnostic runs are summarized below: 105106 2631 Printer 1913 - No simulation 105107 2635 Printing Terminal 1913 - No simulation 105105 2608 Line Printer 2026 - No simulation -105104 9866 Line Printer 1541 - No simulation 111001 Disc File (2883) 1451 3.3-0 Partial 111104 12732 Flexible Disc Subsystem 1708 - No simulation @@ -108,17 +107,31 @@ The results of the diagnostic runs are summarized below: 103006 12909B PROM Writer 1420 - No simulation -In addition, the following stand-alone diagnostics were run for older devices -not supported by the 24396 suite: +The following stand-alone diagnostics were run for devices not supported by the +24396 suite: + + Date SIMH +Part Number DSN Diagnostic Name Code Vers. Result +----------- ------ ------------------------------------ ---- ----- ---------- +13207-16001 101217 2000/Access Comm Processor for 21MX 1728 3.2-3 Passed +20433-????? -- HP 3030 Magnetic Tape Subsystem -- - Not tested +22682-16017 177777 HP 2100 Fixed Head Disc/Drum (277x) 1612 3.3-0 Passed +24197-60001 -- 12875 Processor Interconnect Cable B 3.7-1 Passed +24203-60001 -- HP2100A Cartridge Disc Memory (2871) A 3.3-0 Partial + + +The following online diagnostics were run for devices not supported by the +offline diagnostics: + + Date Host Date SIMH +Part Number Diagnostic Name Code Op. Sys. Code Vers. Result +----------- ------------------------------- ---- -------- ---- ----- ---------- +92067-16013 Extended Memory Area Firmware 1805 RTE-IVB 5010 3.8-0 Passed +92084-16423 Virtual Memory Area Firmware 2121 RTE-6/VM 6200 3.8-0 Passed +12824-16002 Vector Instruction Set Firmware 2026 RTE-IVB 5010 3.8-0 Passed +12829-16006 Vector Instruction Set Firmware 2226 RTE-6/VM 6200 3.8-0 Passed +92835-16006 SIGNAL/1000 Firmware Diagnostic 2040 RTE-6/VM 6200 3.8-0 Passed -Paper Tape Date SIMH -Part Number DSN Diagnostic Name Code Vers. Result ------------ ------ --------------------------------------- ---- ----- ---------- -13207-16001 101217 2000/Access Comm Processor for 21MX 1728 3.2-3 Passed -20433-????? -- HP 3030 Magnetic Tape Subsystem -- - Not tested -24197-60001 -- 12875 Processor Interconnect Cable B 3.7-1 Passed -24203-60001 -- HP2100A Cartridge Disc Memory (2871) A 3.3-0 Partial -22682-16017 177777 HP 2100 Fixed Head Disc/Drum (277x) 1612 3.3-0 Passed The "SIMH Version" is the version number of the earliest SIMH system that was tested with the given diagnostic. Earlier versions may or may not work @@ -392,7 +405,7 @@ TEST REPORT: H061 POWER DOWN COMPUTER HALT instruction 102061 - sim> set MP jsbin,intin,sel1out + sim> set MP jsbout,intout,sel1in sim> go H314 PRESS HALT,PRESET AND RUN WITHIN 30 SECONDS @@ -412,7 +425,7 @@ TEST REPORT: H061 POWER DOWN COMPUTER HALT instruction 102062 - sim> set MP jsbout,intout,sel1in + sim> set MP jsbin,intin,sel1out sim> go HALT instruction 102077 @@ -824,8 +837,6 @@ DSN 101016 - 2000/Access Comm Processor for 2100 TESTED DEVICE: CPU (hp2100_cpu2.c) -BINARY TAPE: 13206-16001 Rev. 1526 - CONFIGURATION: sim> set CPU 2100 sim> set CPU 32K sim> set CPU IOP @@ -1056,14 +1067,196 @@ TEST RESULT: Passed. +---------------------------------------- +DSN 103017 - 12966 Asynchronous Data Set +---------------------------------------- + +TESTED DEVICE: BACI (hp2100_baci.c) + +CONFIGURATION: sim> set BACI realtime + sim> set BACI diag + sim> deposit S 000035 + sim> reset + sim> go 100 + + HALT instruction 102074 + + sim> deposit S 000000 + sim> reset + sim> go + +TEST REPORT: BUFFERED ASYNC COMM INTFC DIAG + H024 PRESS PRESET (EXT&INT),RUN + + HALT instruction 102024 + + sim> reset + sim> go + + H025 BI-O COMP + PASS 000001 + +TEST RESULT: Passed. + + + +------------------------ +DSN 104003 - Teleprinter +------------------------ + +TESTED DEVICE: TTY (hp2100_stddev.c) + +CONFIGURATION: sim> deposit S 000011 + sim> reset + sim> go 100 + + HALT instruction 102074 + + sim> deposit S 001000 + sim> reset + sim> go + + START TTY DIAGNOSTIC + + HALT instruction 102075 + + sim> deposit A 000373 + sim> deposit S 000000 + sim> reset + sim> go + +TEST REPORT: H024 PRESS PRESET (EXT&INT),RUN + + HALT instruction 102024 + + sim> reset + sim> go + + H025 BI-O COMP + H030 TURN TTY PUNCH ON + PRESS RUN + + HALT instruction 102030 + + sim> attach TTY2 scratch.2752.punch + sim> go + + H045 TURN TTY PUNCH OFF + PRESS RUN + + HALT instruction 102045 + + sim> detach TTY2 + sim> deposit S 100000 + sim> go + + HALT instruction 102076 + + sim> go + + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ + + HALT instruction 102076 + + sim> set console WRU=003 + sim> go + + INPUT THE FOLLOWING: + 1 2 3 4 5 6 7 8 9 0 : - + + Q W E R T Y U I O P + + A S D F G H J K L ; + + Z X C V B N M , . / + + SHIFT+ + ! " # $ % & ' ( ) * = + + _ @ + ^ < > ? + + CNTRL+ + WRU TAPE NTAP XOFF EOT RU BELL TAB VT FORM + + + RBOT CR LF + + + HALT instruction 102076 + + sim> set console WRU=005 + sim> go + + INPUT ANY KEY + T H I S 040 I S 040 A 040 + T E S T + + [CTRL+E] + Simulation stopped + + sim> deposit S 000002 + sim> go + + [CTRL+E] + Simulation stopped + + sim> deposit S 000000 + sim> go + + H044 INPUT TERMINATED + + ECHO MODE ANY INPUT IS ECHOED + THIS IS A TEST + + [CTRL+E] + Simulation stopped + + sim> deposit S 000002 + sim> go + + [CTRL+E] + Simulation stopped + + sim> deposit S 100000 + sim> go + + H044 INPUT TERMINATED + + HALT instruction 102076 + + sim> deposit TTY TTIME 158000 + sim> deposit S 000000 + sim> go + + PASS 000001 + + HALT instruction 102077 + +TEST RESULT: Partially passed. + +TEST NOTES: Test 2 is not executed. This test uses the teleprinter paper + tape reader. This feature is not simulated. + + Test 7 is the oscillator tolerance test, so the TTY TTIME is set + for realistic timing. + + + ------------------------------ DSN 105101 - 2767 Line Printer ------------------------------ TESTED DEVICE: LPS (hp2100_lps.c) -BINARY TAPE: 12984-16001 Rev. 1611 - CONFIGURATION: sim> set LPS realtime sim> attach LPS scratch.2767.printer sim> deposit S 000014 @@ -1261,6 +1454,197 @@ TEST NOTES: The standard tests 00-07 are executed. Test 08 (operator +----------------------------------------------------- +DSN 111001 - HP2100A Disc File (2883) (multiple unit) +----------------------------------------------------- + +TESTED DEVICE: DQ (hp2100_dq.c) + +CONFIGURATION: sim> attach DQC0 scratch.U0.2883.disc + sim> attach DQC1 scratch.U1.2883.disc + sim> reset + sim> go 100 + + H0 HP 2100 SERIES DISC FILE(2883) DIAGNOSTIC + + H72 ENTER SELECT CODES,DMA CHANNEL IN SWITCH REGISTER,PRESS RUN + + HALT instruction 107001 + + sim> deposit S 002411 + sim> go + + H1 ENTER PROGRAM OPTIONS IN SWITCH REGISTER,PRESS RUN + + HALT instruction 107077 + + sim> deposit S 000400 + sim> go + +TEST REPORT: H65 PASS 0001 + H65 PASS 0002 + + [CTRL+E] + Simulation stopped + +TEST RESULT: Passed. + +TEST NOTES: Two passes are required to test all head/unit combinations. + + + +-------------------------------------------------------- +DSN 111001 - HP2100A Disc File (2883) (user interaction) +-------------------------------------------------------- + +TESTED DEVICE: DQ (hp2100_dq.c) + +CONFIGURATION: sim> attach DQC0 scratch.U0.2883.disc + sim> reset + sim> go 100 + + H0 HP 2100 SERIES DISC FILE(2883) DIAGNOSTIC + + H72 ENTER SELECT CODES,DMA CHANNEL IN SWITCH REGISTER,PRESS RUN + + HALT instruction 107001 + + sim> deposit S 002411 + sim> go + + H1 ENTER PROGRAM OPTIONS IN SWITCH REGISTER,PRESS RUN + + HALT instruction 107077 + + sim> deposit S 000142 + sim> go + +TEST REPORT: H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN + + HALT instruction 102002 + + sim> go + + H37 READ ADDRESS IN S0 + E47 DATA WORD 0000 IS 000000 SHOULD BE 100000 + H51 CYL 0000 HEAD 00 SECTOR 00 WORD COUNT 0002 UNIT 00 + + HALT instruction 102001 + + sim> go + + H37 READ ADDRESS IN S0 + E47 DATA WORD 0000 IS 000000 SHOULD BE 100001 + H51 CYL 0001 HEAD 01 SECTOR 00 WORD COUNT 0002 UNIT 00 + + HALT instruction 102001 + + sim> go + + H33 WRITE DEFECTIVE TRACK IN S0 + E64 STATUS IS 000000 SHOULD BE 000031 + H51 CYL 0000 HEAD 01 SECTOR 00 WORD COUNT 0128 UNIT 00 + + HALT instruction 102001 + + sim> go + + H41 READ DEFECTIVE TRACK IN S0 + E64 STATUS IS 000000 SHOULD BE 000031 + H51 CYL 0000 HEAD 01 SECTOR 00 WORD COUNT 0128 UNIT 00 + + HALT instruction 102001 + + sim> go + + H67 CLEAR FORMAT SWITCH ON UNIT 0,PUSH RUN + + HALT instruction 102002 + + sim> go + + H33 WRITE DEFECTIVE TRACK IN S0 + E64 STATUS IS 000000 SHOULD BE 000031 + H51 CYL 0000 HEAD 01 SECTOR 00 WORD COUNT 0128 UNIT 00 + + HALT instruction 102001 + + sim> go + + H41 READ DEFECTIVE TRACK IN S0 + E64 STATUS IS 000000 SHOULD BE 000031 + H51 CYL 0000 HEAD 01 SECTOR 00 WORD COUNT 0128 UNIT 00 + + HALT instruction 102001 + + sim> go + + H42 WRITE PROTECTED TRACK IN S0 + E64 STATUS IS 000000 SHOULD BE 000011 + H51 CYL 0000 HEAD 00 SECTOR 00 WORD COUNT 0128 UNIT 00 + + HALT instruction 102001 + + sim> go + + H36 WRITE ADDRESS IN S0 + E64 STATUS IS 000000 SHOULD BE 000011 + H51 CYL 0000 HEAD 00 SECTOR 00 WORD COUNT 0046 UNIT 00 + + HALT instruction 102001 + + sim> go + + H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN + + HALT instruction 102002 + + sim> go + + H67 CLEAR FORMAT SWITCH ON UNIT 0,PUSH RUN + + HALT instruction 102002 + + sim> go + + H70 DISABLE UNIT 0,PUSH RUN + + HALT instruction 102002 + + sim> set DQC0 unloaded + sim> go + + H40 ENABLE UNIT 0 + + [CTRL+E] + Simulation stopped + + sim> set DQC0 loaded + sim> go + + H71 PRESS PRESET THEN PRESS RUN + + HALT instruction 102002 + + sim> deposit S 010140 + sim> reset + sim> go + + H74 SHORT PASS + H65 PASS 0001 + + HALT instruction 102077 + +TEST RESULT: Partially passed. + +TEST NOTES: Step 0 tests the FORMAT OVERRIDE switch, the use of the flagged + track bit to indicate a protected or defective track, and the + ability to write a sector address field that differs from the + sector location to indicate track sparing. These features are + not simulated. + + + ---------------------------------------------------------- DSN 151302 - 7900/01 Cartridge Disc Memory (multiple unit) ---------------------------------------------------------- @@ -2313,157 +2697,6 @@ TEST NOTES: Test 07 is executed to punch a tape loop that is used in tests ------------------------- -DSN 104003 - Teleprinter ------------------------- - -TESTED DEVICE: TTY (hp2100_stddev.c) - -CONFIGURATION: sim> deposit S 000011 - sim> reset - sim> go 100 - - HALT instruction 102074 - - sim> deposit S 001000 - sim> reset - sim> go - - START TTY DIAGNOSTIC - - HALT instruction 102075 - - sim> deposit A 000373 - sim> deposit S 000000 - sim> reset - sim> go - -TEST REPORT: H024 PRESS PRESET (EXT&INT),RUN - - HALT instruction 102024 - - sim> reset - sim> go - - H025 BI-O COMP - H030 TURN TTY PUNCH ON - PRESS RUN - - HALT instruction 102030 - - sim> attach TTY2 scratch.2752.punch - sim> go - - H045 TURN TTY PUNCH OFF - PRESS RUN - - HALT instruction 102045 - - sim> detach TTY2 - sim> deposit S 100000 - sim> go - - HALT instruction 102076 - - sim> go - - !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ - !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ - !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ - !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ - !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ - !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ - !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ - !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ - !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ - !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ - - HALT instruction 102076 - - sim> set console WRU=003 - sim> go - - INPUT THE FOLLOWING: - 1 2 3 4 5 6 7 8 9 0 : - - - Q W E R T Y U I O P - - A S D F G H J K L ; - - Z X C V B N M , . / - - SHIFT+ - ! " # $ % & ' ( ) * = - - _ @ + ^ < > ? - - CNTRL+ - WRU TAPE NTAP XOFF EOT RU BELL TAB VT FORM - - - RBOT CR LF - - - HALT instruction 102076 - - sim> set console WRU=005 - sim> go - - INPUT ANY KEY - T H I S 040 I S 040 A 040 - T E S T - - [CTRL+E] - Simulation stopped - - sim> deposit S 000002 - sim> go - - [CTRL+E] - Simulation stopped - - sim> deposit S 000000 - sim> go - - H044 INPUT TERMINATED - - ECHO MODE ANY INPUT IS ECHOED - THIS IS A TEST - - [CTRL+E] - Simulation stopped - - sim> deposit S 000002 - sim> go - - [CTRL+E] - Simulation stopped - - sim> deposit S 100000 - sim> go - - H044 INPUT TERMINATED - - HALT instruction 102076 - - sim> deposit TTY TTIME 158000 - sim> deposit S 000000 - sim> go - - PASS 000001 - - HALT instruction 102077 - -TEST RESULT: Partially passed. - -TEST NOTES: Test 2 is not executed. This test uses the teleprinter paper - tape reader. This feature is not simulated. - - Test 7 is the oscillator tolerance test, so the TTY TTIME is set - for realistic timing. - - - STAND-ALONE DIAGNOSTIC DETAILED EXECUTION AND RESULTS ===================================================== @@ -2472,7 +2705,7 @@ Each execution note below presumes that the target diagnostic has been loaded. For all runs, the diagnostic configurator was used in automatic mode to load the target diagnostic from a paper tape image, as follows: - sim> attach -r MSC0 24396-13601_Rev-2236.abin.tape + sim> attach -r MSC0 24396-13601_Rev-2326.abin.tape sim> deposit S 000000 sim> boot MSC0 @@ -2485,386 +2718,60 @@ target diagnostic from a paper tape image, as follows: ------------------------------------------------------------------ -DSN (none) - HP2100A Cartridge Disc Memory (2871) (multiple unit) ------------------------------------------------------------------ +------------------------------------------------ +DSN 101217 - 2000/Access Comm Processor for 21MX +------------------------------------------------ -TESTED DEVICE: DP (hp2100_dp.c) +TESTED DEVICE: CPU (hp2100_cpu2.c) -BINARY TAPE: 24203-60001 Rev. A +BINARY TAPE: 13207-16001 Rev. 1728 -CONFIGURATION: sim> set DPC 12557A - sim> attach DPC0 scratch.U0.2871.disc - sim> attach DPC1 scratch.U1.2871.disc - sim> attach DPC2 scratch.U2.2871.disc - sim> attach DPC3 scratch.U3.2871.disc - sim> deposit S 002211 - sim> reset - sim> go 2 +CONFIGURATION: sim> set CPU IOP - HALT instruction 107077 - - sim> deposit S 000400 + sim> deposit S 000013 sim> reset sim> go 100 - H0 HP2100A CARTRIDGE DISC MEMORY DIAGNOSTIC - H34 ENTER UNIT NUMBERS(0-3)SEPARATED BY COMMAS - 0,1,2,3 - - H33 RESET SWITCH 8 - - HALT instruction 102002 - - sim> deposit S 000004 - sim> go - - H24 CYLINDER TABLE - 000,001,002,004,008,016,032,064,128,202 - H25 WISH TO ALTER TABLE? - NO - - H27 PATTERN TABLE - 000000 177777 125252 052525 007417 - 170360 162745 163346 155555 022222 - H25 WISH TO ALTER TABLE? - NO - - H62 TYPE A FOR HEADS 0,1;B FOR 2,3;C FOR ALTERNATELY 0,1 THEN 2,3 - C - - H32 RESET SWITCH 2 - - HALT instruction 102002 + HALT instruction 102074 sim> deposit S 000000 sim> reset - sim> go 100 - -TEST REPORT: H0 HP2100A CARTRIDGE DISC MEMORY DIAGNOSTIC - H65 PASS 0001 - H65 PASS 0002 - H65 PASS 0003 - H65 PASS 0004 - - [CTRL+E] - Simulation stopped - -TEST RESULT: Passed. - -TEST NOTES: Four passes are required to test all head/unit combinations. - - - --------------------------------------------------------------------- -DSN (none) - HP2100A Cartridge Disc Memory (2871) (user interaction) --------------------------------------------------------------------- - -TESTED DEVICE: DP (hp2100_dp.c) - -BINARY TAPE: 24203-60001 Rev. A - -CONFIGURATION: sim> set DPC 12557A - sim> attach DPC0 scratch.U0.2871.disc - sim> deposit S 002211 - sim> reset - sim> go 2 - - HALT instruction 107077 - - sim> deposit S 010020 - sim> reset - sim> go 100 - -TEST REPORT: H0 HP2100A CARTRIDGE DISC MEMORY DIAGNOSTIC - H66 SET OVERRIDE SWITCH,PUSH RUN - - HALT instruction 102002 - sim> go - H37 READ AFTER WRITE ADDRESS IN S0 - E64 STATUS IS 000000 SHOULD BE 000010 - H51 CYL 0000 HEAD 00 SECTOR 00 WORD COUNT 0128 UNIT 00 - - HALT instruction 102001 - - sim> go - - H22 CYCLIC CHECK IN S0 - E64 STATUS IS 000000 SHOULD BE 000010 - H51 CYL 0000 HEAD 00 SECTOR 00 WORD COUNT 0128 UNIT 00 - - HALT instruction 102001 - - sim> go - - H67 CLEAR OVERRIDE SWITCH,PUSH RUN - - HALT instruction 102002 - - sim> go - - H41 READ DEFECTIVE TRACK IN S0 - E64 STATUS IS 000000 SHOULD BE 000031 - H51 CYL 0001 HEAD 00 SECTOR 00 WORD COUNT 0128 UNIT 00 - - HALT instruction 102001 - - sim> go - - H42 WRITE PROTECTED TRACK IN S0 - E64 STATUS IS 000000 SHOULD BE 000011 - H51 CYL 0000 HEAD 00 SECTOR 00 WORD COUNT 0128 UNIT 00 - - HALT instruction 102001 - - sim> go - - H36 WRITE ADDRESS IN S0 - E64 STATUS IS 000000 SHOULD BE 000011 - H51 CYL 0000 HEAD 00 SECTOR 00 WORD COUNT 3072 UNIT 00 - - HALT instruction 102001 - - sim> go - - H66 SET OVERRIDE SWITCH,PUSH RUN - - HALT instruction 102002 - - sim> go - - H67 CLEAR OVERRIDE SWITCH,PUSH RUN - - HALT instruction 102002 - - sim> go - - H70 UNLOCK UNIT 0,PUSH RUN - - HALT instruction 102002 - - sim> set DPC0 unloaded - sim> go - - H40 READY UNIT 0 - - [CTRL+E] - Simulation stopped - - sim> set DPC0 loaded - sim> go - - H71 PRESS PRESET THEN PRESS RUN - - HALT instruction 102002 - - sim> deposit S 000140 - sim> reset - sim> go - - H65 PASS 0001 - -TEST RESULT: Partially passed. - -TEST NOTES: Step 0 tests the the defective and protected cylinder bits and - the FORMAT OVERRIDE switch. These features are not simulated. - - - ------------------------------------------------------ -DSN 111001 - HP2100A Disc File (2883) (multiple unit) ------------------------------------------------------ - -TESTED DEVICE: DQ (hp2100_dq.c) - -BINARY TAPE: 12965-16001 Rev. 1451 - -CONFIGURATION: sim> attach DQC0 scratch.U0.2883.disc - sim> attach DQC1 scratch.U1.2883.disc - sim> reset - sim> go 100 - - H0 HP 2100 SERIES DISC FILE(2883) DIAGNOSTIC - - H72 ENTER SELECT CODES,DMA CHANNEL IN SWITCH REGISTER,PRESS RUN - - HALT instruction 107001 - - sim> deposit S 002411 - sim> go - - H1 ENTER PROGRAM OPTIONS IN SWITCH REGISTER,PRESS RUN - - HALT instruction 107077 - - sim> deposit S 000400 - sim> go - -TEST REPORT: H65 PASS 0001 - H65 PASS 0002 - - [CTRL+E] - Simulation stopped - -TEST RESULT: Passed. - -TEST NOTES: Two passes are required to test all head/unit combinations. - - - --------------------------------------------------------- -DSN 111001 - HP2100A Disc File (2883) (user interaction) --------------------------------------------------------- - -TESTED DEVICE: DQ (hp2100_dq.c) - -BINARY TAPE: 12965-16001 Rev. 1451 - -CONFIGURATION: sim> attach DQC0 scratch.U0.2883.disc - sim> reset - sim> go 100 - - H0 HP 2100 SERIES DISC FILE(2883) DIAGNOSTIC - - H72 ENTER SELECT CODES,DMA CHANNEL IN SWITCH REGISTER,PRESS RUN - - HALT instruction 107001 - - sim> deposit S 002411 - sim> go - - H1 ENTER PROGRAM OPTIONS IN SWITCH REGISTER,PRESS RUN - - HALT instruction 107077 - - sim> deposit S 000142 - sim> go - -TEST REPORT: H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN - - HALT instruction 102002 - - sim> go - - H37 READ ADDRESS IN S0 - E47 DATA WORD 0000 IS 000000 SHOULD BE 100000 - H51 CYL 0000 HEAD 00 SECTOR 00 WORD COUNT 0002 UNIT 00 - - HALT instruction 102001 - - sim> go - - H37 READ ADDRESS IN S0 - E47 DATA WORD 0000 IS 000000 SHOULD BE 100001 - H51 CYL 0001 HEAD 01 SECTOR 00 WORD COUNT 0002 UNIT 00 - - HALT instruction 102001 - - sim> go - - H33 WRITE DEFECTIVE TRACK IN S0 - E64 STATUS IS 000000 SHOULD BE 000031 - H51 CYL 0000 HEAD 01 SECTOR 00 WORD COUNT 0128 UNIT 00 - - HALT instruction 102001 - - sim> go - - H41 READ DEFECTIVE TRACK IN S0 - E64 STATUS IS 000000 SHOULD BE 000031 - H51 CYL 0000 HEAD 01 SECTOR 00 WORD COUNT 0128 UNIT 00 - - HALT instruction 102001 - - sim> go - - H67 CLEAR FORMAT SWITCH ON UNIT 0,PUSH RUN - - HALT instruction 102002 - - sim> go - - H33 WRITE DEFECTIVE TRACK IN S0 - E64 STATUS IS 000000 SHOULD BE 000031 - H51 CYL 0000 HEAD 01 SECTOR 00 WORD COUNT 0128 UNIT 00 - - HALT instruction 102001 - - sim> go - - H41 READ DEFECTIVE TRACK IN S0 - E64 STATUS IS 000000 SHOULD BE 000031 - H51 CYL 0000 HEAD 01 SECTOR 00 WORD COUNT 0128 UNIT 00 - - HALT instruction 102001 - - sim> go - - H42 WRITE PROTECTED TRACK IN S0 - E64 STATUS IS 000000 SHOULD BE 000011 - H51 CYL 0000 HEAD 00 SECTOR 00 WORD COUNT 0128 UNIT 00 - - HALT instruction 102001 - - sim> go - - H36 WRITE ADDRESS IN S0 - E64 STATUS IS 000000 SHOULD BE 000011 - H51 CYL 0000 HEAD 00 SECTOR 00 WORD COUNT 0046 UNIT 00 - - HALT instruction 102001 - - sim> go - - H66 SET FORMAT SWITCH ON UNIT 0,PUSH RUN - - HALT instruction 102002 - - sim> go - - H67 CLEAR FORMAT SWITCH ON UNIT 0,PUSH RUN - - HALT instruction 102002 - - sim> go - - H70 DISABLE UNIT 0,PUSH RUN - - HALT instruction 102002 - - sim> set DQC0 unloaded - sim> go - - H40 ENABLE UNIT 0 - - [CTRL+E] - Simulation stopped - - sim> set DQC0 loaded - sim> go - - H71 PRESS PRESET THEN PRESS RUN - - HALT instruction 102002 - - sim> deposit S 010140 - sim> reset - sim> go - - H74 SHORT PASS - H65 PASS 0001 +TEST REPORT: 21MX 2000 COMPUTER SYSTEM COMM. PROC. FIRMWARE DIAGNOSTIC + H030 CRC TEST + H040 ENQ, DEQ AND PENQ TESTS + H060 IAL TEST + H110 INS,READF, SAVE AND RESTR TESTS + H120 LAI AND SAI TESTS + H130 PFREX TEST + H140 PFREI TEST + H150 PFRIO TEST + PASS 000001 HALT instruction 102077 -TEST RESULT: Partially passed. +TEST RESULT: Passed. -TEST NOTES: Step 0 tests the FORMAT OVERRIDE switch, the use of the flagged - track bit to indicate a protected or defective track, and the - ability to write a sector address field that differs from the - sector location to indicate track sparing. These features are - not simulated. + + +-------------------------------------------- +DSN (none) - HP 3030 Magnetic Tape Subsystem +-------------------------------------------- + +TESTED DEVICE: MT (hp2100_mt.c) + +BINARY TAPE: None available. + +CONFIGURATION: (none) + +TEST REPORT: (none) + +TEST RESULT: Not tested. + +TEST NOTES: The limited documentation available for this unit suggests that + the diagnostic is HP product number 20433, but no copy of this + diagnostic has been found. @@ -3120,43 +3027,6 @@ TEST RESULT: Passed. ------------------------------------------------- -DSN 101217 - 2000/Access Comm Processor for 21MX ------------------------------------------------- - -TESTED DEVICE: CPU (hp2100_cpu2.c) - -BINARY TAPE: 13207-16001 Rev. 1728 - -CONFIGURATION: sim> set CPU IOP - - sim> deposit S 000013 - sim> reset - sim> go 100 - - HALT instruction 102074 - - sim> deposit S 000000 - sim> reset - sim> go - -TEST REPORT: 21MX 2000 COMPUTER SYSTEM COMM. PROC. FIRMWARE DIAGNOSTIC - H030 CRC TEST - H040 ENQ, DEQ AND PENQ TESTS - H060 IAL TEST - H110 INS,READF, SAVE AND RESTR TESTS - H120 LAI AND SAI TESTS - H130 PFREX TEST - H140 PFREI TEST - H150 PFRIO TEST - PASS 000001 - - HALT instruction 102077 - -TEST RESULT: Passed. - - - ----------------------------------------------- DSN (none) - 12875 Processor Interconnect Cable ----------------------------------------------- @@ -3192,20 +3062,310 @@ TEST RESULT: Passed. --------------------------------------------- -DSN (none) - HP 3030 Magnetic Tape Subsystem --------------------------------------------- +----------------------------------------------------------------- +DSN (none) - HP2100A Cartridge Disc Memory (2871) (multiple unit) +----------------------------------------------------------------- -TESTED DEVICE: MT (hp2100_mt.c) +TESTED DEVICE: DP (hp2100_dp.c) -BINARY TAPE: None available. +BINARY TAPE: 24203-60001 Rev. A -CONFIGURATION: (none) +CONFIGURATION: sim> set DPC 12557A + sim> attach DPC0 scratch.U0.2871.disc + sim> attach DPC1 scratch.U1.2871.disc + sim> attach DPC2 scratch.U2.2871.disc + sim> attach DPC3 scratch.U3.2871.disc + sim> deposit S 002211 + sim> reset + sim> go 2 -TEST REPORT: (none) + HALT instruction 107077 -TEST RESULT: Not tested. + sim> deposit S 000400 + sim> reset + sim> go 100 -TEST NOTES: The limited documentation available for this unit suggests that - the diagnostic is HP product number 20433, but no copy of this - diagnostic has been found. + H0 HP2100A CARTRIDGE DISC MEMORY DIAGNOSTIC + H34 ENTER UNIT NUMBERS(0-3)SEPARATED BY COMMAS + 0,1,2,3 + + H33 RESET SWITCH 8 + + HALT instruction 102002 + + sim> deposit S 000004 + sim> go + + H24 CYLINDER TABLE + 000,001,002,004,008,016,032,064,128,202 + H25 WISH TO ALTER TABLE? + NO + + H27 PATTERN TABLE + 000000 177777 125252 052525 007417 + 170360 162745 163346 155555 022222 + H25 WISH TO ALTER TABLE? + NO + + H62 TYPE A FOR HEADS 0,1;B FOR 2,3;C FOR ALTERNATELY 0,1 THEN 2,3 + C + + H32 RESET SWITCH 2 + + HALT instruction 102002 + + sim> deposit S 000000 + sim> reset + sim> go 100 + +TEST REPORT: H0 HP2100A CARTRIDGE DISC MEMORY DIAGNOSTIC + H65 PASS 0001 + H65 PASS 0002 + H65 PASS 0003 + H65 PASS 0004 + + [CTRL+E] + Simulation stopped + +TEST RESULT: Passed. + +TEST NOTES: Four passes are required to test all head/unit combinations. + + + +-------------------------------------------------------------------- +DSN (none) - HP2100A Cartridge Disc Memory (2871) (user interaction) +-------------------------------------------------------------------- + +TESTED DEVICE: DP (hp2100_dp.c) + +BINARY TAPE: 24203-60001 Rev. A + +CONFIGURATION: sim> set DPC 12557A + sim> attach DPC0 scratch.U0.2871.disc + sim> deposit S 002211 + sim> reset + sim> go 2 + + HALT instruction 107077 + + sim> deposit S 010020 + sim> reset + sim> go 100 + +TEST REPORT: H0 HP2100A CARTRIDGE DISC MEMORY DIAGNOSTIC + H66 SET OVERRIDE SWITCH,PUSH RUN + + HALT instruction 102002 + + sim> go + + H37 READ AFTER WRITE ADDRESS IN S0 + E64 STATUS IS 000000 SHOULD BE 000010 + H51 CYL 0000 HEAD 00 SECTOR 00 WORD COUNT 0128 UNIT 00 + + HALT instruction 102001 + + sim> go + + H22 CYCLIC CHECK IN S0 + E64 STATUS IS 000000 SHOULD BE 000010 + H51 CYL 0000 HEAD 00 SECTOR 00 WORD COUNT 0128 UNIT 00 + + HALT instruction 102001 + + sim> go + + H67 CLEAR OVERRIDE SWITCH,PUSH RUN + + HALT instruction 102002 + + sim> go + + H41 READ DEFECTIVE TRACK IN S0 + E64 STATUS IS 000000 SHOULD BE 000031 + H51 CYL 0001 HEAD 00 SECTOR 00 WORD COUNT 0128 UNIT 00 + + HALT instruction 102001 + + sim> go + + H42 WRITE PROTECTED TRACK IN S0 + E64 STATUS IS 000000 SHOULD BE 000011 + H51 CYL 0000 HEAD 00 SECTOR 00 WORD COUNT 0128 UNIT 00 + + HALT instruction 102001 + + sim> go + + H36 WRITE ADDRESS IN S0 + E64 STATUS IS 000000 SHOULD BE 000011 + H51 CYL 0000 HEAD 00 SECTOR 00 WORD COUNT 3072 UNIT 00 + + HALT instruction 102001 + + sim> go + + H66 SET OVERRIDE SWITCH,PUSH RUN + + HALT instruction 102002 + + sim> go + + H67 CLEAR OVERRIDE SWITCH,PUSH RUN + + HALT instruction 102002 + + sim> go + + H70 UNLOCK UNIT 0,PUSH RUN + + HALT instruction 102002 + + sim> set DPC0 unloaded + sim> go + + H40 READY UNIT 0 + + [CTRL+E] + Simulation stopped + + sim> set DPC0 loaded + sim> go + + H71 PRESS PRESET THEN PRESS RUN + + HALT instruction 102002 + + sim> deposit S 000140 + sim> reset + sim> go + + H65 PASS 0001 + +TEST RESULT: Partially passed. + +TEST NOTES: Step 0 tests the the defective and protected cylinder bits and + the FORMAT OVERRIDE switch. These features are not simulated. + + + + +ONLINE DIAGNOSTIC DETAILED EXECUTION AND RESULTS +================================================ + +Online diagnostics were run under the control of the indicated operating +systems. Unless otherwise noted, the programs were loaded with the default +configuration specified by the associated linker command file or the operating +system. + + + +------------------------------------------------ +#EMA - Extended Memory Array Firmware Diagnostic +------------------------------------------------ + +TESTED DEVICE: CPU (hp2100_cpu5.c) + +BINARY FILE: 92067-16013 Rev. 1805 + +HOST SYSTEM: RTE-IVB Rev. 5010 + +CONFIGURATION: sim> set CPU EMA + sim> go + +TEST REPORT: EMA ON-LINE DIAGNOSTIC SUCCESSFUL COMPLETION + +TEST RESULT: Passed. + + + +------------------------------------------------ +VMACK - Virtual Memory Array Firmware Diagnostic +------------------------------------------------ + +TESTED DEVICE: CPU (hp2100_cpu5.c) + +BINARY FILE: 92084-16423 Rev. 2121 + +HOST SYSTEM: RTE-6/VM Rev. 6200 + +CONFIGURATION: sim> set CPU 1000-F + sim> set CPU VMA + sim> go + +TEST REPORT: VMACK - VMA FIRMWARE DIAGNOSTIC, FIRMWARE REV# 003 + VMACK - .IMAR NO ERRORS DETECTED PASS# 1 + VMACK - .JMAR NO ERRORS DETECTED PASS# 1 + VMACK - .LBP NO ERRORS DETECTED PASS# 1 + VMACK - .LBPR NO ERRORS DETECTED PASS# 1 + VMACK - .LPX NO ERRORS DETECTED PASS# 1 + VMACK - .LPXR NO ERRORS DETECTED PASS# 1 + VMACK - .PMAP NO ERRORS DETECTED PASS# 1 + VMACK - .IMAP NO ERRORS DETECTED PASS# 1 + VMACK - .JMAP NO ERRORS DETECTED PASS# 1 + +TEST RESULT: Passed. + + + +-------------------------------------------------- +VISOD - Vector Instruction Set Firmware Diagnostic +-------------------------------------------------- + +TESTED DEVICE: CPU (hp2100_cpu7.c) + +BINARY FILE: 12824-16002 Rev. 2026 + +HOST SYSTEM: RTE-IVB Rev. 5010 + +CONFIGURATION: sim> set CPU 1000-F + sim> set CPU VIS + sim> go + +TEST REPORT: VIS ON-LINE DIAGNOSTIC SUCCESSFUL COMPLETION + +TEST RESULT: Passed. + + + +-------------------------------------------------- +VISOD - Vector Instruction Set Firmware Diagnostic +-------------------------------------------------- + +TESTED DEVICE: CPU (hp2100_cpu7.c) + +BINARY FILE: 12829-16006 Rev. 2226 + +HOST SYSTEM: RTE-6/VM Rev. 6200 + +CONFIGURATION: sim> set CPU 1000-F + sim> set CPU VIS + sim> go + +TEST REPORT: VIS ON-LINE DIAGNOSTIC SUCCESSFUL COMPLETION + +TEST RESULT: Passed. + + + +--------------------------------------- +SDIAG - SIGNAL/1000 Firmware Diagnostic +--------------------------------------- + +TESTED DEVICE: CPU (hp2100_cpu7.c) + +BINARY FILE: 92835-16006 Rev. 2040 + +HOST SYSTEM: RTE-6/VM Rev. 6200 + +CONFIGURATION: sim> set CPU 1000-F + sim> set CPU VIS + sim> set CPU SIGNAL + sim> go + +TEST REPORT: SIGNAL/1000 FIRMWARE DIAGNOSTIC + + SIGNAL/1000 FIRMWARE DIAGNOSTIC SUCCESSFUL COMPLETION + +TEST RESULT: Passed. diff --git a/HP2100/hp2100_dq.c b/HP2100/hp2100_dq.c index 6e3fcf6c..50227a7e 100644 --- a/HP2100/hp2100_dq.c +++ b/HP2100/hp2100_dq.c @@ -331,7 +331,7 @@ switch (inst) { /* case on opcode */ default: break; - } + } if (IR & I_HC) { clrFSR (devd); } /* H/C option */ return dat; diff --git a/HP2100/hp2100_ds.c b/HP2100/hp2100_ds.c index 10fbef9a..08d38143 100644 --- a/HP2100/hp2100_ds.c +++ b/HP2100/hp2100_ds.c @@ -1,6 +1,6 @@ /* hp2100_ds.c: HP 2100 13037 disk controller simulator - Copyright (c) 2004-2006, Robert M. Supnik + Copyright (c) 2004-2007, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,7 +25,9 @@ ds 13037 disk controller - 28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified) + 31-Dec-07 JDB Corrected and verified ioCRS action + 20-Dec-07 JDB Corrected DPTR register definition from FLDATA to DRDATA + 28-Dec-06 JDB Added ioCRS state to I/O decoders 03-Aug-06 JDB Fixed REQUEST STATUS command to clear status-1 Removed redundant attached test in "ds_detach" 18-Mar-05 RMS Added attached test to detach routine @@ -497,7 +499,7 @@ REG ds_reg[] = { { FLDATA (EOC, ds_eoc, 0) }, { FLDATA (EOD, ds_eod, 0) }, { BRDATA (DBUF, dsxb, 8, 16, DS_NUMWDF) }, - { FLDATA (DPTR, ds_ptr, 8) }, + { DRDATA (DPTR, ds_ptr, 8) }, { DRDATA (CTIME, ds_ctime, 24), PV_LEFT + REG_NZ }, { DRDATA (DTIME, ds_dtime, 24), PV_LEFT + REG_NZ }, { DRDATA (STIME, ds_stime, 24), PV_LEFT + REG_NZ }, @@ -598,7 +600,13 @@ switch (inst) { /* case on opcode */ dat = ds_fifo_read (); break; - case ioCRS: /* control reset (action unverif) */ + case ioCRS: /* control reset */ + clrCTL (dev); /* clear control */ + ds_cmdf = 0; /* not expecting command */ + ds_cmdp = 0; /* and none pending */ + ds_reset_cmn (&ds_dev); /* reset ctrl */ + break; + case ioCTL: /* control clear/set */ if (IR & I_CTL) { /* CLC */ clrCTL (dev); /* clear control */ @@ -738,15 +746,15 @@ switch (op) { /* Other controller commands */ - case DSC_SFM: /* set file mask */ - case DSC_CLEAR: /* clear */ - case DSC_AREC: /* address record */ - case DSC_WAKE: /* wakeup */ - case DSC_WTIO: /* write TIO */ + case DSC_SFM: /* set file mask */ + case DSC_CLEAR: /* clear */ + case DSC_AREC: /* address record */ + case DSC_WAKE: /* wakeup */ + case DSC_WTIO: /* write TIO */ ds_sched_ctrl_op (op, 0, SET_BUSY); /* schedule, busy */ break; - case DSC_END: /* end */ + case DSC_END: /* end */ ds_set_idle (); /* idle ctrl */ break; } diff --git a/HP2100/hp2100_fp.c b/HP2100/hp2100_fp.c index 1544696e..7e431ba0 100644 --- a/HP2100/hp2100_fp.c +++ b/HP2100/hp2100_fp.c @@ -1,6 +1,6 @@ /* hp2100_fp.c: HP 2100 floating point instructions - Copyright (c) 2002-2006, Robert M. Supnik + Copyright (c) 2002-2008, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,8 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 21-Jan-08 JDB Corrected fp_unpack mantissa high-word return + (from Mark Pizzolato) 01-Dec-06 JDB Reworked FFP helpers for 1000-F support, deleted f_pwr2 22-Jul-05 RMS Fixed compiler warning in Solaris (from Doug Glyn) 25-Feb-05 JDB Added FFP helpers f_pack, f_unpack, f_pwr2 @@ -397,7 +399,7 @@ uint32 operand; operand = ((uint32) packed.fpk[0] << 16) | packed.fpk[1]; UnpackFP (&fop, operand); -mantissa->fpk[0] = (uint16) fop.fr >> 16; +mantissa->fpk[0] = (uint16) (fop.fr >> 16); mantissa->fpk[1] = (uint16) fop.fr; *exponent = fop.exp; return 0; diff --git a/HP2100/hp2100_fp1.c b/HP2100/hp2100_fp1.c index 9215363a..21793fdf 100644 --- a/HP2100/hp2100_fp1.c +++ b/HP2100/hp2100_fp1.c @@ -1,6 +1,6 @@ /* hp2100_fp1.c: HP 1000 multiple-precision floating point routines - Copyright (c) 2005-2006, J. David Bryan + Copyright (c) 2005-2008, 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"), @@ -23,6 +23,8 @@ in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the author. + 10-May-08 JDB Fixed uninitialized return in fp_accum when setting + 19-Mar-08 JDB Reworked "complement" to avoid inlining bug in gcc-4.x 01-Dec-06 JDB Reworked into generalized multiple-precision ops for FPP 12-Oct-06 JDB Altered x_trun for F-Series FFP compatibility Added F-Series ..TCM FFP helpers @@ -396,7 +398,7 @@ return bits_lost; static t_int64 unpack_int (OP packed, OPSIZE precision) { -int32 i; +uint32 i; t_uint64 unpacked = 0; if (precision == in_s) @@ -438,11 +440,6 @@ unpacked.mantissa = /* unpack and mask manti switch (precision) { - case in_s: - case in_d: - unpacked.exponent = 0; /* integers don't use exponent */ - break; - case fp_f: case fp_x: case fp_t: @@ -457,6 +454,10 @@ switch (precision) { break; case fp_a: /* no action for value in accum */ + case in_s: /* integers don't use exponent */ + case in_d: /* integers don't use exponent */ + default: + unpacked.exponent = 0; break; } @@ -657,9 +658,12 @@ return overflow; static void complement (FPU *result) { -result->mantissa = -result->mantissa; /* negate mantissa */ -if (result->mantissa == FP_MAXNMANT) /* maximum negative? */ - lsrx (result, 1); /* correct it */ +if (result->mantissa == FP_MAXNMANT) { /* maximum negative? */ + result->mantissa = FP_ONEHALF; /* complement of -1.0 * 2 ^ n */ + result->exponent = result->exponent + 1; /* is 0.5 * 2 ^ (n + 1) */ + } +else + result->mantissa = -result->mantissa; /* negate mantissa */ return; } @@ -1278,7 +1282,7 @@ return overflow; OP fp_accum (const OP *operand, OPSIZE precision) { -OP result; +OP result = NOP; uint16 opcode = (uint16) precision | SIGN; /* add special mode bit */ if (operand) diff --git a/HP2100/hp2100_ipl.c b/HP2100/hp2100_ipl.c index 48c27f98..b36e4cdf 100644 --- a/HP2100/hp2100_ipl.c +++ b/HP2100/hp2100_ipl.c @@ -500,7 +500,7 @@ if (sim_switches & SWMASK ('W')) { /* wait? */ if ((i % 10) == 0) /* status every 10 sec */ printf ("Waiting for connnection\n"); sim_os_sleep (1); /* sleep 1 sec */ - } + } if (t) printf ("Connection established\n"); } return SCPE_OK; diff --git a/HP2100/hp2100_mt.c b/HP2100/hp2100_mt.c index 635a5844..61f379ee 100644 --- a/HP2100/hp2100_mt.c +++ b/HP2100/hp2100_mt.c @@ -287,7 +287,7 @@ switch (inst) { /* case on opcode */ (mtc_fnc == FNC_WC) && (mt_ptr > 0)) { /* yes, bad rec */ if (st = sim_tape_wrrecf (&mtc_unit, mtxb, mt_ptr | MTR_ERF)) mt_map_err (&mtc_unit, st); - } + } if (((mtc_fnc == FNC_REW) || (mtc_fnc == FNC_RWS)) && sim_is_active (&mtc_unit)) sim_cancel (&mtc_unit); mtc_1st = mtc_dtf = 0; @@ -362,7 +362,7 @@ if ((mtc_unit.flags & UNIT_ATT) == 0) { /* offline? */ mtc_sta = STA_LOCAL | STA_REJ; /* rejected */ setFSR (devc); /* set cch flg */ return IORETURN (mtc_stopioe, SCPE_UNATT); - } + } switch (mtc_fnc) { /* case on function */ diff --git a/HP2100/hp2100_mux.c b/HP2100/hp2100_mux.c index 1bb073ff..2ec6c537 100644 --- a/HP2100/hp2100_mux.c +++ b/HP2100/hp2100_mux.c @@ -1,6 +1,6 @@ /* hp2100_mux.c: HP 2100 12920A terminal multiplexor simulator - Copyright (c) 2002-2007, Robert M Supnik + Copyright (c) 2002-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ mux,muxl,muxc 12920A terminal multiplexor + 16-Apr-08 JDB Sync mux poll with console poll for idle compatibility 06-Mar-07 JDB Corrected "mux_sta" size from 16 to 21 elements Fixed "muxc_reset" to clear lines 16-20 26-Feb-07 JDB Added debug printouts @@ -75,7 +76,6 @@ #define UNIT_V_DIAG (TTUF_V_UF + 1) /* loopback diagnostic */ #define UNIT_MDM (1 << UNIT_V_MDM) #define UNIT_DIAG (1 << UNIT_V_DIAG) -#define MUXU_INIT_POLL 8000 #define MUXL_WAIT 500 /* Channel number (OTA upper, LIA lower or upper) */ @@ -174,7 +174,6 @@ uint8 mux_rchp[MUX_LINES + MUX_ILINES]; /* rcv chr pend */ uint8 mux_xdon[MUX_LINES]; /* xmt done */ uint8 muxc_ota[MUX_LINES]; /* ctrl: Cn,ESn,SSn */ uint8 muxc_lia[MUX_LINES]; /* ctrl: Sn */ -uint32 mux_tps = 100; /* polls/second */ uint32 muxl_ibuf = 0; /* low in: rcv data */ uint32 muxl_obuf = 0; /* low out: param */ uint32 muxu_ibuf = 0; /* upr in: status */ @@ -229,7 +228,7 @@ DEBTAB mux_deb[] = { { "CMDS", DEB_CMDS }, { "CPU", DEB_CPU }, { "XFER", DEB_XFER }, - { NULL, 0 } }; + { NULL, 0 } }; DIB mux_dib[] = { { MUXL, 0, 0, 0, 0, 0, &muxlio }, @@ -247,7 +246,7 @@ DIB mux_dib[] = { muxu_mod MUX modifiers list */ -UNIT muxu_unit = { UDATA (&muxi_svc, UNIT_ATTABLE, 0), MUXU_INIT_POLL }; +UNIT muxu_unit = { UDATA (&muxi_svc, UNIT_ATTABLE, 0), POLL_WAIT }; REG muxu_reg[] = { { ORDATA (IBUF, muxu_ibuf, 16) }, @@ -398,7 +397,7 @@ DEVICE muxc_dev = { &muxc_dib, DEV_DISABLE }; -/* IO instructions: data cards +/* I/O instructions: data cards Implementation note: the operating manual says that "at least 100 milliseconds of CLC 0s must be programmed" by systems employing the @@ -486,7 +485,7 @@ switch (inst) { /* case on opcode */ fprintf (sim_deb, ">>MUXl STC: Transmit channel %d parameter %06o stored\n", ln, muxl_obuf); - } + } else { /* data */ if (mux_xpar[ln] & OTL_TPAR) /* parity requested? */ @@ -500,7 +499,7 @@ switch (inst) { /* case on opcode */ if (DEBUG_PRI (muxu_dev, DEB_CMDS)) fprintf (sim_deb, ">>MUXl STC: Transmit channel %d data overrun\n", ln); - } + } else { if (muxu_unit.flags & UNIT_DIAG) /* loopback? */ mux_ldsc[ln].conn = 1; /* connect this line */ @@ -509,7 +508,7 @@ switch (inst) { /* case on opcode */ fprintf (sim_deb, ">>MUXl STC: Transmit channel %d data %06o scheduled\n", ln, muxl_obuf); - } + } } } else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* line invalid */ @@ -586,12 +585,12 @@ switch (inst) { /* case on opcode */ return dat; } -/* IO instructions: control card +/* I/O instructions: control card In diagnostic mode, the control signals C1 and C2 are looped back to status signals S1 and S2. Changing the control signals may cause an interrupt, so a test is performed after OTx processing. - */ +*/ int32 muxcio (int32 inst, int32 IR, int32 dat) { @@ -679,7 +678,7 @@ switch (inst) { /* case on opcode */ default: break; - } + } if (IR & I_HC) { /* H/C option */ clrFSR (dev); /* clear flag */ @@ -696,15 +695,15 @@ return dat; t_stat muxi_svc (UNIT *uptr) { -int32 ln, c, t; +int32 ln, c; t_bool loopback; loopback = ((muxu_unit.flags & UNIT_DIAG) != 0); /* diagnostic mode? */ if (!loopback) { /* terminal mode? */ if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */ - t = sim_rtcn_calb (mux_tps, TMR_MUX); /* calibrate */ - sim_activate (uptr, t); /* continue poll */ + muxu_unit.wait = sync_poll (SERVICE); /* synchronize poll */ + sim_activate (uptr, muxu_unit.wait); /* continue poll */ ln = tmxr_poll_conn (&mux_desc); /* look for connect */ if (ln >= 0) { /* got one? */ if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */ @@ -746,7 +745,7 @@ for (ln = 0; ln < MUX_LINES; ln++) { /* loop thru lines */ } } mux_rbuf[ln] = c; /* save char */ - } + } mux_rchp[ln] = 1; /* char pending */ @@ -888,7 +887,7 @@ return; generated. Depending on the scan flag, we check either all 16 lines or just the current line. If an interrupt is requested, the channel counter indicates the interrupting channel. - */ +*/ void mux_ctrl_int (void) { @@ -954,7 +953,7 @@ return; t_stat muxc_reset (DEVICE *dptr) { -int32 i, t; +int32 i; if (dptr == &muxc_dev) { /* make all consistent */ hp_enbdis_pair (dptr, &muxl_dev); @@ -977,8 +976,8 @@ muxc_dib.flg = muxc_dib.fbf = muxc_dib.srq = 1; muxc_chan = muxc_scan = 0; /* init modem scan */ if (muxu_unit.flags & UNIT_ATT) { /* master att? */ if (!sim_is_active (&muxu_unit)) { - t = sim_rtcn_init (muxu_unit.wait, TMR_MUX); - sim_activate (&muxu_unit, t); /* activate */ + muxu_unit.wait = sync_poll (INITIAL); /* synchronize poll */ + sim_activate (&muxu_unit, muxu_unit.wait); /* activate */ } } else sim_cancel (&muxu_unit); /* else stop */ @@ -993,15 +992,14 @@ return SCPE_OK; t_stat mux_attach (UNIT *uptr, char *cptr) { t_stat r; -int32 t; if (muxu_unit.flags & UNIT_DIAG) /* diag mode? */ return SCPE_NOFNC; /* command not allowed */ r = tmxr_attach (&mux_desc, uptr, cptr); /* attach */ if (r != SCPE_OK) return r; /* error */ -t = sim_rtcn_init (muxu_unit.wait, TMR_MUX); -sim_activate (uptr, t); /* start poll */ +muxu_unit.wait = sync_poll (INITIAL); /* synchronize poll */ +sim_activate (uptr, muxu_unit.wait); /* start poll */ return SCPE_OK; } @@ -1035,7 +1033,7 @@ return r; all of the flags are set when the multiplexer is first attached. Until then, the enable flags default to "not enabled," so we enable them explicitly here.) - */ +*/ t_stat mux_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc) { diff --git a/HP2100/hp2100_stddev.c b/HP2100/hp2100_stddev.c index 5e03fac1..8923943c 100644 --- a/HP2100/hp2100_stddev.c +++ b/HP2100/hp2100_stddev.c @@ -1,6 +1,6 @@ /* hp2100_stddev.c: HP2100 standard devices simulator - Copyright (c) 1993-2006, Robert M. Supnik + Copyright (c) 1993-2008, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -28,7 +28,15 @@ tty 12531C buffered teleprinter interface clk 12539C time base generator - 28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified) + 25-Apr-08 JDB Changed TTY output wait from 100 to 200 for MSU BASIC + 18-Apr-08 JDB Removed redundant control char handling definitions + 14-Apr-08 JDB Changed TTY console poll to 10 msec. real time + Synchronized CLK with TTY if set for 10 msec. + Added UNIT_IDLE to TTY and CLK + 09-Jan-08 JDB Fixed PTR trailing null counter for tape re-read + 31-Dec-07 JDB Added IPTICK register to CLK to display CPU instr/tick + Corrected and verified ioCRS actions + 28-Dec-06 JDB Added ioCRS state to I/O decoders 22-Nov-05 RMS Revised for new terminal processing routines 13-Sep-04 JDB Added paper tape loop mode, DIAG/READER modifiers to PTR Added PV_LEFT to PTR TRLLIM register @@ -66,10 +74,20 @@ upon EOF. Normal mode EOF action is to supply TRLLIM nulls and then either return SCPE_IOERR or SCPE_OK without setting the device flag. - The clock autocalibrates. If the specified clock frequency is below - 10Hz, the clock service routine runs at 10Hz and counts down a repeat - counter before generating an interrupt. Autocalibration will not work - if the clock is running at 1Hz or less. + To support CPU idling, the teleprinter interface (which doubles as the + simulator console) polls for input using a calibrated timer with a ten + millisecond period. Other polled-keyboard input devices (multiplexers and + the BACI card) synchronize with the console poll to ensure maximum available + idle time. The console poll is guaranteed to run, as the TTY device cannot + be disabled. + + The clock (time base generator) autocalibrates. If the CLK is set to a ten + millisecond period (e.g., as under RTE), it is synchronized to the console + poll. Otherwise (e.g., as under DOS or TSB, which use 100 millisecond + periods), it runs asynchronously. If the specified clock frequency is below + 10Hz, the clock service routine runs at 10Hz and counts down a repeat counter + before generating an interrupt. Autocalibration will not work if the clock + is running at 1Hz or less. Clock diagnostic mode corresponds to inserting jumper W2 on the 12539C. This turns off autocalibration and divides the longest time intervals down @@ -80,23 +98,15 @@ - 2748B Tape Reader Operating and Service Manual (02748-90041, Oct-1977) - 12597A 8-Bit Duplex Register Interface Kit Operating and Service Manual (12597-9002, Sep-1974) + - 12531C Buffered Teleprinter Interface Kit Operating and Service Manual + (12531-90033, Nov-1972) - 12539C Time Base Generator Interface Kit Operating and Service Manual (12539-90008, Jan-1975) */ #include "hp2100_defs.h" -#include -#define CHAR_FLAG(c) (1u << (c)) - -#define BEL_FLAG CHAR_FLAG('\a') -#define BS_FLAG CHAR_FLAG('\b') -#define LF_FLAG CHAR_FLAG('\n') -#define CR_FLAG CHAR_FLAG('\r') -#define HT_FLAG CHAR_FLAG('\t') - -#define FULL_SET 0xFFFFFFFF -#define CNTL_SET (BEL_FLAG | BS_FLAG | HT_FLAG | LF_FLAG | CR_FLAG) +#define TTY_OUT_WAIT 200 /* TTY output wait */ #define UNIT_V_DIAG (TTUF_V_UF + 0) /* diag mode */ #define UNIT_V_AUTOLF (TTUF_V_UF + 1) /* auto linefeed */ @@ -125,8 +135,6 @@ int32 tty_buf = 0; /* tty buffer */ int32 tty_mode = 0; /* tty mode */ int32 tty_shin = 0377; /* tty shift in */ int32 tty_lf = 0; /* lf flag */ -uint32 tty_cntlprt = CNTL_SET; /* tty print flags */ -uint32 tty_cntlset = CNTL_SET; /* tty cntl set */ int32 clk_select = 0; /* clock time select */ int32 clk_error = 0; /* clock error */ int32 clk_ctr = 0; /* clock counter */ @@ -139,6 +147,7 @@ int32 clk_tps[8] = { /* clock tps */ int32 clk_rpt[8] = { /* number of repeats */ 1, 1, 1, 1, 10, 100, 1000, 10000 }; +uint32 clk_tick = 0; /* instructions per tick */ DEVICE ptr_dev, ptp_dev, tty_dev, clk_dev; int32 ptrio (int32 inst, int32 IR, int32 dat); @@ -266,9 +275,9 @@ DEVICE ptp_dev = { DIB tty_dib = { TTY, 0, 0, 0, 0, 0, &ttyio }; UNIT tty_unit[] = { - { UDATA (&tti_svc, TT_MODE_UC, 0), KBD_POLL_WAIT }, - { UDATA (&tto_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&tto_svc, UNIT_SEQ+UNIT_ATTABLE+TT_MODE_8B, 0), SERIAL_OUT_WAIT } + { UDATA (&tti_svc, UNIT_IDLE | TT_MODE_UC, 0), POLL_WAIT }, + { UDATA (&tto_svc, TT_MODE_UC, 0), TTY_OUT_WAIT }, + { UDATA (&tto_svc, UNIT_SEQ | UNIT_ATTABLE | TT_MODE_8B, 0), SERIAL_OUT_WAIT } }; REG tty_reg[] = { @@ -287,8 +296,6 @@ REG tty_reg[] = { { DRDATA (TTIME, tty_unit[TTO].wait, 24), REG_NZ + PV_LEFT }, { DRDATA (PPOS, tty_unit[TTP].pos, T_ADDR_W), PV_LEFT }, { FLDATA (STOP_IOE, ttp_stopioe, 0) }, - { ORDATA (CNTLPRT, tty_cntlprt, 32), REG_HRO }, - { ORDATA (CNTLSET, tty_cntlset, 32), REG_HIDDEN }, { ORDATA (DEVNO, tty_dib.devno, 6), REG_HRO }, { NULL } }; @@ -323,7 +330,7 @@ DEVICE tty_dev = { DIB clk_dib = { CLK, 0, 0, 0, 0, 0, &clkio }; -UNIT clk_unit = { UDATA (&clk_svc, 0, 0) }; +UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE, 0) }; REG clk_reg[] = { { ORDATA (SEL, clk_select, 3) }, @@ -335,6 +342,7 @@ REG clk_reg[] = { { FLDATA (SRQ, clk_dib.srq, 0) }, { FLDATA (ERR, clk_error, CLK_V_ERROR) }, { BRDATA (TIME, clk_time, 10, 24, 8) }, + { DRDATA (IPTICK, clk_tick, 24), PV_RSPC | REG_RO }, { ORDATA (DEVNO, clk_dib.devno, 6), REG_HRO }, { NULL } }; @@ -384,7 +392,8 @@ switch (inst) { /* case on opcode */ dat = ptr_unit.buf; break; - case ioCRS: /* control reset (action unverif) */ + case ioCRS: /* control reset */ + /* action same as CLC */ case ioCTL: /* control clear/set */ if (IR & I_CTL) { /* CLC */ clrCMD (dev); /* clear cmd, ctl */ @@ -443,6 +452,10 @@ while ((temp = getc (ptr_unit.fileref)) == EOF) { /* read byte, error? */ setFSR (dev); /* set flag */ ptr_unit.buf = temp & 0377; /* put byte in buf */ ptr_unit.pos = ftell (ptr_unit.fileref); + +if (temp) /* character non-null? */ + ptr_trlcnt = 0; /* clear trailing null counter */ + return SCPE_OK; } @@ -562,7 +575,8 @@ switch (inst) { /* case on opcode */ ptp_unit.buf = dat; break; - case ioCRS: /* control reset (action unverif) */ + case ioCRS: /* control reset */ + /* action same as CLC */ case ioCTL: /* control clear/set */ if (IR & I_CTL) { /* CLC */ clrCMD (dev); /* clear cmd, ctl */ @@ -577,7 +591,7 @@ switch (inst) { /* case on opcode */ default: break; - } + } if (IR & I_HC) { clrFSR (dev); } /* H/C option */ return dat; @@ -648,7 +662,15 @@ switch (inst) { /* case on opcode */ tty_buf = dat & 0377; break; - case ioCRS: /* control reset (action unverif) */ + case ioCRS: /* control reset */ + clrCTL (dev); /* clear control */ + setFSR (dev); /* set flag */ + tty_mode = TM_KBD; /* set tty, clear print/punch */ + tty_buf = 0; /* clear buffer */ + tty_shin = 0377; /* input inactive */ + tty_lf = 0; /* no lf pending */ + break; + case ioCTL: /* control clear/set */ if (IR & I_CTL) { clrCTL (dev); } /* CLC */ else { /* STC */ @@ -666,7 +688,23 @@ if (IR & I_HC) { clrFSR (dev); } /* H/C option */ return dat; } -/* Unit service routines. Note from Dave Bryan: +/* TTY input service routine. + + The console input poll routine is scheduled with a ten millisecond period + using a calibrated timer, which is the source of event timing for all of the + keyboard polling routines. Synchronizing other keyboard polls with the + console poll ensures maximum idle time. + + Several HP operating systems require a CR and LF sequence for line + termination. This is awkward on a PC, as there is no LF key (CTRL+J is + needed instead). We provide an AUTOLF mode to add a LF automatically to each + CR input. When this mode is set, entering CR will set a flag, which will + cause a LF to be supplied automatically at the next input poll. + + The 12531C teleprinter interface and the later 12880A CRT interface provide a + clever mechanism to detect a keypress during output. This is used by DOS and + RTE to allow the user to interrupt lengthy output operations to enter system + commands. Referring to the 12531C schematic, the terminal input enters on pin X ("DATA FROM EIA COMPATIBLE DEVICE"). The signal passes through four @@ -688,15 +726,18 @@ return dat; the output operation, the register will read as all ones (octal 377). If, however, any key was struck, at least one zero bit will be present. If the register value doesn't equal 377, the driver sets the system "operator - attention" flag, which will cause RTE to output the asterisk and initiate a - terminal read when the current output line is completed. */ + attention" flag, which will cause DOS or RTE to output an asterisk prompt and + initiate a terminal read when the current output line is completed. +*/ t_stat tti_svc (UNIT *uptr) { int32 c, dev; -dev = tty_dib.devno; /* get device no */ +uptr->wait = sim_rtcn_calb (POLL_RATE, TMR_POLL); /* calibrate poll timer */ sim_activate (uptr, uptr->wait); /* continue poll */ + +dev = tty_dib.devno; /* get device no */ tty_shin = 0377; /* assume inactive */ if (tty_lf) { /* auto lf pending? */ c = 012; /* force lf */ @@ -721,6 +762,8 @@ else tty_shin = c; /* no, char shifts in */ return SCPE_OK; } +/* TTY output service routine */ + t_stat tto_svc (UNIT *uptr) { int32 c, dev; @@ -767,7 +810,7 @@ if (tty_mode & TM_PUN) { /* punching? */ return SCPE_OK; } -/* Reset routine */ +/* TTY reset routine */ t_stat tty_reset (DEVICE *dptr) { @@ -777,6 +820,8 @@ tty_mode = TM_KBD; /* enable input */ tty_buf = 0; tty_shin = 0377; /* input inactive */ tty_lf = 0; /* no lf pending */ +tty_unit[TTI].wait = POLL_WAIT; /* reset initial poll */ +sim_rtcn_init (tty_unit[TTI].wait, TMR_POLL); /* init poll timer */ sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* activate poll */ sim_cancel (&tty_unit[TTO]); /* cancel output */ return SCPE_OK; @@ -801,7 +846,47 @@ if (u != TTI) return SCPE_NOFNC; return SCPE_OK; } -/* Clock IO instructions */ +/* Synchronize polling. + + Return an event time corresponding either with the amount of time remaining + in the current poll (mode = INITIAL) or the amount of time in a full poll + period (mode = SERVICE). If the former call is made when the device service + routine is started, then making the latter call during unit service will + ensure that the polls remain synchronized. + */ + +int32 sync_poll (POLLMODE poll_mode) +{ +int32 poll_time; + + if (poll_mode == INITIAL) { + poll_time = sim_is_active (&tty_unit[TTI]); + + if (poll_time) + return poll_time; + else + return POLL_WAIT; + } + else + return tty_unit[TTI].wait; +} + + +/* Clock I/O instructions. + + The time base generator (CLK) provides periodic interrupts from 100 + microseconds to 1000 seconds. The CLK uses a calibrated timer to provide the + time base. For periods ranging from 1 to 1000 seconds, a 100 millisecond + timer is used, and 10 to 10000 ticks are counted before setting the device + flag to indicate that the period has expired. + + If the period is set to ten milliseconds, the console poll timer is used + instead of an independent timer. This is to maximize the idle period. + + In diagnostic mode, the clock period is set to the expected number of CPU + instructions, rather than wall-clock time, so that the diagnostic executes as + expected. +*/ int32 clkio (int32 inst, int32 IR, int32 dat) { @@ -836,7 +921,8 @@ switch (inst) { /* case on opcode */ clrCTL (dev); /* clear control */ break; - case ioCRS: /* control reset (action unverif) */ + case ioCRS: /* control reset */ + /* action same as CLC */ case ioCTL: /* control clear/set */ if (IR & I_CTL) { /* CLC */ clrCTL (dev); /* turn off clock */ @@ -844,9 +930,22 @@ switch (inst) { /* case on opcode */ } else { /* STC */ setCTL (dev); /* set CTL */ + + if (clk_unit.flags & UNIT_DIAG) /* diag mode? */ + clk_unit.flags = clk_unit.flags & ~UNIT_IDLE; /* not calibrated */ + else + clk_unit.flags = clk_unit.flags | UNIT_IDLE; /* is calibrated */ + if (!sim_is_active (&clk_unit)) { /* clock running? */ - sim_activate (&clk_unit, - sim_rtc_init (clk_delay (0))); /* no, start clock */ + clk_tick = clk_delay (0); /* get tick count */ + + if ((clk_unit.flags & UNIT_DIAG) == 0) /* calibrated? */ + if (clk_select == 2) /* 10 msec. interval? */ + clk_tick = sync_poll (INITIAL); /* sync poll */ + else + sim_rtcn_init (clk_tick, TMR_CLK); /* initialize timer */ + + sim_activate (&clk_unit, clk_tick); /* start clock */ clk_ctr = clk_delay (1); /* set repeat ctr */ } clk_error = 0; /* clear error */ @@ -861,21 +960,29 @@ if (IR & I_HC) { clrFSR (dev); } /* H/C option */ return dat; } -/* Unit service */ +/* CLK unit service. + + As with the I/O handler, if the time base period is set to ten milliseconds, + the console poll timer is used instead of an independent timer. +*/ t_stat clk_svc (UNIT *uptr) { -int32 tim, dev; +int32 dev; dev = clk_dib.devno; /* get device no */ if (!CTL (dev)) return SCPE_OK; /* CTL off? done */ + if (clk_unit.flags & UNIT_DIAG) /* diag mode? */ - tim = clk_delay (0); /* get fixed delay */ -else tim = sim_rtc_calb (clk_tps[clk_select]); /* calibrate delay */ -sim_activate (uptr, tim); /* reactivate */ + clk_tick = clk_delay (0); /* get fixed delay */ +else if (clk_select == 2) /* 10 msec period? */ + clk_tick = sync_poll (SERVICE); /* sync poll */ +else + clk_tick = sim_rtcn_calb (clk_tps[clk_select], TMR_CLK); /* calibrate delay */ + +sim_activate (uptr, clk_tick); /* reactivate */ clk_ctr = clk_ctr - 1; /* decrement counter */ if (clk_ctr <= 0) { /* end of interval? */ - tim = FLG (dev); if (FLG (dev)) clk_error = CLK_ERROR; /* overrun? error */ else { setFSR (dev); } /* else set flag */ clk_ctr = clk_delay (1); /* reset counter */ diff --git a/HP2100/hp2100_sys.c b/HP2100/hp2100_sys.c index 7ea5fe51..b4abeaca 100644 --- a/HP2100/hp2100_sys.c +++ b/HP2100/hp2100_sys.c @@ -1,6 +1,6 @@ /* hp2100_sys.c: HP 2100 simulator interface - Copyright (c) 1993-2005, Robert M. Supnik + Copyright (c) 1993-2008, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,9 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 24-Apr-08 JDB Changed fprint_sym to handle step with irq pending + 07-Dec-07 JDB Added BACI device + 27-Nov-07 JDB Added RTE OS/VMA/EMA mnemonics 21-Dec-06 JDB Added "fwanxm" external for sim_load check 19-Nov-04 JDB Added STOP_OFFLINE, STOP_PWROFF messages 25-Sep-04 JDB Added memory protect device @@ -43,6 +46,7 @@ */ #include "hp2100_defs.h" +#include "hp2100_cpu.h" #include extern DEVICE cpu_dev; @@ -52,6 +56,7 @@ extern DEVICE dma0_dev, dma1_dev; extern DEVICE ptr_dev, ptp_dev; extern DEVICE tty_dev, clk_dev; extern DEVICE lps_dev, lpt_dev; +extern DEVICE baci_dev; extern DEVICE mtd_dev, mtc_dev; extern DEVICE msd_dev, msc_dev; extern DEVICE dpd_dev, dpc_dev; @@ -93,6 +98,7 @@ DEVICE *sim_devices[] = { &clk_dev, &lps_dev, &lpt_dev, + &baci_dev, &dpd_dev, &dpc_dev, &dqd_dev, &dqc_dev, &drd_dev, &drc_dev, @@ -180,6 +186,7 @@ for (zerocnt = 1;; zerocnt = -10) { /* block loop */ #define I_V_IO2 7 /* I/O only */ #define I_V_EGZ 010 /* ext grp, 1 op + 0 */ #define I_V_EG2 011 /* ext grp, 2 op */ +#define I_V_ALT 012 /* alternate use instr */ #define I_NPN (I_V_NPN << I_V_FL) #define I_NPC (I_V_NPC << I_V_FL) #define I_MRF (I_V_MRF << I_V_FL) @@ -190,14 +197,36 @@ for (zerocnt = 1;; zerocnt = -10) { /* block loop */ #define I_IO2 (I_V_IO2 << I_V_FL) #define I_EGZ (I_V_EGZ << I_V_FL) #define I_EG2 (I_V_EG2 << I_V_FL) +#define I_ALT (I_V_ALT << I_V_FL) static const int32 masks[] = { 0177777, 0176777, 0074000, 0170000, 0177760, 0177777, 0176700, 0177700, - 0177777, 0177777 + 0177777, 0177777, 0177777 }; static const char *opcode[] = { + +/* These mnemonics are used by debug printouts, so put them first. */ + + "$LIBR", "$LIBX", ".TICK", ".TNAM", /* RTE-6/VM OS firmware */ + ".STIO", ".FNW", ".IRT", ".LLS", + ".SIP", ".YLD", ".CPM", ".ETEQ", + ".ENTN", "$OTST", ".ENTC", ".DSPI", + "$DCPC", "$MPV", "$DEV", "$TBG", /* alternates for dual-use */ + + ".PMAP", "$LOC", "$VTST",/* --- */ /* RTE-6/VM VMA firmware */ +/* --- --- --- --- */ + ".IMAP", ".IMAR", ".JMAP", ".JMAR", + ".LPXR", ".LPX", ".LBPR", ".LBP", + + ".EMIO", "MMAP", "$ETST",/* --- */ /* RTE-IV EMA firmware */ +/* --- --- --- --- */ +/* --- --- --- --- */ +/* --- --- --- */ ".EMAP", + +/* Regular mnemonics. */ + "NOP", "NOP", "AND", "JSB", "XOR", "JMP", "IOR", "ISZ", "ADA", "ADB" ,"CPA", "CPB", @@ -241,6 +270,22 @@ static const char *opcode[] = { }; static const int32 opc_val[] = { + 0105340+I_NPN, 0105341+I_NPN, 0105342+I_NPN, 0105343+I_NPN, /* RTE-6/VM OS */ + 0105344+I_NPN, 0105345+I_NPN, 0105346+I_NPN, 0105347+I_NPN, + 0105350+I_NPN, 0105351+I_NPN, 0105352+I_NPN, 0105353+I_NPN, + 0105354+I_ALT, 0105355+I_ALT, 0105356+I_ALT, 0105357+I_ALT, + 0105354+I_NPN, 0105355+I_NPN, 0105356+I_NPN, 0105357+I_NPN, /* alternates */ + + 0105240+I_ALT, 0105241+I_ALT, 0105242+I_ALT, /* --- */ /* RTE-6/VM VMA */ +/* --- --- --- --- */ + 0105250+I_NPN, 0105251+I_NPN, 0105252+I_NPN, 0105253+I_NPN, + 0105254+I_NPN, 0105255+I_NPN, 0105256+I_NPN, 0105257+I_ALT, + + 0105240+I_NPN, 0105241+I_NPN, 0105242+I_NPN, /* RTE-IV EMA */ +/* --- --- --- --- */ +/* --- --- --- --- */ +/* --- --- --- */ 0105257+I_NPN, + 0000000+I_NPN, 0002000+I_NPN, 0010000+I_MRF, 0014000+I_MRF, 0020000+I_MRF, 0024000+I_MRF, 0030000+I_MRF, 0034000+I_MRF, 0040000+I_MRF, 0044000+I_MRF, 0050000+I_MRF, 0054000+I_MRF, @@ -339,6 +384,7 @@ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) { int32 cflag, cm, i, j, inst, disp; +uint32 irq; cflag = (uptr == NULL) || (uptr == &cpu_unit); inst = val[0]; @@ -354,6 +400,24 @@ if (sw & SWMASK ('C')) { /* characters? */ } if (!(sw & SWMASK ('M'))) return SCPE_ARG; +/* If we are being called as a result of a VM stop to display the next + instruction to be executed, check to see if an interrupt is pending and not + deferred. If so, then display the interrupt source and the trap cell + instruction as the instruction to be executed, rather than the instruction at + the current PC. +*/ + +if (sw & SIM_SW_STOP) { /* simulator stop? */ + irq = calc_int (); /* check interrupt */ + + if (irq && (!ion_defer || !calc_defer())) { /* pending interrupt and not deferred? */ + inst = val[0] = ReadIO (irq, SMAP); /* load trap cell instruction */ + val[1] = ReadIO (irq + 1, SMAP); /* might be multi-word */ + val[2] = ReadIO (irq + 2, SMAP); /* although it's unlikely */ + fprintf (of, "IAK %2o: ", irq); /* report acknowledged interrupt */ + } + } + for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */ if ((opc_val[i] & DMASK) == (inst & masks[j])) { /* match? */ @@ -423,7 +487,24 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ fprintf (of, " %-o", val[2] & VAMASK); if (val[2] & I_IA) fprintf (of, ",I"); return -2; /* extra words */ + + case I_V_ALT: /* alternate use instr */ + if ((inst >= 0105354) && + (inst <= 0105357) && /* RTE-6/VM OS range? */ + (addr >= 2) && + (addr <= 077)) /* in trap cell? */ + continue; /* use alternate mnemonic */ + + else if ((inst >= 0105240) && /* RTE-6/VM VMA range? */ + (inst <= 0105257) && + (cpu_unit.flags & UNIT_EMA)) /* EMA enabled? */ + continue; /* use EMA mnemonics */ + + else + fprintf (of, "%s", opcode[i]); /* print opcode */ + break; } + return SCPE_OK; } /* end if */ } /* end for */ @@ -505,7 +586,7 @@ if (opcode[i]) { /* found opcode? */ cptr = get_glyph (cptr, gbuf, 0); if (strcmp (gbuf, "C")) return SCPE_ARG; val[0] = val[0] | I_HC; - } + } break; case I_V_MRF: /* mem ref */ diff --git a/I1620/i1620_fp.c b/I1620/i1620_fp.c index 7b600265..6ce4c4b2 100644 --- a/I1620/i1620_fp.c +++ b/I1620/i1620_fp.c @@ -1,6 +1,6 @@ /* i1620_fp.c: IBM 1620 floating point simulator - Copyright (c) 2002-2005, Robert M. Supnik + Copyright (c) 2002-2008, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -30,6 +30,8 @@ M.......MEE where S represents flag bits if the mantissa or exponent are negative. + + 31-May-2008 RMS Fixed add_field call (found by Peter Schorn) */ #include "i1620_defs.h" @@ -55,7 +57,7 @@ t_stat fp_scan_mant (uint32 ad, uint32 *lnt, uint32 *zro); t_stat fp_zero (FPA *fp); extern t_stat xmt_field (uint32 d, uint32 s, uint32 skp); -extern t_stat add_field (uint32 d, uint32 s, t_bool sub, t_bool sto, int32 *sta); +extern t_stat add_field (uint32 d, uint32 s, t_bool sub, t_bool sto, uint32 skp, int32 *sta); extern t_stat mul_field (uint32 d, uint32 s); extern t_stat xmt_divd (uint32 d, uint32 s); extern t_stat div_field (uint32 dvd, uint32 dvr, int32 *ez); @@ -261,7 +263,7 @@ else if (dif < 0) { /* dst exp < src exp? */ dfp.exp = sfp.exp; /* res exp = src exp */ fp_rsh (&dfp, -dif); /* denormalize dst */ } -r = add_field (dfp.addr, sfp.addr, sub, TRUE, &sta); /* add mant, set EZ, HP */ +r = add_field (dfp.addr, sfp.addr, sub, TRUE, 0, &sta); /* add mant, set EZ, HP */ if (dif > 0) { /* src denormalized? */ sad = sfp.addr; /* restore src from */ for (i = 0; i < sfp.lnt; i++) { /* save area */ diff --git a/I7094/i7094_bugs.txt b/I7094/i7094_bug_history.txt similarity index 96% rename from I7094/i7094_bugs.txt rename to I7094/i7094_bug_history.txt index 66179037..e8fb15b8 100644 --- a/I7094/i7094_bugs.txt +++ b/I7094/i7094_bug_history.txt @@ -1,4 +1,4 @@ -Bugs found +Bugs Found and Fixed During Simulator Debug 1. CPU: MPY tested sign of AC instead of sign of MQ. 2. CPU: VLM, VDP, VDH need alternate opcode decode points for large counts. diff --git a/Ibm1130/ibm1130_sca.c b/Ibm1130/ibm1130_sca.c index 37de87f4..3571166c 100644 --- a/Ibm1130/ibm1130_sca.c +++ b/Ibm1130/ibm1130_sca.c @@ -85,8 +85,9 @@ #include "ibm1130_defs.h" #include "sim_sock.h" /* include path must include main simh directory */ #include - -extern SOCKET sim_create_sock (void); /* missing from sim_sock.h */ +#ifndef INADDR_NONE +#define INADDR_NONE ((unsigned long)-1) +#endif #define DEBUG_SCA_FLUSH 0x0001 /* debugging options */ #define DEBUG_SCA_TRANSMIT 0x0002 diff --git a/Interdata/id16_sys.c b/Interdata/id16_sys.c index 62b30dbe..97ae6550 100644 --- a/Interdata/id16_sys.c +++ b/Interdata/id16_sys.c @@ -1,6 +1,6 @@ /* id16_sys.c: Interdata 16b simulator interface - Copyright (c) 2000-2006, Robert M. Supnik + Copyright (c) 2000-2008, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 04-Feb-08 RMS Modified to allow -A, -B use with 8b devices 18-Oct-06 RMS Re-ordered device list 26-Mar-04 RMS Fixed warning with -std=c99 27-Feb-03 RMS Added relative addressing support @@ -279,29 +280,34 @@ static const uint32 opc_val[] = { t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) { -int32 c1, c2, rdx; +int32 bflag, c1, c2, rdx; t_stat r; DEVICE *dptr; if (uptr == NULL) uptr = &cpu_unit; /* anon = CPU */ -else if (uptr != &cpu_unit) return SCPE_ARG; /* CPU only */ dptr = find_dev_from_unit (uptr); /* find dev */ if (dptr == NULL) return SCPE_IERR; +if (dptr->dwidth < 16) bflag = 1; /* 8b dev? */ +else bflag = 0; /* assume 16b */ if (sw & SWMASK ('D')) rdx = 10; /* get radix */ else if (sw & SWMASK ('O')) rdx = 8; else if (sw & SWMASK ('H')) rdx = 16; else rdx = dptr->dradix; if (sw & SWMASK ('A')) { /* ASCII char? */ - c1 = (val[0] >> ((addr & 1)? 0: 8)) & 0x7F; /* get byte */ + if (bflag) c1 = val[0] & 0x7F; + else c1 = (val[0] >> ((addr & 1)? 0: 8)) & 0x7F; /* get byte */ fprintf (of, (c1 < 0x20)? "<%02X>": "%c", c1); return 0; } if (sw & SWMASK ('B')) { /* byte? */ - c1 = (val[0] >> ((addr & 1)? 0: 8)) & 0xFF; /* get byte */ + if (bflag) c1 = val[0] & 0xFF; + else c1 = (val[0] >> ((addr & 1)? 0: 8)) & 0xFF; /* get byte */ fprint_val (of, c1, rdx, 8, PV_RZRO); return 0; } +if (bflag) return SCPE_ARG; /* 16b only */ + if (sw & SWMASK ('C')) { /* string? */ c1 = (val[0] >> 8) & 0x7F; c2 = val[0] & 0x7F; @@ -462,14 +468,15 @@ return SCPE_OK; t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) { -int32 by, rdx, num; +int32 bflag, by, rdx, num; t_stat r; DEVICE *dptr; if (uptr == NULL) uptr = &cpu_unit; /* anon = CPU */ -else if (uptr != &cpu_unit) return SCPE_ARG; /* CPU only */ dptr = find_dev_from_unit (uptr); /* find dev */ if (dptr == NULL) return SCPE_IERR; +if (dptr->dwidth < 16) bflag = 1; /* 8b device? */ +else bflag = 0; /* assume 16b */ if (sw & SWMASK ('D')) rdx = 10; /* get radix */ else if (sw & SWMASK ('O')) rdx = 8; else if (sw & SWMASK ('H')) rdx = 16; @@ -477,17 +484,23 @@ else rdx = dptr->dradix; if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ - if (addr & 1) val[0] = (val[0] & ~0xFF) | ((t_value) cptr[0]); - else val[0] = (val[0] & 0xFF) | (((t_value) cptr[0]) << 8); + if (bflag) val[0] = (t_value) cptr[0]; + else val[0] = (addr & 1)? + (val[0] & ~0xFF) | ((t_value) cptr[0]): + (val[0] & 0xFF) | (((t_value) cptr[0]) << 8); return 0; } if (sw & SWMASK ('B')) { /* byte? */ by = get_uint (cptr, rdx, DMASK8, &r); /* get byte */ if (r != SCPE_OK) return SCPE_ARG; - if (addr & 1) val[0] = (val[0] & ~0xFF) | by; - else val[0] = (val[0] & 0xFF) | (by << 8); + if (bflag) val[0] = by; + else val[0] = (addr & 1)? + (val[0] & ~0xFF) | by: + (val[0] & 0xFF) | (by << 8); return 0; } +if (bflag) return SCPE_ARG; /* 16b only */ + if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII chars? */ if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ val[0] = ((t_value) cptr[0] << 8) | (t_value) cptr[1]; diff --git a/Interdata/id32_sys.c b/Interdata/id32_sys.c index e683f404..3c50c677 100644 --- a/Interdata/id32_sys.c +++ b/Interdata/id32_sys.c @@ -1,6 +1,6 @@ /* id32_sys.c: Interdata 32b simulator interface - Copyright (c) 2000-2007, Robert M. Supnik + Copyright (c) 2000-2008, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 04-Feb-08 RMS Modified to allow -A, -B use with 8b devices 25-Jan-07 RMS Fixed conflict between -h (hex) and -h (halfword) 18-Oct-06 RMS Re-ordered device list 02-Jul-04 RMS Fixed missing type in declaration @@ -337,29 +338,34 @@ return -5; t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) { -int32 c1, c2, rdx; +int32 bflag, c1, c2, rdx; t_stat r; DEVICE *dptr; if (uptr == NULL) uptr = &cpu_unit; /* anon = CPU */ -else if (uptr != &cpu_unit) return SCPE_ARG; /* only for CPU */ dptr = find_dev_from_unit (uptr); /* find dev */ if (dptr == NULL) return SCPE_IERR; +if (dptr->dwidth < 16) bflag = 1; /* 8b dev? */ +else bflag = 0; /* assume 16b */ if (sw & SWMASK ('D')) rdx = 10; /* get radix */ else if (sw & SWMASK ('O')) rdx = 8; else if (sw & SWMASK ('H')) rdx = 16; else rdx = dptr->dradix; if (sw & SWMASK ('A')) { /* ASCII char? */ - c1 = (val[0] >> ((addr & 1)? 0: 8)) & 0x7F; /* get byte */ + if (bflag) c1 = val[0] & 0x7F; + else c1 = (val[0] >> ((addr & 1)? 0: 8)) & 0x7F; /* get byte */ fprintf (of, (c1 < 0x20)? "<%02X>": "%c", c1); return 0; } if (sw & SWMASK ('B')) { /* byte? */ - c1 = (val[0] >> ((addr & 1)? 0: 8)) & 0xFF; /* get byte */ + if (bflag) c1 = val[0] & 0xFF; + else c1 = (val[0] >> ((addr & 1)? 0: 8)) & 0xFF; /* get byte */ fprint_val (of, c1, rdx, 8, PV_RZRO); return 0; } +if (bflag) return SCPE_ARG; /* 16b only */ + if (sw & SWMASK ('C')) { /* string? */ c1 = (val[0] >> 8) & 0x7F; c2 = val[0] & 0x7F; @@ -555,14 +561,15 @@ return SCPE_OK; t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) { -int32 by, rdx, num; +int32 bflag, by, rdx, num; t_stat r; DEVICE *dptr; if (uptr == NULL) uptr = &cpu_unit; /* anon = CPU */ -else if (uptr != &cpu_unit) return SCPE_ARG; /* CPU only */ dptr = find_dev_from_unit (uptr); /* find dev */ if (dptr == NULL) return SCPE_IERR; +if (dptr->dwidth < 16) bflag = 1; /* 8b device? */ +else bflag = 0; /* assume 16b */ if (sw & SWMASK ('D')) rdx = 10; /* get radix */ else if (sw & SWMASK ('O')) rdx = 8; else if (sw & SWMASK ('H')) rdx = 16; @@ -570,17 +577,23 @@ else rdx = dptr->dradix; if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ - if (addr & 1) val[0] = (val[0] & ~0xFF) | ((t_value) cptr[0]); - else val[0] = (val[0] & 0xFF) | (((t_value) cptr[0]) << 8); + if (bflag) val[0] = (t_value) cptr[0]; + else val[0] = (addr & 1)? + (val[0] & ~0xFF) | ((t_value) cptr[0]): + (val[0] & 0xFF) | (((t_value) cptr[0]) << 8); return 0; } if (sw & SWMASK ('B')) { /* byte? */ by = get_uint (cptr, rdx, DMASK8, &r); /* get byte */ if (r != SCPE_OK) return SCPE_ARG; - if (addr & 1) val[0] = (val[0] & ~0xFF) | by; - else val[0] = (val[0] & 0xFF) | (by << 8); + if (bflag) val[0] = by; + else val[0] = (addr & 1)? + (val[0] & ~0xFF) | by: + (val[0] & 0xFF) | (by << 8); return 0; } +if (bflag) return SCPE_ARG; /* 16b only */ + if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII chars? */ if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ val[0] = ((t_value) cptr[0] << 8) | (t_value) cptr[1]; diff --git a/Interdata/id_diag.txt b/Interdata/id_diag.txt index ca736d57..c0daf2fe 100644 --- a/Interdata/id_diag.txt +++ b/Interdata/id_diag.txt @@ -807,7 +807,7 @@ END OF TEST * ------------------------------------------------------------------- -Bugs found +Bugs Found and Fixed During Simulator Debug 1. CPU16: instruction decoding interpreting CPU models incorrectly 2. CPU16: SINT should not be conditional on device existing diff --git a/Interdata/id_lp.c b/Interdata/id_lp.c index c3588398..cb74d437 100644 --- a/Interdata/id_lp.c +++ b/Interdata/id_lp.c @@ -1,6 +1,6 @@ /* id_lp.c: Interdata line printer - Copyright (c) 2001-2007, Robert M. Supnik + Copyright (c) 2001-2008, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ lpt M46-206 line printer + 27-May-08 RMS Fixed bug in printing test (from Davis Johnson) 19-Jan-07 RMS Added UNIT_TEXT flag 25-Apr-03 RMS Revised for extended file support */ @@ -189,7 +190,7 @@ else if (t == CR) { /* CR? */ lpt_spnd = 1; /* set spc pend */ return lpt_bufout (uptr); /* print line */ } -else if (t >= 0x40) { /* printable? */ +else if (t >= 0x20) { /* printable? */ if ((uptr->flags & UNIT_UC) && islower (t)) /* UC only? */ t = toupper (t); if (lpt_bptr < LPT_WIDTH) lpxb[lpt_bptr++] = t; diff --git a/Interdata/id_mt.c b/Interdata/id_mt.c index c91cfc54..d08ccd19 100644 --- a/Interdata/id_mt.c +++ b/Interdata/id_mt.c @@ -54,7 +54,7 @@ #define UST u3 /* unit status */ #define UCMD u4 /* unit command */ -#define MT_MAXFR (1 << 16) /* max transfer */ +#define MT_MAXFR (1 << 24) /* max transfer */ /* Command - in UCMD */ diff --git a/NOVA/eclipse_cpu.c b/NOVA/eclipse_cpu.c index 202e37ff..7802a1a8 100644 --- a/NOVA/eclipse_cpu.c +++ b/NOVA/eclipse_cpu.c @@ -366,6 +366,7 @@ int32 speed = 0; /* Delay for each instru int32 XCT_mode = 0; /* 1 if XCT mode */ int32 XCT_inst = 0; /* XCT instruction */ int32 PPC = -1; +int32 AMASK = 077777; struct ndev dev_table[64]; /* dispatch table */ diff --git a/NOVA/nova_clk.c b/NOVA/nova_clk.c index 1250c935..8a384797 100644 --- a/NOVA/nova_clk.c +++ b/NOVA/nova_clk.c @@ -1,6 +1,6 @@ /* nova_clk.c: NOVA real-time clock simulator - Copyright (c) 1993-2005, Robert M. Supnik + Copyright (c) 1993-2008, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,9 @@ clk real-time clock + 04-Jul-07 BKR DEV_SET/CLR macros now used, + changed CLK name to RTC for DG compatiblity, + device may now bw DISABLED 01-Mar-03 RMS Added SET/SHOW CLK FREQ support 03-Oct-02 RMS Added DIB 17-Sep-01 RMS Added terminal multiplexor support @@ -35,7 +38,7 @@ #include "nova_defs.h" -extern int32 int_req, dev_busy, dev_done, dev_disable; +extern int32 int_req, dev_busy, dev_done, dev_disable ; int32 clk_sel = 0; /* selected freq */ int32 clk_time[4] = { 16000, 100000, 10000, 1000 }; /* freq table */ @@ -43,7 +46,7 @@ int32 clk_tps[4] = { 60, 10, 100, 1000 }; /* ticks per sec */ int32 clk_adj[4] = { 1, -5, 2, 20 }; /* tmxr adjust */ int32 tmxr_poll = 16000; /* tmxr poll */ -int32 clk (int32 pulse, int32 code, int32 AC); +int32 clk (int32 pulse, int32 code, int32 AC); t_stat clk_svc (UNIT *uptr); t_stat clk_reset (DEVICE *dptr); t_stat clk_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc); @@ -85,39 +88,41 @@ MTAB clk_mod[] = { }; DEVICE clk_dev = { - "CLK", &clk_unit, clk_reg, clk_mod, + "RTC", &clk_unit, clk_reg, clk_mod, 1, 0, 0, 0, 0, 0, NULL, NULL, &clk_reset, NULL, NULL, NULL, - &clk_dib, 0 + &clk_dib, DEV_DISABLE }; + /* IOT routine */ int32 clk (int32 pulse, int32 code, int32 AC) { if (code == ioDOA) { /* DOA */ clk_sel = AC & 3; /* save select */ - sim_rtc_init (clk_time[clk_sel]); /* init calibr */ + sim_rtc_init (clk_time[clk_sel]); /* init calibr */ } + switch (pulse) { /* decode IR<8:9> */ - case iopS: /* start */ - dev_busy = dev_busy | INT_CLK; /* set busy */ - dev_done = dev_done & ~INT_CLK; /* clear done, int */ - int_req = int_req & ~INT_CLK; - if (!sim_is_active (&clk_unit)) /* not running? */ - sim_activate (&clk_unit, /* activate */ - sim_rtc_init (clk_time[clk_sel])); /* init calibr */ - break; + case iopS: /* start */ + DEV_SET_BUSY( INT_CLK ) ; + DEV_CLR_DONE( INT_CLK ) ; + DEV_UPDATE_INTR ; + if (!sim_is_active (&clk_unit)) /* not running? */ + sim_activate (&clk_unit, /* activate */ + sim_rtc_init (clk_time[clk_sel])); /* init calibr */ + break; - case iopC: /* clear */ - dev_busy = dev_busy & ~INT_CLK; /* clear busy */ - dev_done = dev_done & ~INT_CLK; /* clear done, int */ - int_req = int_req & ~INT_CLK; - sim_cancel (&clk_unit); /* deactivate unit */ - break; - } /* end switch */ + case iopC: /* clear */ + DEV_CLR_BUSY( INT_CLK ) ; + DEV_CLR_DONE( INT_CLK ) ; + DEV_UPDATE_INTR ; + sim_cancel (&clk_unit); /* deactivate unit */ + break; + } /* end switch */ return 0; } @@ -128,14 +133,19 @@ t_stat clk_svc (UNIT *uptr) { int32 t; -dev_done = dev_done | INT_CLK; /* set done */ -dev_busy = dev_busy & ~INT_CLK; /* clear busy */ -int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); +if ( DEV_IS_BUSY(INT_CLK) ) + { + DEV_CLR_BUSY( INT_CLK ) ; + DEV_SET_DONE( INT_CLK ) ; + DEV_UPDATE_INTR ; + } t = sim_rtc_calb (clk_tps[clk_sel]); /* calibrate delay */ sim_activate (&clk_unit, t); /* reactivate unit */ if (clk_adj[clk_sel] > 0) /* clk >= 60Hz? */ tmxr_poll = t * clk_adj[clk_sel]; /* poll is longer */ -else tmxr_poll = t / (-clk_adj[clk_sel]); /* poll is shorter */ +else + tmxr_poll = t / (-clk_adj[clk_sel]); /* poll is shorter */ + return SCPE_OK; } @@ -144,9 +154,10 @@ return SCPE_OK; t_stat clk_reset (DEVICE *dptr) { clk_sel = 0; -dev_busy = dev_busy & ~INT_CLK; /* clear busy */ -dev_done = dev_done & ~INT_CLK; /* clear done, int */ -int_req = int_req & ~INT_CLK; +DEV_CLR_BUSY( INT_CLK ) ; +DEV_CLR_DONE( INT_CLK ) ; +DEV_UPDATE_INTR ; + sim_cancel (&clk_unit); /* deactivate unit */ tmxr_poll = clk_time[0]; /* poll is default */ return SCPE_OK; diff --git a/NOVA/nova_cpu.c b/NOVA/nova_cpu.c index 921daf5c..58cc8463 100644 --- a/NOVA/nova_cpu.c +++ b/NOVA/nova_cpu.c @@ -1,6 +1,6 @@ /* nova_cpu.c: NOVA CPU simulator - Copyright (c) 1993-2007, Robert M. Supnik + Copyright (c) 1993-2008, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,14 @@ cpu Nova central processor + 04-Jul-07 BKR DEV_SET/CLR macros now used, + support for non-existant devices added + CPU bootstrap code warning: high-speed devices may not boot properly, + execution history facility added, + documented Nova 3 secret LDB/STB/SAVN behavior, + added support for secret Nova 3 LDB/STB/SAVN substitute actions, + 'ind_max' changed from 16 to 65536 for better unmapped system compatibility, + INT_TRAP added for Nova 3, 4 trap instruction handling, 28-Apr-07 RMS Removed clock initialization 06-Feb-06 RMS Fixed bug in DIVS (found by Mark Hittinger) 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) @@ -72,7 +80,7 @@ 00001 JMS AC3 = PC, PC = MA 00010 ISZ M[MA] = M[MA] + 1, skip if M[MA] == 0 00011 DSZ M[MA] = M[MA] - 1, skip if M[MA] == 0 - 001'n LDA ACn = M[MA] + 001'n LDA ACn = M[MA] 010'n STA M[MA] = ACn <5:7> mode action @@ -167,6 +175,22 @@ 5. Nova, Nova 3 and Nova 4 unsigned mul/div instructions are the same instruction code values on all machines. + 6. Undocumented Nova 3 behaviour for LDB, STB and SAVN has been + added to appropriate code. + + 7. Most 3rd party vendors had a user-controlled method to increase the + logical address space from 32 KW to 64 KW. This capability came at + the expense of disabling multi-level indirect addressing when the 64KW + mode is in effect, and keeping DG multi-level indirect compatibility + when 64KW mode is inactive. The most common implementation was to use + an "NIOP ,CPU" instruction to control whether 32 KW or 64 KW + addressing mode was wanted, and bit 15 (the least-significant bit + of an accumulator) determined which mode was set: + 0 = 32 KW (DG compatible), 1 = 64 KW. + + This feature has been implemented in our Nova emulation for all to enjoy. + + This routine is the instruction decode routine for the NOVA. It is called from the simulator control program to execute instructions in simulated memory, starting at the simulated PC. @@ -207,32 +231,62 @@ #include "nova_defs.h" + #define PCQ_SIZE 64 /* must be 2**n */ #define PCQ_MASK (PCQ_SIZE - 1) #define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC + #define INCA(x) (((x) + 1) & AMASK) #define DECA(x) (((x) - 1) & AMASK) #define SEXT(x) (((x) & SIGN)? ((x) | ~DMASK): (x)) #define STK_CHECK(x,y) if (((x) & 0377) < (y)) int_req = int_req | INT_STK -#define IND_STEP(x) M[x] & A_IND; \ - if (((x) & 077770) == AUTO_INC) \ - M[x] = (M[x] + 1) & 0177777; \ - else if (((x) & 077770) == AUTO_DEC) \ - M[x] = (M[x] - 1) & 0177777; \ +#define IND_STEP(x) M[x] & A_IND; /* return next level indicator */ \ + if ( ((x) <= AUTO_TOP) && ((x) >= AUTO_INC) ) \ + if ( (x) < AUTO_DEC ) \ + M[x] = (M[x] + 1) & DMASK; \ + else \ + M[x] = (M[x] - 1) & DMASK; \ x = M[x] & AMASK +#define INCREMENT_PC PC = (PC + 1) & AMASK /* increment PC */ + #define UNIT_V_MDV (UNIT_V_UF + 0) /* MDV present */ #define UNIT_V_STK (UNIT_V_UF + 1) /* stack instr */ #define UNIT_V_BYT (UNIT_V_UF + 2) /* byte instr */ -#define UNIT_V_MSIZE (UNIT_V_UF + 3) /* dummy mask */ +#define UNIT_V_64KW (UNIT_V_UF + 3) /* 64KW mem support */ +#define UNIT_V_MSIZE (UNIT_V_UF + 4) /* dummy mask */ #define UNIT_MDV (1 << UNIT_V_MDV) #define UNIT_STK (1 << UNIT_V_STK) #define UNIT_BYT (1 << UNIT_V_BYT) +#define UNIT_64KW (1 << UNIT_V_64KW) #define UNIT_MSIZE (1 << UNIT_V_MSIZE) -#define UNIT_IOPT (UNIT_MDV | UNIT_STK | UNIT_BYT) +#define UNIT_IOPT (UNIT_MDV | UNIT_STK | UNIT_BYT | UNIT_64KW) #define UNIT_NOVA3 (UNIT_MDV | UNIT_STK) #define UNIT_NOVA4 (UNIT_MDV | UNIT_STK | UNIT_BYT) +#define UNIT_KERONIX (UNIT_MDV | UNIT_64KW) + +#define MODE_64K (cpu_unit.flags & UNIT_64KW) +#define MODE_64K_ACTIVE ((cpu_unit.flags & UNIT_64KW) && (0xFFFF == AMASK)) + + +typedef struct + { + int32 pc; + int16 ir; + int16 ac0 ; + int16 ac1 ; + int16 ac2 ; + int16 ac3 ; + int16 carry ; + int16 sp ; + int16 fp ; + int32 devDone ; + int32 devBusy ; + int32 devDisable ; + int32 devIntr ; + } Hist_entry ; + uint16 M[MAXMEMSIZE] = { 0 }; /* memory */ int32 AC[4] = { 0 }; /* accumulators */ @@ -247,16 +301,18 @@ int32 dev_disable = 0; /* int disable flags */ int32 int_req = 0; /* interrupt requests */ int32 pimask = 0; /* priority int mask */ int32 pwr_low = 0; /* power fail flag */ -int32 ind_max = 16; /* iadr nest limit */ +int32 ind_max = 65536; /* iadr nest limit */ int32 stop_dev = 0; /* stop on ill dev */ uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ int32 pcq_p = 0; /* PC queue ptr */ REG *pcq_r = NULL; /* PC queue reg ptr */ struct ndev dev_table[64]; /* dispatch table */ +int32 AMASK = 077777 ; /* current memory address mask */ + /* (default to 32KW) */ +static int32 hist_p = 0 ; /* history pointer */ +static int32 hist_cnt = 0 ; /* history count */ +static Hist_entry * hist = NULL ; /* instruction history */ -extern int32 sim_int_char; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ -extern DEVICE *sim_devices[]; t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); @@ -265,6 +321,22 @@ t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cpu_boot (int32 unitno, DEVICE *dptr); t_stat build_devtab (void); +t_stat hist_set( UNIT * uptr, int32 val, char * cptr, void * desc ) ; +t_stat hist_show( FILE * st, UNIT * uptr, int32 val, void * desc ) ; +static int hist_save( int32 pc, int32 our_ir ) ; +char * devBitNames( int32 flags, char * ptr, char * sepStr ) ; + +void mask_out (int32 mask); + + +extern int32 sim_interval; +extern int32 sim_int_char; +extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern DEVICE * sim_devices[]; +extern t_stat fprint_sym(FILE *ofile, t_addr addr, t_value *val, UNIT *uptr, int32 sw); + + + /* CPU data structures cpu_dev CPU device descriptor @@ -274,7 +346,7 @@ t_stat build_devtab (void); */ UNIT cpu_unit = { - UDATA (NULL, UNIT_FIX+UNIT_BINK+UNIT_MDV, MAXMEMSIZE) + UDATA (NULL, UNIT_FIX+UNIT_BINK+UNIT_MDV, DFTMEMSIZE /* MAXMEMSIZE */ ) }; REG cpu_reg[] = { @@ -297,7 +369,9 @@ REG cpu_reg[] = { { ORDATA (DONE, dev_done, INT_V_ION+1), REG_RO }, { ORDATA (DISABLE, dev_disable, INT_V_ION+1), REG_RO }, { FLDATA (STOP_DEV, stop_dev, 0) }, - { DRDATA (INDMAX, ind_max, 16), REG_NZ + PV_LEFT }, + { DRDATA (INDMAX, ind_max, 32), REG_NZ + PV_LEFT }, + { ORDATA (AMASK, AMASK, 16) }, + { DRDATA (MEMSIZE, cpu_unit.capac, 32), REG_NZ + PV_LEFT }, { BRDATA (PCQ, pcq, 8, 16, PCQ_SIZE), REG_RO+REG_CIRC }, { ORDATA (PCQP, pcq_p, 6), REG_HRO }, { ORDATA (WRU, sim_int_char, 8) }, @@ -307,32 +381,44 @@ REG cpu_reg[] = { MTAB cpu_mod[] = { { UNIT_IOPT, UNIT_NOVA3, "NOVA3", "NOVA3", NULL }, { UNIT_IOPT, UNIT_NOVA4, "NOVA4", "NOVA4", NULL }, - { UNIT_IOPT, UNIT_MDV, "MDV", "MDV", NULL }, - { UNIT_IOPT, 0, "none", "NONE", NULL }, - { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size }, - { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size }, - { UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size }, - { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size }, - { UNIT_MSIZE, 20480, NULL, "20K", &cpu_set_size }, - { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size }, - { UNIT_MSIZE, 28672, NULL, "28K", &cpu_set_size }, - { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size }, + { UNIT_IOPT, UNIT_KERONIX, "KERONIX", "KERONIX", NULL }, + { UNIT_IOPT, UNIT_MDV, "MDV", "MDV", NULL }, + { UNIT_IOPT, UNIT_64KW, "EXT64KW", "EXT64KW", NULL }, + { UNIT_IOPT, 0, "none", "NONE", NULL }, + { UNIT_MSIZE, ( 4 * 1024), NULL, "4K", &cpu_set_size }, + { UNIT_MSIZE, ( 8 * 1024), NULL, "8K", &cpu_set_size }, + { UNIT_MSIZE, (12 * 1024), NULL, "12K", &cpu_set_size }, + { UNIT_MSIZE, (16 * 1024), NULL, "16K", &cpu_set_size }, + { UNIT_MSIZE, (20 * 1024), NULL, "20K", &cpu_set_size }, + { UNIT_MSIZE, (24 * 1024), NULL, "24K", &cpu_set_size }, + { UNIT_MSIZE, (28 * 1024), NULL, "28K", &cpu_set_size }, + { UNIT_MSIZE, (32 * 1024), NULL, "32K", &cpu_set_size }, + + { UNIT_MSIZE, (36 * 1024), NULL, "36K", &cpu_set_size }, + { UNIT_MSIZE, (40 * 1024), NULL, "40K", &cpu_set_size }, + { UNIT_MSIZE, (44 * 1024), NULL, "44K", &cpu_set_size }, + { UNIT_MSIZE, (48 * 1024), NULL, "48K", &cpu_set_size }, + { UNIT_MSIZE, (52 * 1024), NULL, "52K", &cpu_set_size }, + { UNIT_MSIZE, (56 * 1024), NULL, "56K", &cpu_set_size }, + { UNIT_MSIZE, (60 * 1024), NULL, "60K", &cpu_set_size }, + { UNIT_MSIZE, (64 * 1024), NULL, "64K", &cpu_set_size }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", + &hist_set, &hist_show }, + { 0 } }; DEVICE cpu_dev = { "CPU", &cpu_unit, cpu_reg, cpu_mod, - 1, 8, 15, 1, 8, 16, + 1, 8, 16 /* = 64 KW, 15 = 32KW */, 1, 8, 16, &cpu_ex, &cpu_dep, &cpu_reset, NULL, NULL, NULL }; t_stat sim_instr (void) { -extern int32 sim_interval; int32 PC, IR, i; t_stat reason; -void mask_out (int32 mask); /* Restore register state */ @@ -347,19 +433,34 @@ reason = 0; while (reason == 0) { /* loop until halted */ if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) break; + if ( (reason = sim_process_event ()) ) break; } - if (int_req > INT_PENDING) { /* interrupt? */ + if (int_req > INT_PENDING) { /* interrupt or exception? */ int32 MA, indf; - int_req = int_req & ~INT_ION; /* intr off */ - PCQ_ENTRY; /* save old PC */ - M[INT_SAV] = PC; - if (int_req & INT_STK) { /* stack overflow? */ - int_req = int_req & ~INT_STK; /* clear */ - MA = STK_JMP; /* jmp @3 */ + + if (int_req & INT_TRAP) { /* trap instruction? */ + int_req = int_req & ~INT_TRAP ; /* clear */ + PCQ_ENTRY; /* save old PC */ + M[TRP_SAV] = (PC - 1) & AMASK; + MA = TRP_JMP; /* jmp @47 */ } - else MA = INT_JMP; /* intr: jmp @1 */ + else { + int_req = int_req & ~INT_ION; /* intr off */ + PCQ_ENTRY; /* save old PC */ + M[INT_SAV] = PC; + if (int_req & INT_STK) { /* stack overflow? */ + int_req = int_req & ~INT_STK; /* clear */ + MA = STK_JMP; /* jmp @3 */ + } + else + MA = INT_JMP; /* intr: jmp @1 */ + } + if ( MODE_64K_ACTIVE ) { + indf = IND_STEP (MA); + } + else + { for (i = 0, indf = 1; indf && (i < ind_max); i++) { indf = IND_STEP (MA); /* indirect loop */ } @@ -367,8 +468,9 @@ while (reason == 0) { /* loop until halted */ reason = STOP_IND_INT; break; } - PC = MA; - } /* end interrupt */ + } + PC = MA; + } /* end interrupt */ if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ reason = STOP_IBKPT; /* stop simulation */ @@ -376,7 +478,12 @@ while (reason == 0) { /* loop until halted */ } IR = M[PC]; /* fetch instr */ - PC = (PC + 1) & AMASK; + if ( hist_cnt ) + { + hist_save( PC, IR ) ; /* PC, int_req unchanged */ + } + + INCREMENT_PC ; int_req = int_req | INT_NO_ION_PENDING; /* clear ION delay */ sim_interval = sim_interval - 1; @@ -400,7 +507,7 @@ while (reason == 0) { /* loop until halted */ case 3: /* complement */ src = AC[srcAC] | (C ^ CBIT); break; - } /* end switch carry */ + } /* end switch carry */ switch (I_GETALU (IR)) { /* decode ALU */ case 0: /* COM */ @@ -446,40 +553,30 @@ while (reason == 0) { /* loop until halted */ switch (I_GETSKP (IR)) { /* decode skip */ case 0: /* nop */ if ((IR & I_NLD) && (cpu_unit.flags & UNIT_STK)) { - int32 indf, MA; /* Nova 3 or 4 trap */ - PCQ_ENTRY; /* save old PC */ - M[TRP_SAV] = (PC - 1) & AMASK; - MA = TRP_JMP; /* jmp @47 */ - for (i = 0, indf = 1; indf && (i < ind_max); i++) { - indf = IND_STEP (MA); /* resolve ind */ - } - if (i >= ind_max) { /* indirect loop? */ - reason = STOP_IND_TRP; - break; - } - PC = MA; /* new PC */ + int_req = int_req | INT_TRAP ; /* Nova 3 or 4 trap */ + continue ; } break; case 1: /* SKP */ - PC = (PC + 1) & AMASK; + INCREMENT_PC ; break; case 2: /* SZC */ - if (src < CBIT) PC = (PC + 1) & AMASK; + if (src < CBIT) INCREMENT_PC ; break; case 3: /* SNC */ - if (src >= CBIT) PC = (PC + 1) & AMASK; + if (src >= CBIT) INCREMENT_PC ; break; case 4: /* SZR */ - if ((src & DMASK) == 0) PC = (PC + 1) & AMASK; + if ((src & DMASK) == 0) INCREMENT_PC ; break; case 5: /* SNR */ - if ((src & DMASK) != 0) PC = (PC + 1) & AMASK; + if ((src & DMASK) != 0) INCREMENT_PC ; break; case 6: /* SEZ */ - if (src <= CBIT) PC = (PC + 1) & AMASK; + if (src <= CBIT) INCREMENT_PC ; break; case 7: /* SBN */ - if (src > CBIT) PC = (PC + 1) & AMASK; + if (src > CBIT) INCREMENT_PC ; break; } /* end switch skip */ if ((IR & I_NLD) == 0) { /* load? */ @@ -498,28 +595,34 @@ while (reason == 0) { /* loop until halted */ case 0: /* page zero */ break; case 1: /* PC relative */ - if (MA & DISPSIGN) MA = 077400 | MA; + if (MA & DISPSIGN) MA = 0177400 | MA; MA = (MA + PC - 1) & AMASK; break; case 2: /* AC2 relative */ - if (MA & DISPSIGN) MA = 077400 | MA; + if (MA & DISPSIGN) MA = 0177400 | MA; MA = (MA + AC[2]) & AMASK; break; case 3: /* AC3 relative */ - if (MA & DISPSIGN) MA = 077400 | MA; + if (MA & DISPSIGN) MA = 0177400 | MA; MA = (MA + AC[3]) & AMASK; break; } /* end switch mode */ - if (indf = IR & I_IND) { /* indirect? */ - for (i = 0; indf && (i < ind_max); i++) { /* count */ - indf = IND_STEP (MA); /* resolve indirect */ + if ( (indf = IR & I_IND) ) { /* indirect? */ + if ( MODE_64K_ACTIVE ) { /* 64k mode? */ + indf = IND_STEP (MA); } - if (i >= ind_max) { /* too many? */ - reason = STOP_IND; - break; + else /* compat mode */ + { + for (i = 0; indf && (i < ind_max); i++) { /* count */ + indf = IND_STEP (MA); /* resolve indirect */ + } + if (i >= ind_max) { /* too many? */ + reason = STOP_IND; + break; } } + } switch (I_GETOPAC (IR)) { /* decode op + AC */ case 001: /* JSR */ @@ -530,13 +633,13 @@ while (reason == 0) { /* loop until halted */ break; case 002: /* ISZ */ src = (M[MA] + 1) & DMASK; - if (MEM_ADDR_OK (MA)) M[MA] = src; - if (src == 0) PC = (PC + 1) & AMASK; + if (MEM_ADDR_OK(MA)) M[MA] = src; + if (src == 0) INCREMENT_PC ; break; case 003: /* DSZ */ src = (M[MA] - 1) & DMASK; - if (MEM_ADDR_OK (MA)) M[MA] = src; - if (src == 0) PC = (PC + 1) & AMASK; + if (MEM_ADDR_OK(MA)) M[MA] = src; + if (src == 0) INCREMENT_PC ; break; case 004: /* LDA 0 */ AC[0] = M[MA]; @@ -551,16 +654,16 @@ while (reason == 0) { /* loop until halted */ AC[3] = M[MA]; break; case 010: /* STA 0 */ - if (MEM_ADDR_OK (MA)) M[MA] = AC[0]; + if (MEM_ADDR_OK(MA)) M[MA] = AC[0]; break; case 011: /* STA 1 */ - if (MEM_ADDR_OK (MA)) M[MA] = AC[1]; + if (MEM_ADDR_OK(MA)) M[MA] = AC[1]; break; case 012: /* STA 2 */ - if (MEM_ADDR_OK (MA)) M[MA] = AC[2]; + if (MEM_ADDR_OK(MA)) M[MA] = AC[2]; break; case 013: /* STA 3 */ - if (MEM_ADDR_OK (MA)) M[MA] = AC[3]; + if (MEM_ADDR_OK(MA)) M[MA] = AC[3]; break; } /* end switch */ } /* end mem ref */ @@ -580,81 +683,121 @@ while (reason == 0) { /* loop until halted */ case 0: /* skip if busy */ if ((device == DEV_CPU)? (int_req & INT_ION) != 0: (dev_busy & dev_table[device].mask) != 0) - PC = (PC + 1) & AMASK; + INCREMENT_PC ; break; case 1: /* skip if not busy */ if ((device == DEV_CPU)? (int_req & INT_ION) == 0: (dev_busy & dev_table[device].mask) == 0) - PC = (PC + 1) & AMASK; + INCREMENT_PC ; break; case 2: /* skip if done */ if ((device == DEV_CPU)? pwr_low != 0: (dev_done & dev_table[device].mask) != 0) - PC = (PC + 1) & AMASK; + INCREMENT_PC ; break; case 3: /* skip if not done */ if ((device == DEV_CPU)? pwr_low == 0: (dev_done & dev_table[device].mask) == 0) - PC = (PC + 1) & AMASK; + INCREMENT_PC ; break; } /* end switch */ } /* end IO skip */ + /* Hmm, this means a Nova 3 _must_ have DEV_MDV enabled - not true in DG land */ + else if (device == DEV_MDV) { switch (code) { /* case on opcode */ case ioNIO: /* frame ptr */ if (cpu_unit.flags & UNIT_STK) { - if (pulse == iopN) FP = AC[dstAC] & AMASK; - if (pulse == iopC) AC[dstAC] = FP; + if (pulse == iopN) FP = AC[dstAC] & AMASK ; + if (pulse == iopC) AC[dstAC] = FP & AMASK ; } break; case ioDIA: /* load byte */ if (cpu_unit.flags & UNIT_BYT) - AC[dstAC] = (M[AC[pulse] >> 1] >> - ((AC[pulse] & 1)? 0: 8)) & 0377; - else AC[dstAC] = 0; + { + AC[dstAC] = (M[AC[pulse] >> 1] >> ((AC[pulse] & 1)? 0: 8)) & 0377 ; + } + else if (cpu_unit.flags & UNIT_STK) /* if Nova 3 this is really a SAV... 2007-Jun-01, BKR */ + { + SP = INCA (SP); + if (MEM_ADDR_OK (SP)) M[SP] = AC[0]; + SP = INCA (SP); + if (MEM_ADDR_OK (SP)) M[SP] = AC[1]; + SP = INCA (SP); + if (MEM_ADDR_OK (SP)) M[SP] = AC[2]; + SP = INCA (SP); + if (MEM_ADDR_OK (SP)) M[SP] = FP; + SP = INCA (SP); + if (MEM_ADDR_OK (SP)) M[SP] = (C >> 1) | (AC[3] & AMASK); + AC[3] = FP = SP & AMASK; + STK_CHECK (SP, 5); + } + else + { + AC[dstAC] = 0; + } break; case ioDOA: /* stack ptr */ if (cpu_unit.flags & UNIT_STK) { if (pulse == iopN) SP = AC[dstAC] & AMASK; - if (pulse == iopC) AC[dstAC] = SP; + if (pulse == iopC) AC[dstAC] = SP & AMASK; } break; case ioDIB: /* push, pop */ if (cpu_unit.flags & UNIT_STK) { - if (pulse == iopN) { /* push */ + if (pulse == iopN) { /* push (PSHA) */ SP = INCA (SP); if (MEM_ADDR_OK (SP)) M[SP] = AC[dstAC]; STK_CHECK (SP, 1); } - if (pulse == iopC) { /* pop */ - AC[dstAC] = M[SP]; - SP = DECA (SP); - } - if ((pulse == iopP) && /* Nova 4 pshn */ + if ((pulse == iopS) && /* Nova 4 pshn (PSHN) */ (cpu_unit.flags & UNIT_BYT)) { SP = INCA (SP); if (MEM_ADDR_OK (SP)) M[SP] = AC[dstAC]; - if (SP > M[042]) int_req = int_req | INT_STK ; + if ( (SP & 0xFFFF) > (M[042] & 0xFFFF) ) + { + int_req = int_req | INT_STK ; + } + } + if (pulse == iopC) { /* pop (POPA) */ + AC[dstAC] = M[SP]; + SP = DECA (SP); } } break; case ioDOB: /* store byte */ - if (cpu_unit.flags & UNIT_BYT) { + if (cpu_unit.flags & UNIT_BYT) + { int32 MA, val; - MA = AC[pulse] >> 1; + MA = AC[pulse] >> 1; val = AC[dstAC] & 0377; if (MEM_ADDR_OK (MA)) M[MA] = (AC[pulse] & 1)? - ((M[MA] & ~0377) | val): - ((M[MA] & 0377) | (val << 8)); + ((M[MA] & ~0377) | val) + : ((M[MA] & 0377) | (val << 8)); + } + else if (cpu_unit.flags & UNIT_STK) /* if Nova 3 this is really a SAV... 2007-Jun-01, BKR */ + { + SP = INCA (SP); + if (MEM_ADDR_OK (SP)) M[SP] = AC[0]; + SP = INCA (SP); + if (MEM_ADDR_OK (SP)) M[SP] = AC[1]; + SP = INCA (SP); + if (MEM_ADDR_OK (SP)) M[SP] = AC[2]; + SP = INCA (SP); + if (MEM_ADDR_OK (SP)) M[SP] = FP; + SP = INCA (SP); + if (MEM_ADDR_OK (SP)) M[SP] = (C >> 1) | (AC[3] & AMASK); + AC[3] = FP = SP & AMASK; + STK_CHECK (SP, 5); } break; @@ -670,12 +813,11 @@ while (reason == 0) { /* loop until halted */ SP = INCA (SP); if (MEM_ADDR_OK (SP)) M[SP] = FP; SP = INCA (SP); - if (MEM_ADDR_OK (SP)) M[SP] = (C >> 1) | - (AC[3] & AMASK); + if (MEM_ADDR_OK (SP)) M[SP] = (C >> 1) | (AC[3] & AMASK); AC[3] = FP = SP & AMASK; STK_CHECK (SP, 5); } - if (pulse == iopC) { /* retn */ + else if (pulse == iopC) { /* retn */ PCQ_ENTRY; SP = FP & AMASK; C = (M[SP] << 1) & CBIT; @@ -691,7 +833,7 @@ while (reason == 0) { /* loop until halted */ SP = DECA (SP); FP = AC[3] & AMASK; } - if ((pulse == iopP) && /* Nova 4 saven */ + else if ((pulse == iopS) && /* Nova 4 SAVN */ (cpu_unit.flags & UNIT_BYT)) { int32 frameSz = M[PC] ; PC = INCA (PC) ; @@ -704,58 +846,85 @@ while (reason == 0) { /* loop until halted */ SP = INCA (SP); if (MEM_ADDR_OK (SP)) M[SP] = FP; SP = INCA (SP); - if (MEM_ADDR_OK (SP)) M[SP] = (C >> 1) | - (AC[3] & AMASK); + if (MEM_ADDR_OK (SP)) M[SP] = (C >> 1) | (AC[3] & AMASK); AC[3] = FP = SP & AMASK ; SP = (SP + frameSz) & AMASK ; - if (SP > M[042]) int_req = int_req | INT_STK; + if (SP > M[042]) + { + int_req = int_req | INT_STK; + } } } break; case ioDOC: - if ((dstAC == 2) && (cpu_unit.flags & UNIT_MDV)) { + if ((dstAC == 2) && (cpu_unit.flags & UNIT_MDV)) + { /* Nova, Nova3 or Nova 4 */ uint32 mddata, uAC0, uAC1, uAC2; + uAC0 = (uint32) AC[0]; uAC1 = (uint32) AC[1]; uAC2 = (uint32) AC[2]; - if (pulse == iopP) { /* mul */ + if (pulse == iopP) + { /* mul */ mddata = (uAC1 * uAC2) + uAC0; - AC[0] = (mddata >> 16) & DMASK; - AC[1] = mddata & DMASK; + AC[0] = (mddata >> 16) & DMASK; + AC[1] = mddata & DMASK; } - if (pulse == iopS) { /* div */ - if ((uAC0 >= uAC2) || (uAC2 == 0)) C = CBIT; - else { + if (pulse == iopS) + { /* div */ + if ((uAC0 >= uAC2) || (uAC2 == 0)) + { + C = CBIT; + } + else + { C = 0; mddata = (uAC0 << 16) | uAC1; - AC[1] = mddata / uAC2; - AC[0] = mddata % uAC2; + AC[1] = mddata / uAC2; + AC[0] = mddata % uAC2; } } } - if ((dstAC == 3) && (cpu_unit.flags & UNIT_BYT)) { + else if ((dstAC == 3) && (cpu_unit.flags & UNIT_BYT) /* assuming UNIT_BYT = Nova 4 */) + { int32 mddata; - if (pulse == iopC) { /* muls */ + if (pulse == iopC) + { /* muls */ mddata = (SEXT (AC[1]) * SEXT (AC[2])) + SEXT (AC[0]); - AC[0] = (mddata >> 16) & DMASK; - AC[1] = mddata & DMASK; + AC[0] = (mddata >> 16) & DMASK; + AC[1] = mddata & DMASK; } - if (pulse == iopN) { /* divs */ + else if (pulse == iopN) + { /* divs */ if ((AC[2] == 0) || /* overflow? */ ((AC[0] == 0100000) && (AC[1] == 0) && (AC[2] == 0177777))) + { C = CBIT; - else { + } + else + { mddata = (SEXT (AC[0]) << 16) | AC[1]; - AC[1] = mddata / SEXT (AC[2]); - AC[0] = mddata % SEXT (AC[2]); + AC[1] = mddata / SEXT (AC[2]); + AC[0] = mddata % SEXT (AC[2]); if ((AC[1] > 077777) || (AC[1] < -0100000)) + { C = CBIT; - else C = 0; + } + else + { + C = 0; + } AC[0] = AC[0] & DMASK; } } } + else if ((dstAC == 3) && (cpu_unit.flags & UNIT_STK)) /* if Nova 3 this is really a PSHA... 2007-Jun-01, BKR */ + { + SP = INCA (SP); + if (MEM_ADDR_OK (SP)) M[SP] = AC[dstAC]; + STK_CHECK (SP, 1); + } break; } /* end case code */ } /* end if mul/div */ @@ -763,13 +932,25 @@ while (reason == 0) { /* loop until halted */ else if (device == DEV_CPU) { /* CPU control */ switch (code) { /* decode IR<5:7> */ + case ioNIO: /* NIOP CPU ? */ + if ( pulse == iopP ) + if ( MODE_64K ) + { + /* Keronix/Point4/SCI/INI/IDP (and others) */ + /* 64 KW memory extension: */ + /* NIOP - set memory mode (32/64 KW) per AC: */ + /* B15: 0 = 32 KW, 1 = 64 KW mode */ + AMASK = (AC[dstAC] & 0x0001) ? 0177777 : 077777 ; + } + break ; + case ioDIA: /* read switches */ AC[dstAC] = SR; break; case ioDIB: /* int ack */ AC[dstAC] = 0; - int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); + DEV_UPDATE_INTR ; iodata = int_req & (-int_req); for (i = DEV_LOW; i <= DEV_HIGH; i++) { if (iodata & dev_table[i].mask) { @@ -785,6 +966,8 @@ while (reason == 0) { /* loop until halted */ case ioDIC: /* io reset */ reset_all (0); /* reset devices */ + mask_out( 0 ) ; /* clear all device masks */ + AMASK = 077777 ; /* reset memory mode */ break; case ioDOC: /* halt */ @@ -809,15 +992,42 @@ while (reason == 0) { /* loop until halted */ reason = iodata >> IOT_V_REASON; if (code & 1) AC[dstAC] = iodata & 0177777; } - else reason = stop_dev; - } /* end if IOT */ + +/* bkr, 2007-May-30 + * if device does not exist certain I/O instructions will still + * return data: DIA/B/C will return idle data bus value and + * SKPBZ/SKPDZ will sense zero value (and will therefore skip). + * + * Perform these non-supported device functions only if 'stop_dev' + * is zero (i.e. I/O access trap is not in effect). + */ + else if ( stop_dev == 0 ) + { + switch (code) /* decode IR<5:7> */ + { + case ioDIA: + case ioDIB: + case ioDIC: + AC[dstAC] = 0 ; /* idle I/O bus data */ + break; + + case ioSKP: + /* (This should have been caught in previous CPU skip code) */ + if ( (pulse == 1 /* SKPBZ */) || (pulse == 3 /* SKPDZ */) ) + { + INCREMENT_PC ; + } + } /* end of 'switch' */ + } /* end of handling non-existant device */ + else reason = stop_dev; + } /* end if IOT */ } /* end while */ /* Simulation halted */ saved_PC = PC; pcq_r->qptr = pcq_p; /* update pc q ptr */ -return reason; +return ( reason ) ; } /* New priority mask out */ @@ -831,7 +1041,7 @@ for (i = DEV_LOW; i <= DEV_HIGH; i++) { if (newmask & dev_table[i].pi) dev_disable = dev_disable | dev_table[i].mask; } -int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); +DEV_UPDATE_INTR ; return; } @@ -839,10 +1049,11 @@ return; t_stat cpu_reset (DEVICE *dptr) { -int_req = int_req & ~(INT_ION | INT_STK); +int_req = int_req & ~(INT_ION | INT_STK | INT_TRAP); pimask = 0; dev_disable = 0; pwr_low = 0; +AMASK = 077777 ; /* 32KW mode */ pcq_r = find_reg ("PCQ", NULL, dptr); if (pcq_r) pcq_r->qptr = 0; else return SCPE_IERR; @@ -900,7 +1111,7 @@ for (i = 0; i < 64; i++) { /* clr dev_table */ } for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ if (!(dptr->flags & DEV_DIS) && /* enabled and */ - (dibp = (DIB *) dptr->ctxt)) { /* defined DIB? */ + ( (dibp = (DIB *) dptr->ctxt)) ) { /* defined DIB? */ dn = dibp->dnum; /* get dev num */ dev_table[dn].mask = dibp->mask; /* copy entries */ dev_table[dn].pi = dibp->pi; @@ -910,13 +1121,45 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ return SCPE_OK; } -/* Bootstrap routine for CPU */ +/* BKR notes: + * + * Data General APL (Automatic Program Load) boot code + * + * - This bootstrap code is called the "APL option" in DG documentation (Automatic + * Program Load), and cost ~$400 USD (in 1970 - wow!) to load 32(10) words from + * a PROM to main (core) memory location 0 - 32. + * - This code is documented in various DG Nova programming manuals and was + * quite static (i.e. no revisions or updates to code were made). + * - switch register is used to determine device code and device type. + * - lower 6-bits of switch register determines device code (0-63.). + * - most significant bit determines if device is "low speed" or "high speed". + * - "high speed" devices have effective boot program logic of: + * + * IORST + * NIOS + * JMP . + * + * - "high speed" devices use data channel (DCH) to read first sector/record + * of device into memory (usually starting at location 0), which then over-writes + * the 'JMP .' instruction of boot code. This usually has a jump to some other + * device and operating system specific boot code that was loaded from the device. + * - "low speed" devices are assumed to be sequential character-oriented devices + * (i.e. Teletype (r) reader, paper tape reader). + * - "low speed" devices are assumed to start read operations with a 'S' pulse, + * read data buffer with a DIA instruction and have standard DG I/O Busy/Done logic. + * - "low speed" devices usually read in a more full-featured 'binary loader' with + * the APL boot code: + * + * DG paper tape: 091-000004-xx, Binary Loader (BLDR.AB) + * + * - The Binary Loader was in turn used to load tapes in the usual DG 'absolute binary' format. + */ -#define BOOT_START 00000 -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int)) +#define BOOT_START 00000 +#define BOOT_LEN (sizeof(boot_rom) / sizeof(int32)) static const int32 boot_rom[] = { - 0062677, /* IORST ;reset all I/O */ + 0062677, /* IORST ;reset all I/O */ 0060477, /* READS 0 ;read SR into AC0 */ 0024026, /* LDA 1,C77 ;get dev mask */ 0107400, /* AND 0,1 ;isolate dev code */ @@ -929,7 +1172,7 @@ static const int32 boot_rom[] = { 0030016, /* LDA 2,C377 ;place JMP 377 into */ 0050377, /* STA 2,377 ;location 377 */ 0060077, /* OP1: 060077 ;start device (NIOS 0) */ - 00101102, /* MOVL 0,0,SZC ;test switch 0, low speed? */ + 0101102, /* MOVL 0,0,SZC ;test switch 0, low speed? */ 0000377, /* C377: JMP 377 ;no - jmp 377 & wait */ 0004030, /* LOOP2: JSR GET+1 ;get a frame */ 0101065, /* MOVC 0,0,SNR ;is it non-zero? */ @@ -955,8 +1198,7 @@ static const int32 boot_rom[] = { t_stat cpu_boot (int32 unitno, DEVICE *dptr) { -int32 i; -extern int32 saved_PC; +int32 i; for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i]; saved_PC = BOOT_START; @@ -969,3 +1211,262 @@ int32 MapAddr (int32 map, int32 addr) { return addr; } + +/* History subsystem + +global routines + +t_stat hist_set( UNIT * uptr, int32 val, char * cptr, void * desc, void ** HistCookie, sizeof(usrHistInfo) ) ; +t_stat hist_show( FILE * st, UNIT * uptr, int32 val, void * desc, void * HistCookie ) ; +int hist_save( int32 next_pc, int32 our_ir, void * usrHistInfo ) + +local user struct: + +usrHistInfo + +local user routines: + +int uHist_save( int32 next_pc, int32 our_ir, void * usrHistInfo ) ; +int uHist_fprintf( FILE * fp, int itemNum, void * usrHistInfo ) ; + +typedef struct + { + int hMax ; // total # entries in queue (0 = inactive) + int hCount ; // current entry + void * hPtr ; // pointer to save area + int hSize ; // size of each user save area (not used by global routines?) + } Hist_info ; + */ + +/* generalized CPU execution trace */ + +#define HIST_IR_INVALID -1 +#define HIST_MIN 0 /* 0 == deactivate history feature, else size of queue */ +#define HIST_MAX 1000000 /* completely arbitrary max size value */ + +/* save history entry (proposed local routine) */ + +static int hist_save( int32 pc, int32 our_ir ) +{ +Hist_entry * hist_ptr ; + +if ( hist ) + if ( hist_cnt ) + { + hist_p = (hist_p + 1) ; /* next entry */ + if ( hist_p >= hist_cnt ) + { + hist_p = 0 ; + } + hist_ptr = &hist[ hist_p ] ; + + /* (machine-specific stuff) */ + + hist_ptr->pc = pc ; + hist_ptr->ir = our_ir ; + hist_ptr->ac0 = AC[ 0 ] ; + hist_ptr->ac1 = AC[ 1 ] ; + hist_ptr->ac2 = AC[ 2 ] ; + hist_ptr->ac3 = AC[ 3 ] ; + hist_ptr->carry = C ; + hist_ptr->fp = FP ; + hist_ptr->sp = SP ; + hist_ptr->devBusy = dev_busy ; + hist_ptr->devDone = dev_done ; + hist_ptr->devDisable = dev_disable ; + hist_ptr->devIntr = int_req ; + /* how 'bout state and AMASK? */ + return ( hist_p ) ; + } +return ( -1 ) ; +} /* end of 'hist_save' */ + +/* setup history save area (proposed global routine) */ + +t_stat hist_set( UNIT * uptr, int32 val, char * cptr, void * desc ) +{ +int32 i, lnt ; +t_stat r ; + +if ( cptr == NULL ) + { + for (i = 0 ; i < hist_cnt ; ++i ) + { + hist[i].pc = 0 ; + hist[i].ir = HIST_IR_INVALID ; + } + hist_p = 0 ; + return ( SCPE_OK ) ; + } +lnt = (int32) get_uint(cptr, 10, HIST_MAX, &r) ; +if ( (r != SCPE_OK) || (lnt && (lnt < HIST_MIN)) ) + { + return ( SCPE_ARG ) ; + } +hist_p = 0; +if ( hist_cnt ) + { + free( hist ) ; + hist_cnt = 0 ; + hist = NULL ; + } +if ( lnt ) + { + hist = (Hist_entry *) calloc( lnt, sizeof(Hist_entry) ) ; + if ( hist == NULL ) + { + return ( SCPE_MEM ) ; + } + hist_cnt = lnt ; + } +return ( SCPE_OK ) ; +} /* end of 'hist_set' */ + + +int hist_fprintf( FILE * fp, int itemNum, Hist_entry * hptr ) +{ +t_value sim_eval ; + +if ( hptr ) + { + if ( itemNum == 0 ) + { + fprintf( fp, "\n\n" ) ; + } + fprintf( fp, "%05o / %06o %06o %06o %06o %06o %o ", + (hptr->pc & 0x7FFF), + (hptr->ir & 0xFFFF), + (hptr->ac0 & 0xFFFF), + (hptr->ac1 & 0xFFFF), + (hptr->ac2 & 0xFFFF), + (hptr->ac3 & 0xFFFF), + ((hptr->carry) ? 1 : 0) + ) ; + if ( cpu_unit.flags & UNIT_STK /* Nova 3 or Nova 4 */ ) + { + fprintf( fp, "%06o %06o ", SP, FP ) ; + } + + sim_eval = (hptr->ir & 0xFFFF) ; + if ( (fprint_sym(fp, (hptr->pc & AMASK), &sim_eval, &cpu_unit, SWMASK ('M'))) > 0 ) + { + fprintf( fp, "(undefined) %04o", (hptr->ir & 0xFFFF) ) ; + } + /* + display ION flag value, pend value? + display devBusy, devDone, devIntr info? + */ + + if ( 0 ) /* display INTRP codes? */ + { + char tmp[ 500 ] ; + + devBitNames( hptr->devIntr, tmp, NULL ) ; + fprintf( fp, " %s", tmp ) ; + } + + fprintf( fp, "\n" ) ; + } +return ( 0 ) ; +} /* end of 'hist_fprintf' */ + + +/* show execution history (proposed global routine) */ + +t_stat hist_show( FILE * st, UNIT * uptr, int32 val, void * desc ) +{ +int32 k, di, lnt ; +char * cptr = (char *) desc ; +t_stat r ; +Hist_entry * hptr ; + + +if (hist_cnt == 0) + { + return ( SCPE_NOFNC ) ; /* enabled? */ + } +if ( cptr ) + { /* number of entries specified */ + lnt = (int32) get_uint( cptr, 10, hist_cnt, &r ) ; + if ( (r != SCPE_OK) || (lnt == 0) ) + { + return ( SCPE_ARG ) ; + } + } + else + { + lnt = hist_cnt ; /* display all entries */ + } + di = hist_p - lnt; /* work forward */ + if ( di < 0 ) + { + di = di + hist_cnt ; + } + +for ( k = 0 ; k < lnt ; ++k ) + { /* print specified */ + hptr = &hist[ (++di) % hist_cnt] ; /* entry pointer */ + if ( hptr->ir != HIST_IR_INVALID ) /* valid entry? */ + { + hist_fprintf( st, k, hptr ) ; + } /* end else instruction */ + } /* end for */ +return SCPE_OK; +} /* end of 'hist_show' */ + + + +struct Dbits + { + int32 dBit ; + int32 dInvertMask ; + char * dName ; + } devBits [] = + + { + { INT_TRAP, 0, "TRAP" }, /* (in order of approximate DG interrupt mask priority) */ + { INT_ION, 0, "ION" }, + { INT_NO_ION_PENDING, 1, "IONPND" }, /* (invert this logic to provide cleaner display) */ + { INT_STK, 0, "STK" }, + { INT_PIT, 0, "PIT" }, + { INT_DKP, 0, "DKP" }, + { INT_DSK, 0, "DSK" }, + { INT_MTA, 0, "MTA" }, + { INT_LPT, 0, "LPT" }, + { INT_PTR, 0, "PTR" }, + { INT_PTP, 0, "PTP" }, + { INT_PLT, 0, "PLT" }, + { INT_CLK, 0, "CLK" }, + { INT_ALM, 0, "ALM" }, + { INT_QTY, 0, "QTY" }, + { INT_TTO1, 0, "TTO1" }, + { INT_TTI1, 0, "TTI1" }, + { INT_TTO, 0, "TTO" }, + { INT_TTI, 0, "TTI" }, + { 0, 0, NULL } + } ; + + +char * devBitNames( int32 flags, char * ptr, char * sepStr ) +{ +int a ; + +if ( ptr ) + { + *ptr = 0 ; + for ( a = 0 ; (devBits[a].dBit) ; ++a ) + if ( devBits[a].dBit & ((devBits[a].dInvertMask)? ~flags : flags) ) + { + if ( *ptr ) + { + strcat( ptr, (sepStr) ? sepStr : " " ) ; + strcat( ptr, devBits[a].dName ) ; + } + else + { + strcpy( ptr, devBits[a].dName ) ; + } + } + } +return ( ptr ) ; +} /* end of 'devBitNames' */ diff --git a/NOVA/nova_defs.h b/NOVA/nova_defs.h index 3ec5ccbd..b5edbd36 100644 --- a/NOVA/nova_defs.h +++ b/NOVA/nova_defs.h @@ -1,6 +1,6 @@ /* nova_defs.h: NOVA/Eclipse simulator definitions - Copyright (c) 1993-2005, Robert M. Supnik + Copyright (c) 1993-2008, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,10 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 04-Jul-07 BKR BUSY/DONE/INTR "convenience" macros added, + INT_TRAP added for Nova 3, 4 trap instruction handling, + support for 3rd-party 64KW Nova extensions added, + removed STOP_IND_TRP definition due to common INT/TRP handling 14-Jan-04 BKR Added support for QTY and ALM 22-Nov-03 CEO Added support for PIT device 19-Jan-03 RMS Changed CMASK to CDMASK for Apple Dev kit conflict @@ -46,27 +50,41 @@ #include "sim_defs.h" /* simulator defns */ /* Simulator stop codes */ - + #define STOP_RSRV 1 /* must be 1 */ #define STOP_HALT 2 /* HALT */ #define STOP_IBKPT 3 /* breakpoint */ #define STOP_IND 4 /* indirect loop */ -#define STOP_IND_INT 5 /* ind loop, intr */ -#define STOP_IND_TRP 6 /* ind loop, trap */ +#define STOP_IND_INT 5 /* ind loop, intr or trap */ + /* Memory */ #if defined (ECLIPSE) -#define MAXMEMSIZE 1048576 /* max memory size */ -#else -#define MAXMEMSIZE 32768 /* max memory size */ -#endif -#define AMASK 077777 /* logical addr mask */ + /*----------------------*/ + /* Eclipse */ + /*----------------------*/ + +#define MAXMEMSIZE 1048576 /* max memory size in 16-bit words */ #define PAMASK (MAXMEMSIZE - 1) /* physical addr mask */ +#define MEM_ADDR_OK(x) (((uint32) (x)) < (uint32) MEMSIZE) + +#else + /*----------------------*/ + /* Nova */ + /*----------------------*/ + +#define MAXMEMSIZE 65536 /* max memory size in 16-bit words: 32KW = DG max, */ + /* 64 KW = 3rd-party extended memory feature */ +#define DFTMEMSIZE 32768 /* default/initial mem size */ +#define MEM_ADDR_OK(x) (((uint32) (x)) < (uint32) MEMSIZE) + +#endif + + #define MEMSIZE (cpu_unit.capac) /* actual memory size */ #define A_V_IND 15 /* ind: indirect */ #define A_IND (1 << A_V_IND) -#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) /* Architectural constants */ @@ -82,8 +100,11 @@ #define STK_JMP 3 /* stack jmp @ */ #define TRP_SAV 046 /* trap saved PC */ #define TRP_JMP 047 /* trap jmp @ */ -#define AUTO_INC 020 /* start autoinc */ + +#define AUTO_TOP 037 /* top of autoindex */ #define AUTO_DEC 030 /* start autodec */ +#define AUTO_INC 020 /* start autoinc */ + /* Instruction format */ @@ -235,6 +256,7 @@ typedef struct { #define INT_V_STK 17 /* stack overflow */ #define INT_V_NO_ION_PENDING 18 /* ion delay */ #define INT_V_ION 19 /* interrupts on */ +#define INT_V_TRAP 20 /* trap instruction */ #define INT_PIT (1 << INT_V_PIT) #define INT_DKP (1 << INT_V_DKP) @@ -256,6 +278,7 @@ typedef struct { #define INT_ION (1 << INT_V_ION) #define INT_DEV ((1 << INT_V_STK) - 1) /* device ints */ #define INT_PENDING INT_ION+INT_NO_ION_PENDING +#define INT_TRAP (1 << INT_V_TRAP) /* PI disable bits */ @@ -279,6 +302,18 @@ typedef struct { /* #define PI_CAS 0000040 */ /* #define PI_ADCV 0000002 */ + + /* Macros to clear/set BUSY/DONE/INTR bits */ + +#define DEV_SET_BUSY( x ) dev_busy = dev_busy | (x) +#define DEV_CLR_BUSY( x ) dev_busy = dev_busy & (~(x)) +#define DEV_SET_DONE( x ) dev_done = dev_done | (x) +#define DEV_CLR_DONE( x ) dev_done = dev_done & (~(x)) +#define DEV_UPDATE_INTR int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable) + +#define DEV_IS_BUSY( x ) (dev_busy & (x)) +#define DEV_IS_DONE( x ) (dev_done & (x)) + /* Function prototypes */ int32 MapAddr (int32 map, int32 addr); diff --git a/NOVA/nova_dkp.c b/NOVA/nova_dkp.c index b482f630..c38b4436 100644 --- a/NOVA/nova_dkp.c +++ b/NOVA/nova_dkp.c @@ -1,6 +1,6 @@ /* nova_dkp.c: NOVA moving head disk simulator - Copyright (c) 1993-2005, Robert M. Supnik + Copyright (c) 1993-2008, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,23 @@ dkp moving head disk + 04-Jul-04 BKR device name changed to DG's DKP from DEC's DP, + DEV_SET/CLR/INTR macro use started, + fixed 'P' pulse code and secret quirks, + added 6097 diag and size support, + fixed losing unit drive type during unit change, + tightened sector size determination calculations, + controller DONE flag handling fixed, + fixed cylinder overflow test error, + seek error code fixed, + restructured dkp_go() and dkp_svc() routines + (for known future fixes needed), + fixed DIA status calculation, + fixed DKP read/write loop to properly emulate DG cylinder and sector overflows, + added trace facility, + changed 'stime' calculation to force delay time if no cylinders are crossed + (this fixes some DG code that assumes disk seek takes some time), + fixed boot code to match DG hardware standard 04-Jan-04 RMS Changed attach routine to use sim_fsize 28-Nov-03 CEO Boot from DP now puts device address in SR 24-Nov-03 CEO Added support for disk sizing on 6099/6103 @@ -110,15 +127,35 @@ #define FCCY_SEEK 2 #define FCCY_RECAL 3 #define FCCY_FLAGS 0174000 /* flags */ + #define GET_CMD(x,dt) ((drv_tab[dt].newf)? \ (((x) >> FCCY_V_NCMD) & FCCY_M_NCMD): \ (((x) >> FCCY_V_OCMD) & FCCY_M_OCMD) ) + +#define SET_CMD(x,dt) dkp_fccy = (dkp_fccy & ((drv_tab[dt].newf)? \ + (FCCY_M_NCMD << FCCY_V_NCMD) : (FCCY_M_OCMD << FCCY_V_OCMD))) | \ + ((drv_tab[dt].newf)? \ + (((x) & FCCY_M_NCMD) << FCCY_V_NCMD): \ + (((x) & FCCY_M_OCMD) << FCCY_V_OCMD) ) + #define GET_CYL(x,dt) ((drv_tab[dt].newf)? \ (((x) >> FCCY_V_NCYL) & FCCY_M_NCYL): \ ((((x) >> FCCY_V_OCYL) & FCCY_M_OCYL) | \ ((dt != TYPE_D44)? 0: \ (((x) & FCCY_OCEX) >> (FCCY_V_OCEX - FCCY_V_OCMD)))) ) + + /* (Warning: no sector or surface masking is done!) */ + +#define DKP_UPDATE_USSC( type, count, surf, sect ) \ + dkp_ussc = (dkp_ussc & USSC_UNIT) \ + | ((dkp_ussc + count) & USSC_M_COUNT) \ + | ((drv_tab[dtype].newf)? \ + ((surf << USSC_V_NSURFACE) | (sect << USSC_V_NSECTOR)): \ + ((surf << USSC_V_OSURFACE) | (sect << USSC_V_OSECTOR)) \ + ); + + /* Status */ #define STA_ERR 0000001 /* error */ @@ -154,14 +191,17 @@ floppy 8 1 77 no DS/DD floppy 16 2 77 yes + (6097 "quad floppy") Diablo 31 12 2 203 no 6225 20 2 245 yes Century 111 6 10 203 no + 4048 (same as Century 111) Diablo 44 12 4 408 no 6099 32 4 192 yes 6227 20 6 245 yes 6070 24 4 408 yes Century 114 12 20 203 no + 4057 (same as Century 114) 6103 32 8 192 yes 4231 23 19 411 yes @@ -178,6 +218,7 @@ #define NFMT_FLP FALSE #define TYPE_DSDD 1 +#define TYPE_6097 TYPE_DSDD #define SECT_DSDD 16 #define SURF_DSDD 2 #define CYL_DSDD 77 @@ -278,9 +319,20 @@ struct drvtyp drv_tab[] = { { 0 } }; +#define DKP_TRACE(x) (dkp_trace & (1<<(x))) +#define DKP_TRACE_FP stderr +/* current trace bit use (bit 0 = LSB) + 0 I/O instructions + 1 pre-seek/read/write event setup + 2 seek events + 3 read/write events + 4 post read/write events + */ + extern uint16 M[]; extern UNIT cpu_unit; extern int32 int_req, dev_busy, dev_done, dev_disable; +extern int32 saved_PC, SR, AMASK; int32 dkp_ma = 0; /* memory address */ int32 dkp_map = 0; /* DCH map 0=A 3=B */ @@ -291,13 +343,15 @@ int32 dkp_swait = 100; /* seek latency */ int32 dkp_rwait = 100; /* rotate latency */ int32 dkp_diagmode = 0; /* diagnostic mode */ +int32 dkp_trace = 0 ; + DEVICE dkp_dev; int32 dkp (int32 pulse, int32 code, int32 AC); t_stat dkp_svc (UNIT *uptr); t_stat dkp_reset (DEVICE *dptr); t_stat dkp_boot (int32 unitno, DEVICE *dptr); t_stat dkp_attach (UNIT *uptr, char *cptr); -t_stat dkp_go (void); +t_stat dkp_go ( int32 pulse ); t_stat dkp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); /* DKP data structures @@ -330,7 +384,8 @@ REG dkp_reg[] = { { FLDATA (BUSY, dev_busy, INT_V_DKP) }, { FLDATA (DONE, dev_done, INT_V_DKP) }, { FLDATA (DISABLE, dev_disable, INT_V_DKP) }, - { FLDATA (DIAG, dkp_diagmode, 0) }, + { FLDATA (DIAG, dkp_diagmode, 0) }, + { DRDATA (TRACE, dkp_trace, 32) }, { ORDATA (MAP, dkp_map, 2) }, { DRDATA (STIME, dkp_swait, 24), PV_LEFT }, { DRDATA (RTIME, dkp_rwait, 24), PV_LEFT }, @@ -438,13 +493,14 @@ MTAB dkp_mod[] = { }; DEVICE dkp_dev = { - "DP", dkp_unit, dkp_reg, dkp_mod, + "DKP", dkp_unit, dkp_reg, dkp_mod, DKP_NUMDR, 8, 30, 1, 8, 16, NULL, NULL, &dkp_reset, &dkp_boot, &dkp_attach, NULL, &dkp_dib, DEV_DISABLE }; + /* IOT routine */ int32 dkp (int32 pulse, int32 code, int32 AC) @@ -456,14 +512,26 @@ rval = 0; uptr = dkp_dev.units + GET_UNIT (dkp_ussc); /* select unit */ dtype = GET_DTYPE (uptr->flags); /* get drive type */ +if ( DKP_TRACE(0) ) + { + static char * f[8] = + { "NIO", "DIA", "DOA", "DIB", "DOB", "DIC", "DOC", "SKP" } ; + static char * s[4] = + { " ", "S", "C", "P" } ; + + printf( " [DKP %s%s %06o ", f[code & 0x07], s[pulse & 0x03], (AC & 0xFFFF) ) ; + } + switch (code) { /* decode IR<5:7> */ case ioDIA: /* DIA */ - dkp_sta = dkp_sta & ~STA_DYN; /* clear dynamic */ - if (uptr->flags & UNIT_ATT) dkp_sta = dkp_sta | STA_DRDY; + dkp_sta = dkp_sta & (~STA_DRDY) ; /* keep error flags */ + if (uptr->flags & UNIT_ATT) /* update ready */ + dkp_sta = dkp_sta | STA_DRDY; if (uptr->CYL >= drv_tab[dtype].cyl) dkp_sta = dkp_sta | STA_CYL; /* bad cylinder? */ - if (dkp_sta & STA_EFLGS) dkp_sta = dkp_sta | STA_ERR; + if (dkp_sta & STA_EFLGS) + dkp_sta = dkp_sta | STA_ERR; rval = dkp_sta; break; @@ -474,20 +542,25 @@ switch (code) { /* decode IR<5:7> */ dkp_fccy = AC; /* save cmd, cyl */ dkp_sta = dkp_sta & ~(AC & FCCY_FLAGS); } - if ((dkp_sta & STA_DFLGS) == 0) /* done flags = 0? */ - dev_done = dev_done & ~INT_DKP; /* clear intr */ + DEV_CLR_DONE( INT_DKP ) ; /* assume done flags 0 */ + if ( dkp_sta & STA_DFLGS ) /* done flags = 0? */ + DEV_SET_DONE( INT_DKP ) ; /* nope - set done */ + DEV_UPDATE_INTR ; /* update intr */ break; case ioDIB: /* DIB */ - rval = dkp_ma; /* return buf addr */ + rval = dkp_ma & 077777 ; /* return buf addr */ + /* with B0 clear (no DCH B map support) */ break; case ioDOB: /* DOB */ if ((dev_busy & INT_DKP) == 0) { dkp_ma = AC & (drv_tab[dtype].newf? DMASK: AMASK); - if (AC & 0100000) dkp_map = 3; /* high bit is map */ - else dkp_map = 0; - } + if (AC & 0100000) + dkp_map = 3; /* high bit is map */ + else + dkp_map = 0; + } break; case ioDIC: /* DIC */ @@ -495,63 +568,97 @@ switch (code) { /* decode IR<5:7> */ break; case ioDOC: /* DOC */ - if ((dev_busy & INT_DKP) == 0) dkp_ussc = AC; /* save unit, sect */ - if (((dtype == TYPE_6099) || /* for 6099 and 6103 */ - (dtype == TYPE_6103)) && /* if data<0> set, */ - AC & 010000) dkp_diagmode = 1; /* set diagnostic mode */ + if ((dev_busy & INT_DKP) == 0) /* if device is not busy */ + dkp_ussc = AC ; /* save unit, sect */ + if (((dtype == TYPE_6099) || /* (BKR: don't forget 6097) */ + (dtype == TYPE_6097) || /* for 6099 and 6103 */ + (dtype == TYPE_6103)) && /* if data<0> set, */ + (AC & 010000) ) + dkp_diagmode = 1; /* set diagnostic mode */ break; } /* end switch code */ -u = GET_UNIT(dkp_ussc); /* select unit */ +u = GET_UNIT(dkp_ussc); /* update current unit */ +uptr = dkp_dev.units + u ; /* select unit */ +dtype = GET_DTYPE (uptr->flags); /* get drive type */ + +if ( DKP_TRACE(0) ) + { + if ( code & 1 ) + printf( " [%06o] ", (rval & 0xFFFF) ) ; + printf( "] \n" ) ; + } switch (pulse) { /* decode IR<8:9> */ case iopS: /* start */ - dev_busy = dev_busy | INT_DKP; /* set busy */ - dev_done = dev_done & ~INT_DKP; /* clear done */ - int_req = int_req & ~INT_DKP; /* clear int */ + DEV_SET_BUSY( INT_DKP ) ; /* set busy */ + DEV_CLR_DONE( INT_DKP ) ; /* clear done */ + DEV_UPDATE_INTR ; /* update ints */ if (dkp_diagmode) { /* in diagnostic mode? */ - dkp_diagmode = 0; /* reset it */ + dkp_diagmode = 0; /* reset it */ + if (dtype == TYPE_6097) dkp_ussc = 010001; /* (BKR - quad floppy) */ if (dtype == TYPE_6099) dkp_ussc = 010002; /* return size bits */ if (dtype == TYPE_6103) dkp_ussc = 010003; /* for certain types */ } else { /* normal mode ... */ - if (dkp_go ()) break; /* new cmd, error? */ + if (dkp_go (pulse)) /* do command */ + break ; /* break if no error */ } - dev_busy = dev_busy & ~INT_DKP; /* clear busy */ - dev_done = dev_done | INT_DKP; /* set done */ - int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); - dkp_sta = dkp_sta | STA_DONE; + DEV_CLR_BUSY( INT_DKP ) ; /* clear busy */ + DEV_SET_DONE( INT_DKP ) ; /* set done */ + DEV_UPDATE_INTR ; /* update ints */ + dkp_sta = dkp_sta | STA_DONE; /* set controller done */ break; case iopC: /* clear */ - dev_busy = dev_busy & ~INT_DKP; /* clear busy */ - dev_done = dev_done & ~INT_DKP; /* clear done */ - int_req = int_req & ~INT_DKP; /* clear int */ - dkp_sta = dkp_sta & ~(STA_DFLGS + STA_EFLGS); - if (dkp_unit[u].FUNC != FCCY_SEEK) sim_cancel (&dkp_unit[u]); + DEV_CLR_BUSY( INT_DKP ) ; /* clear busy */ + DEV_CLR_DONE( INT_DKP ) ; /* set done */ + DEV_UPDATE_INTR ; /* update ints */ + dkp_sta = dkp_sta & ~(STA_DFLGS + STA_EFLGS); /* clear controller flags */ + if (dkp_unit[u].FUNC != FCCY_SEEK) + sim_cancel (&dkp_unit[u]); /* cancel any r/w op */ break; case iopP: /* pulse */ - dev_done = dev_done & ~INT_DKP; /* clear done */ - if (dkp_go ()) break; /* new seek command */ - dev_done = dev_done | INT_DKP; /* set done */ - int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); - dkp_sta = dkp_sta | (STA_SKDN0 >> u); /* set seek done */ + if ( dkp_diagmode ) + { + dkp_diagmode = 0 ; /* clear DG diagnostic mode */ + } + else + { + DEV_CLR_DONE( INT_DKP ) ; /* clear done */ + DEV_UPDATE_INTR ; + + /* DG "undocumented feature": 'P' pulse can not start a read/write operation! + * Diagnostic routines will use this crock to do 'crazy things' to size a disk + * and many assume that a recal is done, other assume that they can stop the + * read operation before any damage is done. Must also [re]calculate unit, function + * and type because DOx instruction may have updated the controller info after + * start of this procedure and before our 'P' handler. BKR + */ + if (dkp_go(pulse)) + break; /* no error - do not set done and status */ + } + + DEV_SET_DONE( INT_DKP ) ; /* set done */ + DEV_UPDATE_INTR ; /* update ints */ + dkp_sta = dkp_sta | (STA_SKDN0 >> u); /* set controller seek done */ break; - } /* end case pulse */ + } /* end case pulse */ return rval; } + /* New command, start vs pulse handled externally Returns true if command ok, false if error */ -t_stat dkp_go (void) +t_stat dkp_go ( int32 pulse ) { -UNIT *uptr; -int32 newcyl, func, u, dtype; +UNIT * uptr; +int32 oldCyl, u, dtype; dkp_sta = dkp_sta & ~STA_EFLGS; /* clear errors */ u = GET_UNIT (dkp_ussc); /* get unit number */ @@ -560,31 +667,117 @@ if (((uptr->flags & UNIT_ATT) == 0) || sim_is_active (uptr)) { dkp_sta = dkp_sta | STA_ERR; /* attached or busy? */ return FALSE; } -dtype = GET_DTYPE (uptr->flags); /* get drive type */ -func = GET_CMD (dkp_fccy, dtype); /* get function */ -newcyl = GET_CYL (dkp_fccy, dtype); /* get cylinder */ -switch (func) { /* decode command */ +if (dkp_diagmode) { /* diagnostic mode? */ + dkp_sta = (dkp_sta | STA_DONE); /* Set error bit only */ + DEV_CLR_BUSY( INT_DKP ) ; /* clear busy */ + DEV_SET_DONE( INT_DKP ) ; /* set done */ + DEV_UPDATE_INTR ; /* update interrupts */ + return ( TRUE ) ; /* do not do function */ + } - case FCCY_READ: case FCCY_WRITE: - sim_activate (uptr, dkp_rwait); /* schedule */ +oldCyl = uptr->CYL ; /* get old cylinder */ +dtype = GET_DTYPE (uptr->flags); /* get drive type */ +uptr->FUNC = GET_CMD (dkp_fccy, dtype) ; /* save command */ +uptr->CYL = GET_CYL (dkp_fccy, dtype) ; + +if ( DKP_TRACE(1) ) + { + int32 xSect ; + int32 xSurf ; + int32 xCyl ; + int32 xCnt ; + + xSect = GET_SECT(dkp_ussc, dtype) ; + xSurf = GET_SURF(dkp_ussc, dtype) ; + xCyl = GET_CYL (dkp_fccy, dtype) ; + xCnt = 16 - (GET_COUNT(dkp_ussc)) ; + + fprintf( DKP_TRACE_FP, + " [%s:%c %-5s: %3d / %2d / %2d %2d %06o ] \r\n", + "DKP", + (char) (u + '0'), + ((uptr->FUNC == FCCY_READ) ? + "read" + : ((uptr->FUNC == FCCY_WRITE) ? + "write" + : ((uptr->FUNC == FCCY_SEEK) ? + "seek" + : "" + ) + ) + ), + (unsigned) xCyl, + (unsigned) xSurf, + (unsigned) xSect, + (unsigned) (16 - xCnt), + (unsigned) (dkp_ma & 0xFFFF) /* show all 16-bits in case DCH B */ + ) ; + } + + +switch (uptr->FUNC) { /* decode command */ + + case FCCY_READ: + case FCCY_WRITE: + if (((uptr->flags & UNIT_ATT) == 0) || /* not attached? */ + ((uptr->flags & UNIT_WPRT) && (uptr->FUNC == FCCY_WRITE))) + { + dkp_sta = dkp_sta | STA_DONE | STA_ERR; /* error */ + } + else if ( uptr->CYL >= drv_tab[dtype].cyl ) /* bad cylinder */ + { + dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_CYL ; + } + else if ( GET_SURF(dkp_ussc, dtype) >= drv_tab[dtype].surf ) /* bad surface */ + { + dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_UNS; /* older drives may not even do this... */ + /* dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_XCY ; /- newer disks give this error */ + } + else if ( GET_SECT(dkp_ussc, dtype) >= drv_tab[dtype].sect ) /* or bad sector? */ + { + /* dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_UNS; /- older drives may not even do this... */ + dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_XCY ; /* newer disks give this error */ + } + if ( (pulse != iopS) || (dkp_sta & STA_ERR) ) + { + return ( FALSE ) ; + } + sim_activate (uptr, dkp_rwait); /* schedule read or write request */ break; case FCCY_RECAL: /* recalibrate */ - newcyl = 0; - func = FCCY_SEEK; + uptr->FUNC = FCCY_SEEK ; /* save command */ + uptr->CYL = 0 ; case FCCY_SEEK: /* seek */ - sim_activate (uptr, dkp_swait * abs (newcyl - uptr->CYL)); + if ( ! (uptr->flags & UNIT_ATT) ) /* not attached? */ + { + dkp_sta = dkp_sta | STA_DONE | STA_ERR; /* error */ + } + else if ( uptr->CYL >= drv_tab[dtype].cyl ) /* bad cylinder? */ + { + dkp_sta = dkp_sta | STA_ERR | STA_CYL; + } + if ( (pulse != iopP) || (dkp_sta & STA_ERR) ) + { + return ( FALSE ) ; /* only 'P' pulse start seeks! */ + } + + /* do the seek */ + /* must check for "do we support seeking bits" flag before setting SEEK0'ish bits! */ dkp_sta = dkp_sta | (STA_SEEK0 >> u); /* set seeking */ - uptr->CYL = newcyl; /* on cylinder */ + oldCyl = abs(oldCyl - uptr->CYL) ; + if ( (dkp_swait) && (! (oldCyl)) ) /* enforce minimum wait if req */ + oldCyl = 1 ; + sim_activate ( uptr, (dkp_swait * oldCyl) ) ; break; } /* end case command */ -uptr->FUNC = func; /* save command */ -return TRUE; /* no error */ +return ( TRUE ) ; /* no error */ } + /* Unit service If seek done, put on cylinder; @@ -599,73 +792,127 @@ return TRUE; /* no error */ t_stat dkp_svc (UNIT *uptr) { -int32 sc, sa, xcsa, bda; -int32 sx, dx, pa, u; +int32 sa, bda; +int32 dx, pa, u; int32 dtype, err, newsect, newsurf; uint32 awc; t_stat rval; static uint16 tbuf[DKP_NUMWD]; /* transfer buffer */ -rval = SCPE_OK; + +rval = SCPE_OK; dtype = GET_DTYPE (uptr->flags); /* get drive type */ -if (dkp_diagmode) { /* diagnostic mode? */ - dkp_sta = (dkp_sta | STA_DONE); /* Set error bit only */ - dev_busy = dev_busy & ~INT_DKP; /* clear busy */ - dev_done = dev_done | INT_DKP; /* set done */ - int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); - return SCPE_OK; /* do not do function */ - } +u = uptr - dkp_dev.units; /* get unit number */ + if (uptr->FUNC == FCCY_SEEK) { /* seek? */ - if (uptr->CYL >= drv_tab[dtype].cyl) /* bad cylinder? */ + if ( ! (uptr->flags & UNIT_ATT) ) /* not attached? */ + { + dkp_sta = dkp_sta | STA_DONE | STA_ERR; /* error (changed during queue time?) */ + } + else if ( uptr->CYL >= drv_tab[dtype].cyl ) /* bad cylinder? */ + { dkp_sta = dkp_sta | STA_ERR | STA_CYL; - dev_done = dev_done | INT_DKP; /* set done */ - int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); - u = uptr - dkp_dev.units; /* get unit number */ + } + DEV_SET_DONE( INT_DKP ) ; + DEV_UPDATE_INTR ; dkp_sta = (dkp_sta | (STA_SKDN0 >> u)) /* set seek done */ - & ~(STA_SEEK0 >> u); /* clear seeking */ + & ~(STA_SEEK0 >> u); /* clear seeking */ + if ( DKP_TRACE(2) ) + { + fprintf( DKP_TRACE_FP, + " [%s:%c seek : %4d ] \r\n", + "DKP", + (char) (u + '0'), + (unsigned) (uptr->CYL) + ) ; + } return SCPE_OK; } +/* read or write */ + if (((uptr->flags & UNIT_ATT) == 0) || /* not attached? */ ((uptr->flags & UNIT_WPRT) && (uptr->FUNC == FCCY_WRITE))) - dkp_sta = dkp_sta | STA_DONE | STA_ERR; /* error */ - -else if ((uptr->CYL >= drv_tab[dtype].cyl) || /* bad cylinder */ - (GET_SURF (dkp_ussc, dtype) >= drv_tab[dtype].surf) || /* bad surface */ - (GET_SECT (dkp_ussc, dtype) >= drv_tab[dtype].sect)) /* or bad sector? */ - dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_UNS; - -else if (GET_CYL (dkp_fccy, dtype) != uptr->CYL) /* address error? */ - dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_UNS; - + { + dkp_sta = dkp_sta | STA_DONE | STA_ERR; /* error */ + } +else if ( uptr->CYL >= drv_tab[dtype].cyl ) /* bad cylinder */ + { + dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_CYL ; + dkp_sta = dkp_sta | STA_ERR | STA_CYL; + DEV_SET_DONE( INT_DKP ) ; + DEV_UPDATE_INTR ; + return SCPE_OK ; + } +else if ( GET_SURF(dkp_ussc, dtype) >= drv_tab[dtype].surf ) /* bad surface */ + { + dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_UNS; /* older drives may not even do this... */ +/* dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_XCY ; /- newer disks give this error */ +/* set sector to some bad value and wait then exit? */ + } +else if ( GET_SECT(dkp_ussc, dtype) >= drv_tab[dtype].sect ) /* or bad sector? */ + { +/* dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_UNS; /- older DG drives do not even give error(!), but we do */ + dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_XCY ; /* newer disks give this error */ + } else { - sc = 16 - GET_COUNT (dkp_ussc); /* get sector count */ - sa = GET_SA (uptr->CYL, GET_SURF (dkp_ussc, dtype), - GET_SECT (dkp_ussc, dtype), dtype); /* get disk block */ - xcsa = GET_SA (uptr->CYL + 1, 0, 0, dtype); /* get next cyl addr */ - if ((sa + sc) > xcsa ) { /* across cylinder? */ - sc = xcsa - sa; /* limit transfer */ - dkp_sta = dkp_sta | STA_XCY; /* xcyl error */ +err = 0 ; +do { + if ( DKP_TRACE(3) ) + { + fprintf( DKP_TRACE_FP, + " [%s:%c %-5s: %3d / %2d / %2d %06o ] \r\n", + "DKP", + (char) (u + '0'), + ((uptr->FUNC == FCCY_READ) ? + "read" + : ((uptr->FUNC == FCCY_WRITE) ? + "write" + : "") + ), + (unsigned) (uptr->CYL), + (unsigned) (GET_SURF(dkp_ussc, dtype)), + (unsigned) (GET_SECT(dkp_ussc, dtype)), + (unsigned) (dkp_ma & 0xFFFF) /* show all 16-bits in case DCH B */ + ) ; } - bda = sa * DKP_NUMWD * sizeof (short); /* to words, bytes */ + + if ( GET_SECT(dkp_ussc, dtype) >= drv_tab[dtype].sect ) /* or bad sector? */ + { + /* sector overflows to 0 ; + * surface gets incremented + */ + newsurf = GET_SURF(dkp_ussc, dtype) + 1 ; + newsurf = newsurf & ((drv_tab[dtype].newf) ? USSC_M_NSURFACE : USSC_M_OSURFACE) ; + DKP_UPDATE_USSC( type, 0, newsurf, 0 ) + + if ( (GET_SURF(dkp_ussc, dtype)) >= drv_tab[dtype].surf ) + { + /* dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_UNS; /- older drives may not even do this... */ + dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_XCY ; /* newer disks give this error */ + /* DG retains overflowed surface number, + * other vendors have different/expanded options + */ + break ; + } + } + sa = GET_SA (uptr->CYL, GET_SURF (dkp_ussc, dtype), + GET_SECT (dkp_ussc, dtype), dtype); /* get disk block */ + bda = sa * DKP_NUMWD * sizeof(uint16) ; /* to words, bytes */ err = fseek (uptr->fileref, bda, SEEK_SET); /* position drive */ if (uptr->FUNC == FCCY_READ) { /* read? */ - for (sx = 0; sx < sc; sx++) { /* loop thru sectors */ awc = fxread (tbuf, sizeof(uint16), DKP_NUMWD, uptr->fileref); for ( ; awc < DKP_NUMWD; awc++) tbuf[awc] = 0; if (err = ferror (uptr->fileref)) break; - for (dx = 0; dx < DKP_NUMWD; dx++) { /* loop thru buffer */ + for (dx = 0; dx < DKP_NUMWD; dx++) { /* loop thru buffer */ pa = MapAddr (dkp_map, (dkp_ma & AMASK)); if (MEM_ADDR_OK (pa)) M[pa] = tbuf[dx]; dkp_ma = (dkp_ma + 1) & AMASK; } - } } - - if (uptr->FUNC == FCCY_WRITE) { /* write? */ - for (sx = 0; sx < sc; sx++) { /* loop thru sectors */ + else if (uptr->FUNC == FCCY_WRITE) { /* write? */ for (dx = 0; dx < DKP_NUMWD; dx++) { /* loop into buffer */ pa = MapAddr (dkp_map, (dkp_ma & AMASK)); tbuf[dx] = M[pa]; @@ -674,27 +921,41 @@ else { fxwrite (tbuf, sizeof(int16), DKP_NUMWD, uptr->fileref); if (err = ferror (uptr->fileref)) break; } - } if (err != 0) { perror ("DKP I/O error"); - clearerr (uptr->fileref); + clearerr (uptr->fileref); rval = SCPE_IOERR; + break ; } - sa = sa + sc; /* update sector addr */ - newsect = sa % drv_tab[dtype].sect; - newsurf = (sa / drv_tab[dtype].sect) % drv_tab[dtype].surf; - dkp_ussc = (dkp_ussc & USSC_UNIT) | ((dkp_ussc + sc) & USSC_M_COUNT) | - ((drv_tab[dtype].newf)? - ((newsurf << USSC_V_NSURFACE) | (newsect << USSC_V_NSECTOR)): - ((newsurf << USSC_V_OSURFACE) | (newsect << USSC_V_OSECTOR)) ); +newsect = GET_SECT (dkp_ussc, dtype) + 1 ; /* update next sector */ +newsurf = GET_SURF (dkp_ussc, dtype) ; /* and next head */ + /* (count set below) */ +DKP_UPDATE_USSC( type, 1, newsurf, newsect ) +} /* end read/write loop */ + + while ( (GET_COUNT(dkp_ussc)) ) ; dkp_sta = dkp_sta | STA_DONE; /* set status */ + + if ( DKP_TRACE(4) ) + { + fprintf( DKP_TRACE_FP, + " [%s:%c %-5s: %3d / %2d / %2d %06o ] \r\n", + "DKP", + (char) (u + '0'), + "post", + (unsigned) (uptr->CYL), + (unsigned) (GET_SURF(dkp_ussc, dtype)), + (unsigned) (GET_SECT(dkp_ussc, dtype)), + (unsigned) (dkp_ma & 0xFFFF) /* show all 16-bits in case DCH B */ + ) ; + } } -dev_busy = dev_busy & ~INT_DKP; /* clear busy */ -dev_done = dev_done | INT_DKP; /* set done */ -int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); +DEV_CLR_BUSY( INT_DKP ) ; +DEV_SET_DONE( INT_DKP ) ; +DEV_UPDATE_INTR ; return rval; } @@ -705,9 +966,9 @@ t_stat dkp_reset (DEVICE *dptr) int32 u; UNIT *uptr; -dev_busy = dev_busy & ~INT_DKP; /* clear busy */ -dev_done = dev_done & ~INT_DKP; /* clear done, int */ -int_req = int_req & ~INT_DKP; +DEV_CLR_BUSY( INT_DKP ) ; /* clear busy */ +DEV_CLR_DONE( INT_DKP ) ; /* clear done */ +DEV_UPDATE_INTR ; /* update ints */ dkp_fccy = dkp_ussc = dkp_ma = dkp_sta = 0; /* clear registers */ dkp_diagmode = 0; /* clear diagnostic mode */ dkp_map = 0; @@ -724,7 +985,7 @@ return SCPE_OK; t_stat dkp_attach (UNIT *uptr, char *cptr) { int32 i, p; -t_stat r; +t_stat r; uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size; /* restore capac */ r = attach_unit (uptr, cptr); /* attach */ @@ -751,10 +1012,12 @@ return SCPE_OK; /* Bootstrap routine */ +#if defined(_OLD_CODE_) + #define BOOT_START 02000 #define BOOT_UNIT 02021 #define BOOT_SEEK 02022 -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int)) +#define BOOT_LEN (sizeof(boot_rom) / sizeof(int32)) static const int32 boot_rom[] = { 0060233, /* NIOC 0,DKP ; clear disk */ @@ -774,12 +1037,13 @@ static const int32 boot_rom[] = { 0101113, /* MOVL# 0,0,SNC ; skip if done */ 0000776, /* JMP .-2 */ 0000377, /* JMP 377 */ - 0000016, /* USSC: 0.B1+0.B7+0.B11+16 */ + 0000016, /* USSC: 0.B1+0.B7+0.B11+16 */ 0175000, /* SEKCMD: 175000 */ - 0074000, /* SEKDN: 074000 */ + 0074000, /* SEKDN: 074000 */ 0174000 /* REDCMD: 174000 */ }; + t_stat dkp_boot (int32 unitno, DEVICE *dptr) { int32 i, dtype; @@ -794,3 +1058,27 @@ saved_PC = BOOT_START; SR = 0100000 + DEV_DKP; return SCPE_OK; } + +#endif /* _OLD_CODE_ */ + + + +#define BOOT_START 0375 +#define BOOT_LEN (sizeof (boot_rom) / sizeof (int32)) + +static const int32 boot_rom[] = { + 0062677 /* IORST ; reset the I/O system */ + , 0060133 /* NIOS DKP ; start the disk */ + , 0000377 /* JMP 377 ; wait for the world */ + } ; + + +t_stat dkp_boot (int32 unitno, DEVICE *dptr) +{ +int32 i; + +for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = (uint16) boot_rom[i]; +saved_PC = BOOT_START; +SR = 0100000 + DEV_DKP; +return SCPE_OK; +} diff --git a/NOVA/nova_dsk.c b/NOVA/nova_dsk.c index 6d3f616f..315a4804 100644 --- a/NOVA/nova_dsk.c +++ b/NOVA/nova_dsk.c @@ -1,6 +1,6 @@ /* nova_dsk.c: 4019 fixed head disk simulator - Copyright (c) 1993-2006, Robert M. Supnik + Copyright (c) 1993-2008, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,10 @@ dsk fixed head disk + 04-Jul-07 BKR device name changed to DG's DSK from DEC's DK, + DEV_xxx macros now used for consistency, + added secret DG DIC function, + fixed boot info table size calculation 15-May-06 RMS Fixed bug in autosize attach (reported by David Gesswein) 04-Jan-04 RMS Changed sim_fsize calling sequence 26-Jul-03 RMS Fixed bug in set size routine @@ -95,12 +99,13 @@ static const int32 sector_map[] = { extern uint16 M[]; extern UNIT cpu_unit; extern int32 int_req, dev_busy, dev_done, dev_disable; +extern int32 saved_PC, SR, AMASK; int32 dsk_stat = 0; /* status register */ int32 dsk_da = 0; /* disk address */ int32 dsk_ma = 0; /* memory address */ int32 dsk_wlk = 0; /* wrt lock switches */ -int32 dsk_stopioe = 1; /* stop on error */ +int32 dsk_stopioe = 0; /* stop on error */ int32 dsk_time = 100; /* time per sector */ DEVICE dsk_dev; @@ -153,13 +158,14 @@ MTAB dsk_mod[] = { }; DEVICE dsk_dev = { - "DK", &dsk_unit, dsk_reg, dsk_mod, + "DSK", &dsk_unit, dsk_reg, dsk_mod, 1, 8, 21, 1, 8, 16, NULL, NULL, &dsk_reset, &dsk_boot, &dsk_attach, NULL, &dsk_dib, DEV_DISABLE }; + /* IOT routine */ int32 dsk (int32 pulse, int32 code, int32 AC) @@ -184,32 +190,37 @@ switch (code) { /* decode IR<5:7> */ case ioDOB: /* DOB */ dsk_ma = AC & AMASK; /* save mem addr */ break; + + case ioDIC: /* DIC - undocumented DG feature(!) */ + rval = 256 ; /* return fixed sector size for DG for now */ + break ; } /* end switch code */ if (pulse) { /* any pulse? */ - dev_busy = dev_busy & ~INT_DSK; /* clear busy */ - dev_done = dev_done & ~INT_DSK; /* clear done */ - int_req = int_req & ~INT_DSK; /* clear int */ + DEV_CLR_BUSY( INT_DSK ) ; + DEV_CLR_DONE( INT_DSK ) ; + DEV_UPDATE_INTR ; dsk_stat = 0; /* clear status */ sim_cancel (&dsk_unit); /* stop I/O */ } if ((pulse == iopP) && ((dsk_wlk >> GET_DISK (dsk_da)) & 1)) { /* wrt lock? */ - dev_done = dev_done | INT_DSK; /* set done */ - int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); + DEV_SET_DONE( INT_DSK ) ; + DEV_UPDATE_INTR ; dsk_stat = DSKS_ERR + DSKS_WLS; /* set status */ return rval; } if (pulse & 1) { /* read or write? */ if (((uint32) (dsk_da * DSK_NUMWD)) >= dsk_unit.capac) { /* inv sev? */ - dev_done = dev_done | INT_DSK; /* set done */ - int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); + DEV_SET_DONE( INT_DSK ) ; + DEV_UPDATE_INTR ; dsk_stat = DSKS_ERR + DSKS_NSD; /* set status */ return rval; /* done */ } dsk_unit.FUNC = pulse; /* save command */ - dev_busy = dev_busy | INT_DSK; /* set busy */ + DEV_SET_BUSY( INT_DSK ) ; + DEV_UPDATE_INTR ; t = sector_map[dsk_da & DSK_MMASK] - GET_SECTOR (dsk_time); if (t < 0) t = t + DSK_NUMSC; sim_activate (&dsk_unit, t * dsk_time); /* activate */ @@ -217,6 +228,7 @@ if (pulse & 1) { /* read or write? */ return rval; } + /* Unit service */ t_stat dsk_svc (UNIT *uptr) @@ -224,9 +236,9 @@ t_stat dsk_svc (UNIT *uptr) int32 i, da, pa; int16 *fbuf = uptr->filebuf; -dev_busy = dev_busy & ~INT_DSK; /* clear busy */ -dev_done = dev_done | INT_DSK; /* set done */ -int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); +DEV_CLR_BUSY( INT_DSK ) ; +DEV_SET_DONE( INT_DSK ) ; +DEV_UPDATE_INTR ; if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */ dsk_stat = DSKS_ERR + DSKS_NSD; /* set status */ @@ -241,7 +253,7 @@ if (uptr->FUNC == iopS) { /* read? */ } dsk_ma = (dsk_ma + DSK_NUMWD) & AMASK; } -if (uptr->FUNC == iopP) { /* write? */ +else if (uptr->FUNC == iopP) { /* write? */ for (i = 0; i < DSK_NUMWD; i++) { /* copy sector */ pa = MapAddr (0, (dsk_ma + i) & AMASK); /* map address */ fbuf[da + i] = M[pa]; @@ -255,43 +267,43 @@ dsk_stat = 0; /* set status */ return SCPE_OK; } + /* Reset routine */ t_stat dsk_reset (DEVICE *dptr) { dsk_stat = dsk_da = dsk_ma = 0; -dev_busy = dev_busy & ~INT_DSK; /* clear busy */ -dev_done = dev_done & ~INT_DSK; /* clear done */ -int_req = int_req & ~INT_DSK; /* clear int */ +DEV_CLR_BUSY( INT_DSK ) ; +DEV_CLR_DONE( INT_DSK ) ; +DEV_UPDATE_INTR ; sim_cancel (&dsk_unit); return SCPE_OK; } + /* Bootstrap routine */ -#define BOOT_START 2000 -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int)) +#define BOOT_START 0375 +#define BOOT_LEN (sizeof (boot_rom) / sizeof (int32)) static const int32 boot_rom[] = { - 060220, /* NIOC DSK ; clear disk */ - 0102400, /* SUB 0,0 ; addr = 0 */ - 061020, /* DOA 0,DSK ; set disk addr */ - 062120, /* DOBS 0,DSK ; set mem addr, rd */ - 063620, /* SKPDN DSK ; done? */ - 000776, /* JMP .-2 */ - 000377, /* JMP 377 */ - }; + 0062677 /* IORST ; reset the I/O system */ + , 0060120 /* NIOS DSK ; start the disk */ + , 0000377 /* JMP 377 ; wait for the world */ + } ; + t_stat dsk_boot (int32 unitno, DEVICE *dptr) { -int32 i; -extern int32 saved_PC; +int32 i; -for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i]; +for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = (uint16) boot_rom[i]; saved_PC = BOOT_START; +SR = 0100000 + DEV_DSK; return SCPE_OK; } + /* Attach routine */ t_stat dsk_attach (UNIT *uptr, char *cptr) @@ -308,6 +320,7 @@ uptr->capac = UNIT_GETP (uptr->flags) * DSK_DKSIZE; /* set capacity */ return attach_unit (uptr, cptr); } + /* Change disk size */ t_stat dsk_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) diff --git a/NOVA/nova_lp.c b/NOVA/nova_lp.c index d3980d02..c2e3923c 100644 --- a/NOVA/nova_lp.c +++ b/NOVA/nova_lp.c @@ -1,6 +1,6 @@ /* nova_lp.c: NOVA line printer simulator - Copyright (c) 1993-2007, Robert M. Supnik + Copyright (c) 1993-2008, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,16 +25,27 @@ lpt line printer + 04-Jul-07 BKR DEV_SET/CLR macros now used, + , , output character delay now contingent upon non-zero TIME value, + LPT can now be DISABLED 19-Jan-07 RMS Added UNIT_TEXT 25-Apr-03 RMS Revised for extended file support 30-May-02 RMS Widened POS to 32b + + +Notes: + - data currently masked to 7 bits. + - if register TIME is non-zero, then delay TIME events if , or seen + - register POS show the current file position + - register STOP_IOE determines return value issued if output to unattached LPT is attempted */ #include "nova_defs.h" extern int32 int_req, dev_busy, dev_done, dev_disable; -int32 lpt_stopioe = 0; /* stop on error */ + +int32 lpt_stopioe = 0; /* stop on error flag */ int32 lpt (int32 pulse, int32 code, int32 AC); t_stat lpt_svc (UNIT *uptr); @@ -49,7 +60,7 @@ t_stat lpt_reset (DEVICE *dptr); DIB lpt_dib = { DEV_LPT, INT_LPT, PI_LPT, &lpt }; -UNIT lpt_unit = { +UNIT lpt_unit = { /* 2007-May-30, bkr */ UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT }; @@ -73,42 +84,51 @@ DEVICE lpt_dev = { &lpt_dib, DEV_DISABLE }; + /* IOT routine */ int32 lpt (int32 pulse, int32 code, int32 AC) { +if (code == ioDOA) + lpt_unit.buf = AC & 0177 ; -if (code == ioDOA) lpt_unit.buf = AC & 0177; -switch (pulse) { /* decode IR<8:9> */ - - case iopS: /* start */ - dev_busy = dev_busy | INT_LPT; /* set busy */ - dev_done = dev_done & ~INT_LPT; /* clear done, int */ - int_req = int_req & ~INT_LPT; - if ((lpt_unit.buf != 015) && (lpt_unit.buf != 014) && - (lpt_unit.buf != 012)) - return (lpt_svc (&lpt_unit) << IOT_V_REASON); +switch (pulse) + { /* decode IR<8:9> */ + case iopS: /* start */ + DEV_SET_BUSY( INT_LPT ) ; + DEV_CLR_DONE( INT_LPT ) ; + DEV_UPDATE_INTR ; + if ( lpt_unit.wait ) + if ( (lpt_unit.buf == 015) + || (lpt_unit.buf == 014) + || (lpt_unit.buf == 012) + ) + { sim_activate (&lpt_unit, lpt_unit.wait); - break; + break ; + } + return (lpt_svc (&lpt_unit) << IOT_V_REASON); + break; - case iopC: /* clear */ - dev_busy = dev_busy & ~INT_LPT; /* clear busy */ - dev_done = dev_done & ~INT_LPT; /* clear done, int */ - int_req = int_req & ~INT_LPT; - sim_cancel (&lpt_unit); /* deactivate unit */ - break; - } /* end switch */ + case iopC: /* clear */ + DEV_CLR_BUSY( INT_LPT ) ; + DEV_CLR_DONE( INT_LPT ) ; + DEV_UPDATE_INTR ; + sim_cancel (&lpt_unit); /* deactivate unit */ + break; + } /* end switch */ return 0; } + /* Unit service */ t_stat lpt_svc (UNIT *uptr) { -dev_busy = dev_busy & ~INT_LPT; /* clear busy */ -dev_done = dev_done | INT_LPT; /* set done */ -int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); +DEV_CLR_BUSY( INT_LPT ) ; +DEV_SET_DONE( INT_LPT ) ; +DEV_UPDATE_INTR ; if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */ return IORETURN (lpt_stopioe, SCPE_UNATT); fputc (uptr->buf, uptr->fileref); @@ -121,14 +141,15 @@ if (ferror (uptr->fileref)) { return SCPE_OK; } + /* Reset routine */ t_stat lpt_reset (DEVICE *dptr) { -lpt_unit.buf = 0; -dev_busy = dev_busy & ~INT_LPT; /* clear busy */ -dev_done = dev_done & ~INT_LPT; /* clear done, int */ -int_req = int_req & ~INT_LPT; +lpt_unit.buf = 0; /* (not DG compatible) */ +DEV_CLR_BUSY( INT_LPT ) ; +DEV_CLR_DONE( INT_LPT ) ; +DEV_UPDATE_INTR ; sim_cancel (&lpt_unit); /* deactivate unit */ return SCPE_OK; } diff --git a/NOVA/nova_mta.c b/NOVA/nova_mta.c index 0a4f03ae..2dd287e4 100644 --- a/NOVA/nova_mta.c +++ b/NOVA/nova_mta.c @@ -1,6 +1,6 @@ /* nova_mta.c: NOVA magnetic tape simulator - Copyright (c) 1993-2005, Robert M. Supnik + Copyright (c) 1993-2008, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,9 @@ mta magnetic tape + 04-Jul-07 BKR fixed boot code to properly boot self-boot tapes; + boot routine now uses standard DG APL boot code; + device name changed to DG's MTA from DEC's MT. 16-Aug-05 RMS Fixed C++ declaration and cast problems 18-Mar-05 RMS Added attached test to detach routine 22-Nov-03 CEO DIB returns # records skipped after space fwd @@ -146,9 +149,13 @@ #define STA_MON (STA_REW | STA_BOT | STA_WLK | STA_RDY | \ STA_PEM) /* set status chg */ -extern uint16 M[]; -extern UNIT cpu_unit; -extern int32 int_req, dev_busy, dev_done, dev_disable; +extern uint16 M[]; +extern UNIT cpu_unit; +extern int32 int_req, dev_busy, dev_done, dev_disable; +extern int32 SR, AMASK; + +extern t_stat cpu_boot(int32 unitno, DEVICE * dptr ) ; + int32 mta_ma = 0; /* memory address */ int32 mta_wc = 0; /* word count */ @@ -225,7 +232,7 @@ MTAB mta_mod[] = { }; DEVICE mta_dev = { - "MT", mta_unit, mta_reg, mta_mod, + "MTA", mta_unit, mta_reg, mta_mod, MTA_NUMDR, 10, 31, 1, 8, 8, NULL, NULL, &mta_reset, &mta_boot, &mta_attach, &mta_detach, @@ -601,42 +608,21 @@ else mta_upddsta (uptr, uptr->USTAT & ~STA_WLK); return SCPE_OK; } -/* Bootstrap routine */ -#define BOOT_START 02000 -#define BOOT_UNIT 02020 -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int)) - -static const int32 boot_rom[] = { - 0060222, /* NIOC 0,MTA ; clear disk */ - 0020417, /* LDA 0,UNIT ; unit */ - 0024417, /* LDA 1,REWIND ; cmd */ - 0107000, /* ADD 0,1 ; cmd + unit */ - 0065122, /* DOAS 1,MTA ; start rewind */ - 0070422, /* DIA 2,MTA ; get status */ - 0151213, /* MOVR# 2,2,SNC ; skip if done */ - 0000776, /* JMP .-2 */ - 0126400, /* SUB 1,1 ; ma, wc = 0 */ - 0066022, /* DOB 1,MTA */ - 0067022, /* DOC 1,MTA */ - 0061122, /* DOAS 0,MTA ; start read */ - 0070422, /* DIA 2,MTA ; get status */ - 0151213, /* MOVR# 2,2,SNC ; skip if done */ - 0000776, /* JMP .-2 */ - 0000377, /* JMP 377 */ - 0000000, /* UNIT: */ - 0000010 /* REWIND: 10 */ - }; +/* Boot routine */ t_stat mta_boot (int32 unitno, DEVICE *dptr) -{ -int32 i; -extern int32 saved_PC, SR; - -sim_tape_rewind (&mta_unit[unitno]); -for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i]; -M[BOOT_UNIT] = (unitno & CU_M_UNIT) << CU_V_UNIT; -saved_PC = BOOT_START; -SR = 0100000 + DEV_MTA; -return SCPE_OK; -} + { + sim_tape_rewind( &mta_unit[unitno] ) ; + /* + use common rewind/reset code + device reset + rewind 'tape' file + device + unit + controller + */ + cpu_boot( unitno, dptr ) ; + SR = 0100000 + DEV_MTA ; + return ( SCPE_OK ); + } /* end of 'mta_boot' */ diff --git a/NOVA/nova_plt.c b/NOVA/nova_plt.c index 88704d7f..9375e182 100644 --- a/NOVA/nova_plt.c +++ b/NOVA/nova_plt.c @@ -1,6 +1,6 @@ /* nova_plt.c: NOVA plotter simulator - Copyright (c) 2000-2005, Robert M. Supnik + Copyright (c) 2000-2008, Robert M. Supnik Written by Bruce Ray and used with his gracious permission. Permission is hereby granted, free of charge, to any person obtaining a @@ -26,11 +26,20 @@ plt plotter + 04-Jul-07 BKR added 7B/8B support (default is 8B), + DEV_SET/CLR macros now used 25-Apr-03 RMS Revised for extended file support 03-Oct-02 RMS Added DIB 30-May-02 RMS Widened POS to 32b 06-Jan-02 RMS Revised enable/disable support 26-Apr-01 RMS Added device enable/disable support + + +Notes: + - data masked to 7- or 8- bits, based on 7B or 8B, default is 8-bits + - if register TIME is non-zero, then delay TIME events if , or seen + - register POS show the current file position + - register STOP_IOE determines return value issued if output to unattached PLT is attempted */ #include "nova_defs.h" @@ -44,6 +53,12 @@ int32 plt (int32 pulse, int32 code, int32 AC); t_stat plt_svc (UNIT *uptr); t_stat plt_reset (DEVICE *dptr); + + /* 7 or 8 bit data mask support for either device */ + +#define UNIT_V_8B (UNIT_V_UF + 0) /* 8b output */ +#define UNIT_8B (1 << UNIT_V_8B) + /* PLT data structures plt_dev PLT device descriptor @@ -53,8 +68,8 @@ t_stat plt_reset (DEVICE *dptr); DIB plt_dib = { DEV_PLT, INT_PLT, PI_PLT, &plt }; -UNIT plt_unit = { - UDATA (&plt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT +UNIT plt_unit = { /* 2007-May-30, bkr */ + UDATA (&plt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_8B, 0), SERIAL_OUT_WAIT }; REG plt_reg[] = { @@ -69,46 +84,58 @@ REG plt_reg[] = { { NULL } }; +MTAB plt_mod[] = /* 2007-May-30, bkr */ + { + { UNIT_8B, 0, "7b", "7B", NULL }, + { UNIT_8B, UNIT_8B, "8b", "8B", NULL }, + { 0, 0, NULL, NULL, NULL } + } ; + DEVICE plt_dev = { - "PLT", &plt_unit, plt_reg, NULL, + "PLT", &plt_unit, plt_reg, plt_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &plt_reset, NULL, NULL, NULL, &plt_dib, DEV_DISABLE }; + /* plotter: IOT routine */ int32 plt (int32 pulse, int32 code, int32 AC) { -if (code == ioDOA) plt_unit.buf = AC & 0377; -switch (pulse) { /* decode IR<8:9> */ +if (code == ioDOA) + plt_unit.buf = AC & ((plt_unit.flags & UNIT_8B)? + 0377 + : 0177); +switch (pulse) + { /* decode IR<8:9> */ + case iopS: /* start */ + DEV_SET_BUSY( INT_PLT ) ; + DEV_CLR_DONE( INT_PLT ) ; + DEV_UPDATE_INTR ; + sim_activate (&plt_unit, plt_unit.wait); /* activate unit */ + break; - case iopS: /* start */ - dev_busy = dev_busy | INT_PLT; /* set busy */ - dev_done = dev_done & ~INT_PLT; /* clear done, int */ - int_req = int_req & ~INT_PLT; - sim_activate (&plt_unit, plt_unit.wait); /* activate unit */ - break; - - case iopC: /* clear */ - dev_busy = dev_busy & ~INT_PLT; /* clear busy */ - dev_done = dev_done & ~INT_PLT; /* clear done, int */ - int_req = int_req & ~INT_PLT; - sim_cancel (&plt_unit); /* deactivate unit */ - break; - } /* end switch */ + case iopC: /* clear */ + DEV_CLR_BUSY( INT_PLT ) ; + DEV_CLR_DONE( INT_PLT ) ; + DEV_UPDATE_INTR ; + sim_cancel (&plt_unit); /* deactivate unit */ + break; + } /* end switch */ return 0; } + /* Unit service */ t_stat plt_svc (UNIT *uptr) { -dev_busy = dev_busy & ~INT_PLT; /* clear busy */ -dev_done = dev_done | INT_PLT; /* set done */ -int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); +DEV_CLR_BUSY( INT_PLT ) ; +DEV_SET_DONE( INT_PLT ) ; +DEV_UPDATE_INTR ; if ((plt_unit.flags & UNIT_ATT) == 0) /* attached? */ return IORETURN (plt_stopioe, SCPE_UNATT); if (putc (plt_unit.buf, plt_unit.fileref) == EOF) { @@ -116,18 +143,19 @@ if (putc (plt_unit.buf, plt_unit.fileref) == EOF) { clearerr (plt_unit.fileref); return SCPE_IOERR; } -plt_unit.pos = plt_unit.pos + 1; +++(plt_unit.pos); return SCPE_OK; } + /* Reset routine */ t_stat plt_reset (DEVICE *dptr) { -plt_unit.buf = 0; -dev_busy = dev_busy & ~INT_PLT; /* clear busy */ -dev_done = dev_done & ~INT_PLT; /* clear done, int */ -int_req = int_req & ~INT_PLT; +plt_unit.buf = 0; /* */ +DEV_CLR_BUSY( INT_PLT ) ; +DEV_CLR_DONE( INT_PLT ) ; +DEV_UPDATE_INTR ; sim_cancel (&plt_unit); /* deactivate unit */ return SCPE_OK; } diff --git a/NOVA/nova_pt.c b/NOVA/nova_pt.c index 9559ea75..47788503 100644 --- a/NOVA/nova_pt.c +++ b/NOVA/nova_pt.c @@ -1,6 +1,6 @@ /* nova_pt.c: NOVA paper tape read/punch simulator - Copyright (c) 1993-2005, Robert M. Supnik + Copyright (c) 1993-2008, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,15 +26,30 @@ ptr paper tape reader ptp paper tape punch + 04-Jul-07 BKR added PTR and PTP device DISABLE capability, + added 7B/8B support PTR and PTP (default is 8B), + DEV_SET/CLR macros now used, + PTR and PTP can now be DISABLED 25-Apr-03 RMS Revised for extended file support 03-Oct-02 RMS Added DIBs 30-May-02 RMS Widened POS to 32b 29-Nov-01 RMS Added read only unit support + + +Notes: + - data masked to 7- or 8- bits, based on 7B or 8B, default is 8-bits + - register TIME is the delay between character read or write operations + - register POS show the number of characters read from or sent to the PTR or PTP + - register STOP_IOE determines return value issued if output to unattached PTR or PTP is attempted */ #include "nova_defs.h" -extern int32 int_req, dev_busy, dev_done, dev_disable; +extern int32 int_req, dev_busy, dev_done, dev_disable ; +extern int32 SR ; + +extern t_stat cpu_boot(int32 unitno, DEVICE * dptr ) ; + int32 ptr_stopioe = 0, ptp_stopioe = 0; /* stop on error */ @@ -44,6 +59,14 @@ t_stat ptr_svc (UNIT *uptr); t_stat ptp_svc (UNIT *uptr); t_stat ptr_reset (DEVICE *dptr); t_stat ptp_reset (DEVICE *dptr); +t_stat ptr_boot (int32 unitno, DEVICE *dptr); + + + /* 7 or 8 bit data mask support for either device */ + +#define UNIT_V_8B (UNIT_V_UF + 0) /* 8b output */ +#define UNIT_8B (1 << UNIT_V_8B) + /* PTR data structures @@ -54,8 +77,8 @@ t_stat ptp_reset (DEVICE *dptr); DIB ptr_dib = { DEV_PTR, INT_PTR, PI_PTR, &ptr }; -UNIT ptr_unit = { - UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), +UNIT ptr_unit = { /* 2007-May-30, bkr */ + UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE+UNIT_8B, 0), SERIAL_IN_WAIT }; @@ -71,12 +94,19 @@ REG ptr_reg[] = { { NULL } }; +MTAB ptr_mod[] = /* 2007-May-30, bkr */ + { + { UNIT_8B, 0, "7b", "7B", NULL }, + { UNIT_8B, UNIT_8B, "8b", "8B", NULL }, + { 0, 0, NULL, NULL, NULL } + } ; + DEVICE ptr_dev = { - "PTR", &ptr_unit, ptr_reg, NULL, + "PTR", &ptr_unit, ptr_reg, ptr_mod /* 2007-May-30, bkr */, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptr_reset, - NULL, NULL, NULL, - &ptr_dib, 0 + &ptr_boot, NULL, NULL, + &ptr_dib, DEV_DISABLE /* 2007-May-30, bkr */ }; /* PTP data structures @@ -88,8 +118,9 @@ DEVICE ptr_dev = { DIB ptp_dib = { DEV_PTP, INT_PTP, PI_PTP, &ptp }; -UNIT ptp_unit = { - UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT +UNIT ptp_unit = + { + UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_8B, 0), SERIAL_OUT_WAIT }; REG ptp_reg[] = { @@ -104,46 +135,58 @@ REG ptp_reg[] = { { NULL } }; -DEVICE ptp_dev = { - "PTP", &ptp_unit, ptp_reg, NULL, +MTAB ptp_mod[] = + { + { UNIT_8B, 0, "7b", "7B", NULL }, + { UNIT_8B, UNIT_8B, "8b", "8B", NULL }, + { 0, 0, NULL, NULL, NULL } + } ; + +DEVICE ptp_dev = + { + "PTP", &ptp_unit, ptp_reg, ptp_mod /* 2007-May-30, bkr */, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptp_reset, NULL, NULL, NULL, - &ptp_dib, 0 + &ptp_dib, DEV_DISABLE /* 2007-May-30, bkr */ }; + /* Paper tape reader: IOT routine */ int32 ptr (int32 pulse, int32 code, int32 AC) { -int32 iodata; +int32 iodata; -iodata = (code == ioDIA)? ptr_unit.buf & 0377: 0; -switch (pulse) { /* decode IR<8:9> */ +iodata = (code == ioDIA)? + ptr_unit.buf & 0377 + : 0; +switch (pulse) + { /* decode IR<8:9> */ + case iopS: /* start */ + DEV_SET_BUSY( INT_PTR ) ; + DEV_CLR_DONE( INT_PTR ) ; + DEV_UPDATE_INTR ; + sim_activate (&ptr_unit, ptr_unit.wait); /* activate unit */ + break; - case iopS: /* start */ - dev_busy = dev_busy | INT_PTR; /* set busy */ - dev_done = dev_done & ~INT_PTR; /* clear done, int */ - int_req = int_req & ~INT_PTR; - sim_activate (&ptr_unit, ptr_unit.wait); /* activate unit */ - break; - - case iopC: /* clear */ - dev_busy = dev_busy & ~INT_PTR; /* clear busy */ - dev_done = dev_done & ~INT_PTR; /* clear done, int */ - int_req = int_req & ~INT_PTR; - sim_cancel (&ptr_unit); /* deactivate unit */ - break; - } /* end switch */ + case iopC: /* clear */ + DEV_CLR_BUSY( INT_PTR ) ; + DEV_CLR_DONE( INT_PTR ) ; + DEV_UPDATE_INTR ; + sim_cancel (&ptr_unit); /* deactivate unit */ + break; + } /* end switch */ return iodata; } + /* Unit service */ t_stat ptr_svc (UNIT *uptr) { -int32 temp; +int32 temp; if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */ return IORETURN (ptr_stopioe, SCPE_UNATT); @@ -156,77 +199,99 @@ if ((temp = getc (ptr_unit.fileref)) == EOF) { /* end of file? */ clearerr (ptr_unit.fileref); return SCPE_IOERR; } -dev_busy = dev_busy & ~INT_PTR; /* clear busy */ -dev_done = dev_done | INT_PTR; /* set done */ -int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); -ptr_unit.buf = temp & 0377; -ptr_unit.pos = ptr_unit.pos + 1; + +DEV_CLR_BUSY( INT_PTR ) ; +DEV_SET_DONE( INT_PTR ) ; +DEV_UPDATE_INTR ; +ptr_unit.buf = temp & ((ptr_unit.flags & UNIT_8B)? 0377: 0177); +++(ptr_unit.pos); return SCPE_OK; } + /* Reset routine */ t_stat ptr_reset (DEVICE *dptr) { -ptr_unit.buf = 0; -dev_busy = dev_busy & ~INT_PTR; /* clear busy */ -dev_done = dev_done & ~INT_PTR; /* clear done, int */ -int_req = int_req & ~INT_PTR; +ptr_unit.buf = 0; /* */ +DEV_CLR_BUSY( INT_PTR ) ; +DEV_CLR_DONE( INT_PTR ) ; +DEV_UPDATE_INTR ; sim_cancel (&ptr_unit); /* deactivate unit */ return SCPE_OK; } + +/* Boot routine */ + +t_stat ptr_boot (int32 unitno, DEVICE *dptr) +{ +ptr_reset( dptr ) ; +/* set position to 0? */ +cpu_boot( unitno, dptr ) ; +SR = /* low-speed: no high-order bit set */ DEV_PTR ; +return ( SCPE_OK ); +} /* end of 'ptr_boot' */ + + + + + /* Paper tape punch: IOT routine */ int32 ptp (int32 pulse, int32 code, int32 AC) { -if (code == ioDOA) ptp_unit.buf = AC & 0377; -switch (pulse) { /* decode IR<8:9> */ +if (code == ioDOA) + ptp_unit.buf = AC & 0377; - case iopS: /* start */ - dev_busy = dev_busy | INT_PTP; /* set busy */ - dev_done = dev_done & ~INT_PTP; /* clear done, int */ - int_req = int_req & ~INT_PTP; - sim_activate (&ptp_unit, ptp_unit.wait); /* activate unit */ - break; +switch (pulse) + { /* decode IR<8:9> */ + case iopS: /* start */ + DEV_SET_BUSY( INT_PTP ) ; + DEV_CLR_DONE( INT_PTP ) ; + DEV_UPDATE_INTR ; + sim_activate (&ptp_unit, ptp_unit.wait); /* activate unit */ + break; - case iopC: /* clear */ - dev_busy = dev_busy & ~INT_PTP; /* clear busy */ - dev_done = dev_done & ~INT_PTP; /* clear done, int */ - int_req = int_req & ~INT_PTP; - sim_cancel (&ptp_unit); /* deactivate unit */ - break; - } /* end switch */ + case iopC: /* clear */ + DEV_CLR_BUSY( INT_PTP ) ; + DEV_CLR_DONE( INT_PTP ) ; + DEV_UPDATE_INTR ; + sim_cancel (&ptp_unit); /* deactivate unit */ + break; + } /* end switch */ return 0; } + /* Unit service */ t_stat ptp_svc (UNIT *uptr) { -dev_busy = dev_busy & ~INT_PTP; /* clear busy */ -dev_done = dev_done | INT_PTP; /* set done */ -int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); +DEV_CLR_BUSY( INT_PTP ) ; +DEV_SET_DONE( INT_PTP ) ; +DEV_UPDATE_INTR ; if ((ptp_unit.flags & UNIT_ATT) == 0) /* attached? */ return IORETURN (ptp_stopioe, SCPE_UNATT); -if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { +if (putc ((ptp_unit.buf & ((ptp_unit.flags & UNIT_8B)? 0377: 0177)), ptp_unit.fileref) == EOF) { perror ("PTP I/O error"); clearerr (ptp_unit.fileref); return SCPE_IOERR; } -ptp_unit.pos = ptp_unit.pos + 1; +++(ptp_unit.pos); return SCPE_OK; } + /* Reset routine */ t_stat ptp_reset (DEVICE *dptr) { -ptp_unit.buf = 0; -dev_busy = dev_busy & ~INT_PTP; /* clear busy */ -dev_done = dev_done & ~INT_PTP; /* clear done, int */ -int_req = int_req & ~INT_PTP; +ptp_unit.buf = 0; /* */ +DEV_CLR_BUSY( INT_PTP ) ; +DEV_CLR_DONE( INT_PTP ) ; +DEV_UPDATE_INTR ; sim_cancel (&ptp_unit); /* deactivate unit */ return SCPE_OK; } diff --git a/NOVA/nova_qty.c b/NOVA/nova_qty.c index 258fbeb6..e4c928b5 100644 --- a/NOVA/nova_qty.c +++ b/NOVA/nova_qty.c @@ -1,6 +1,6 @@ /* nova_qty.c: NOVA multiplexor (QTY/ALM) simulator - Copyright (c) 2000-2005, Robert M. Supnik + Copyright (c) 2000-2008, Robert M. Supnik Written by Bruce Ray and used with his gracious permission. Permission is hereby granted, free of charge, to any person obtaining a @@ -26,6 +26,7 @@ qty multiplexor: QTY = 4060, ALM = 42xx + 04-Jul-07 BKR fixed QTY output line number calculation (affected higher line numbers), 25-Mar-04 RMS Updated for V3.2 12-Jan-04 BKR Initial release includes both original DG "quad" multiplexor (QTY) @@ -198,16 +199,6 @@ DEVICE qty_dev = &qty_dib, (DEV_DISABLE | DEV_DIS | DEV_NET) }; - - /* */ - /* (need to mask off non-interrupt bit devices) */ - -#define DEV_SET_BUSY( dibp ) dev_busy = dev_busy | ( (dibp)->mask ) ; -#define DEV_CLEAR_BUSY( dibp ) dev_busy = dev_busy & ~( (dibp)->mask ) ; -#define DEV_SET_DONE( dibp ) dev_done = dev_done | ( (dibp)->mask ) ; int_req = int_req & ~( (dibp)->mask ) ; -#define DEV_CLEAR_DONE( dibp ) dev_done = dev_done & ~( (dibp)->mask ) ; int_req = int_req & ~( (dibp)->mask ) ; -#define DEV_UPDATE_INTR int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable) ; - #define DG_RETURN( status, data ) (int32)(((status) << IOT_V_REASON) | ((data) & 0x0FFFF) ) /* @@ -466,17 +457,17 @@ int qty_update_status( DIB * dibp, TMXR * tmxr_desc ) } } /* */ - DEV_CLEAR_BUSY( dibp ) - DEV_CLEAR_DONE( dibp ) + DEV_CLR_BUSY( INT_QTY ) ; + DEV_CLR_DONE( INT_QTY ) ; if ( txbusy ) { - DEV_SET_BUSY( dibp ) ; + DEV_SET_BUSY( INT_QTY ) ; } if ( status & (QTY_S_RI | QTY_S_TI) ) { - DEV_SET_DONE( dibp ) + DEV_SET_DONE( INT_QTY ) ; } - DEV_UPDATE_INTR /* update final intr status */ + DEV_UPDATE_INTR ; /* update final intr status */ return ( status ) ; } /* end of 'qty_update_status' */ @@ -568,9 +559,9 @@ t_stat qty_common_reset( DIB * dibp, UNIT * unitp, DEVICE * dptr ) else qty_dev.flags |= DEV_DIS; } qty_clear( TRUE ) ; - DEV_CLEAR_BUSY( dibp ) /* clear busy */ - DEV_CLEAR_DONE( dibp ) /* clear done, int */ - DEV_UPDATE_INTR + DEV_CLR_BUSY( INT_QTY ) ; /* clear busy */ + DEV_CLR_DONE( INT_QTY ) ; /* clear done, int */ + DEV_UPDATE_INTR ; if ( QTY_MASTER_ACTIVE(&qty_desc) ) { sim_activate( unitp, tmxr_poll ) ; @@ -692,7 +683,7 @@ int32 qty( int32 pulse, int32 code, int32 AC ) break ; case ioDOA : /* send character to QTY */ - line = QTY_LINE_EXTRACT( iodata ) ; + line = QTY_LINE_EXTRACT( AC ) ; if ( line < qty_max ) if ( QTY_LINE_BIT_SET(line,QTY_L_TXE) ) { @@ -979,7 +970,7 @@ int32 alm( int32 pulse, int32 code, int32 AC ) /* (mask with 'alm_line_mask' in case ALM mask is different than QTY */ alm_section = 0 ; if ( ! ( iodata & QTY_S_RI) ) - if ( iodata & QTY_S_TI ) + if ( iodata & QTY_S_TI ) { alm_section = 1 ; /* receiver quiet - transmitter done */ } @@ -1100,7 +1091,7 @@ int32 alm( int32 pulse, int32 code, int32 AC ) * clear device busy */ for ( a = 0 ; a < qty_max ; ++a ) - if ( 1 ) + if ( 1 /* (not yet optimized) */ ) { QTY_LINE_CLEAR_BIT( a, (QTY_L_RXBZ | QTY_L_RXDN | QTY_L_TXBZ | QTY_L_TXDN) ) ; } @@ -1112,7 +1103,7 @@ int32 alm( int32 pulse, int32 code, int32 AC ) case iopC : for ( a = 0 ; a < qty_max ; ++a ) - if ( 1 ) + if ( 1 /* (not yet optimized) */ ) { QTY_LINE_CLEAR_BIT( a, (QTY_L_RXBZ | QTY_L_RXDN | QTY_L_TXBZ | QTY_L_TXDN) ) ; } diff --git a/NOVA/nova_sys.c b/NOVA/nova_sys.c index c5a278a6..54dfc740 100644 --- a/NOVA/nova_sys.c +++ b/NOVA/nova_sys.c @@ -1,6 +1,6 @@ /* nova_sys.c: NOVA simulator interface - Copyright (c) 1993-2005, Robert M. Supnik + Copyright (c) 1993-2008, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,10 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 04-Jul-07 BKR DEC's IOF/ION changed to DG's INTDS/INTEN mnemonic, + Fixed QTY/ADCV device name, + RDSW changed to DDG's READS mnemonic, + fixed/enhanced 'load' command for DG-compatible binary tape format 26-Mar-04 RMS Fixed warning with -std=c99 14-Jan-04 BKR Added support for QTY and ALM 04-Jan-04 RMS Fixed 64b issues found by VMS 8.1 @@ -45,13 +49,6 @@ extern DEVICE cpu_dev; extern UNIT cpu_unit; -#if defined (ECLIPSE) -extern DEVICE map_dev; -extern DEVICE fpu_dev; -extern DEVICE pit_dev; -extern int32 Usermap; -extern int32 MapStat; -#endif extern DEVICE ptr_dev; extern DEVICE ptp_dev; extern DEVICE plt_dev; @@ -69,6 +66,20 @@ extern DEVICE alm_dev; extern REG cpu_reg[]; extern uint16 M[]; extern int32 saved_PC; +extern int32 AMASK; + +#if defined (ECLIPSE) + +extern DEVICE map_dev; +extern DEVICE fpu_dev; +extern DEVICE pit_dev; +extern int32 Usermap; +extern int32 MapStat; + +#endif + +extern int32 sim_switches; + /* SCP data structures @@ -120,8 +131,7 @@ const char *sim_stop_messages[] = { "HALT instruction", "Breakpoint", "Nested indirect address limit exceeded", - "Nested indirect interrupt address limit exceeded", - "Nested indirect trap address limit exceeded", + "Nested indirect interrupt or trap address limit exceeded", "Read breakpoint", "Write breakpoint" }; @@ -147,29 +157,57 @@ const char *sim_stop_messages[] = { If the word count is [-21,-n], then the block is repeated data. If the word count is 1, the block is the start address. If the word count is >1, the block is an error block. + +Notes: + 'start' block terminates loading. + 'start' block starting address 1B0 = do not auto-start, 0B0 = auto-start. + 'start' block starting address is saved in 'save_PC' so a "continue" + should start the program. + + specify -i switch ignores checksum errors + + +internal state machine: + + 0,1 get byte count (low and high), ignore leader bytes (<000>) + 2,3 get origin + 4,5 get checksum + 6,7 process data block + 8 process 'ignore' (error) block */ t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) { -int32 data, csum, count, state, i; -uint32 origin; +int32 data, csum, count, state, i; +int32 origin; +int pos ; +int block_start ; +int done ; -if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; +if ((*cptr != 0) || (flag != 0)) + return ( SCPE_ARG ) ; state = 0; -while ((i = getc (fileref)) != EOF) { +block_start = -1 ; +done = 0 ; +for ( pos = 0 ; (! done) && ((i=getc(fileref)) != EOF) ; ++pos ) + { + i &= 0x00FF ; /* (insure no sign extension) */ switch (state) { case 0: /* leader */ count = i; - state = (count != 0); + state = (count != 0) ; + if ( state ) + block_start = pos ; break; case 1: /* high count */ - csum = count = (i << 8) | count; + csum = count = (i << 8) | count ; state = 2; break; case 2: /* low origin */ origin = i; state = 3; - break; + break ; + case 3: /* high origin */ origin = (i << 8) | origin; csum = csum + origin; @@ -180,56 +218,88 @@ while ((i = getc (fileref)) != EOF) { state = 5; break; case 5: /* high checksum */ - csum = csum + (i << 8); - if (count == 1) saved_PC = origin; /* count = 1? */ - if (count <= 1) { /* count = 0/1? */ - if (csum & 0177777) return SCPE_CSUM; - state = 0; - break; - } - if (count < 0100000) { /* count > 1 */ - state = 8; - break; - } - count = 0200000 - count; - state = 6; + csum = (csum + (i << 8)) & 0xFFFF ; + if (count == 1) + { + /* 'start' block */ + /* do any auto-start check or inhibit check */ + saved_PC = (origin & 077777) ; /* 0B0 = auto-start program */ + /* 1B0 = do not auto start */ + state = 0 ; /* indicate okay state */ + done = 1 ; /* we're done! */ + if ( ! (origin & 0x8000) ) + { + printf( "auto start @ %05o \n", (origin & 0x7FFF) ) ; + } + break ; + } + if ( ((count & 0x8000) == 0) && (count > 1)) + { + /* 'ignore' block */ + state = 8 ; + } + /* 'data' or 'repeat' block */ + count = 0200000 - count ; + if ( count <= 020 ) + { + /* 'data' block */ + state = 6 ; + break ; + } + /* 'repeat' block (multiple data) */ + + if (count > 020) { /* large block */ + for (count = count - 1; count > 1; count--) { + if (origin >= AMASK /* MEMSIZE? */) + { + return ( SCPE_NXM ); + } + M[origin] = data; + origin = origin + 1; + } + state = 0 ; + } + state = 0; break; case 6: /* low data */ - data = i; + data = i; state = 7; break; case 7: /* high data */ data = (i << 8) | data; - csum = csum + data; - if (count > 20) { /* large block */ - for (count = count - 1; count == 1; count--) { - if (origin >= MEMSIZE) return SCPE_NXM; - M[origin] = data; - origin = origin + 1; - } - } - if (origin >= MEMSIZE) return SCPE_NXM; + csum = (csum + data) & 0xFFFF ; + + if (origin >= AMASK /* MEMSIZE? */) + return SCPE_NXM; M[origin] = data; origin = origin + 1; count = count - 1; if (count == 0) { - if (csum & 0177777) return SCPE_CSUM; + if ( csum ) + { + printf( "checksum error: block start at %d [0x%x] \n", block_start, block_start ) ; + printf( "calculated: 0%o [0x%4x]\n", csum, csum ) ; + if ( ! (sim_switches & SWMASK('I')) ) + return SCPE_CSUM; + } state = 0; break; } state = 6; break; - case 8: /* error block */ - if (i == 0377) state = 0; + case 8: /* error (ignore) block */ + if (i == 0377) + state = 0; /* (wait for 'RUBOUT' char) */ break; } /* end switch */ } /* end while */ /* Ok to find end of tape between blocks or in error state */ -return ((state == 0) || (state == 8))? SCPE_OK: SCPE_FMT; +return ( ((state == 0) || (state == 8)) ? SCPE_OK : SCPE_FMT ) ; } + /* Symbol tables */ #define I_V_FL 18 /* flag bits */ @@ -382,8 +452,8 @@ static const char *opcode[] = { "ANDL#", "ANDZL#", "ANDOL#", "ANDCL#", "ANDR#", "ANDZR#", "ANDOR#", "ANDCR#", "ANDS#", "ANDZS#", "ANDOS#", "ANDCS#", - "ION", "IOF", - "RDSW", "INTA", "MSKO", "IORST", "HALT", + "INTEN", "INTDS", + "READS", "INTA", "MSKO", "IORST", "HALT", #if !defined (ECLIPSE) "MUL", "DIV", "MULS", "DIVS", "PSHA", "POPA", "SAV", "RET", @@ -517,7 +587,7 @@ static const int32 opc_val[] = { 0061001+I_R, 0060001+I_R, 0061201+I_R, 0060201+I_R, 0060401+I_BY, 0062001+I_BY, #endif - 0060000+I_D, 0060100+I_D, 0060200+I_D, 0060300+I_D, + 0060000+I_RD, 0060100+I_RD, 0060200+I_RD, 0060300+I_RD, 0060400+I_RD, 0060500+I_RD, 0060600+I_RD, 0060700+I_RD, 0061000+I_RD, 0061100+I_RD, 0061200+I_RD, 0061300+I_RD, 0061400+I_RD, 0061500+I_RD, 0061600+I_RD, 0061700+I_RD, @@ -541,7 +611,7 @@ static const char *device[] = { "ERCC", "MAP", #endif "TTI", "TTO", "PTR", "PTP", "RTC", "PLT", "CDR", "LPT", - "DSK", "MTA", "DCM", "ADCV", "DKP", "CAS", + "DSK", "MTA", "DCM", "QTY" /* "ADCV" */, "DKP", "CAS", "TTI1", "TTO1", "CPU", NULL }; diff --git a/NOVA/nova_tt.c b/NOVA/nova_tt.c index a15ee97b..59491d5c 100644 --- a/NOVA/nova_tt.c +++ b/NOVA/nova_tt.c @@ -1,6 +1,6 @@ /* nova_tt.c: NOVA console terminal simulator - Copyright (c) 1993-2005, Robert M. Supnik + Copyright (c) 1993-2008, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,9 @@ tti terminal input tto terminal output + 04-Jul-07 BKR fixed Dasher CR/LF swap function in 'tti_svc()', + DEV_SET/CLR macros now used, + TTO device may now be DISABLED 29-Dec-03 RMS Added console backpressure support 25-Apr-03 RMS Revised for extended file support 05-Jan-02 RMS Fixed calling sequence for setmod @@ -35,12 +38,21 @@ 17-Sep-01 RMS Removed multiconsole support 07-Sep-01 RMS Moved function prototypes 31-May-01 RMS Added multiconsole support + + Notes: + - TTO output is always masked to 7 bits in this rev + - TTO "Dasher" attribute sends '\b' to console instead of '\031' + - TTO may be disabled + - TTI input is always masked to 7 bits in this rev + - TTI "Dasher" attribute swaps and + - TTI may not be disabled */ #include "nova_defs.h" #define UNIT_V_DASHER (UNIT_V_UF + 0) /* Dasher mode */ #define UNIT_DASHER (1 << UNIT_V_DASHER) + extern int32 int_req, dev_busy, dev_done, dev_disable; int32 tti (int32 pulse, int32 code, int32 AC); @@ -78,7 +90,7 @@ MTAB ttx_mod[] = { { UNIT_DASHER, 0, "ANSI", "ANSI", &ttx_setmod }, { UNIT_DASHER, UNIT_DASHER, "Dasher", "DASHER", &ttx_setmod }, { 0 } - }; + } ; DEVICE tti_dev = { "TTI", &tti_unit, tti_reg, ttx_mod, @@ -115,7 +127,7 @@ DEVICE tto_dev = { 1, 10, 31, 1, 8, 8, NULL, NULL, &tto_reset, NULL, NULL, NULL, - &tto_dib, 0 + &tto_dib, DEV_DISABLE }; /* Terminal input: IOT routine */ @@ -124,21 +136,25 @@ int32 tti (int32 pulse, int32 code, int32 AC) { int32 iodata; -iodata = (code == ioDIA)? tti_unit.buf & 0377: 0; -switch (pulse) { /* decode IR<8:9> */ - case iopS: /* start */ - dev_busy = dev_busy | INT_TTI; /* set busy */ - dev_done = dev_done & ~INT_TTI; /* clear done, int */ - int_req = int_req & ~INT_TTI; - break; +if (code == ioDIA) + iodata = tti_unit.buf & 0377; +else iodata = 0; - case iopC: /* clear */ - dev_busy = dev_busy & ~INT_TTI; /* clear busy */ - dev_done = dev_done & ~INT_TTI; /* clear done, int */ - int_req = int_req & ~INT_TTI; - break; - } /* end switch */ +switch (pulse) + { /* decode IR<8:9> */ + case iopS: /* start */ + DEV_SET_BUSY( INT_TTI ) ; + DEV_CLR_DONE( INT_TTI ) ; + DEV_UPDATE_INTR ; + break; + + case iopC: /* clear */ + DEV_CLR_BUSY( INT_TTI ) ; + DEV_CLR_DONE( INT_TTI ) ; + DEV_UPDATE_INTR ; + break; + } /* end switch */ return iodata; } @@ -150,14 +166,19 @@ t_stat tti_svc (UNIT *uptr) int32 temp; sim_activate (&tti_unit, tti_unit.wait); /* continue poll */ -if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */ +if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) + return temp; /* no char or error? */ tti_unit.buf = temp & 0177; -if ((tti_unit.flags & UNIT_DASHER) && (tti_unit.buf == '\r')) - tti_unit.buf = '\n'; /* Dasher: cr -> nl */ -dev_busy = dev_busy & ~INT_TTI; /* clear busy */ -dev_done = dev_done | INT_TTI; /* set done */ -int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); -tti_unit.pos = tti_unit.pos + 1; +if (tti_unit.flags & UNIT_DASHER) { + if (tti_unit.buf == '\r') + tti_unit.buf = '\n'; /* Dasher: cr -> nl */ + else if (tti_unit.buf == '\n') + tti_unit.buf = '\r' ; /* Dasher: nl -> cr */ + } +DEV_CLR_BUSY( INT_TTI ) ; +DEV_SET_DONE( INT_TTI ) ; +DEV_UPDATE_INTR ; +++(uptr->pos) ; return SCPE_OK; } @@ -165,10 +186,10 @@ return SCPE_OK; t_stat tti_reset (DEVICE *dptr) { -tti_unit.buf = 0; -dev_busy = dev_busy & ~INT_TTI; /* clear busy */ -dev_done = dev_done & ~INT_TTI; /* clear done, int */ -int_req = int_req & ~INT_TTI; +tti_unit.buf = 0; /* */ +DEV_CLR_BUSY( INT_TTI ) ; +DEV_CLR_DONE( INT_TTI ) ; +DEV_UPDATE_INTR ; sim_activate (&tti_unit, tti_unit.wait); /* activate unit */ return SCPE_OK; } @@ -177,44 +198,47 @@ return SCPE_OK; int32 tto (int32 pulse, int32 code, int32 AC) { -if (code == ioDOA) tto_unit.buf = AC & 0377; -switch (pulse) { /* decode IR<8:9> */ +if (code == ioDOA) + tto_unit.buf = AC & 0377; - case iopS: /* start */ - dev_busy = dev_busy | INT_TTO; /* set busy */ - dev_done = dev_done & ~INT_TTO; /* clear done, int */ - int_req = int_req & ~INT_TTO; - sim_activate (&tto_unit, tto_unit.wait); /* activate unit */ - break; - - case iopC: /* clear */ - dev_busy = dev_busy & ~INT_TTO; /* clear busy */ - dev_done = dev_done & ~INT_TTO; /* clear done, int */ - int_req = int_req & ~INT_TTO; - sim_cancel (&tto_unit); /* deactivate unit */ - break; - } /* end switch */ +switch (pulse) + { /* decode IR<8:9> */ + case iopS: /* start */ + DEV_SET_BUSY( INT_TTO ) ; + DEV_CLR_DONE( INT_TTO ) ; + DEV_UPDATE_INTR ; + sim_activate (&tto_unit, tto_unit.wait); /* activate unit */ + break; + case iopC: /* clear */ + DEV_CLR_BUSY( INT_TTO ) ; + DEV_CLR_DONE( INT_TTO ) ; + DEV_UPDATE_INTR ; + sim_cancel (&tto_unit); /* deactivate unit */ + break; + } /* end switch */ return 0; } + /* Unit service */ t_stat tto_svc (UNIT *uptr) { -int32 c; -t_stat r; +int32 c; +t_stat r; c = tto_unit.buf & 0177; -if ((tto_unit.flags & UNIT_DASHER) && (c == 031)) c = '\b'; +if ((tto_unit.flags & UNIT_DASHER) && (c == 031)) + c = '\b'; if ((r = sim_putchar_s (c)) != SCPE_OK) { /* output; error? */ sim_activate (uptr, uptr->wait); /* try again */ - return ((r == SCPE_STALL)? SCPE_OK: r); /* !stall? report */ + return ((r == SCPE_STALL)? SCPE_OK : r); /* !stall? report */ } -dev_busy = dev_busy & ~INT_TTO; /* clear busy */ -dev_done = dev_done | INT_TTO; /* set done */ -int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); -tto_unit.pos = tto_unit.pos + 1; +DEV_CLR_BUSY( INT_TTO ) ; +DEV_SET_DONE( INT_TTO ) ; +DEV_UPDATE_INTR ; +++(tto_unit.pos); return SCPE_OK; } @@ -222,10 +246,10 @@ return SCPE_OK; t_stat tto_reset (DEVICE *dptr) { -tto_unit.buf = 0; -dev_busy = dev_busy & ~INT_TTO; /* clear busy */ -dev_done = dev_done & ~INT_TTO; /* clear done, int */ -int_req = int_req & ~INT_TTO; +tto_unit.buf = 0; /* */ +DEV_CLR_BUSY( INT_TTO ) ; +DEV_CLR_DONE( INT_TTO ) ; +DEV_UPDATE_INTR ; sim_cancel (&tto_unit); /* deactivate unit */ return SCPE_OK; } diff --git a/NOVA/nova_tt1.c b/NOVA/nova_tt1.c index 6e014f8d..ad451593 100644 --- a/NOVA/nova_tt1.c +++ b/NOVA/nova_tt1.c @@ -1,6 +1,6 @@ /* nova_tt1.c: NOVA second terminal simulator - Copyright (c) 1993-2004, Robert M. Supnik + Copyright (c) 1993-2008, Robert M. Supnik Written by Bruce Ray and used with his gracious permission. Permission is hereby granted, free of charge, to any person obtaining a @@ -207,7 +207,7 @@ return SCPE_OK; t_stat tti1_reset (DEVICE *dptr) { ttx1_enbdis (dptr->flags & DEV_DIS); /* sync devices */ -tti1_unit.buf = 0; +tti1_unit.buf = 0; /* */ dev_busy = dev_busy & ~INT_TTI1; /* clear busy */ dev_done = dev_done & ~INT_TTI1; /* clear done, int */ int_req = int_req & ~INT_TTI1; @@ -275,7 +275,7 @@ return SCPE_OK; t_stat tto1_reset (DEVICE *dptr) { ttx1_enbdis (dptr->flags & DEV_DIS); /* sync devices */ -tto1_unit.buf = 0; +tto1_unit.buf = 0; /* */ dev_busy = dev_busy & ~INT_TTO1; /* clear busy */ dev_done = dev_done & ~INT_TTO1; /* clear done, int */ int_req = int_req & ~INT_TTO1; diff --git a/PDP10/pdp10_diag.txt b/PDP10/pdp10_bug_history.txt similarity index 93% rename from PDP10/pdp10_diag.txt rename to PDP10/pdp10_bug_history.txt index f5a01b87..b4a31144 100644 --- a/PDP10/pdp10_diag.txt +++ b/PDP10/pdp10_bug_history.txt @@ -1,5 +1,4 @@ -Bugs Found ----------- +Bugs Found and Fixed During Simulator Debug 1. pushj cleared T2 after setting it 2. if timer autoadjust is enabled, timer diagnostic may fail, diff --git a/PDP11/pdp11_cpu.c b/PDP11/pdp11_cpu.c index 904d0f76..f977fb24 100644 --- a/PDP11/pdp11_cpu.c +++ b/PDP11/pdp11_cpu.c @@ -1,6 +1,6 @@ /* pdp11_cpu.c: PDP-11 CPU simulator - Copyright (c) 1993-2007, Robert M Supnik + Copyright (c) 1993-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,8 @@ cpu PDP-11 CPU + 22-Apr-08 RMS Fixed MMR0 treatment in RESET (found by Walter Mueller) + 02-Feb-08 RMS Fixed DMA memory address limit test (found by John Dundas) 28-Apr-07 RMS Removed clock initialization 27-Oct-06 RMS Added idle support 18-Oct-06 RMS Fixed bug in ASH -32 C value @@ -296,6 +298,7 @@ int32 hst_p = 0; /* history pointer */ int32 hst_lnt = 0; /* history length */ InstHistory *hst = NULL; /* instruction history */ int32 dsmask[4] = { MMR3_KDS, MMR3_SDS, 0, MMR3_UDS }; /* dspace enables */ +t_addr cpu_memsize = INIMEMSIZE; /* last mem addr */ extern int32 CPUERR, MAINT; extern int32 sim_interval; @@ -646,6 +649,9 @@ t_stat reason; reason = build_dib_tab (); /* build, chk dib_tab */ if (reason != SCPE_OK) return reason; +if (MEMSIZE < cpu_tab[cpu_model].maxm) /* mem size < max? */ + cpu_memsize = MEMSIZE; /* then okay */ +else cpu_memsize = cpu_tab[cpu_model].maxm - IOPAGESIZE;/* max - io page */ cpu_type = 1u << cpu_model; /* reset type mask */ cpu_bme = (MMR3 & MMR3_BME) && (cpu_opt & OPT_UBM); /* map enabled? */ PC = saved_PC; @@ -863,11 +869,11 @@ while (reason == 0) { case 5: /* RESET */ if (cm == MD_KER) { reset_all (2); /* skip CPU, sys reg */ - PIRQ = 0; /* clear PIRQ, STKLIM, */ - STKLIM = 0; /* MMR0<15:12,0>, */ + PIRQ = 0; /* clear PIRQ */ + STKLIM = 0; /* clear STKLIM */ + MMR0 = 0; /* clear MMR0 */ + MMR3 = 0; /* clear MMR3 */ for (i = 0; i < IPL_HLVL; i++) int_req[i] = 0; - MMR0 = MMR0 & ~(MMR0_MME | MMR0_FREEZE); - MMR3 = 0; /* MMR3 */ trap_req = trap_req & ~TRAP_INT; dsenable = calc_ds (cm); } diff --git a/PDP11/pdp11_cpumod.c b/PDP11/pdp11_cpumod.c index b77c8a22..4624b0e2 100644 --- a/PDP11/pdp11_cpumod.c +++ b/PDP11/pdp11_cpumod.c @@ -1,6 +1,6 @@ /* pdp11_cpumod.c: PDP-11 CPU model-specific features - Copyright (c) 2004-2007, Robert M Supnik + Copyright (c) 2004-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,9 @@ system PDP-11 model-specific registers + 20-May-08 RMS Added JCSR default for KDJ11B, KDJ11E + 22-Apr-08 RMS Fixed write behavior of 11/70 MBRK, LOSIZE, HISIZE + (found by Walter Mueller) 29-Apr-07 RMS Don't run bus setup routine during RESTORE 30-Aug-05 RMS Added additional 11/60 registers 16-Aug-05 RMS Fixed C++ declaration and cast problems @@ -65,6 +68,7 @@ int32 CCR = 0; /* cache control reg */ int32 HITMISS = 0; /* hit/miss reg */ int32 MAINT = 0; /* maint reg */ int32 JCSR = 0; /* J11 control */ +int32 JCSR_dflt = 0; /* J11 boot ctl def */ int32 JPCR = 0; /* J11 page ctrl */ int32 JASR = 0; /* J11 addtl status */ int32 UDCR = 0; /* UBA diag ctrl */ @@ -118,6 +122,8 @@ t_stat sys_reset (DEVICE *dptr); int32 toy_read (void); void toy_write (int32 bit); uint8 toy_set (int32 val); +t_stat sys_set_jclk_dflt (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat sys_show_jclk_dflt (FILE *st, UNIT *uptr, int32 val, void *desc); extern t_stat PSW_rd (int32 *data, int32 addr, int32 access); extern t_stat PSW_wr (int32 data, int32 addr, int32 access); @@ -243,6 +249,10 @@ static const char *opt_name[] = { "RH11", "RH70", "PARITY", "NOPARITY", "Unibus map", "No map", NULL }; +static const char *jcsr_val[4] = { + "LINE", "50HZ", "60HZ", "800HZ" + }; + /* SYSTEM data structures sys_dev SYSTEM device descriptor @@ -264,6 +274,7 @@ REG sys_reg[] = { { ORDATA (WCS, WCS, 16) }, { ORDATA (SYSID, SYSID, 16) }, { ORDATA (JCSR, JCSR, 16) }, + { ORDATA (JCSR_DFLT, JCSR_dflt, 16), REG_HRO }, { ORDATA (JPCR, JPCR, 16) }, { ORDATA (JASR, JASR, 16) }, { ORDATA (UDCR, UDCR, 16) }, @@ -276,8 +287,14 @@ REG sys_reg[] = { { NULL} }; +MTAB sys_mod[] = { + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "JCLK_DFLT", "JCLK_DFLT", + &sys_set_jclk_dflt, &sys_show_jclk_dflt }, + { 0 } + }; + DEVICE sys_dev = { - "SYSTEM", &sys_unit, sys_reg, NULL, + "SYSTEM", &sys_unit, sys_reg, sys_mod, 1, 0, 0, 0, 0, 0, NULL, NULL, &sys_reset, NULL, NULL, NULL, @@ -541,7 +558,11 @@ t_stat CPU70_rd (int32 *data, int32 pa, int32 access) { switch ((pa >> 1) & 017) { /* decode pa<4:1> */ - case 000: case 001: case 011: /* LO,HI ERR, HI SIZE */ + case 000: /* low error */ + *data = 0; + return SCPE_OK; + + case 001: /* high error */ *data = 0; return SCPE_OK; @@ -561,10 +582,14 @@ switch ((pa >> 1) & 017) { /* decode pa<4:1> */ *data = HITMISS; return SCPE_OK; - case 010: /* lower size */ + case 010: /* low size */ *data = (MEMSIZE >> 6) - 1; return SCPE_OK; + case 011: /* high size */ + *data = 0; + return SCPE_OK; + case 012: /* system ID */ *data = SYSID; return SCPE_OK; @@ -610,12 +635,19 @@ switch ((pa >> 1) & 017) { /* decode pa<4:1> */ case 005: /* Hit/miss */ return SCPE_OK; + case 010: /* low size */ + return SCPE_OK; + + case 011: /* high size */ + return SCPE_OK; + case 013: /* CPUERR */ CPUERR = 0; return SCPE_OK; case 014: /* MBRK */ - MBRK = data; + ODD_IGN (data); + MBRK = data & MBRK70_WR; return SCPE_OK; case 015: /* PIRQ */ @@ -1143,7 +1175,9 @@ MEMERR = 0; if (!CPUT (CPUT_J)) MAINT = 0; MBRK = 0; WCS = 0; -JCSR = 0; +if (CPUT (CPUT_JB|CPUT_JE)) + JCSR = JCSR_dflt; +else JCSR = 0; JPCR = 0; JASR = 0; UDCR = 0; @@ -1156,3 +1190,28 @@ for (i = 0; i < UBM_LNT_LW; i++) ub_map[i] = 0; for (i = 0; i < TOY_LNT; i++) toy_data[i] = 0; return SCPE_OK; } + +/* Set/show JCLK default values */ + +t_stat sys_set_jclk_dflt (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 i; + +if ((CPUT (CPUT_JB|CPUT_JE)) && cptr) { + for (i = 0; i < 4; i++) { + if (strncmp (cptr, jcsr_val[i], strlen (cptr)) == 0) { + JCSR_dflt = i << CSRJ_V_LTCSEL; + return SCPE_OK; + } + } + } +return SCPE_ARG; +} + +t_stat sys_show_jclk_dflt (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +if (CPUT (CPUT_JB|CPUT_JE)) + fprintf (st, "JCLK default=%s\n", jcsr_val[CSRJ_LTCSEL (JCSR_dflt)]); +else fprintf (st, "Not implemented\n"); +return SCPE_OK; +} diff --git a/PDP11/pdp11_cpumod.h b/PDP11/pdp11_cpumod.h index d5297d24..b1851313 100644 --- a/PDP11/pdp11_cpumod.h +++ b/PDP11/pdp11_cpumod.h @@ -1,6 +1,6 @@ /* pdp11_cpumod.h: PDP-11 CPU model definitions - Copyright (c) 2004-2005, Robert M Supnik + Copyright (c) 2004-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 22-Apr-08 RMS Added 11/70 MBRK register 30-Aug-05 RMS Added additional 11/60 registers */ @@ -177,6 +178,10 @@ #define CPUE60_RD (CPUE_ODD|CPUE_TMO|CPUE_RED) +/* 11/70 specific registers */ + +#define MBRK70_WR 0000377 /* microbreak */ + /* J11 specific registers */ /* Maintenance register */ diff --git a/PDP11/pdp11_dc.c b/PDP11/pdp11_dc.c new file mode 100644 index 00000000..743c0391 --- /dev/null +++ b/PDP11/pdp11_dc.c @@ -0,0 +1,651 @@ +/* pdp11_dc.c: PDP-11 DC11 multiple terminal interface simulator + + Copyright (c) 1993-2008, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + dci,dco DC11 terminal input/output + + The simulator supports both hardwired and modem-like behavior. If modem + control is not enabled, carrier detect, ring, and carrier change are + never set. +*/ + +#if defined (VM_PDP10) /* PDP10 version */ +#error "DC11 is not supported on the PDP-10!" + +#elif defined (VM_VAX) /* VAX version */ +#error "DC11 is not supported on the VAX!" + +#else /* PDP-11 version */ +#include "pdp11_defs.h" +#endif +#include "sim_sock.h" +#include "sim_tmxr.h" + +#define DCX_MASK (DCX_LINES - 1) + +/* Parity and modem control */ + +#define DCX_V_OPAR (TTUF_V_UF + 0) +#define DCX_V_EPAR (TTUF_V_UF + 1) +#define DCX_V_MDM (TTUF_V_UF + 2) +#define DCX_OPAR (1u << DCX_V_OPAR) +#define DCX_EPAR (1u << DCX_V_EPAR) +#define DCX_MDM (1u << DCX_V_MDM) + +/* registers */ + +#define DCICSR_RD 0173777 +#define DCICSR_WR 0003533 +#define DCICSR_DTR 0000001 /* DTR (RW) */ +#define DCICSR_XBR 0000002 /* xmit brk (RWNI) */ +#define DCICSR_CDT 0000004 /* car det (RO) */ +#define DCICSR_PAR 0000040 /* odd par (RO) */ +#define DCICSR_OVR 0010000 /* overrun (RO) */ +#define DCICSR_RNG 0020000 /* ring (RO) */ +#define DCICSR_CCH 0040000 /* car change (RO) */ +#define DCICSR_ALLERR (DCICSR_OVR|DCICSR_RNG|DCICSR_CCH) +#define DCICSR_ERR 0100000 /* error */ +#define DCOCSR_RD 0100737 +#define DCOCSR_WR 0000535 +#define DCOCSR_RTS 0000001 /* req to send (RW) */ +#define DCOCSR_CTS 0000002 /* clr to send (RO) */ +#define DCOCSR_MNT 0000004 /* maint (RWNI) */ + +extern int32 int_req[IPL_HLVL]; +extern int32 tmxr_poll; + +uint16 dci_csr[DCX_LINES] = { 0 }; /* control/status */ +uint8 dci_buf[DCX_LINES] = { 0 }; +uint32 dci_ireq = 0; +uint16 dco_csr[DCX_LINES] = { 0 }; /* control/status */ +uint8 dco_buf[DCX_LINES] = { 0 }; +uint32 dco_ireq = 0; +TMLN dcx_ldsc[DCX_LINES] = { 0 }; /* line descriptors */ +TMXR dcx_desc = { DCX_LINES, 0, 0, dcx_ldsc }; /* mux descriptor */ + +static const uint8 odd_par[] = { + 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 00 */ + 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, + 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 10 */ + 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, + 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 20 */ + 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, + 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 30 */ + 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, + 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 40 */ + 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, + 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 50 */ + 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, + 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 60 */ + 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, + 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 70 */ + 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, + 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 80 */ + 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, + 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 90 */ + 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, + 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* A0 */ + 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, + 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* B0 */ + 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, + 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* C0 */ + 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, + 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* D0 */ + 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, + 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* E0 */ + 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, + 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* F0 */ + 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80 + }; + +t_stat dcx_rd (int32 *data, int32 PA, int32 access); +t_stat dcx_wr (int32 data, int32 PA, int32 access); +t_stat dcx_reset (DEVICE *dptr); +t_stat dci_svc (UNIT *uptr); +t_stat dco_svc (UNIT *uptr); +t_stat dcx_attach (UNIT *uptr, char *cptr); +t_stat dcx_detach (UNIT *uptr); +t_stat dcx_summ (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat dcx_show (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat dcx_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat dcx_set_lines (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat dcx_show_lines (FILE *st, UNIT *uptr, int32 val, void *desc); +void dcx_enbdis (int32 dis); +void dci_clr_int (int32 ln); +void dci_set_int (int32 ln); +int32 dci_iack (void); +void dco_clr_int (int32 ln); +void dco_set_int (int32 ln); +int32 dco_iack (void); +void dcx_reset_ln (int32 ln); + +/* DCI data structures + + dci_dev DCI device descriptor + dci_unit DCI unit descriptor + dci_reg DCI register list +*/ + +DIB dci_dib = { + IOBA_DC, IOLN_DC, &dcx_rd, &dcx_wr, + 2, IVCL (DCI), VEC_DCI, { &dci_iack, &dco_iack } + }; + +UNIT dci_unit = { UDATA (&dci_svc, 0, 0), KBD_POLL_WAIT }; + +REG dci_reg[] = { + { BRDATA (BUF, dci_buf, DEV_RDX, 8, DCX_LINES) }, + { BRDATA (CSR, dci_csr, DEV_RDX, 16, DCX_LINES) }, + { GRDATA (IREQ, dci_ireq, DEV_RDX, DCX_LINES, 0) }, + { DRDATA (LINES, dcx_desc.lines, 6), REG_HRO }, + { GRDATA (DEVADDR, dci_dib.ba, DEV_RDX, 32, 0), REG_HRO }, + { GRDATA (DEVIOLN, dci_dib.lnt, DEV_RDX, 32, 0), REG_HRO }, + { GRDATA (DEVVEC, dci_dib.vec, DEV_RDX, 16, 0), REG_HRO }, + { NULL } + }; + +MTAB dci_mod[] = { + { UNIT_ATT, UNIT_ATT, "summary", NULL, NULL, &dcx_summ }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", + &tmxr_dscln, NULL, &dcx_desc }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, + NULL, &dcx_show, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, + NULL, &dcx_show, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, + &set_addr, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, + &set_vec, &dcx_show_vec, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "lines", "LINES", + &dcx_set_lines, &dcx_show_lines }, + { 0 } + }; + +DEVICE dci_dev = { + "DCI", &dci_unit, dci_reg, dci_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &dcx_reset, + NULL, &dcx_attach, &dcx_detach, + &dci_dib, DEV_UBUS | DEV_QBUS | DEV_DISABLE | DEV_DIS + }; + +/* DCO data structures + + dco_dev DCO device descriptor + dco_unit DCO unit descriptor + dco_reg DCO register list +*/ + +UNIT dco_unit[] = { + { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, + { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, + { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, + { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, + { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, + { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, + { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, + { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, + { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, + { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, + { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, + { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, + { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, + { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, + { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, + { UDATA (&dco_svc, TT_MODE_7P+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT } + }; + +REG dco_reg[] = { + { BRDATA (BUF, dco_buf, DEV_RDX, 8, DCX_LINES) }, + { BRDATA (CSR, dco_csr, DEV_RDX, 16, DCX_LINES) }, + { GRDATA (IREQ, dco_ireq, DEV_RDX, DCX_LINES, 0) }, + { URDATA (TIME, dco_unit[0].wait, 10, 31, 0, + DCX_LINES, PV_LEFT) }, + { NULL } + }; + +MTAB dco_mod[] = { + { TT_MODE, TT_MODE_UC, "UC", "UC", NULL }, + { TT_MODE, TT_MODE_7B, "7b", "7B", NULL }, + { TT_MODE, TT_MODE_8B, "8b", "8B", NULL }, + { TT_MODE, TT_MODE_7P, "7p", "7P", NULL }, + { DCX_OPAR+DCX_EPAR, 0, "no parity", "NOPARITY", NULL }, + { DCX_OPAR+DCX_EPAR, DCX_OPAR, "odd parity", "ODDPARITY", NULL }, + { DCX_OPAR+DCX_EPAR, DCX_EPAR, "even parity", "EVENPARITY", NULL }, + { DCX_MDM, 0, "no dataset", "NODATASET", NULL }, + { DCX_MDM, DCX_MDM, "dataset", "DATASET", NULL }, + { MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT", + &tmxr_dscln, NULL, &dcx_desc }, + { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG", + &tmxr_set_log, &tmxr_show_log, &dcx_desc }, + { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG", + &tmxr_set_nolog, NULL, &dcx_desc }, + { 0 } + }; + +DEVICE dco_dev = { + "DCO", dco_unit, dco_reg, dco_mod, + DCX_LINES, 10, 31, 1, 8, 8, + NULL, NULL, &dcx_reset, + NULL, NULL, NULL, + NULL, DEV_UBUS | DEV_DISABLE | DEV_DIS + }; + +/* Terminal input routines */ + +t_stat dcx_rd (int32 *data, int32 PA, int32 access) +{ +int32 ln = ((PA - dci_dib.ba) >> 3) & DCX_MASK; + +switch ((PA >> 1) & 03) { /* decode PA<2:1> */ + + case 00: /* dci csr */ + if (dci_csr[ln] & DCICSR_ALLERR) + dci_csr[ln] |= DCICSR_ERR; + else dci_csr[ln] &= ~DCICSR_ERR; + *data = dci_csr[ln] & DCICSR_RD; + dci_csr[ln] &= ~(CSR_DONE|DCICSR_ALLERR|DCICSR_ERR); + return SCPE_OK; + + case 01: /* dci buf */ + dci_clr_int (ln); + *data = dci_buf[ln]; + return SCPE_OK; + + case 02: /* dco csr */ + *data = dco_csr[ln] & DCOCSR_RD; + return SCPE_OK; + + case 03: /* dco buf */ + *data = dco_buf[ln]; + return SCPE_OK; + } /* end switch PA */ + +return SCPE_NXM; +} + +t_stat dcx_wr (int32 data, int32 PA, int32 access) +{ +int32 ln = ((PA - dci_dib.ba) >> 3) & DCX_MASK; +TMLN *lp = &dcx_ldsc[ln]; + +switch ((PA >> 1) & 03) { /* decode PA<2:1> */ + + case 00: /* dci csr */ + if (access == WRITEB) /* byte write? */ + data = (PA & 1)? + (dci_csr[ln] & 0377) | (data << 8): + (dci_csr[ln] & ~0377) | data; + if ((data & CSR_IE) == 0) /* clr ie? */ + dci_clr_int (ln); /* clr int req */ + else if ((dci_csr[ln] & (CSR_DONE + CSR_IE)) == CSR_DONE) + dci_set_int (ln); + if (((data ^ dci_csr[ln]) & DCICSR_DTR) && /* DTR change? */ + (dco_unit[ln].flags & DCX_MDM)) { /* modem ctl? */ + if (data & DCICSR_DTR) { /* setting DTR? */ + if (lp->conn) { /* ringing? */ + dci_csr[ln] = (dci_csr[ln] & ~DCICSR_RNG) | + (DCICSR_CDT|DCICSR_CCH|DCICSR_ERR); + dco_csr[ln] |= DCOCSR_CTS; /* set CDT,CCH,CTS */ + if (data & CSR_IE) /* if ie, req int */ + dci_set_int (ln); + } + } /* end DTR 0->1 */ + else { /* clearing DTR */ + if (lp->conn) { /* connected? */ + tmxr_linemsg (lp, "\r\nLine hangup\r\n"); + tmxr_reset_ln (lp); /* reset line */ + if (dci_csr[ln] & DCICSR_CDT) { /* carrier det? */ + dci_csr[ln] |= (DCICSR_CCH|DCICSR_ERR); + if (data & CSR_IE) /* if ie, req int */ + dci_set_int (ln); + } + } + dci_csr[ln] &= ~(DCICSR_CDT|DCICSR_RNG); + dco_csr[ln] &= ~DCOCSR_CTS; /* clr CDT,RNG,CTS */ + } /* end DTR 1->0 */ + } /* end DTR chg+modem */ + dci_csr[ln] = (uint16) ((dci_csr[ln] & ~DCICSR_WR) | (data & DCICSR_WR)); + return SCPE_OK; + + case 01: /* dci buf */ + return SCPE_OK; + + case 02: /* dco csr */ + if (access == WRITEB) /* byte write? */ + data = (PA & 1)? + (dco_csr[ln] & 0377) | (data << 8): + (dco_csr[ln] & ~0377) | data; + if ((data & CSR_IE) == 0) /* clr ie? */ + dco_clr_int (ln); /* clr int req */ + else if ((dco_csr[ln] & (CSR_DONE + CSR_IE)) == CSR_DONE) + dco_set_int (ln); + dco_csr[ln] = (uint16) ((dco_csr[ln] & ~DCOCSR_WR) | (data & DCOCSR_WR)); + return SCPE_OK; + + case 03: /* dco buf */ + if ((PA & 1) == 0) + dco_buf[ln] = data & 0377; + dco_csr[ln] &= ~CSR_DONE; /* clr done */ + dco_clr_int (ln); /* clr int req */ + sim_activate (&dco_unit[ln], dco_unit[ln].wait); + return SCPE_OK; + } /* end switch PA */ + +return SCPE_NXM; +} + +/* Terminal input service */ + +t_stat dci_svc (UNIT *uptr) +{ +int32 ln, c, temp; + +if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ + return SCPE_OK; +sim_activate (uptr, tmxr_poll); /* continue poll */ +ln = tmxr_poll_conn (&dcx_desc); /* look for connect */ +if (ln >= 0) { /* got one? */ + dcx_ldsc[ln].rcve = 1; /* set rcv enb */ + if (dco_unit[ln].flags & DCX_MDM) { /* modem control? */ + if (dci_csr[ln] & DCICSR_DTR) /* DTR already set? */ + dci_csr[ln] |= (DCICSR_CDT|DCICSR_CCH|DCICSR_ERR); + else dci_csr[ln] |= (DCICSR_RNG|DCICSR_ERR); /* no, ring */ + if (dci_csr[ln] & CSR_IE) /* if ie, */ + dci_set_int (ln); /* req int */ + } + else dco_csr[ln] |= DCOCSR_CTS; /* just connect */ + } +tmxr_poll_rx (&dcx_desc); /* poll for input */ +for (ln = 0; ln < DCX_LINES; ln++) { /* loop thru lines */ + if (dcx_ldsc[ln].conn) { /* connected? */ + if ((temp = tmxr_getc_ln (&dcx_ldsc[ln])) && /* get char */ + !(temp & SCPE_BREAK)) { /* not break? */ + c = sim_tt_inpcvt (temp, TT_GET_MODE (dco_unit[ln].flags)); + if (dci_csr[ln] & CSR_DONE) /* overrun? */ + dci_csr[ln] |= DCICSR_OVR; + else dci_csr[ln] |= CSR_DONE; /* set done */ + if (dci_csr[ln] & CSR_IE) /* if ie, */ + dci_set_int (ln); /* req int */ + if (dco_unit[ln].flags & DCX_OPAR) /* odd parity */ + c = (c & 0177) | odd_par[c & 0177]; + else if (dco_unit[ln].flags & DCX_EPAR) /* even parity */ + c = (c & 0177) | (odd_par[c & 0177] ^ 0200); + dci_buf[ln] = c; + if ((c & 0200) == odd_par[c & 0177]) /* odd par? */ + dci_csr[ln] |= DCICSR_PAR; + else dci_csr[ln] &= ~DCICSR_PAR; + } + } + else { /* disconnected */ + if ((dco_unit[ln].flags & DCX_MDM) && /* modem control? */ + (dci_csr[ln] & DCICSR_CDT)) { /* carrier detect? */ + dci_csr[ln] |= (DCICSR_CCH|DCICSR_ERR); /* carrier change */ + if (dci_csr[ln] & CSR_IE) /* if ie, */ + dci_set_int (ln); /* req int */ + } + dci_csr[ln] &= ~(DCICSR_CDT|DCICSR_RNG); /* clr CDT,RNG,CTS */ + dco_csr[ln] &= ~DCOCSR_CTS; + } + } +return SCPE_OK; +} + +/* Terminal output service */ + +t_stat dco_svc (UNIT *uptr) +{ +int32 c; +int32 ln = uptr - dco_unit; /* line # */ + +if (dcx_ldsc[ln].conn) { /* connected? */ + if (dcx_ldsc[ln].xmte) { /* tx enabled? */ + TMLN *lp = &dcx_ldsc[ln]; /* get line */ + c = sim_tt_outcvt (dco_buf[ln], TT_GET_MODE (dco_unit[ln].flags)); + if (c >= 0) tmxr_putc_ln (lp, c); /* output char */ + tmxr_poll_tx (&dcx_desc); /* poll xmt */ + } + else { + tmxr_poll_tx (&dcx_desc); /* poll xmt */ + sim_activate (uptr, dco_unit[ln].wait); /* wait */ + return SCPE_OK; + } + } +dco_csr[ln] |= CSR_DONE; /* set done */ +if (dco_csr[ln] & CSR_IE) /* ie set? */ + dco_set_int (ln); /* req int */ +return SCPE_OK; +} + +/* Interrupt routines */ + +void dci_clr_int (int32 ln) +{ +dci_ireq &= ~(1 << ln); /* clr mux rcv int */ +if (dci_ireq == 0) /* all clr? */ + CLR_INT (DCI); +else SET_INT (DCI); /* no, set intr */ +return; +} + +void dci_set_int (int32 ln) +{ +dci_ireq |= (1 << ln); /* clr mux rcv int */ +SET_INT (DCI); /* set master intr */ +return; +} + +int32 dci_iack (void) +{ +int32 ln; + +for (ln = 0; ln < DCX_LINES; ln++) { /* find 1st line */ + if (dci_ireq & (1 << ln)) { + dci_clr_int (ln); /* clear intr */ + return (dci_dib.vec + (ln * 010)); /* return vector */ + } + } +return 0; +} + +void dco_clr_int (int32 ln) +{ +dco_ireq &= ~(1 << ln); /* clr mux rcv int */ +if (dco_ireq == 0) /* all clr? */ + CLR_INT (DCO); +else SET_INT (DCO); /* no, set intr */ +return; +} + +void dco_set_int (int32 ln) +{ +dco_ireq |= (1 << ln); /* clr mux rcv int */ +SET_INT (DCO); /* set master intr */ +return; +} + +int32 dco_iack (void) +{ +int32 ln; + +for (ln = 0; ln < DCX_LINES; ln++) { /* find 1st line */ + if (dco_ireq & (1 << ln)) { + dco_clr_int (ln); /* clear intr */ + return (dci_dib.vec + (ln * 010) + 4); /* return vector */ + } + } +return 0; +} + +/* Reset */ + +t_stat dcx_reset (DEVICE *dptr) +{ +int32 ln; + +dcx_enbdis (dptr->flags & DEV_DIS); /* sync enables */ +sim_cancel (&dci_unit); /* assume stop */ +if (dci_unit.flags & UNIT_ATT) /* if attached, */ + sim_activate (&dci_unit, tmxr_poll); /* activate */ +for (ln = 0; ln < DCX_LINES; ln++) /* for all lines */ + dcx_reset_ln (ln); +return auto_config (dci_dev.name, dcx_desc.lines); /* auto config */ +} + +/* Reset individual line */ + +void dcx_reset_ln (int32 ln) +{ +dci_buf[ln] = 0; /* clear buf */ +dci_csr[ln] = 0; +dco_buf[ln] = 0; /* clear buf */ +dco_csr[ln] = CSR_DONE; +sim_cancel (&dco_unit[ln]); /* deactivate */ +dci_clr_int (ln); +dco_clr_int (ln); +return; +} + +/* Attach master unit */ + +t_stat dcx_attach (UNIT *uptr, char *cptr) +{ +t_stat r; + +r = tmxr_attach (&dcx_desc, uptr, cptr); /* attach */ +if (r != SCPE_OK) /* error? */ + return r; +sim_activate (uptr, tmxr_poll); /* start poll */ +return SCPE_OK; +} + +/* Detach master unit */ + +t_stat dcx_detach (UNIT *uptr) +{ +int32 i; +t_stat r; + +r = tmxr_detach (&dcx_desc, uptr); /* detach */ +for (i = 0; i < DCX_LINES; i++) /* all lines, */ + dcx_ldsc[i].rcve = 0; /* disable rcv */ +sim_cancel (uptr); /* stop poll */ +return r; +} + +/* Show summary processor */ + +t_stat dcx_summ (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +int32 i, t; + +for (i = t = 0; i < DCX_LINES; i++) t = t + (dcx_ldsc[i].conn != 0); +if (t == 1) fprintf (st, "1 connection"); +else fprintf (st, "%d connections", t); +return SCPE_OK; +} + +/* SHOW CONN/STAT processor */ + +t_stat dcx_show (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +int32 i, t; + +for (i = t = 0; i < DCX_LINES; i++) t = t + (dcx_ldsc[i].conn != 0); +if (t) { + for (i = 0; i < DCX_LINES; i++) { + if (dcx_ldsc[i].conn) { + if (val) tmxr_fconns (st, &dcx_ldsc[i], i); + else tmxr_fstats (st, &dcx_ldsc[i], i); + } + } + } +else fprintf (st, "all disconnected\n"); +return SCPE_OK; +} + +/* Enable/disable device */ + +void dcx_enbdis (int32 dis) +{ +if (dis) { + dci_dev.flags = dco_dev.flags | DEV_DIS; + dco_dev.flags = dco_dev.flags | DEV_DIS; + } +else { + dci_dev.flags = dci_dev.flags & ~DEV_DIS; + dco_dev.flags = dco_dev.flags & ~DEV_DIS; + } +return; +} + +/* SHOW VECTOR processor */ + +t_stat dcx_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +return show_vec (st, uptr, dcx_desc.lines * 2, desc); +} + +/* Change number of lines */ + +t_stat dcx_set_lines (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 newln, i, t; +t_stat r; + +if (cptr == NULL) return SCPE_ARG; +newln = get_uint (cptr, 10, DCX_LINES, &r); +if ((r != SCPE_OK) || (newln == dcx_desc.lines)) return r; +if (newln == 0) return SCPE_ARG; +if (newln < dcx_desc.lines) { + for (i = newln, t = 0; i < dcx_desc.lines; i++) t = t | dcx_ldsc[i].conn; + if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE)) + return SCPE_OK; + for (i = newln; i < dcx_desc.lines; i++) { + if (dcx_ldsc[i].conn) { + tmxr_linemsg (&dcx_ldsc[i], "\r\nOperator disconnected line\r\n"); + tmxr_reset_ln (&dcx_ldsc[i]); /* reset line */ + } + dco_unit[i].flags |= UNIT_DIS; + dcx_reset_ln (i); + } + } +else { + for (i = dcx_desc.lines; i < newln; i++) { + dco_unit[i].flags &= ~UNIT_DIS; + dcx_reset_ln (i); + } + } +dcx_desc.lines = newln; +dci_dib.lnt = newln * 010; /* upd IO page lnt */ +return auto_config (dci_dev.name, newln); /* auto config */ +} + +/* Show number of lines */ + +t_stat dcx_show_lines (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fprintf (st, "lines=%d", dcx_desc.lines); +return SCPE_OK; +} diff --git a/PDP11/pdp11_defs.h b/PDP11/pdp11_defs.h index c879efec..bfa55521 100644 --- a/PDP11/pdp11_defs.h +++ b/PDP11/pdp11_defs.h @@ -1,6 +1,6 @@ /* pdp11_defs.h: PDP-11 simulator definitions - Copyright (c) 1993-2006, Robert M Supnik + Copyright (c) 1993-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,9 @@ The author gratefully acknowledges the help of Max Burnet, Megan Gentry, and John Wilson in resolving questions about the PDP-11 + 16-May-08 RMS Added KE11A, DC11 support + 02-Feb-08 RMS Fixed DMA memory address limit test (found by John Dundas) + 25-Jan-08 RMS Added RC11, KG11A support (from John Dundas) 16-Dec-06 RMS Added TA11 support 29-Oct-06 RMS Added clock coscheduling 06-Jul-06 RMS Added multiple KL11/DL11 support @@ -92,7 +95,7 @@ #define MAXMEMSIZE 020000000 /* 2**22 */ #define PAMASK (MAXMEMSIZE - 1) /* 2**22 - 1 */ #define MEMSIZE (cpu_unit.capac) -#define ADDR_IS_MEM(x) (((t_addr) (x)) < MEMSIZE) +#define ADDR_IS_MEM(x) (((t_addr) (x)) < cpu_memsize) /* use only in sim! */ #define DMASK 0177777 /* CPU models */ @@ -469,7 +472,8 @@ typedef struct { #define DZ_MUXES 4 /* max # of DZ muxes */ #define DZ_LINES 8 /* lines per DZ mux */ #define VH_MUXES 4 /* max # of VH muxes */ -#define TTX_LINES 16 /* max # of KL11/DL11's */ +#define DLX_LINES 16 /* max # of KL11/DL11's */ +#define DCX_LINES 16 /* max # of DC11's */ #define MT_MAXFR (1 << 16) /* magtape max rec */ #define AUTO_LNT 34 /* autoconfig ranks */ #define DIB_MAX 100 /* max DIBs */ @@ -521,6 +525,8 @@ typedef struct pdp_dib DIB; #define IOLN_VH 020 #define IOBA_UBM (IOPAGEBASE + 010200) /* Unibus map */ #define IOLN_UBM (UBM_LNT_LW * sizeof (int32)) +#define IOBA_KG (IOPAGEBASE + 010700) /* KG11-A */ +#define IOLN_KG 006 #define IOBA_RQ (IOPAGEBASE + 012150) /* RQDX3 */ #define IOLN_RQ 004 #define IOBA_SUP (IOPAGEBASE + 012200) /* supervisor APR's */ @@ -543,6 +549,8 @@ typedef struct pdp_dib DIB; #define IOLN_TS 004 #define IOBA_PCLK (IOPAGEBASE + 012540) /* KW11P */ #define IOLN_PCLK 006 +#define IOBA_DC (IOPAGEBASE + 014000) /* DC11 */ +#define IOLN_DC (DCX_LINES * 010) #define IOBA_RL (IOPAGEBASE + 014400) /* RL11 */ #define IOLN_RL 012 #define IOBA_XQ (IOPAGEBASE + 014440) /* DEQNA/DELQA */ @@ -553,8 +561,8 @@ typedef struct pdp_dib DIB; #define IOLN_TQ 004 #define IOBA_XU (IOPAGEBASE + 014510) /* DEUNA/DELUA */ #define IOLN_XU 010 -#define IOBA_TTIX (IOPAGEBASE + 016500) /* extra KL11/DL11 */ -#define IOLN_TTIX (TTX_LINES * 010) +#define IOBA_DL (IOPAGEBASE + 016500) /* extra KL11/DL11 */ +#define IOLN_DL (DLX_LINES * 010) #define IOBA_RP (IOPAGEBASE + 016700) /* RP/RM */ #define IOLN_RP 054 #define IOBA_CR (IOPAGEBASE + 017160) /* CD/CR/CM */ @@ -563,10 +571,14 @@ typedef struct pdp_dib DIB; #define IOLN_RX 004 #define IOBA_RY (IOPAGEBASE + 017170) /* RY11 */ #define IOLN_RY 004 +#define IOBA_KE (IOPAGEBASE + 017300) /* KE11-A */ +#define IOLN_KE 020 #define IOBA_TC (IOPAGEBASE + 017340) /* TC11 */ #define IOLN_TC 012 #define IOBA_RK (IOPAGEBASE + 017400) /* RK11 */ #define IOLN_RK 020 +#define IOBA_RC (IOPAGEBASE + 017440) /* RC11/RS64 */ +#define IOLN_RC 020 #define IOBA_HK (IOPAGEBASE + 017440) /* RK611 */ #define IOLN_HK 040 #define IOBA_RF (IOPAGEBASE + 017460) /* RF11 */ @@ -636,7 +648,8 @@ typedef struct pdp_dib DIB; #define INT_V_XU 13 #define INT_V_TU 14 #define INT_V_RF 15 -#define INT_V_PIR5 16 +#define INT_V_RC 16 +#define INT_V_PIR5 17 #define INT_V_TTI 0 /* BR4 */ #define INT_V_TTO 1 @@ -646,9 +659,11 @@ typedef struct pdp_dib DIB; #define INT_V_VHRX 5 #define INT_V_VHTX 6 #define INT_V_CR 7 -#define INT_V_TTIX 8 -#define INT_V_TTOX 9 -#define INT_V_PIR4 10 +#define INT_V_DLI 8 +#define INT_V_DLO 9 +#define INT_V_DCI 10 +#define INT_V_DCO 11 +#define INT_V_PIR4 12 #define INT_V_PIR3 0 /* BR3 */ #define INT_V_PIR2 0 /* BR2 */ @@ -676,6 +691,7 @@ typedef struct pdp_dib DIB; #define INT_XU (1u << INT_V_XU) #define INT_TU (1u << INT_V_TU) #define INT_RF (1u << INT_V_RF) +#define INT_RC (1u << INT_V_RC) #define INT_PIR5 (1u << INT_V_PIR5) #define INT_PTR (1u << INT_V_PTR) #define INT_PTP (1u << INT_V_PTP) @@ -685,8 +701,10 @@ typedef struct pdp_dib DIB; #define INT_VHRX (1u << INT_V_VHRX) #define INT_VHTX (1u << INT_V_VHTX) #define INT_CR (1u << INT_V_CR) -#define INT_TTIX (1u << INT_V_TTIX) -#define INT_TTOX (1u << INT_V_TTOX) +#define INT_DLI (1u << INT_V_DLI) +#define INT_DLO (1u << INT_V_DLO) +#define INT_DCI (1u << INT_V_DCI) +#define INT_DCO (1u << INT_V_DCO) #define INT_PIR4 (1u << INT_V_PIR4) #define INT_PIR3 (1u << INT_V_PIR3) #define INT_PIR2 (1u << INT_V_PIR2) @@ -712,6 +730,7 @@ typedef struct pdp_dib DIB; #define IPL_XU 5 #define IPL_TU 5 #define IPL_RF 5 +#define IPL_RC 5 #define IPL_PTR 4 #define IPL_PTP 4 #define IPL_TTI 4 @@ -720,8 +739,10 @@ typedef struct pdp_dib DIB; #define IPL_VHRX 4 #define IPL_VHTX 4 #define IPL_CR 4 -#define IPL_TTIX 4 -#define IPL_TTOX 4 +#define IPL_DLI 4 +#define IPL_DLO 4 +#define IPL_DCI 4 +#define IPL_DCO 4 #define IPL_PIR7 7 #define IPL_PIR6 6 @@ -748,6 +769,7 @@ typedef struct pdp_dib DIB; #define VEC_LPT 0200 #define VEC_RF 0204 #define VEC_HK 0210 +#define VEC_RC 0210 #define VEC_RK 0220 #define VEC_DTA 0214 #define VEC_TM 0224 @@ -759,8 +781,10 @@ typedef struct pdp_dib DIB; #define VEC_TA 0260 #define VEC_RX 0264 #define VEC_RY 0264 -#define VEC_TTIX 0300 -#define VEC_TTOX 0304 +#define VEC_DLI 0300 +#define VEC_DLO 0304 +#define VEC_DCI 0300 +#define VEC_DCO 0304 #define VEC_DZRX 0300 #define VEC_DZTX 0304 #define VEC_VHRX 0310 diff --git a/PDP11/pdp11_dl.c b/PDP11/pdp11_dl.c index fdfe7f9e..65ade265 100644 --- a/PDP11/pdp11_dl.c +++ b/PDP11/pdp11_dl.c @@ -23,9 +23,10 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - ttix,ttox DL11 terminal input/output -*/ + dli,dlo DL11 terminal input/output + 20-May-2008 RMS Added modem control support +*/ #if defined (VM_PDP10) /* PDP10 version */ #error "DL11 is not supported on the PDP-10!" @@ -39,198 +40,258 @@ #include "sim_sock.h" #include "sim_tmxr.h" -#define TTX_MASK (TTX_LINES - 1) +#define DLX_MASK (DLX_LINES - 1) +#define DLI_RCI 0 /* rcv ints */ +#define DLI_DSI 1 /* dset ints */ -#define TTIXCSR_IMP (CSR_DONE + CSR_IE) /* terminal input */ -#define TTIXCSR_RW (CSR_IE) -#define TTIXBUF_ERR 0100000 -#define TTIXBUF_OVR 0040000 -#define TTIXBUF_RBRK 0020000 -#define TTOXCSR_IMP (CSR_DONE + CSR_IE) /* terminal output */ -#define TTOXCSR_RW (CSR_IE) +/* Modem control */ + +#define DLX_V_MDM (TTUF_V_UF + 0) +#define DLX_MDM (1u << DLX_V_MDM) + +/* registers */ + +#define DLICSR_DSI 0100000 /* dataset int, RO */ +#define DLICSR_RNG 0040000 /* ring, RO */ +#define DLICSR_CTS 0020000 /* CTS, RO */ +#define DLICSR_CDT 0010000 /* CDT, RO */ +#define DLICSR_SEC 0002000 /* sec rcv, RONI */ +#define DLICSR_DSIE 0000040 /* DSI ie, RW */ +#define DLICSR_SECX 0000010 /* sec xmt, RWNI */ +#define DLICSR_RTS 0000004 /* RTS, RW */ +#define DLICSR_DTR 0000002 /* DTR, RW */ +#define DLICSR_RD (CSR_DONE|CSR_IE) /* DL11C */ +#define DLICSR_WR (CSR_IE) +#define DLICSR_RD_M (DLICSR_DSI|DLICSR_RNG|DLICSR_CTS|DLICSR_CDT|DLICSR_SEC| \ + CSR_DONE|CSR_IE|DLICSR_DSIE|DLICSR_SECX|DLICSR_RTS|DLICSR_DTR) +#define DLICSR_WR_M (CSR_IE|DLICSR_DSIE|DLICSR_SECX|DLICSR_RTS|DLICSR_DTR) +#define DLIBUF_ERR 0100000 +#define DLIBUF_OVR 0040000 +#define DLIBUF_RBRK 0020000 +#define DLIBUF_RD (DLIBUF_ERR|DLIBUF_OVR|DLIBUF_RBRK|0377) +#define DLOCSR_MNT 0000004 /* maint, RWNI */ +#define DLOCSR_XBR 0000001 /* xmit brk, RWNI */ +#define DLOCSR_RD (CSR_DONE|CSR_IE|DLOCSR_MNT|DLOCSR_XBR) +#define DLOCSR_WR (CSR_IE|DLOCSR_MNT|DLOCSR_XBR) extern int32 int_req[IPL_HLVL]; extern int32 tmxr_poll; -uint16 ttix_csr[TTX_LINES] = { 0 }; /* control/status */ -uint16 ttix_buf[TTX_LINES] = { 0 }; -uint32 ttix_ireq = 0; -uint16 ttox_csr[TTX_LINES] = { 0 }; /* control/status */ -uint8 ttox_buf[TTX_LINES] = { 0 }; -uint32 ttox_ireq = 0; -TMLN ttx_ldsc[TTX_LINES] = { 0 }; /* line descriptors */ -TMXR ttx_desc = { TTX_LINES, 0, 0, ttx_ldsc }; /* mux descriptor */ +uint16 dli_csr[DLX_LINES] = { 0 }; /* control/status */ +uint16 dli_buf[DLX_LINES] = { 0 }; +uint32 dli_ireq[2] = { 0, 0}; +uint16 dlo_csr[DLX_LINES] = { 0 }; /* control/status */ +uint8 dlo_buf[DLX_LINES] = { 0 }; +uint32 dlo_ireq = 0; +TMLN dlx_ldsc[DLX_LINES] = { 0 }; /* line descriptors */ +TMXR dlx_desc = { DLX_LINES, 0, 0, dlx_ldsc }; /* mux descriptor */ -t_stat ttx_rd (int32 *data, int32 PA, int32 access); -t_stat ttx_wr (int32 data, int32 PA, int32 access); -t_stat ttx_reset (DEVICE *dptr); -t_stat ttix_svc (UNIT *uptr); -t_stat ttox_svc (UNIT *uptr); -t_stat ttx_attach (UNIT *uptr, char *cptr); -t_stat ttx_detach (UNIT *uptr); -t_stat ttx_summ (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat ttx_show (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat ttx_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat ttx_set_lines (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat ttx_show_lines (FILE *st, UNIT *uptr, int32 val, void *desc); -void ttx_enbdis (int32 dis); -void ttix_clr_int (uint32 ln); -void ttix_set_int (int32 ln); -int32 ttix_iack (void); -void ttox_clr_int (int32 ln); -void ttox_set_int (int32 ln); -int32 ttox_iack (void); -void ttx_reset_ln (uint32 ln); +t_stat dlx_rd (int32 *data, int32 PA, int32 access); +t_stat dlx_wr (int32 data, int32 PA, int32 access); +t_stat dlx_reset (DEVICE *dptr); +t_stat dli_svc (UNIT *uptr); +t_stat dlo_svc (UNIT *uptr); +t_stat dlx_attach (UNIT *uptr, char *cptr); +t_stat dlx_detach (UNIT *uptr); +t_stat dlx_summ (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat dlx_show (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat dlx_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat dlx_set_lines (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat dlx_show_lines (FILE *st, UNIT *uptr, int32 val, void *desc); +void dlx_enbdis (int32 dis); +void dli_clr_int (int32 ln, uint32 wd); +void dli_set_int (int32 ln, uint32 wd); +int32 dli_iack (void); +void dlo_clr_int (int32 ln); +void dlo_set_int (int32 ln); +int32 dlo_iack (void); +void dlx_reset_ln (int32 ln); -/* TTIX data structures +/* DLI data structures - ttix_dev TTIX device descriptor - ttix_unit TTIX unit descriptor - ttix_reg TTIX register list + dli_dev DLI device descriptor + dli_unit DLI unit descriptor + dli_reg DLI register list */ -DIB ttix_dib = { - IOBA_TTIX, IOLN_TTIX, &ttx_rd, &ttx_wr, - 2, IVCL (TTIX), VEC_TTIX, { &ttix_iack, &ttox_iack } +DIB dli_dib = { + IOBA_DL, IOLN_DL, &dlx_rd, &dlx_wr, + 2, IVCL (DLI), VEC_DLI, { &dli_iack, &dlo_iack } }; -UNIT ttix_unit = { UDATA (&ttix_svc, 0, 0), KBD_POLL_WAIT }; +UNIT dli_unit = { UDATA (&dli_svc, 0, 0), KBD_POLL_WAIT }; -REG ttix_reg[] = { - { BRDATA (BUF, ttix_buf, DEV_RDX, 16, TTX_LINES) }, - { BRDATA (CSR, ttix_csr, DEV_RDX, 16, TTX_LINES) }, - { GRDATA (IREQ, ttix_ireq, DEV_RDX, TTX_LINES, 0) }, - { DRDATA (LINES, ttx_desc.lines, 6), REG_HRO }, - { GRDATA (DEVADDR, ttix_dib.ba, DEV_RDX, 32, 0), REG_HRO }, - { GRDATA (DEVVEC, ttix_dib.vec, DEV_RDX, 16, 0), REG_HRO }, +REG dli_reg[] = { + { BRDATA (BUF, dli_buf, DEV_RDX, 16, DLX_LINES) }, + { BRDATA (CSR, dli_csr, DEV_RDX, 16, DLX_LINES) }, + { GRDATA (IREQ, dli_ireq[DLI_RCI], DEV_RDX, DLX_LINES, 0) }, + { GRDATA (DSI, dli_ireq[DLI_DSI], DEV_RDX, DLX_LINES, 0) }, + { DRDATA (LINES, dlx_desc.lines, 6), REG_HRO }, + { GRDATA (DEVADDR, dli_dib.ba, DEV_RDX, 32, 0), REG_HRO }, + { GRDATA (DEVIOLN, dli_dib.lnt, DEV_RDX, 32, 0), REG_HRO }, + { GRDATA (DEVVEC, dli_dib.vec, DEV_RDX, 16, 0), REG_HRO }, { NULL } }; -MTAB ttix_mod[] = { - { UNIT_ATT, UNIT_ATT, "summary", NULL, NULL, &ttx_summ }, +MTAB dli_mod[] = { + { UNIT_ATT, UNIT_ATT, "summary", NULL, NULL, &dlx_summ }, { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", - &tmxr_dscln, NULL, &ttx_desc }, + &tmxr_dscln, NULL, &dlx_desc }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, - NULL, &ttx_show, NULL }, + NULL, &dlx_show, NULL }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, - NULL, &ttx_show, NULL }, + NULL, &dlx_show, NULL }, { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, &set_addr, &show_addr, NULL }, { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, - &set_vec, &ttx_show_vec, NULL }, + &set_vec, &dlx_show_vec, NULL }, { MTAB_XTD | MTAB_VDV, 0, "lines", "LINES", - &ttx_set_lines, &ttx_show_lines }, + &dlx_set_lines, &dlx_show_lines }, { 0 } }; -DEVICE ttix_dev = { - "TTIX", &ttix_unit, ttix_reg, ttix_mod, +DEVICE dli_dev = { + "DLI", &dli_unit, dli_reg, dli_mod, 1, 10, 31, 1, 8, 8, - NULL, NULL, &ttx_reset, - NULL, &ttx_attach, &ttx_detach, - &ttix_dib, DEV_UBUS | DEV_QBUS | DEV_DISABLE | DEV_DIS + NULL, NULL, &dlx_reset, + NULL, &dlx_attach, &dlx_detach, + &dli_dib, DEV_UBUS | DEV_QBUS | DEV_DISABLE | DEV_DIS }; -/* TTOX data structures +/* DLO data structures - ttox_dev TTOX device descriptor - ttox_unit TTOX unit descriptor - ttox_reg TTOX register list + dlo_dev DLO device descriptor + dlo_unit DLO unit descriptor + dlo_reg DLO register list */ -UNIT ttox_unit[] = { - { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&ttox_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT } +UNIT dlo_unit[] = { + { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, + { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, + { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, + { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, + { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, + { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, + { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, + { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, + { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, + { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, + { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, + { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, + { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, + { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, + { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, + { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT } }; -REG ttox_reg[] = { - { BRDATA (BUF, ttox_buf, DEV_RDX, 8, TTX_LINES) }, - { BRDATA (CSR, ttox_csr, DEV_RDX, 16, TTX_LINES) }, - { GRDATA (IREQ, ttox_ireq, DEV_RDX, TTX_LINES, 0) }, - { URDATA (TIME, ttox_unit[0].wait, 10, 31, 0, - TTX_LINES, PV_LEFT) }, +REG dlo_reg[] = { + { BRDATA (BUF, dlo_buf, DEV_RDX, 8, DLX_LINES) }, + { BRDATA (CSR, dlo_csr, DEV_RDX, 16, DLX_LINES) }, + { GRDATA (IREQ, dlo_ireq, DEV_RDX, DLX_LINES, 0) }, + { URDATA (TIME, dlo_unit[0].wait, 10, 31, 0, + DLX_LINES, PV_LEFT) }, { NULL } }; -MTAB ttox_mod[] = { +MTAB dlo_mod[] = { { TT_MODE, TT_MODE_UC, "UC", "UC", NULL }, { TT_MODE, TT_MODE_7B, "7b", "7B", NULL }, { TT_MODE, TT_MODE_8B, "8b", "8B", NULL }, { TT_MODE, TT_MODE_7P, "7p", "7P", NULL }, + { DLX_MDM, 0, "no dataset", "NODATASET", NULL }, + { DLX_MDM, DLX_MDM, "dataset", "DATASET", NULL }, { MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT", - &tmxr_dscln, NULL, &ttx_desc }, + &tmxr_dscln, NULL, &dlx_desc }, { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG", - &tmxr_set_log, &tmxr_show_log, &ttx_desc }, + &tmxr_set_log, &tmxr_show_log, &dlx_desc }, { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG", - &tmxr_set_nolog, NULL, &ttx_desc }, + &tmxr_set_nolog, NULL, &dlx_desc }, { 0 } }; -DEVICE ttox_dev = { - "TTOX", ttox_unit, ttox_reg, ttox_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ttx_reset, +DEVICE dlo_dev = { + "DLO", dlo_unit, dlo_reg, dlo_mod, + DLX_LINES, 10, 31, 1, 8, 8, + NULL, NULL, &dlx_reset, NULL, NULL, NULL, NULL, DEV_UBUS | DEV_QBUS | DEV_DISABLE | DEV_DIS }; /* Terminal input routines */ -t_stat ttx_rd (int32 *data, int32 PA, int32 access) +t_stat dlx_rd (int32 *data, int32 PA, int32 access) { -uint32 ln = ((PA - ttix_dib.ba) >> 3) & TTX_MASK; +int32 ln = ((PA - dli_dib.ba) >> 3) & DLX_MASK; switch ((PA >> 1) & 03) { /* decode PA<2:1> */ case 00: /* tti csr */ - *data = ttix_csr[ln] & TTIXCSR_IMP; + *data = dli_csr[ln] & + ((dlo_unit[ln].flags & DLX_MDM)? DLICSR_RD_M: DLICSR_RD); + dli_csr[ln] &= ~DLICSR_DSI; /* clr DSI flag */ + dli_clr_int (ln, DLI_DSI); /* clr dset int req */ return SCPE_OK; case 01: /* tti buf */ - ttix_csr[ln] &= ~CSR_DONE; - ttix_clr_int (ln); - *data = ttix_buf[ln]; + *data = dli_buf[ln] & DLIBUF_RD; + dli_csr[ln] &= ~CSR_DONE; /* clr rcv done */ + dli_clr_int (ln, DLI_RCI); /* clr rcv int req */ return SCPE_OK; case 02: /* tto csr */ - *data = ttox_csr[ln] & TTOXCSR_IMP; + *data = dlo_csr[ln] & DLOCSR_RD; return SCPE_OK; case 03: /* tto buf */ - *data = ttox_buf[ln]; + *data = dlo_buf[ln]; return SCPE_OK; } /* end switch PA */ return SCPE_NXM; } -t_stat ttx_wr (int32 data, int32 PA, int32 access) +t_stat dlx_wr (int32 data, int32 PA, int32 access) { -uint32 ln = ((PA - ttix_dib.ba) >> 3) & TTX_MASK; +int32 ln = ((PA - dli_dib.ba) >> 3) & DLX_MASK; +TMLN *lp = &dlx_ldsc[ln]; switch ((PA >> 1) & 03) { /* decode PA<2:1> */ case 00: /* tti csr */ - if (PA & 1) return SCPE_OK; + if (PA & 1) return SCPE_OK; /* odd byte RO */ if ((data & CSR_IE) == 0) - ttix_clr_int (ln); - else if ((ttix_csr[ln] & (CSR_DONE + CSR_IE)) == CSR_DONE) - ttix_set_int (ln); - ttix_csr[ln] = (uint16) ((ttix_csr[ln] & ~TTIXCSR_RW) | (data & TTIXCSR_RW)); + dli_clr_int (ln, DLI_RCI); + else if ((dli_csr[ln] & (CSR_DONE + CSR_IE)) == CSR_DONE) + dli_set_int (ln, DLI_RCI); + if (dlo_unit[ln].flags & DLX_MDM) { /* modem control */ + if ((data & DLICSR_DSIE) == 0) + dli_clr_int (ln, DLI_DSI); + else if ((dli_csr[ln] & (DLICSR_DSI|DLICSR_DSIE)) == DLICSR_DSI) + dli_set_int (ln, DLI_DSI); + if ((data ^ dli_csr[ln]) & DLICSR_DTR) { /* DTR change? */ + if ((data & DLICSR_DTR) && lp->conn) { /* setting DTR? */ + dli_csr[ln] = (dli_csr[ln] & ~DLICSR_RNG) | + (DLICSR_CDT|DLICSR_CTS|DLICSR_DSI); + if (data & DLICSR_DSIE) /* if ie, req int */ + dli_set_int (ln, DLI_DSI); + } /* end DTR 0->1 + ring */ + else { /* clearing DTR */ + if (lp->conn) { /* connected? */ + tmxr_linemsg (lp, "\r\nLine hangup\r\n"); + tmxr_reset_ln (lp); /* reset line */ + if (dli_csr[ln] & DLICSR_CDT) { /* carrier det? */ + dli_csr[ln] |= DLICSR_DSI; + if (data & DLICSR_DSIE) /* if ie, req int */ + dli_set_int (ln, DLI_DSI); + } + } + dli_csr[ln] &= ~(DLICSR_CDT|DLICSR_RNG|DLICSR_CTS); + /* clr CDT,RNG,CTS */ + } /* end DTR 1->0 */ + } /* end DTR chg */ + dli_csr[ln] = (uint16) ((dli_csr[ln] & ~DLICSR_WR_M) | (data & DLICSR_WR_M)); + } /* end modem */ + dli_csr[ln] = (uint16) ((dli_csr[ln] & ~DLICSR_WR) | (data & DLICSR_WR)); return SCPE_OK; case 01: /* tti buf */ @@ -239,18 +300,18 @@ switch ((PA >> 1) & 03) { /* decode PA<2:1> */ case 02: /* tto csr */ if (PA & 1) return SCPE_OK; if ((data & CSR_IE) == 0) - ttox_clr_int (ln); - else if ((ttox_csr[ln] & (CSR_DONE + CSR_IE)) == CSR_DONE) - ttox_set_int (ln); - ttox_csr[ln] = (uint16) ((ttox_csr[ln] & ~TTOXCSR_RW) | (data & TTOXCSR_RW)); + dlo_clr_int (ln); + else if ((dlo_csr[ln] & (CSR_DONE + CSR_IE)) == CSR_DONE) + dlo_set_int (ln); + dlo_csr[ln] = (uint16) ((dlo_csr[ln] & ~DLOCSR_WR) | (data & DLOCSR_WR)); return SCPE_OK; case 03: /* tto buf */ if ((PA & 1) == 0) - ttox_buf[ln] = data & 0377; - ttox_csr[ln] &= ~CSR_DONE; - ttox_clr_int (ln); - sim_activate (&ttox_unit[ln], ttox_unit[ln].wait); + dlo_buf[ln] = data & 0377; + dlo_csr[ln] &= ~CSR_DONE; + dlo_clr_int (ln); + sim_activate (&dlo_unit[ln], dlo_unit[ln].wait); return SCPE_OK; } /* end switch PA */ @@ -259,112 +320,132 @@ return SCPE_NXM; /* Terminal input service */ -t_stat ttix_svc (UNIT *uptr) +t_stat dli_svc (UNIT *uptr) { int32 ln, c, temp; if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */ sim_activate (uptr, tmxr_poll); /* continue poll */ -ln = tmxr_poll_conn (&ttx_desc); /* look for connect */ -if (ln >= 0) ttx_ldsc[ln].rcve = 1; /* got one? rcv enb */ -tmxr_poll_rx (&ttx_desc); /* poll for input */ -for (ln = 0; ln < TTX_LINES; ln++) { /* loop thru lines */ - if (ttx_ldsc[ln].conn) { /* connected? */ - if (temp = tmxr_getc_ln (&ttx_ldsc[ln])) { /* get char */ +ln = tmxr_poll_conn (&dlx_desc); /* look for connect */ +if (ln >= 0) { /* got one? rcv enb */ + dlx_ldsc[ln].rcve = 1; + if (dlo_unit[ln].flags & DLX_MDM) { /* modem control? */ + if (dli_csr[ln] & DLICSR_DTR) /* DTR already set? */ + dli_csr[ln] |= (DLICSR_CDT|DLICSR_CTS|DLICSR_DSI); + else dli_csr[ln] |= (DLICSR_RNG|DLICSR_DSI); /* no, ring */ + if (dli_csr[ln] & DLICSR_DSIE) /* if ie, */ + dli_set_int (ln, DLI_DSI); /* req int */ + } /* end modem */ + } /* end new conn */ +tmxr_poll_rx (&dlx_desc); /* poll for input */ +for (ln = 0; ln < DLX_LINES; ln++) { /* loop thru lines */ + if (dlx_ldsc[ln].conn) { /* connected? */ + if (temp = tmxr_getc_ln (&dlx_ldsc[ln])) { /* get char */ if (temp & SCPE_BREAK) /* break? */ - c = TTIXBUF_ERR|TTIXBUF_RBRK; - else c = sim_tt_inpcvt (temp, TT_GET_MODE (ttox_unit[ln].flags)); - if (ttix_csr[ln] & CSR_DONE) - c |= TTIXBUF_ERR|TTIXBUF_OVR; - else { - ttix_csr[ln] |= CSR_DONE; - if (ttix_csr[ln] & CSR_IE) ttix_set_int (ln); - } - ttix_buf[ln] = c; + c = DLIBUF_ERR|DLIBUF_RBRK; + else c = sim_tt_inpcvt (temp, TT_GET_MODE (dlo_unit[ln].flags)); + if (dli_csr[ln] & CSR_DONE) + c |= DLIBUF_ERR|DLIBUF_OVR; + else dli_csr[ln] |= CSR_DONE; + if (dli_csr[ln] & CSR_IE) + dli_set_int (ln, DLI_RCI); + dli_buf[ln] = c; } } + else if (dlo_unit[ln].flags & DLX_MDM) { /* discpnn & modem? */ + if (dli_csr[ln] & DLICSR_CDT) { /* carrier detect? */ + dli_csr[ln] |= DLICSR_DSI; /* dataset change */ + if (dli_csr[ln] & DLICSR_DSIE) /* if ie, */ + dli_set_int (ln, DLI_DSI); /* req int */ + } + dli_csr[ln] &= ~(DLICSR_CDT|DLICSR_RNG|DLICSR_CTS); + /* clr CDT,RNG,CTS */ + } } return SCPE_OK; } /* Terminal output service */ -t_stat ttox_svc (UNIT *uptr) +t_stat dlo_svc (UNIT *uptr) { int32 c; -uint32 ln = uptr - ttox_unit; /* line # */ +int32 ln = uptr - dlo_unit; /* line # */ -if (ttx_ldsc[ln].conn) { /* connected? */ - if (ttx_ldsc[ln].xmte) { /* tx enabled? */ - TMLN *lp = &ttx_ldsc[ln]; /* get line */ - c = sim_tt_outcvt (ttox_buf[ln], TT_GET_MODE (ttox_unit[ln].flags)); +if (dlx_ldsc[ln].conn) { /* connected? */ + if (dlx_ldsc[ln].xmte) { /* tx enabled? */ + TMLN *lp = &dlx_ldsc[ln]; /* get line */ + c = sim_tt_outcvt (dlo_buf[ln], TT_GET_MODE (dlo_unit[ln].flags)); if (c >= 0) tmxr_putc_ln (lp, c); /* output char */ - tmxr_poll_tx (&ttx_desc); /* poll xmt */ + tmxr_poll_tx (&dlx_desc); /* poll xmt */ } else { - tmxr_poll_tx (&ttx_desc); /* poll xmt */ - sim_activate (uptr, ttox_unit[ln].wait); /* wait */ + tmxr_poll_tx (&dlx_desc); /* poll xmt */ + sim_activate (uptr, dlo_unit[ln].wait); /* wait */ return SCPE_OK; } } -ttox_csr[ln] |= CSR_DONE; /* set done */ -if (ttox_csr[ln] & CSR_IE) ttox_set_int (ln); +dlo_csr[ln] |= CSR_DONE; /* set done */ +if (dlo_csr[ln] & CSR_IE) + dlo_set_int (ln); return SCPE_OK; } /* Interrupt routines */ -void ttix_clr_int (uint32 ln) +void dli_clr_int (int32 ln, uint32 wd) { -ttix_ireq &= ~(1 << ln); /* clr mux rcv int */ -if (ttix_ireq == 0) CLR_INT (TTIX); /* all clr? */ -else SET_INT (TTIX); /* no, set intr */ +dli_ireq[wd] &= ~(1 << ln); /* clr rcv/dset int */ +if ((dli_ireq[DLI_RCI] | dli_ireq[DLI_DSI]) == 0) /* all clr? */ + CLR_INT (DLI); /* all clr? */ +else SET_INT (DLI); /* no, set intr */ return; } -void ttix_set_int (int32 ln) +void dli_set_int (int32 ln, uint32 wd) { -ttix_ireq |= (1 << ln); /* clr mux rcv int */ -SET_INT (TTIX); /* set master intr */ +dli_ireq[wd] |= (1 << ln); /* set rcv/dset int */ +SET_INT (DLI); /* set master intr */ return; } -int32 ttix_iack (void) +int32 dli_iack (void) { int32 ln; -for (ln = 0; ln < TTX_LINES; ln++) { /* find 1st line */ - if (ttix_ireq & (1 << ln)) { - ttix_clr_int (ln); /* clear intr */ - return (ttix_dib.vec + (ln * 010)); /* return vector */ +for (ln = 0; ln < DLX_LINES; ln++) { /* find 1st line */ + if ((dli_ireq[DLI_RCI] | dli_ireq[DLI_DSI]) & (1 << ln)) { + dli_clr_int (ln, DLI_RCI); /* clr both req */ + dli_clr_int (ln, DLI_DSI); + return (dli_dib.vec + (ln * 010)); /* return vector */ } } return 0; } -void ttox_clr_int (int32 ln) +void dlo_clr_int (int32 ln) { -ttox_ireq &= ~(1 << ln); /* clr mux rcv int */ -if (ttox_ireq == 0) CLR_INT (TTOX); /* all clr? */ -else SET_INT (TTOX); /* no, set intr */ +dlo_ireq &= ~(1 << ln); /* clr xmit int */ +if (dlo_ireq == 0) CLR_INT (DLO); /* all clr? */ +else SET_INT (DLO); /* no, set intr */ return; } -void ttox_set_int (int32 ln) +void dlo_set_int (int32 ln) { -ttox_ireq |= (1 << ln); /* clr mux rcv int */ -SET_INT (TTOX); /* set master intr */ +dlo_ireq |= (1 << ln); /* set xmit int */ +SET_INT (DLO); /* set master intr */ return; } -int32 ttox_iack (void) +int32 dlo_iack (void) { int32 ln; -for (ln = 0; ln < TTX_LINES; ln++) { /* find 1st line */ - if (ttox_ireq & (1 << ln)) { - ttox_clr_int (ln); /* clear intr */ - return (ttix_dib.vec + (ln * 010) + 4); /* return vector */ +for (ln = 0; ln < DLX_LINES; ln++) { /* find 1st line */ + if (dlo_ireq & (1 << ln)) { + dlo_clr_int (ln); /* clear intr */ + return (dli_dib.vec + (ln * 010) + 4); /* return vector */ } } return 0; @@ -372,40 +453,43 @@ return 0; /* Reset */ -t_stat ttx_reset (DEVICE *dptr) +t_stat dlx_reset (DEVICE *dptr) { int32 ln; -ttx_enbdis (dptr->flags & DEV_DIS); /* sync enables */ -sim_cancel (&ttix_unit); /* assume stop */ -if (ttix_unit.flags & UNIT_ATT) /* if attached, */ - sim_activate (&ttix_unit, tmxr_poll); /* activate */ -for (ln = 0; ln < TTX_LINES; ln++) /* for all lines */ - ttx_reset_ln (ln); -return auto_config (ttix_dev.name, ttx_desc.lines); /* auto config */ +dlx_enbdis (dptr->flags & DEV_DIS); /* sync enables */ +sim_cancel (&dli_unit); /* assume stop */ +if (dli_unit.flags & UNIT_ATT) /* if attached, */ + sim_activate (&dli_unit, tmxr_poll); /* activate */ +for (ln = 0; ln < DLX_LINES; ln++) /* for all lines */ + dlx_reset_ln (ln); +return auto_config (dli_dev.name, dlx_desc.lines); /* auto config */ } /* Reset individual line */ -void ttx_reset_ln (uint32 ln) +void dlx_reset_ln (int32 ln) { -ttix_buf[ln] = 0; /* clear buf, */ -ttix_csr[ln] = CSR_DONE; -ttox_buf[ln] = 0; /* clear buf */ -ttox_csr[ln] = CSR_DONE; -sim_cancel (&ttox_unit[ln]); /* deactivate */ -ttix_clr_int (ln); -ttox_clr_int (ln); +dli_buf[ln] = 0; /* clear buf */ +if (dlo_unit[ln].flags & DLX_MDM) /* modem */ + dli_csr[ln] &= DLICSR_DTR; /* dont clr DTR */ +else dli_csr[ln] = 0; +dlo_buf[ln] = 0; /* clear buf */ +dlo_csr[ln] = CSR_DONE; +sim_cancel (&dlo_unit[ln]); /* deactivate */ +dli_clr_int (ln, DLI_RCI); +dli_clr_int (ln, DLI_DSI); +dlo_clr_int (ln); return; } /* Attach master unit */ -t_stat ttx_attach (UNIT *uptr, char *cptr) +t_stat dlx_attach (UNIT *uptr, char *cptr) { t_stat r; -r = tmxr_attach (&ttx_desc, uptr, cptr); /* attach */ +r = tmxr_attach (&dlx_desc, uptr, cptr); /* attach */ if (r != SCPE_OK) return r; /* error */ sim_activate (uptr, tmxr_poll); /* start poll */ return SCPE_OK; @@ -413,25 +497,25 @@ return SCPE_OK; /* Detach master unit */ -t_stat ttx_detach (UNIT *uptr) +t_stat dlx_detach (UNIT *uptr) { int32 i; t_stat r; -r = tmxr_detach (&ttx_desc, uptr); /* detach */ -for (i = 0; i < TTX_LINES; i++) /* all lines, */ - ttx_ldsc[i].rcve = 0; /* disable rcv */ +r = tmxr_detach (&dlx_desc, uptr); /* detach */ +for (i = 0; i < DLX_LINES; i++) /* all lines, */ + dlx_ldsc[i].rcve = 0; /* disable rcv */ sim_cancel (uptr); /* stop poll */ return r; } /* Show summary processor */ -t_stat ttx_summ (FILE *st, UNIT *uptr, int32 val, void *desc) +t_stat dlx_summ (FILE *st, UNIT *uptr, int32 val, void *desc) { int32 i, t; -for (i = t = 0; i < TTX_LINES; i++) t = t + (ttx_ldsc[i].conn != 0); +for (i = t = 0; i < DLX_LINES; i++) t = t + (dlx_ldsc[i].conn != 0); if (t == 1) fprintf (st, "1 connection"); else fprintf (st, "%d connections", t); return SCPE_OK; @@ -439,16 +523,16 @@ return SCPE_OK; /* SHOW CONN/STAT processor */ -t_stat ttx_show (FILE *st, UNIT *uptr, int32 val, void *desc) +t_stat dlx_show (FILE *st, UNIT *uptr, int32 val, void *desc) { int32 i, t; -for (i = t = 0; i < TTX_LINES; i++) t = t + (ttx_ldsc[i].conn != 0); +for (i = t = 0; i < DLX_LINES; i++) t = t + (dlx_ldsc[i].conn != 0); if (t) { - for (i = 0; i < TTX_LINES; i++) { - if (ttx_ldsc[i].conn) { - if (val) tmxr_fconns (st, &ttx_ldsc[i], i); - else tmxr_fstats (st, &ttx_ldsc[i], i); + for (i = 0; i < DLX_LINES; i++) { + if (dlx_ldsc[i].conn) { + if (val) tmxr_fconns (st, &dlx_ldsc[i], i); + else tmxr_fstats (st, &dlx_ldsc[i], i); } } } @@ -458,64 +542,65 @@ return SCPE_OK; /* Enable/disable device */ -void ttx_enbdis (int32 dis) +void dlx_enbdis (int32 dis) { if (dis) { - ttix_dev.flags = ttox_dev.flags | DEV_DIS; - ttox_dev.flags = ttox_dev.flags | DEV_DIS; + dli_dev.flags = dlo_dev.flags | DEV_DIS; + dlo_dev.flags = dlo_dev.flags | DEV_DIS; } else { - ttix_dev.flags = ttix_dev.flags & ~DEV_DIS; - ttox_dev.flags = ttox_dev.flags & ~DEV_DIS; + dli_dev.flags = dli_dev.flags & ~DEV_DIS; + dlo_dev.flags = dlo_dev.flags & ~DEV_DIS; } return; } /* SHOW VECTOR processor */ -t_stat ttx_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc) +t_stat dlx_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc) { -return show_vec (st, uptr, ttx_desc.lines * 2, desc); +return show_vec (st, uptr, dlx_desc.lines * 2, desc); } /* Change number of lines */ -t_stat ttx_set_lines (UNIT *uptr, int32 val, char *cptr, void *desc) +t_stat dlx_set_lines (UNIT *uptr, int32 val, char *cptr, void *desc) { int32 newln, i, t; t_stat r; if (cptr == NULL) return SCPE_ARG; -newln = get_uint (cptr, 10, TTX_LINES, &r); -if ((r != SCPE_OK) || (newln == ttx_desc.lines)) return r; +newln = get_uint (cptr, 10, DLX_LINES, &r); +if ((r != SCPE_OK) || (newln == dlx_desc.lines)) return r; if (newln == 0) return SCPE_ARG; -if (newln < ttx_desc.lines) { - for (i = newln, t = 0; i < ttx_desc.lines; i++) t = t | ttx_ldsc[i].conn; +if (newln < dlx_desc.lines) { + for (i = newln, t = 0; i < dlx_desc.lines; i++) t = t | dlx_ldsc[i].conn; if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE)) return SCPE_OK; - for (i = newln; i < ttx_desc.lines; i++) { - if (ttx_ldsc[i].conn) { - tmxr_linemsg (&ttx_ldsc[i], "\r\nOperator disconnected line\r\n"); - tmxr_reset_ln (&ttx_ldsc[i]); /* reset line */ + for (i = newln; i < dlx_desc.lines; i++) { + if (dlx_ldsc[i].conn) { + tmxr_linemsg (&dlx_ldsc[i], "\r\nOperator disconnected line\r\n"); + tmxr_reset_ln (&dlx_ldsc[i]); /* reset line */ } - ttox_unit[i].flags |= UNIT_DIS; - ttx_reset_ln (i); + dlo_unit[i].flags |= UNIT_DIS; + dlx_reset_ln (i); } } else { - for (i = ttx_desc.lines; i < newln; i++) { - ttox_unit[i].flags &= ~UNIT_DIS; - ttx_reset_ln (i); + for (i = dlx_desc.lines; i < newln; i++) { + dlo_unit[i].flags &= ~UNIT_DIS; + dlx_reset_ln (i); } } -ttx_desc.lines = newln; -return auto_config (ttix_dev.name, newln); /* auto config */ +dlx_desc.lines = newln; +dli_dib.lnt = newln * 010; /* upd IO page lnt */ +return auto_config (dli_dev.name, newln); /* auto config */ } /* Show number of lines */ -t_stat ttx_show_lines (FILE *st, UNIT *uptr, int32 val, void *desc) +t_stat dlx_show_lines (FILE *st, UNIT *uptr, int32 val, void *desc) { -fprintf (st, "lines=%d", ttx_desc.lines); +fprintf (st, "lines=%d", dlx_desc.lines); return SCPE_OK; } diff --git a/PDP11/pdp11_io.c b/PDP11/pdp11_io.c index 6a68ac26..c4e1c5e7 100644 --- a/PDP11/pdp11_io.c +++ b/PDP11/pdp11_io.c @@ -1,6 +1,6 @@ /* pdp11_io.c: PDP-11 I/O simulator - Copyright (c) 1993-2006, Robert M Supnik + Copyright (c) 1993-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,9 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 16-May-08 RMS Added multiple DC11 support + Renamed DL11 in autoconfigure + 02-Feb-08 RMS Fixed DMA memory address limit test (found by John Dundas) 06-Jul-06 RMS Added multiple KL11/DL11 support 15-Oct-05 RMS Fixed bug in autoconfiguration (missing XU) 25-Jul-05 RMS Revised autoconfiguration algorithm and interface @@ -54,7 +57,7 @@ extern int32 autcon_enb; extern int32 uba_last; extern FILE *sim_log; extern DEVICE *sim_devices[], cpu_dev; -extern UNIT cpu_unit; +extern t_addr cpu_memsize; int32 calc_ints (int32 nipl, int32 trq); @@ -239,7 +242,7 @@ if (cpu_bme) { /* map enabled? */ } else { /* physical */ if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */ - else if (ADDR_IS_MEM (ba)) alim = MEMSIZE; /* no, strt ok? */ + else if (ADDR_IS_MEM (ba)) alim = cpu_memsize; /* no, strt ok? */ else return bc; /* no, err */ for ( ; ba < alim; ba++) { /* by bytes */ if (ba & 1) *buf++ = (M[ba >> 1] >> 8) & 0377; /* get byte */ @@ -265,7 +268,7 @@ if (cpu_bme) { /* map enabled? */ } else { /* physical */ if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */ - else if (ADDR_IS_MEM (ba)) alim = MEMSIZE; /* no, strt ok? */ + else if (ADDR_IS_MEM (ba)) alim = cpu_memsize; /* no, strt ok? */ else return bc; /* no, err */ for ( ; ba < alim; ba = ba + 2) { /* by words */ *buf++ = M[ba >> 1]; @@ -292,7 +295,7 @@ if (cpu_bme) { /* map enabled? */ } else { /* physical */ if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */ - else if (ADDR_IS_MEM (ba)) alim = MEMSIZE; /* no, strt ok? */ + else if (ADDR_IS_MEM (ba)) alim = cpu_memsize; /* no, strt ok? */ else return bc; /* no, err */ for ( ; ba < alim; ba++) { /* by bytes */ if (ba & 1) M[ba >> 1] = (M[ba >> 1] & 0377) | @@ -319,7 +322,7 @@ if (cpu_bme) { /* map enabled? */ } else { /* physical */ if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */ - else if (ADDR_IS_MEM (ba)) alim = MEMSIZE; /* no, strt ok? */ + else if (ADDR_IS_MEM (ba)) alim = cpu_memsize; /* no, strt ok? */ else return bc; /* no, err */ for ( ; ba < alim; ba = ba + 2) { /* by words */ M[ba >> 1] = *buf++; @@ -600,7 +603,8 @@ typedef struct { } AUTO_CON; AUTO_CON auto_tab[] = { - { { "TTIX" }, TTX_LINES, 2, 0, 8, { 0 } }, /* KL11/DL11/DLV11 - fx CSRs */ + { { "DCI" }, DCX_LINES, 2, 0, 8, { 0 } }, /* DC11 - fx CSRs */ + { { "DLI" }, DLX_LINES, 2, 0, 8, { 0 } }, /* KL11/DL11/DLV11 - fx CSRs */ { { NULL }, 1, 2, 8, 8 }, /* DJ11 */ { { NULL }, 1, 2, 16, 8 }, /* DH11 */ { { NULL }, 1, 2, 8, 8 }, /* DQ11 */ diff --git a/PDP11/pdp11_ke.c b/PDP11/pdp11_ke.c new file mode 100644 index 00000000..711c1c30 --- /dev/null +++ b/PDP11/pdp11_ke.c @@ -0,0 +1,348 @@ +/* pdp11_ke.c: PDP-11/20 extended arithmetic element + + Copyright (c) 1993-2008, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + 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 + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ke_ACTION OF CONTRke_ACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + This code draws on prior work by Tim Shoppa and Brad Parker. My thanks for + to them for letting me use their work. + + EAE PDP-11/20 extended arithmetic element +*/ + +#include "pdp11_defs.h" + +#define GET_SIGN_L(v) (((v) >> 31) & 1) +#define GET_SIGN_W(v) (((v) >> 15) & 1) +#define GET_SIGN_B(v) (((v) >> 7) & 1) + +/* KE11A I/O address offsets 0177300 - 0177316 */ + +#define KE_DIV 000 /* divide */ +#define KE_AC 002 /* accumulator */ +#define KE_MQ 004 /* MQ */ +#define KE_MUL 006 /* multiply */ +#define KE_SC 010 /* step counter */ +#define KE_NOR 012 /* normalize */ +#define KE_LSH 014 /* logical shift */ +#define KE_ASH 016 /* arithmetic shift */ + +/* Status register */ + +#define KE_SR_C 0001 /* carry */ +#define KE_SR_SXT 0002 /* AC<15:0> = MQ<15> */ +#define KE_SR_Z 0004 /* AC = MQ = 0 */ +#define KE_SR_MQZ 0010 /* MQ = 0 */ +#define KE_SR_ACZ 0020 /* AC = 0 */ +#define KE_SR_ACM1 0040 /* AC = 177777 */ +#define KE_SR_N 0100 /* last op negative */ +#define KE_SR_NXV 0200 /* last op ovf XOR N */ +#define KE_SR_DYN (KE_SR_SXT|KE_SR_Z|KE_SR_MQZ|KE_SR_ACZ|KE_SR_ACM1) + +/* Visible state */ + +uint32 ke_AC = 0; +uint32 ke_MQ = 0; +uint32 ke_SC = 0; +uint32 ke_SR = 0; + +DEVICE ke_dev; +t_stat ke_rd (int32 *data, int32 PA, int32 access); +t_stat ke_wr (int32 data, int32 PA, int32 access); +t_stat ke_reset (DEVICE *dptr); +uint32 ke_set_SR (void); + +DIB ke_dib = { IOBA_KE, IOLN_KE, &ke_rd, &ke_wr, 0 }; + +UNIT ke_unit = { + UDATA (NULL, UNIT_DISABLE, 0) + }; + +REG ke_reg[] = { + { ORDATA (AC, ke_AC, 16) }, + { ORDATA (MQ, ke_MQ, 16) }, + { ORDATA (SC, ke_SC, 6) }, + { ORDATA (SR, ke_SR, 8) }, + { NULL } + }; + +MTAB ke_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, + NULL, &show_addr, NULL }, + { 0 } + }; + +DEVICE ke_dev = { + "KE", &ke_unit, ke_reg, ke_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &ke_reset, + NULL, NULL, NULL, + &ke_dib, DEV_DISABLE | DEV_DIS | DEV_UBUS + }; + +/* KE read - reads are always 16b, to even addresses */ + +t_stat ke_rd (int32 *data, int32 PA, int32 access) +{ +switch (PA & 016) { /* decode PA<3:1> */ + + case KE_AC: /* AC */ + *data = ke_AC; + break; + + case KE_MQ: /* MQ */ + *data = ke_MQ; + break; + + case KE_NOR: /* norm (SC) */ + *data = ke_SC; + break; + + case KE_SC: /* SR/SC */ + *data = (ke_set_SR () << 8) | ke_SC; + break; + + default: + *data = 0; + break; + } + +return SCPE_OK; +} + +/* KE write - writes trigger actual arithmetic */ + +t_stat ke_wr (int32 data, int32 PA, int32 access) +{ +int32 quo, t32, sout, sign; +uint32 absd, absr; + +switch (PA & 017) { /* decode PA<3:0> */ + + case KE_DIV: /* divide */ + if ((access == WRITEB) && GET_SIGN_B (data)) /* byte write? */ + data |= 0177400; /* sext data to 16b */ + ke_SR = 0; /* N = V = C = 0 */ + t32 = (ke_AC << 16) | ke_MQ; /* 32b divd */ + if (GET_SIGN_W (ke_AC)) /* sext (divd) */ + t32 = t32 | ~017777777777; + if (GET_SIGN_W (data)) /* sext (divr) */ + data = data | ~077777; + absd = abs (t32); + absr = abs (data); + if ((absd >> 16) >= absr) { /* divide fails? */ + +/* Based on the documentation, here's what has happened: + + SC = 16. + SR = (AC<15> == data<15>) + AC'MQ = (AC'MQ << 1) | SR + AC = SR? AC - data: AC + data + SR = (AC<15> == data<15>) + SC = SC - 1 + stop +*/ + + sign = GET_SIGN_W (ke_AC ^ data) ^ 1; /* 1 if signs match */ + ke_AC = (ke_AC << 1) | (ke_MQ >> 15); + ke_AC = (sign? ke_AC - data: ke_AC + data) & DMASK; + ke_MQ = ((ke_MQ << 1) | sign) & DMASK; + if (GET_SIGN_W (ke_AC ^ data) == 0) /* 0 if signs match */ + ke_SR |= KE_SR_C; + ke_SC = 15; /* SC clocked once */ + ke_SR |= KE_SR_NXV; /* set overflow */ + } + else { + ke_SC = 0; + quo = t32 / data; + ke_MQ = quo & DMASK; /* MQ has quo */ + ke_AC = (t32 % data) & DMASK; /* AC has rem */ + if ((quo > 32767) || (quo < -32768)) /* quo overflow? */ + ke_SR |= KE_SR_NXV; /* set overflow */ + } + if (GET_SIGN_W (ke_MQ)) /* result negative? */ + ke_SR ^= (KE_SR_N | KE_SR_NXV); /* N = 1, compl NXV */ + break; + + case KE_AC: /* AC */ + if ((access == WRITEB) && GET_SIGN_B (data)) /* byte write? */ + data |= 0177400; /* sext data to 16b */ + ke_AC = data; + break; + + case KE_AC + 1: /* AC odd byte */ + ke_AC = (ke_AC & 0377) | (data << 8); + break; + + case KE_MQ: /* MQ */ + if ((access == WRITEB) && GET_SIGN_B (data)) /* byte write? */ + data |= 0177400; /* sext data to 16b */ + ke_MQ = data; + if (GET_SIGN_W (ke_MQ)) /* sext MQ to AC */ + ke_AC = 0177777; + else ke_AC = 0; + break; + + case KE_MQ + 1: /* MQ odd byte */ + ke_MQ = (ke_MQ & 0377) | (data << 8); + if (GET_SIGN_W (ke_MQ)) /* sext MQ to AC */ + ke_AC = 0177777; + else ke_AC = 0; + break; + + case KE_MUL: /* multiply */ + if ((access == WRITEB) && GET_SIGN_B (data)) /* byte write? */ + data |= 0177400; /* sext data to 16b */ + ke_SC = 0; + if (GET_SIGN_W (data)) /* sext operands */ + data |= ~077777; + t32 = ke_MQ; + if (GET_SIGN_W (t32)) + t32 |= ~077777; + t32 = t32 * data; + ke_AC = (t32 >> 16) & DMASK; + ke_MQ = t32 & DMASK; + if (GET_SIGN_W (ke_AC)) /* result negative? */ + ke_SR = KE_SR_N | KE_SR_NXV; /* N = 1, V = C = 0 */ + else ke_SR = 0; /* N = 0, V = C = 0 */ + break; + + case KE_SC: /* SC */ + if (access == WRITEB) /* ignore byte writes */ + return SCPE_OK; + ke_SR = (data >> 8) & (KE_SR_NXV|KE_SR_N|KE_SR_C); + ke_SC = data & 077; + break; + + case KE_NOR: /* normalize */ + for (ke_SC = 0; ke_SC < 31; ke_SC++) { /* max 31 shifts */ + if (((ke_AC == 0140000) && (ke_MQ == 0)) || /* special case? */ + (GET_SIGN_W (ke_AC ^ (ke_AC << 1)))) /* AC<15> != AC<14>? */ + break; + ke_AC = ((ke_AC << 1) | (ke_MQ >> 15)) & DMASK; + ke_MQ = (ke_MQ << 1) & DMASK; + } + if (GET_SIGN_W (ke_AC)) /* result negative? */ + ke_SR = KE_SR_N | KE_SR_NXV; /* N = 1, V = C = 0 */ + else ke_SR = 0; /* N = 0, V = C = 0 */ + break; + + case KE_LSH: /* logical shift */ + ke_SC = 0; + ke_SR = 0; /* N = V = C = 0 */ + data = data & 077; /* 6b shift count */ + if (data != 0) { + t32 = (ke_AC << 16) | ke_MQ; /* 32b operand */ + if (sign = GET_SIGN_W (ke_AC)) /* sext operand */ + t32 = t32 | ~017777777777; + if (data < 32) { /* [1,31] - left */ + sout = (t32 >> (32 - data)) | (-sign << data); + t32 = ((uint32) t32) << data; /* do shift (zext) */ + if (sout != (GET_SIGN_L (t32)? -1: 0)) /* bits lost = sext? */ + ke_SR |= KE_SR_NXV; /* no, V = 1 */ + if (sout & 1) /* last bit lost = 1? */ + ke_SR |= KE_SR_C; /* yes, C = 1 */ + } + else { /* [32,63] = -32,-1 */ + if ((t32 >> (63 - data)) & 1) /* last bit lost = 1? */ + ke_SR |= KE_SR_C; /* yes, C = 1*/ + t32 = (data != 32)? ((uint32) t32) >> (64 - data): 0; + } + ke_AC = (t32 >> 16) & DMASK; + ke_MQ = t32 & DMASK; + } + if (GET_SIGN_W (ke_AC)) /* result negative? */ + ke_SR ^= (KE_SR_N | KE_SR_NXV); /* N = 1, compl NXV */ + break; + +/* EAE ASH differs from EIS ASH and cannot use the same overflow test */ + + case KE_ASH: /* arithmetic shift */ + ke_SC = 0; + ke_SR = 0; /* N = V = C = 0 */ + data = data & 077; /* 6b shift count */ + if (data != 0) { + t32 = (ke_AC << 16) | ke_MQ; /* 32b operand */ + if (sign = GET_SIGN_W (ke_AC)) /* sext operand */ + t32 = t32 | ~017777777777; + if (data < 32) { /* [1,31] - left */ + sout = (t32 >> (31 - data)) | (-sign << data); + t32 = (t32 & 020000000000) | ((t32 << data) & 017777777777); + if (sout != (GET_SIGN_L (t32)? -1: 0)) /* bits lost = sext? */ + ke_SR |= KE_SR_NXV; /* no, V = 1 */ + if (sout & 1) /* last bit lost = 1? */ + ke_SR |= KE_SR_C; /* yes, C = 1 */ + } + else { /* [32,63] = -32,-1 */ + if ((t32 >> (63 - data)) & 1) /* last bit lost = 1? */ + ke_SR |= KE_SR_C; /* yes, C = 1 */ + t32 = (data != 32)? /* special case 32 */ + (((uint32) t32) >> (64 - data)) | (-sign << (data - 32)): + -sign; + } + ke_AC = (t32 >> 16) & DMASK; + ke_MQ = t32 & DMASK; + } + if (GET_SIGN_W (ke_AC)) /* result negative? */ + ke_SR ^= (KE_SR_N | KE_SR_NXV); /* N = 1, compl NXV */ + break; + + default: /* all others ignored */ + return SCPE_OK; + } /* end switch PA */ + +ke_set_SR (); +return SCPE_OK; +} + +/* Update status register based on current AC, MQ */ + +uint32 ke_set_SR (void) +{ +ke_SR &= ~KE_SR_DYN; /* clr dynamic bits */ +if (ke_MQ == 0) /* MQ == 0? */ + ke_SR |= KE_SR_MQZ; +if (ke_AC == 0) { /* AC == 0? */ + ke_SR |= KE_SR_ACZ; + if (GET_SIGN_W (ke_MQ) == 0) /* MQ positive? */ + ke_SR |= KE_SR_SXT; + if (ke_MQ == 0) /* MQ zero? */ + ke_SR |= KE_SR_Z; + } +if (ke_AC == 0177777) { /* AC == 177777? */ + ke_SR |= KE_SR_ACM1; + if (GET_SIGN_W (ke_MQ) == 1) /* MQ negative? */ + ke_SR |= KE_SR_SXT; + } +return ke_SR; +} + +/* Reset routine */ + +t_stat ke_reset (DEVICE *dptr) +{ +ke_SR = 0; +ke_SC = 0; +ke_AC = 0; +ke_MQ = 0; +return SCPE_OK; +} diff --git a/PDP11/pdp11_kg.c b/PDP11/pdp11_kg.c new file mode 100644 index 00000000..3e643531 --- /dev/null +++ b/PDP11/pdp11_kg.c @@ -0,0 +1,477 @@ +/* pdp11_kg.c - Communications Arithmetic Option KG11-A + + Copyright (c) 2007-2008, John A. Dundas III + + 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 + ROBERT M SUPNIK 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. + + kg KG11-A Communications Arithmetic Option (M7251) + + 08-Jan-08 JAD First public release integrated with SIMH V3.7-3. + 09-Dec-07 JAD SIMH-style debugging. + Finished validating against real hardware. + Support for up to 8 units, the maximum. + Keep all module data in the UNIT structure. + Clean up bit and mask definitions. + 01-Dec-07 JAD Now work on the corner cases that the + diagnostic does not check. + CLR does not clear the QUO bit. + Correct SR write logic. + 29-Nov-07 JAD Original implementation and testing based on + an idea from 07-Jul-03. Passes the ZKGAB0 + diagnostic. + + Information necessary to create this simulation was gathered from + a number of sources including: + + KG11-A Exclusive-OR and CRC block check manual, DEC-11-HKGAA-B-D + + Maintenance print set + + A Painless Guide to CRC Error Detection Algorithms, Ross N. Williams + + + The original PDP-11 instruction set, as implemented in the /20, + /15, /10, and /5, did not include XOR. [One of the differences + tables incorrectly indicates the /04 does not implement this + instruction.] This device implements XOR, XORB, and a variety of + CRCs. + + The maintenance prints indicate that the device was probably available + starting in late 1971. May need to check further. The first edition + of the manual was May 1972. + + The device was still sold at least as late as mid-1982 according + to the PDP-11 Systems and Options Summary. RSTS/E included support + for up to 8 units in support of the 2780 emulation or for use with + DP11, DU11, or DUP11. The device appears to have been retired by + 1983-03, and possibly earlier. + + I/O Page Registers + + SR 7707x0 (read-write) status + BCC 7707x2 (read-only) BCC (block check character) + DR 7707x4 (write-only) data + + Vector: none + + Priority: none + + The KG11-A is a programmed-I/O, non-interrupting device. Therefore + no vector or bus request level are necessary. It is a Unibus device + but since it does not address memory itself (it only presents + registers in the I/O page) it is compatible with extended Unibus + machines (22-bit) as well as traditional Unibus. + + Implements 5 error detection codes: + LRC-8 + LRC-16 + CRC-12 + CRC-16 + CRC-CCITT +*/ + +#if !defined (VM_PDP11) +#error "KG11 is not supported!" +#endif +#include "pdp11_defs.h" + +extern FILE *sim_deb; +extern REG cpu_reg[]; +extern int32 R[]; + +#ifndef KG_UNITS +#define KG_UNITS (8) +#endif + +/* Control and Status Register */ + +#define KGSR_V_QUO (8) /* RO */ +#define KGSR_V_DONE (7) /* RO */ +#define KGSR_V_SEN (6) /* R/W shift enable */ +#define KGSR_V_STEP (5) /* W */ +#define KGSR_V_CLR (4) /* W */ +#define KGSR_V_DDB (3) /* R/W double data byte */ +#define KGSR_V_CRCIC (2) /* R/W */ +#define KGSR_V_LRC (1) /* R/W */ +#define KGSR_V_16 (0) /* R/W */ + +#define KGSR_M_QUO (1u << KGSR_V_QUO) +#define KGSR_M_DONE (1u << KGSR_V_DONE) +#define KGSR_M_SEN (1u << KGSR_V_SEN) +#define KGSR_M_STEP (1u << KGSR_V_STEP) +#define KGSR_M_CLR (1u << KGSR_V_CLR) +#define KGSR_M_DDB (1u << KGSR_V_DDB) +#define KGSR_M_CRCIC (1u << KGSR_V_CRCIC) +#define KGSR_M_LRC (1u << KGSR_V_LRC) +#define KGSR_M_16 (1u << KGSR_V_16) + +#define KG_SR_RDMASK (KGSR_M_QUO | KGSR_M_DONE | KGSR_M_SEN | KGSR_M_DDB | \ + KGSR_M_CRCIC | KGSR_M_LRC | KGSR_M_16) +#define KG_SR_WRMASK (KGSR_M_SEN | KGSR_M_DDB | KGSR_M_CRCIC | \ + KGSR_M_LRC | KGSR_M_16) + +#define KG_SR_POLYMASK (KGSR_M_CRCIC|KGSR_M_LRC|KGSR_M_16) + +/* Unit structure redefinitions */ +#define SR u3 +#define BCC u4 +#define DR u5 +#define PULSCNT u6 + +#define POLY_LRC8 (0x0008) +#define POLY_LRC16 (0x0080) +#define POLY_CRC12 (0x0f01) +#define POLY_CRC16 (0xa001) +#define POLY_CCITT (0x8408) + +static const struct { + uint16 poly; + uint16 pulses; + const char * const name; +} config[] = { + /* DDB=0 */ + { POLY_CRC12, 6, "CRC-12" }, + { POLY_CRC16, 8, "CRC-16" }, + { POLY_LRC8, 8, "LRC-8" }, + { POLY_LRC16, 8, "LRC-16" }, + { 0, 0, "undefined" }, + { POLY_CCITT, 8, "CRC-CCITT" }, + { 0, 0, "undefined" }, + { 0, 0, "undefined" }, + /* DDB=1 */ + { POLY_CRC12, 12, "CRC-12" }, + { POLY_CRC16, 16, "CRC-16" }, + { POLY_LRC8, 16, "LRC-8" }, + { POLY_LRC16, 16, "LRC-16" }, + { 0, 0, "undefined" }, + { POLY_CCITT, 16, "CRC-CCITT" }, + { 0, 0, "undefined" }, + { 0, 0, "undefined" } +}; + +/* Forward declarations */ + +static t_stat kg_rd (int32 *, int32, int32); +static t_stat kg_wr (int32, int32, int32); +static t_stat kg_reset (DEVICE *); +static void do_poly (int, t_bool); +static t_stat set_units (UNIT *, int32, char *, void *); + +/* 16-bit rotate right */ + +#define ROR(n,v) (((v >> n) & DMASK) | (v << (16 - n)) & DMASK) + +/* 8-bit rotate right */ + +#define RORB(n,v) (((v & 0377) >> n) | ((v << (8 - n)) & 0377)) + +/* KG data structures + + kg_dib KG PDP-11 device information block + kg_unit KG unit descriptor + kg_reg KG register list + kg_mod KG modifiers table + kg_debug KG debug names table + kg_dev KG device descriptor +*/ + +static DIB kg_dib = { + IOBA_KG, + (IOLN_KG + 2) * KG_UNITS, + &kg_rd, + &kg_wr, + 0, 0, 0, { NULL } +}; + +static UNIT kg_unit[] = { + { UDATA (NULL, 0, 0) }, + { UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) }, + { UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) }, + { UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) }, + { UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) }, + { UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) }, + { UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) }, + { UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) }, +}; + +static const REG kg_reg[] = { + { ORDATA (SR0, kg_unit[0].SR, 16) }, + { ORDATA (SR1, kg_unit[1].SR, 16) }, + { ORDATA (SR2, kg_unit[2].SR, 16) }, + { ORDATA (SR3, kg_unit[3].SR, 16) }, + { ORDATA (SR4, kg_unit[4].SR, 16) }, + { ORDATA (SR5, kg_unit[5].SR, 16) }, + { ORDATA (SR6, kg_unit[6].SR, 16) }, + { ORDATA (SR7, kg_unit[7].SR, 16) }, + { ORDATA (BCC0, kg_unit[0].BCC, 16) }, + { ORDATA (BCC1, kg_unit[1].BCC, 16) }, + { ORDATA (BCC2, kg_unit[2].BCC, 16) }, + { ORDATA (BCC3, kg_unit[3].BCC, 16) }, + { ORDATA (BCC4, kg_unit[4].BCC, 16) }, + { ORDATA (BCC5, kg_unit[5].BCC, 16) }, + { ORDATA (BCC6, kg_unit[6].BCC, 16) }, + { ORDATA (BCC7, kg_unit[7].BCC, 16) }, + { ORDATA (DR0, kg_unit[0].DR, 16) }, + { ORDATA (DR1, kg_unit[1].DR, 16) }, + { ORDATA (DR2, kg_unit[2].DR, 16) }, + { ORDATA (DR3, kg_unit[3].DR, 16) }, + { ORDATA (DR4, kg_unit[4].DR, 16) }, + { ORDATA (DR5, kg_unit[5].DR, 16) }, + { ORDATA (DR6, kg_unit[6].DR, 16) }, + { ORDATA (DR7, kg_unit[7].DR, 16) }, + { ORDATA (PULSCNT0, kg_unit[0].PULSCNT, 16) }, + { ORDATA (PULSCNT1, kg_unit[1].PULSCNT, 16) }, + { ORDATA (PULSCNT2, kg_unit[2].PULSCNT, 16) }, + { ORDATA (PULSCNT3, kg_unit[3].PULSCNT, 16) }, + { ORDATA (PULSCNT4, kg_unit[4].PULSCNT, 16) }, + { ORDATA (PULSCNT5, kg_unit[5].PULSCNT, 16) }, + { ORDATA (PULSCNT6, kg_unit[6].PULSCNT, 16) }, + { ORDATA (PULSCNT7, kg_unit[7].PULSCNT, 16) }, + { ORDATA (DEVADDR, kg_dib.ba, 32), REG_HRO }, + { NULL } +}; + +static const MTAB kg_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, NULL, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "UNITS=0..8", &set_units, NULL, NULL }, + { 0 } +}; + +#define DBG_REG (01) +#define DBG_POLY (02) +#define DBG_CYCLE (04) + +static const DEBTAB kg_debug[] = { + {"REG", DBG_REG}, + {"POLY", DBG_POLY}, + {"CYCLE", DBG_CYCLE}, + {0}, +}; + +DEVICE kg_dev = { + "KG", (UNIT *) &kg_unit, (REG *) kg_reg, (MTAB *) kg_mod, + KG_UNITS, 8, 16, 2, 8, 16, + NULL, /* examine */ + NULL, /* deposit */ + &kg_reset, /* reset */ + NULL, /* boot */ + NULL, /* attach */ + NULL, /* detach */ + &kg_dib, + DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG, + 0, /* debug control */ + (DEBTAB *) &kg_debug, /* debug flags */ + NULL, /* memory size chage */ + NULL /* logical name */ +}; + /* KG I/O address routines */ + +static t_stat kg_rd (int32 *data, int32 PA, int32 access) +{ + int unit = (PA >> 3) & 07; + + if ((unit >= KG_UNITS) || (kg_unit[unit].flags & UNIT_DIS)) + return (SCPE_NXM); + switch ((PA >> 1) & 03) { + + case 00: /* SR */ + if (DEBUG_PRI(kg_dev, DBG_REG)) + fprintf (sim_deb, ">>KG%d: rd SR %06o, PC %06o\n", + unit, kg_unit[unit].SR, PC); + *data = kg_unit[unit].SR & KG_SR_RDMASK; + break; + + case 01: /* BCC */ + if (DEBUG_PRI(kg_dev, DBG_REG)) + fprintf (sim_deb, ">>KG%d rd BCC %06o, PC %06o\n", + unit, kg_unit[unit].BCC, PC); + *data = kg_unit[unit].BCC & DMASK; + break; + + case 02: /* DR */ + break; + + default: + break; + } + return (SCPE_OK); +} + +static t_stat kg_wr (int32 data, int32 PA, int32 access) +{ + int setup; + int unit = (PA >> 3) & 07; + + if ((unit >= KG_UNITS) || (kg_unit[unit].flags & UNIT_DIS)) + return (SCPE_NXM); + switch ((PA >> 1) & 03) { + + case 00: /* SR */ + if (access == WRITEB) + data = (PA & 1) ? + (kg_unit[unit].SR & 0377) | (data << 8) : + (kg_unit[unit].SR & ~0377) | data; + if (DEBUG_PRI(kg_dev, DBG_REG)) + fprintf (sim_deb, ">>KG%d: wr SR %06o, PC %06o\n", + unit, data, PC); + if (data & KGSR_M_CLR) { + kg_unit[unit].PULSCNT = 0; /* not sure about this */ + kg_unit[unit].BCC = 0; + kg_unit[unit].SR |= KGSR_M_DONE; + } + setup = (kg_unit[unit].SR & 017) ^ (data & 017); + kg_unit[unit].SR = (kg_unit[unit].SR & ~KG_SR_WRMASK) | + (data & KG_SR_WRMASK); + /* if low 4b changed, reset C1 & C2 */ + if (setup) { + kg_unit[unit].PULSCNT = 0; + if (DEBUG_PRI(kg_dev, DBG_POLY)) + fprintf (sim_deb, ">>KG%d poly %s %d\n", + unit, config[data & 017].name, config[data & 017].pulses); + } + if (data & KGSR_M_SEN) + break; + if (data & KGSR_M_STEP) { + do_poly (unit, TRUE); + break; + } + break; + + case 01: /* BCC */ + break; /* ignored */ + + case 02: /* DR */ + if (access == WRITEB) + data = (PA & 1) ? + (kg_unit[unit].DR & 0377) | (data << 8) : + (kg_unit[unit].DR & ~0377) | data; + kg_unit[unit].DR = data & DMASK; + if (DEBUG_PRI(kg_dev, DBG_REG)) + fprintf (sim_deb, ">>KG%d: wr DR %06o, data %06o, PC %06o\n", + unit, kg_unit[unit].DR, data, PC); + kg_unit[unit].SR &= ~KGSR_M_DONE; + +/* In a typical device, this is normally where we would use sim_activate() + to initiate an I/O to be completed later. The KG is a little + different. When it was first introduced, it's computation operation + completed before another instruction could execute (on early PDP-11s), + and software often took "advantage" of this fact by not bothering + to check the status of the DONE bit. In reality, the execution + time of the polynomial is dependent upon the width of the poly; if + 8 bits 1us, if 16 bits, 2us. Since known existing software will + break if we actually defer the computation, it is performed immediately + instead. However this could easily be made into a run-time option, + if there were software to validate correct operation. */ + + if (kg_unit[unit].SR & KGSR_M_SEN) + do_poly (unit, FALSE); + break; + + default: + break; + } + return (SCPE_OK); +} + +/* KG reset */ + +static t_stat kg_reset (DEVICE *dptr) +{ + int i; + + if (DEBUG_PRI(kg_dev, DBG_REG)) + fprintf (sim_deb, ">>KG: reset PC %06o\n", PC); + for (i = 0; i < KG_UNITS; i++) { + kg_unit[i].SR = KGSR_M_DONE; + kg_unit[i].BCC = 0; + kg_unit[i].PULSCNT = 0; + } + return (SCPE_OK); +} + +static void cycleOneBit (int unit) +{ + int quo; + + if (DEBUG_PRI(kg_dev, DBG_CYCLE)) + fprintf (sim_deb, ">>KG%d: cycle s BCC %06o DR %06o\n", + unit, kg_unit[unit].BCC, kg_unit[unit].DR); + if (kg_unit[unit].SR & KGSR_M_DONE) + return; + if ((kg_unit[unit].SR & KG_SR_POLYMASK) == 0) + kg_unit[unit].BCC = (kg_unit[unit].BCC & 077) | + ((kg_unit[unit].BCC >> 2) & 07700); + kg_unit[unit].SR &= ~KGSR_M_QUO; + quo = (kg_unit[unit].BCC & 01) ^ (kg_unit[unit].DR & 01); + kg_unit[unit].BCC = (kg_unit[unit].BCC & ~01) | quo; + if (kg_unit[unit].SR & KGSR_M_LRC) + kg_unit[unit].BCC = (kg_unit[unit].SR & KGSR_M_16) ? + ROR(1, kg_unit[unit].BCC) : + RORB(1, kg_unit[unit].BCC); + else + kg_unit[unit].BCC = (kg_unit[unit].BCC & 01) ? + (kg_unit[unit].BCC >> 1) ^ config[kg_unit[unit].SR & 07].poly : + kg_unit[unit].BCC >> 1; + kg_unit[unit].DR >>= 1; + kg_unit[unit].SR |= quo << KGSR_V_QUO; + if ((kg_unit[unit].SR & KG_SR_POLYMASK) == 0) + kg_unit[unit].BCC = (kg_unit[unit].BCC & 077) | + ((kg_unit[unit].BCC & 07700) << 2); + kg_unit[unit].PULSCNT++; + if (kg_unit[unit].PULSCNT >= config[kg_unit[unit].SR & 017].pulses) + kg_unit[unit].SR |= KGSR_M_DONE; + if (DEBUG_PRI(kg_dev, DBG_CYCLE)) + fprintf (sim_deb, ">>KG%d: cycle e BCC %06o DR %06o\n", + unit, kg_unit[unit].BCC, kg_unit[unit].DR); +} + +static void do_poly (int unit, t_bool step) +{ + if (kg_unit[unit].SR & KGSR_M_DONE) + return; + if (step) + cycleOneBit (unit); + else { + while (!(kg_unit[unit].SR & KGSR_M_DONE)) + cycleOneBit (unit); + } +} + +static t_stat set_units (UNIT *u, int32 val, char *s, void *desc) +{ + int32 i, units; + t_stat stat; + + if (s == NULL) + return (SCPE_ARG); + units = get_uint (s, 10, KG_UNITS, &stat); + if (stat != SCPE_OK) + return (stat); + for (i = 0; i < KG_UNITS; i++) { + if (i < units) + kg_unit[i].flags &= ~UNIT_DIS; + else + kg_unit[i].flags |= UNIT_DIS; + } + kg_dev.numunits = units; + return (SCPE_OK); +} diff --git a/PDP11/pdp11_pclk.c b/PDP11/pdp11_pclk.c index f5076849..f2ff1470 100644 --- a/PDP11/pdp11_pclk.c +++ b/PDP11/pdp11_pclk.c @@ -1,6 +1,6 @@ /* pdp11_pclk.c: KW11P programmable clock simulator - Copyright (c) 1993-2007, Robert M Supnik + Copyright (c) 1993-2008, Robert M Supnik Written by John Dundas, used with his gracious permission Permission is hereby granted, free of charge, to any person obtaining a @@ -26,6 +26,7 @@ pclk KW11P line frequency clock + 20-May-08 RMS Standardized clock delay at 1mips 18-Jun-07 RMS Added UNIT_IDLE flag 07-Jul-05 RMS Removed extraneous externs @@ -133,7 +134,7 @@ uint32 pclk_csr = 0; /* control/status */ uint32 pclk_csb = 0; /* count set buffer */ uint32 pclk_ctr = 0; /* counter */ static uint32 rate[4] = { 100000, 10000, 60, 10 }; /* ticks per second */ -static uint32 xtim[4] = { 10, 100, 16000, 100000 }; /* nominal time delay */ +static uint32 xtim[4] = { 10, 100, 16667, 100000 }; /* nominal time delay */ DEVICE pclk_dev; t_stat pclk_rd (int32 *data, int32 PA, int32 access); diff --git a/PDP11/pdp11_rc.c b/PDP11/pdp11_rc.c new file mode 100644 index 00000000..1f32ec59 --- /dev/null +++ b/PDP11/pdp11_rc.c @@ -0,0 +1,583 @@ +/* pdp11_rc.c: RC11/RS64 fixed head disk simulator + + Copyright (c) 2007-2008, John A. Dundas III + + 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 + ROBERT M SUPNIK 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. + + rc RC11/RS64 fixed head disk + + 28-Dec-07 JAD Correct extraction of unit number from da in rc_svc. + Clear _all_ error bits when a new operation starts. + Passes all diagnostics in all configurations. + 25-Dec-07 JAD Compute the CRC-16 of the last sector read via + a READ or WCHK. + 20-Dec-07 JAD Correctly simulate rotation over the selected + track for RCLA. Also update the register + correctly during I/O operations. + Insure function activation time is non-zero. + Handle unit number wrap correctly. + 19-Dec-07 JAD Iterate over a full sector regardless of the + actual word count so that RCDA ends correctly. + Honor the read-only vs. read-write status of the + attached file. + 16-Dec-07 JAD The RCDA must be checked for validity when it is + written to, not just when GO is received. + 15-Dec-07 JAD Better handling of disk address errors and the RCLA + register. + Add more registers to the visible device state. + 07-Jan-07 JAD Initial creation and testing. Adapted from pdp11_rf.c. + + The RS64 is a head-per-track disk. To minimize overhead, the entire RC11 + is buffered in memory. Up to 4 RS64 "platters" may be controlled by one + RC11 for a total of 262,144 words (65536kW/platter). [Later in time the + RK611 was assigned the same CSR address.] + + Diagnostic routines: + ZRCAB0.BIC - passes w/1-4 platters + ZRCBB0.BIC - passes w/1-4 platters + ZRCCB0.BIC - passes w/1-4 platters + Note that the diagnostics require R/W disks (i.e., will destroy any + existing data). + + For regression, must pass all three diagnostics configured for 1-4 + platters for a total of 12 tests. + + Information necessary to create this simulation was gathered from the + PDP11 Peripherals Handbook, 1973-74 edition. + + One timing parameter is provided: + + rc_time Minimum I/O operation time, must be non-zero +*/ + +#if !defined (VM_PDP11) +#error "RC11 is not supported!" +#endif +#include "pdp11_defs.h" +#include + +#define UNIT_V_AUTO (UNIT_V_UF + 0) /* autosize */ +#define UNIT_V_PLAT (UNIT_V_UF + 1) /* #platters - 1 */ +#define UNIT_M_PLAT 03 +#define UNIT_GETP(x) ((((x) >> UNIT_V_PLAT) & UNIT_M_PLAT) + 1) +#define UNIT_AUTO (1 << UNIT_V_AUTO) +#define UNIT_PLAT (UNIT_M_PLAT << UNIT_V_PLAT) + +/* Constants */ + +#define RC_NUMWD (32*64) /* words/track */ +#define RC_NUMTR 32 /* tracks/disk */ +#define RC_DKSIZE (RC_NUMTR * RC_NUMWD) /* words/disk */ +#define RC_NUMDK 4 /* disks/controller */ +#define RC_WMASK (RC_NUMWD - 1) /* word mask */ + +/* Parameters in the unit descriptor */ + +#define FUNC u4 /* function */ + +/* Control and status register (RCCS) */ + +#define RCCS_ERR (CSR_ERR) /* error */ +#define RCCS_DATA 0040000 /* data error */ +#define RCCS_ADDR 0020000 /* address error */ +#define RCCS_WLK 0010000 /* write lock */ +#define RCCS_NED 0004000 /* nx disk */ +#define RCCS_WCHK 0002000 /* write check */ +#define RCCS_INH 0001000 /* inhibit CA incr */ +#define RCCS_ABO 0000400 /* abort */ +#define RCCS_DONE (CSR_DONE) +#define RCCS_IE (CSR_IE) +#define RCCS_M_MEX 0000003 /* memory extension */ +#define RCCS_V_MEX 4 +#define RCCS_MEX (RCCS_M_MEX << RCCS_V_MEX) +#define RCCS_MAINT 0000010 /* maint */ +#define RCCS_M_FUNC 0000003 /* function */ +#define RFNC_LAH 0 +#define RFNC_WRITE 1 +#define RFNC_READ 2 +#define RFNC_WCHK 3 +#define RCCS_V_FUNC 1 +#define RCCS_FUNC (RCCS_M_FUNC << RCCS_V_FUNC) +#define RCCS_GO 0000001 + +#define RCCS_ALLERR (RCCS_DATA|RCCS_ADDR|RCCS_WLK|RCCS_NED|RCCS_WCHK) +#define RCCS_W (RCCS_INH | RCCS_ABO |RCCS_IE | RCCS_MEX | RCCS_MAINT | \ + RCCS_FUNC | RCCS_GO) + +/* Disk error status register (RCER) */ + +#define RCER_DLT 0100000 /* data late */ +#define RCER_CHK 0040000 /* block check */ +#define RCER_SYNC 0020000 /* data sync */ +#define RCER_NXM 0010000 /* nonexistant memory */ +#define RCER_TRK 0001000 /* track error */ +#define RCER_APAR 0000200 /* address parity */ +#define RCER_SADDR 0000100 /* sync address */ +#define RCER_OVFL 0000040 /* disk overflow */ +#define RCER_MIS 0000020 /* missed transfer */ + +/* Lood Ahead Register (RCLA) */ + +#define RCLA_BADD 0100000 /* bad address */ + +/* extract device operation code */ +#define GET_FUNC(x) (((x) >> RCCS_V_FUNC) & RCCS_M_FUNC) +/* extract memory extension address (bits 17,18) */ +#define GET_MEX(x) (((x) & RCCS_MEX) << (16 - RCCS_V_MEX)) +#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \ + ((double) RC_NUMWD))) + +extern int32 int_req[IPL_HLVL]; +extern FILE *sim_deb; +extern int32 R[]; + +static uint32 rc_la = 0; /* look-ahead */ +static uint32 rc_da = 0; /* disk address */ +static uint32 rc_er = 0; /* error status */ +static uint32 rc_cs = 0; /* command and status */ +static uint32 rc_wc = 0; /* word count */ +static uint32 rc_ca = 0; /* current address */ +static uint32 rc_maint = 0; /* maintenance */ +static uint32 rc_db = 0; /* data buffer */ +static uint32 rc_wlk = 0; /* write lock */ +static uint32 rc_time = 16; /* inter-word time: 16us */ +static uint32 rc_stopioe = 1; /* stop on error */ + +/* forward references */ + +DEVICE rc_dev; +static t_stat rc_rd (int32 *, int32, int32); +static t_stat rc_wr (int32, int32, int32); +static t_stat rc_svc (UNIT *); +static t_stat rc_reset (DEVICE *); +static t_stat rc_attach (UNIT *, char *); +static t_stat rc_set_size (UNIT *, int32, char *, void *); +static uint32 update_rccs (uint32, uint32); + +/* RC11 data structures + + rc_dev RC device descriptor + rc_unit RC unit descriptor + rc_reg RC register list +*/ + +static DIB rc_dib = { + IOBA_RC, + IOLN_RC, + &rc_rd, + &rc_wr, + 1, IVCL (RC), VEC_RC, { NULL } +}; + +static UNIT rc_unit = { + UDATA (&rc_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_BUFABLE + + UNIT_MUSTBUF + UNIT_ROABLE + UNIT_BINK, RC_DKSIZE) +}; + +static const REG rc_reg[] = { + { ORDATA (RCLA, rc_la, 16) }, + { ORDATA (RCDA, rc_da, 16) }, + { ORDATA (RCER, rc_er, 16) }, + { ORDATA (RCCS, rc_cs, 16) }, + { ORDATA (RCWC, rc_wc, 16) }, + { ORDATA (RCCA, rc_ca, 16) }, + { ORDATA (RCMN, rc_maint, 16) }, + { ORDATA (RCDB, rc_db, 16) }, + { ORDATA (RCWLK, rc_wlk, 32) }, + { FLDATA (INT, IREQ (RC), INT_V_RC) }, + { FLDATA (ERR, rc_cs, CSR_V_ERR) }, + { FLDATA (DONE, rc_cs, CSR_V_DONE) }, + { FLDATA (IE, rc_cs, CSR_V_IE) }, + { DRDATA (TIME, rc_time, 24), REG_NZ + PV_LEFT }, + { FLDATA (STOP_IOE, rc_stopioe, 0) }, + { ORDATA (DEVADDR, rc_dib.ba, 32), REG_HRO }, + { ORDATA (DEVVEC, rc_dib.vec, 16), REG_HRO }, + { NULL } +}; + +static const MTAB rc_mod[] = { + { UNIT_PLAT, (0 << UNIT_V_PLAT), NULL, "1P", &rc_set_size }, + { UNIT_PLAT, (1 << UNIT_V_PLAT), NULL, "2P", &rc_set_size }, + { UNIT_PLAT, (2 << UNIT_V_PLAT), NULL, "3P", &rc_set_size }, + { UNIT_PLAT, (3 << UNIT_V_PLAT), NULL, "4P", &rc_set_size }, + { UNIT_AUTO, UNIT_AUTO, "autosize", "AUTOSIZE", NULL }, + { MTAB_XTD|MTAB_VDV, 020, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", + &set_vec, &show_vec, NULL }, + { 0 } +}; + +DEVICE rc_dev = { + "RC", &rc_unit, (REG *) rc_reg, (MTAB *) rc_mod, + 1, 8, 21, 1, 8, 16, + NULL, /* examine */ + NULL, /* deposit */ + &rc_reset, /* reset */ + NULL, /* boot */ + &rc_attach, /* attach */ + NULL, /* detach */ + &rc_dib, + DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG +}; + +/* I/O dispatch routine, I/O addresses 17777440 - 17777456 */ + +static t_stat rc_rd (int32 *data, int32 PA, int32 access) +{ + uint32 t; + + switch ((PA >> 1) & 07) { /* decode PA<3:1> */ + + case 0: /* RCLA */ + t = rc_la & 017777; + if ((rc_cs & RCCS_NED) || (rc_er & RCER_OVFL)) + t |= RCLA_BADD; + *data = t; + /* simulate sequential rotation about the current track */ + rc_la = (rc_la & ~077) | ((rc_la + 1) & 077); + if (DEBUG_PRS (rc_dev)) + fprintf (sim_deb, ">>RC rd: RCLA %06o\n", rc_la); + break; + + case 1: /* RCDA */ + *data = rc_da; + if (DEBUG_PRS (rc_dev)) + fprintf (sim_deb, ">>RC rd: RCDA %06o, PC %06o\n", + rc_da, PC); + break; + + case 2: /* RCER */ + *data = rc_er; + if (DEBUG_PRS (rc_dev)) + fprintf (sim_deb, ">>RC rd: RCER %06o\n", rc_er); + break; + + case 3: /* RCCS */ + *data = update_rccs (0, 0) & ~(RCCS_ABO | RCCS_GO); + if (DEBUG_PRS (rc_dev)) + fprintf (sim_deb, ">>RC rd: RCCS %06o\n", *data); + break; + + case 4: /* RCWC */ + *data = rc_wc; + if (DEBUG_PRS (rc_dev)) + fprintf (sim_deb, ">>RC rd: RCWC %06o\n", rc_wc); + break; + + case 5: /* RCCA */ + *data = rc_ca; + if (DEBUG_PRS (rc_dev)) + fprintf (sim_deb, ">>RC rd: RCCA %06o\n", rc_ca); + break; + + case 6: /* RCMN */ + *data = rc_maint; + if (DEBUG_PRS (rc_dev)) + fprintf (sim_deb, ">>RC rd: RCMN %06o\n", rc_maint); + break; + + case 7: /* RCDB */ + *data = rc_db; + if (DEBUG_PRS (rc_dev)) + fprintf (sim_deb, ">>RC rd: RCDB %06o\n", rc_db); + break; + + default: + return (SCPE_NXM); /* can't happen */ + } /* end switch */ + return (SCPE_OK); +} + +static t_stat rc_wr (int32 data, int32 PA, int32 access) +{ + int32 t; + + switch ((PA >> 1) & 07) { /* decode PA<3:1> */ + + case 0: /* RCLA */ + if (DEBUG_PRS (rc_dev)) + fprintf (sim_deb, ">>RC wr: RCLA\n"); + break; /* read only */ + + case 1: /* RCDA */ + if (access == WRITEB) + data = (PA & 1) ? + (rc_da & 0377) | (data << 8) : + (rc_da & ~0377) | data; + rc_da = data & 017777; + rc_cs &= ~RCCS_NED; + update_rccs (0, 0); + /* perform unit select */ + if (((rc_da >> 11) & 03) >= UNIT_GETP(rc_unit.flags)) + update_rccs (RCCS_NED, 0); + else + rc_la = rc_da; + if (DEBUG_PRS (rc_dev)) + fprintf (sim_deb, ">>RC wr: RCDA %06o, PC %06o\n", + rc_da, PC); + break; + + case 2: /* RCER */ + if (DEBUG_PRS (rc_dev)) + fprintf (sim_deb, ">>RC wr: RCER\n"); + break; /* read only */ + + case 3: /* RCCS */ + if (access == WRITEB) + data = (PA & 1) ? + (rc_cs & 0377) | (data << 8) : + (rc_cs & ~0377) | data; + if (data & RCCS_ABO) { + update_rccs (RCCS_DONE, 0); + sim_cancel (&rc_unit); + } + if ((data & RCCS_IE) == 0) /* int disable? */ + CLR_INT (RC); /* clr int request */ + else if ((rc_cs & (RCCS_DONE | RCCS_IE)) == RCCS_DONE) + SET_INT (RC); /* set int request */ + rc_cs = (rc_cs & ~RCCS_W) | (data & RCCS_W); /* merge */ + if ((rc_cs & RCCS_DONE) && (data & RCCS_GO)) { /* new function? */ + rc_unit.FUNC = GET_FUNC (data); /* save function */ + t = (rc_da & RC_WMASK) - GET_POS (rc_time); /* delta to new loc */ + if (t <= 0) /* wrap around? */ + t = t + RC_NUMWD; + sim_activate (&rc_unit, t * rc_time); /* schedule op */ + /* clear error indicators for new operation */ + rc_cs &= ~(RCCS_ALLERR | RCCS_ERR | RCCS_DONE); + rc_er = 0; + CLR_INT (RC); + if (DEBUG_PRS (rc_dev)) + fprintf (sim_deb, ">>RC start: cs = %o, da = %o, ma = %o, wc = %o\n", + update_rccs (0, 0), rc_da, + GET_MEX (rc_cs) | rc_ca, rc_wc); + } + break; + + case 4: /* RCWC */ + if (access == WRITEB) + data = (PA & 1) ? + (rc_wc & 0377) | (data << 8) : + (rc_wc & ~0377) | data; + rc_wc = data & DMASK; + if (DEBUG_PRS (rc_dev)) + fprintf (sim_deb, ">>RC wr: RCWC %06o, PC %06o\n", + rc_wc, PC); + break; + + case 5: /* RCCA */ + /* TBD: write byte fixup? */ + rc_ca = data & 0177776; + if (DEBUG_PRS (rc_dev)) + fprintf (sim_deb, ">>RC wr: RCCA %06o\n", rc_ca); + break; + + case 6: /* RCMN */ + /* TBD: write byte fixup? */ + rc_maint = data & 0177700; + if (DEBUG_PRS (rc_dev)) + fprintf (sim_deb, ">>RC wr: RCMN %06o\n", rc_maint); + break; + + case 7: /* RCDB */ + if (DEBUG_PRS (rc_dev)) + fprintf (sim_deb, ">>RC wr: RCDB\n"); + break; /* read only */ + + default: /* can't happen */ + return (SCPE_NXM); + } /* end switch */ + update_rccs (0, 0); + return (SCPE_OK); +} + +/* sector (32W) CRC-16 */ + +static uint32 sectorCRC (const uint16 *data) +{ + uint32 crc, i, j, d; + + crc = 0; + for (i = 0; i < 32; i++) { + d = *data++; + /* cribbed from KG11-A */ + for (j = 0; j < 16; j++) { + crc = (crc & ~01) | ((crc & 01) ^ (d & 01)); + crc = (crc & 01) ? (crc >> 1) ^ 0120001 : crc >> 1; + d >>= 1; + } + } + return (crc); +} + +/* Unit service + + Note that for reads and writes, memory addresses wrap around in the + current field. This code assumes the entire disk is buffered. +*/ + +static t_stat rc_svc (UNIT *uptr) +{ + uint32 ma, da, t, u_old, u_new, last_da; + uint16 dat; + uint16 *fbuf = uptr->filebuf; + + if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */ + update_rccs (RCCS_NED | RCCS_DONE, 0); /* nx disk */ + return (IORETURN (rc_stopioe, SCPE_UNATT)); + } + + ma = GET_MEX (rc_cs) | rc_ca; /* 18b mem addr */ + da = rc_da * RC_NUMTR; /* sector->word offset */ + u_old = (da >> 16) & 03; /* save starting unit# */ + do { + u_new = (da >> 16) & 03; + if (u_new < u_old) { /* unit # overflow? */ + update_rccs (RCCS_NED, RCER_OVFL); + break; + } + if (u_new >= UNIT_GETP(uptr->flags)) { /* disk overflow? */ + update_rccs (RCCS_NED, 0); + break; + } + if (uptr->FUNC == RFNC_READ) { /* read? */ + last_da = da & ~037; + dat = fbuf[da]; /* get disk data */ + rc_db = dat; + if (Map_WriteW (ma, 2, &dat)) { /* store mem, nxm? */ + update_rccs (0, RCER_NXM); + break; + } + } else if (uptr->FUNC == RFNC_WCHK) { /* write check? */ + last_da = da & ~037; + rc_db = fbuf[da]; /* get disk data */ + if (Map_ReadW (ma, 2, &dat)) { /* read mem, nxm? */ + update_rccs (0, RCER_NXM); + break; + } + if (rc_db != dat) { /* miscompare? */ + update_rccs (RCCS_WCHK, 0); + break; + } + } else if (uptr->FUNC == RFNC_WRITE) { /* write */ + t = (da >> 15) & 037; + if (((rc_wlk >> t) & 1) || + (uptr->flags & UNIT_RO)) { /* write locked? */ + update_rccs (RCCS_WLK, 0); + break; + } + /* not locked */ + if (Map_ReadW (ma, 2, &dat)) { /* read mem, nxm? */ + update_rccs (0, RCER_NXM); + break; + } + fbuf[da] = dat; /* write word */ + rc_db = dat; + if (da >= uptr->hwmark) + uptr->hwmark = da + 1; + } else { /* look ahead */ + break; /* no op for now */ + } + rc_wc = (rc_wc + 1) & DMASK; /* incr word count */ + da = (da + 1) & 0777777; /* incr disk addr */ + if ((rc_cs & RCCS_INH) == 0) /* inhibit clear? */ + ma = (ma + 2) & UNIMASK; /* incr mem addr */ + } while (rc_wc != 0); /* brk if wc */ + rc_ca = ma & DMASK; /* split ma */ + rc_cs = (rc_cs & ~RCCS_MEX) | ((ma >> (16 - RCCS_V_MEX)) & RCCS_MEX); + da += 31; + rc_da = (da >> 5) & 017777; + /* CRC of last 32W, if necessary */ + if ((uptr->FUNC == RFNC_READ) || (uptr->FUNC == RFNC_WCHK)) + rc_db = sectorCRC (&fbuf[last_da]); + if (uptr->FUNC != RFNC_LAH) + rc_la = rc_da; + update_rccs (RCCS_DONE, 0); + if (DEBUG_PRS (rc_dev)) + fprintf (sim_deb, ">>RC done: cs = %o, da = %o, ma = %o, wc = %o\n", + rc_cs, rc_da, rc_ca, rc_wc); + return (SCPE_OK); +} + +/* Update CS register */ + +static uint32 update_rccs (uint32 newcs, uint32 newer) +{ + uint32 oldcs = rc_cs; + + rc_er |= newer; /* update RCER */ + rc_cs |= newcs; /* update CS */ + if ((rc_cs & RCCS_ALLERR) || (rc_er != 0)) /* update CS */ + rc_cs |= RCCS_ERR; + else + rc_cs &= ~RCCS_ERR; + if ((rc_cs & RCCS_IE) && /* IE and */ + (rc_cs & RCCS_DONE) && !(oldcs & RCCS_DONE)) /* done 0->1? */ + SET_INT (RC); + return (rc_cs); +} + +/* Reset routine */ + +static t_stat rc_reset (DEVICE *dptr) +{ + rc_cs = RCCS_DONE; + rc_la = rc_da = 0; + rc_er = 0; + rc_wc = 0; + rc_ca = 0; + rc_maint = 0; + rc_db = 0; + CLR_INT (RC); + sim_cancel (&rc_unit); + return (SCPE_OK); +} + +/* Attach routine */ + +static t_stat rc_attach (UNIT *uptr, char *cptr) +{ + uint32 sz, p; + static const uint32 ds_bytes = RC_DKSIZE * sizeof (int16); + + if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize_name (cptr))) { + p = (sz + ds_bytes - 1) / ds_bytes; + if (p >= RC_NUMDK) + p = RC_NUMDK - 1; + uptr->flags = (uptr->flags & ~UNIT_PLAT) | (p << UNIT_V_PLAT); + } + uptr->capac = UNIT_GETP (uptr->flags) * RC_DKSIZE; + return (attach_unit (uptr, cptr)); +} + +/* Change disk size */ + +static t_stat rc_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ + if (val < 0) + return (SCPE_IERR); + if (uptr->flags & UNIT_ATT) + return (SCPE_ALATT); + uptr->capac = UNIT_GETP (val) * RC_DKSIZE; + uptr->flags = uptr->flags & ~UNIT_AUTO; + return (SCPE_OK); +} diff --git a/PDP11/pdp11_rh.c b/PDP11/pdp11_rh.c index 0c365d48..f5413fb6 100644 --- a/PDP11/pdp11_rh.c +++ b/PDP11/pdp11_rh.c @@ -1,6 +1,6 @@ /* pdp11_rh.c: PDP-11 Massbus adapter simulator - Copyright (c) 2005-2007, Robert M Supnik + Copyright (c) 2005-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ rha, rhb RH11/RH70 Massbus adapter + 02-Feb-08 RMS Fixed DMA memory address limit test (found by John Dundas) 17-May-07 RMS Moved CS1 drive enable to devices 21-Nov-05 RMS Added enable/disable routine 07-Jul-05 RMS Removed extraneous externs @@ -160,7 +161,7 @@ MBACTX massbus[MBA_NUM]; extern int32 cpu_opt, cpu_bme; extern uint16 *M; extern int32 int_req[IPL_HLVL]; -extern UNIT cpu_unit; +extern t_addr cpu_memsize; extern FILE *sim_deb; extern FILE *sim_log; extern int32 sim_switches; diff --git a/PDP11/pdp11_stddev.c b/PDP11/pdp11_stddev.c index d80ff6ae..eae91e78 100644 --- a/PDP11/pdp11_stddev.c +++ b/PDP11/pdp11_stddev.c @@ -1,6 +1,6 @@ /* pdp11_stddev.c: PDP-11 standard I/O devices simulator - Copyright (c) 1993-2007, Robert M Supnik + Copyright (c) 1993-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,7 @@ tti,tto DL11 terminal input/output clk KW11L (and other) line frequency clock + 20-May-08 RMS Standardized clock delay at 1mips 18-Jun-07 RMS Added UNIT_IDLE flag to console input, clock 29-Oct-06 RMS Synced keyboard and clock Added clock coscheduling support @@ -66,7 +67,7 @@ #define TTOCSR_RW (CSR_IE) #define CLKCSR_IMP (CSR_DONE + CSR_IE) /* real-time clock */ #define CLKCSR_RW (CSR_IE) -#define CLK_DELAY 8000 +#define CLK_DELAY 16667 extern int32 int_req[IPL_HLVL]; extern uint32 cpu_type; @@ -202,7 +203,7 @@ DIB clk_dib = { 1, IVCL (CLK), VEC_CLK, { &clk_inta } }; -UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE, 0), 8000 }; +UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE, 0), CLK_DELAY }; REG clk_reg[] = { { ORDATA (CSR, clk_csr, 16) }, diff --git a/PDP11/pdp11_sys.c b/PDP11/pdp11_sys.c index 17009d24..c89f36d4 100644 --- a/PDP11/pdp11_sys.c +++ b/PDP11/pdp11_sys.c @@ -1,6 +1,6 @@ /* pdp11_sys.c: PDP-11 simulator interface - Copyright (c) 1993-2006, Robert M Supnik + Copyright (c) 1993-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,11 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 15-May-08 RMS Added KE11-A, DC11 support + Renamed DL11 + 04-Feb-08 RMS Modified to allow -A, -B use with 8b devices + 25-Jan-08 RMS Added RC11, KG11A support from John Dundas + 10-Sep-07 RMS Cleaned up binary loader 20-Dec-06 RMS Added TA11 support 12-Nov-06 RMS Fixed operand order in EIS instructions (found by W.F.J. Mueller) 14-Jul-06 RMS Reordered device list @@ -69,11 +74,14 @@ extern DEVICE lpt_dev; extern DEVICE cr_dev; extern DEVICE clk_dev; extern DEVICE pclk_dev; -extern DEVICE ttix_dev; -extern DEVICE ttox_dev; +extern DEVICE dli_dev; +extern DEVICE dlo_dev; +extern DEVICE dci_dev; +extern DEVICE dco_dev; extern DEVICE dz_dev; extern DEVICE vh_dev; extern DEVICE dt_dev; +extern DEVICE rc_dev; extern DEVICE rf_dev; extern DEVICE rk_dev; extern DEVICE rl_dev; @@ -90,6 +98,8 @@ extern DEVICE tu_dev; extern DEVICE ta_dev; extern DEVICE xq_dev, xqb_dev; extern DEVICE xu_dev, xub_dev; +extern DEVICE ke_dev; +extern DEVICE kg_dev; extern UNIT cpu_unit; extern REG cpu_reg[]; extern uint16 *M; @@ -124,10 +134,13 @@ DEVICE *sim_devices[] = { &tto_dev, &cr_dev, &lpt_dev, - &ttix_dev, - &ttox_dev, + &dli_dev, + &dlo_dev, + &dci_dev, + &dco_dev, &dz_dev, &vh_dev, + &rc_dev, &rf_dev, &rk_dev, &rl_dev, @@ -149,6 +162,8 @@ DEVICE *sim_devices[] = { &xqb_dev, &xu_dev, &xub_dev, + &ke_dev, + &kg_dev, NULL }; @@ -202,66 +217,44 @@ const char *sim_stop_messages[] = { t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) { -int32 csum, count, state, i; -uint32 origin; +int32 c[6], d, i, cnt, csum; +uint32 org; -if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; -state = csum = 0; -while ((i = getc (fileref)) != EOF) { - csum = csum + i; /* add into chksum */ - switch (state) { - - case 0: /* leader */ - if (i == 1) state = 1; - else csum = 0; - break; - - case 1: /* ignore after 001 */ - state = 2; - break; - - case 2: /* low count */ - count = i; - state = 3; - break; - - case 3: /* high count */ - count = (i << 8) | count; - state = 4; - break; - - case 4: /* low origin */ - origin = i; - state = 5; - break; - - case 5: /* high origin */ - origin = (i << 8) | origin; - if (count == 6) { - if (origin != 1) saved_PC = origin & 0177776; - return SCPE_OK; - } - count = count - 6; - state = 6; - break; - - case 6: /* data */ - if (origin >= MEMSIZE) return SCPE_NXM; - M[origin >> 1] = (origin & 1)? - (M[origin >> 1] & 0377) | (i << 8): - (M[origin >> 1] & 0177400) | i; - origin = origin + 1; - count = count - 1; - state = state + (count == 0); - break; - - case 7: /* checksum */ - if (csum & 0377) return SCPE_CSUM; - csum = state = 0; - break; - } /* end switch */ - } /* end while */ -return SCPE_FMT; /* unexpected eof */ +if ((*cptr != 0) || (flag != 0)) + return SCPE_ARG; +do { /* block loop */ + csum = 0; /* init checksum */ + for (i = 0; i < 6; ) { /* 6 char header */ + if ((c[i] = getc (fileref)) == EOF) + return SCPE_FMT; + if ((i != 0) || (c[i] == 1)) /* 1st must be 1 */ + csum = csum + c[i++]; /* add into csum */ + } + cnt = (c[3] << 8) | c[2]; /* count */ + org = (c[5] << 8) | c[4]; /* origin */ + if (cnt < 6) /* invalid? */ + return SCPE_FMT; + if (cnt == 6) { /* end block? */ + if (org != 1) /* set PC? */ + saved_PC = org & 0177776; + return SCPE_OK; + } + for (i = 6; i < cnt; i++) { /* exclude hdr */ + if ((d = getc (fileref)) == EOF) /* data char */ + return SCPE_FMT; + csum = csum + d; /* add into csum */ + if (org >= MEMSIZE) /* invalid addr? */ + return SCPE_NXM; + M[org >> 1] = (org & 1)? /* store data */ + (M[org >> 1] & 0377) | (d << 8): + (M[org >> 1] & 0177400) | d; + org = (org + 1) & 0177777; /* inc origin */ + } + if ((d = getc (fileref)) == EOF) /* get csum */ + return SCPE_FMT; + csum = csum + d; /* add in */ + } while ((csum & 0377) == 0); /* result mbz */ +return SCPE_CSUM; } /* Factory bad block table creation routine @@ -288,20 +281,27 @@ t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds) int32 i, da; uint16 *buf; -if ((sec < 2) || (wds < 16)) return SCPE_ARG; -if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; -if (uptr->flags & UNIT_RO) return SCPE_RO; -if (!get_yn ("Create bad block table on last track? [N]", FALSE)) return SCPE_OK; -da = (uptr->capac - (sec * wds)) * sizeof (int16); -if (fseek (uptr->fileref, da, SEEK_SET)) return SCPE_IOERR; -if ((buf = (uint16 *) malloc (wds * sizeof (uint16))) == NULL) return SCPE_MEM; +if ((sec < 2) || (wds < 16)) + return SCPE_ARG; +if ((uptr->flags & UNIT_ATT) == 0) + return SCPE_UNATT; +if (uptr->flags & UNIT_RO) + return SCPE_RO; +if (!get_yn ("Create bad block table on last track? [N]", FALSE)) + return SCPE_OK; +da = (uptr->capac - (sec * wds)) * sizeof (uint16); +if (fseek (uptr->fileref, da, SEEK_SET)) + return SCPE_IOERR; +if ((buf = (uint16 *) malloc (wds * sizeof (uint16))) == NULL) + return SCPE_MEM; buf[0] = buf[1] = 012345u; buf[2] = buf[3] = 0; for (i = 4; i < wds; i++) buf[i] = 0177777u; for (i = 0; (i < sec) && (i < 10); i++) fxwrite (buf, sizeof (uint16), wds, uptr->fileref); free (buf); -if (ferror (uptr->fileref)) return SCPE_IOERR; +if (ferror (uptr->fileref)) + return SCPE_IOERR; return SCPE_OK; } @@ -532,7 +532,8 @@ mode = ((spec >> 3) & 07); switch (mode) { case 0: - if (iflag) fprintf (of, "%s", rname[reg]); + if (iflag) + fprintf (of, "%s", rname[reg]); else fprintf (of, "%s", fname[reg]); break; @@ -541,12 +542,14 @@ switch (mode) { break; case 2: - if (reg != 7) fprintf (of, "(%s)+", rname[reg]); + if (reg != 7) + fprintf (of, "(%s)+", rname[reg]); else fprintf (of, "#%-o", nval); break; case 3: - if (reg != 7) fprintf (of, "@(%s)+", rname[reg]); + if (reg != 7) + fprintf (of, "@(%s)+", rname[reg]); else fprintf (of, "@#%-o", nval); break; @@ -559,12 +562,14 @@ switch (mode) { break; case 6: - if ((reg != 7) || !flag) fprintf (of, "%-o(%s)", nval, rname[reg]); + if ((reg != 7) || !flag) + fprintf (of, "%-o(%s)", nval, rname[reg]); else fprintf (of, "%-o", (nval + addr + 4) & 0177777); break; case 7: - if ((reg != 7) || !flag) fprintf (of, "@%-o(%s)", nval, rname[reg]); + if ((reg != 7) || !flag) + fprintf (of, "@%-o(%s)", nval, rname[reg]); else fprintf (of, "@%-o", (nval + addr + 4) & 0177777); break; } /* end case */ @@ -589,20 +594,35 @@ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) { int32 cflag, i, j, c1, c2, c3, inst, fac, srcm, srcr, dstm, dstr; -int32 l8b, brdisp, wd1, wd2; +int32 bflag, l8b, brdisp, wd1, wd2; extern int32 FPS; -cflag = (uptr == NULL) || (uptr == &cpu_unit); +bflag = 0; /* assume 16b */ +cflag = (uptr == NULL) || (uptr == &cpu_unit); /* cpu? */ +if (!cflag) { /* not cpu? */ + DEVICE *dptr = find_dev_from_unit (uptr); + if (dptr == NULL) + return SCPE_IERR; + if (dptr->dwidth < 16) + bflag = 1; + } + if (sw & SWMASK ('A')) { /* ASCII? */ - c1 = (val[0] >> ((addr & 1)? 8: 0)) & 0177; + if (bflag) + c1 = val[0] & 0177; + else c1 = (val[0] >> ((addr & 1)? 8: 0)) & 0177; fprintf (of, (c1 < 040)? "<%03o>": "%c", c1); return 0; } if (sw & SWMASK ('B')) { /* byte? */ - c1 = (val[0] >> ((addr & 1)? 8: 0)) & 0377; + if (bflag) + c1 = val[0] & 0177; + else c1 = (val[0] >> ((addr & 1)? 8: 0)) & 0377; fprintf (of, "%o", c1); return 0; } +if (bflag) return SCPE_ARG; /* 16b only */ + if (sw & SWMASK ('C')) { /* character? */ c1 = val[0] & 0177; c2 = (val[0] >> 8) & 0177; @@ -669,8 +689,10 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ case I_V_BR: /* cond branch */ fprintf (of, "%s ", opcode[i]); brdisp = (l8b + l8b + ((l8b & 0200)? 0177002: 2)) & 0177777; - if (cflag) fprintf (of, "%-o", (addr + brdisp) & 0177777); - else if (brdisp < 01000) fprintf (of, ".+%-o", brdisp); + if (cflag) + fprintf (of, "%-o", (addr + brdisp) & 0177777); + else if (brdisp < 01000) + fprintf (of, ".+%-o", brdisp); else fprintf (of, ".-%-o", 0200000 - brdisp); break; @@ -681,8 +703,10 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ case I_V_SOB: /* sob */ fprintf (of, "%s %s,", opcode[i], rname[srcr]); brdisp = (dstm * 2) - 2; - if (cflag) fprintf (of, "%-o", (addr - brdisp) & 0177777); - else if (brdisp <= 0) fprintf (of, ".+%-o", -brdisp); + if (cflag) + fprintf (of, "%-o", (addr - brdisp) & 0177777); + else if (brdisp <= 0) + fprintf (of, ".+%-o", -brdisp); else fprintf (of, ".-%-o", brdisp); break; @@ -741,7 +765,8 @@ int32 i; if (*(cptr + 2) != mchar) return -1; for (i = 0; i < 8; i++) { - if (strncmp (cptr, strings[i], 2) == 0) return i; + if (strncmp (cptr, strings[i], 2) == 0) + return i; } return -1; } @@ -782,11 +807,13 @@ if (*cptr == '-') { /* -? */ errno = 0; val = strtoul (cptr, &tptr, 8); if (cptr == tptr) { /* no number? */ - if (*pflag == (A_REL + A_NUM)) return NULL; /* .+, .-? */ + if (*pflag == (A_REL + A_NUM)) /* .+, .-? */ + return NULL; *dptr = 0; return cptr; } -if (errno || (*pflag == A_REL)) return NULL; /* .n? */ +if (errno || (*pflag == A_REL)) /* .n? */ + return NULL; *dptr = (minus? -val: val) & 0177777; *pflag = *pflag | A_NUM; return tptr; @@ -832,7 +859,8 @@ if (strncmp (cptr, "-(", 2) == 0) { /* autodecrement? */ else if ((cptr = get_addr (cptr, &disp, &pflag)) == NULL) return 1; if (*cptr == '(') { /* register index? */ pflag = pflag | A_PAR; - if ((reg = get_reg (cptr + 1, rname, ')')) < 0) return 1; + if ((reg = get_reg (cptr + 1, rname, ')')) < 0) + return 1; cptr = cptr + 4; if (*cptr == '+') { /* autoincrement? */ pflag = pflag | A_PLS; @@ -843,7 +871,8 @@ else if ((reg = get_reg (cptr, iflag? rname: fname, 0)) >= 0) { pflag = pflag | A_REG; cptr = cptr + 2; } -if (*cptr != 0) return 1; /* all done? */ +if (*cptr != 0) /* all done? */ + return 1; switch (pflag) { /* case on syntax */ case A_REG: /* Rn, @Rn */ @@ -873,7 +902,8 @@ switch (pflag) { /* case on syntax */ return -1; case A_PND+A_REL: case A_PND+A_REL+A_NUM: /* #.+n, @#.+n */ - if (!cflag) return 1; + if (!cflag) + return 1; disp = (disp + addr) & 0177777; /* fall through */ case A_PND+A_NUM: /* #n, @#n */ *sptr = 027 + indir; @@ -917,37 +947,59 @@ switch (pflag) { /* case on syntax */ t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) { -int32 cflag, d, i, j, reg, spec, n1, n2, disp, pflag; +int32 bflag, cflag, d, i, j, reg, spec, n1, n2, disp, pflag; t_value by; t_stat r; char *tptr, gbuf[CBUFSIZE]; -cflag = (uptr == NULL) || (uptr == &cpu_unit); +bflag = 0; /* assume 16b */ +cflag = (uptr == NULL) || (uptr == &cpu_unit); /* cpu? */ +if (!cflag) { /* not cpu? */ + DEVICE *dptr = find_dev_from_unit (uptr); + if (dptr == NULL) + return SCPE_IERR; + if (dptr->dwidth < 16) + bflag = 1; + } + while (isspace (*cptr)) cptr++; /* absorb spaces */ if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ - if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ - if (addr & 1) val[0] = (val[0] & 0377) | (((t_value) cptr[0]) << 8); - else val[0] = (val[0] & ~0377) | ((t_value) cptr[0]); + if (cptr[0] == 0) /* must have 1 char */ + return SCPE_ARG; + if (bflag) + val[0] = (t_value) cptr[0]; + else val[0] = (addr & 1)? + (val[0] & 0377) | (((t_value) cptr[0]) << 8): + (val[0] & ~0377) | ((t_value) cptr[0]); return 0; } if (sw & SWMASK ('B')) { /* byte? */ by = get_uint (cptr, 8, 0377, &r); /* get byte */ - if (r != SCPE_OK) return SCPE_ARG; - if (addr & 1) val[0] = (val[0] & 0377) | (by << 8); - else val[0] = (val[0] & ~0377) | by; + if (r != SCPE_OK) + return SCPE_ARG; + if (bflag) + val[0] = by; + else val[0] = (addr & 1)? + (val[0] & 0377) | (by << 8): + (val[0] & ~0377) | by; return 0; } +if (bflag) return SCPE_ARG; + if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */ - if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ + if (cptr[0] == 0) /* must have 1 char */ + return SCPE_ARG; val[0] = ((t_value) cptr[1] << 8) | (t_value) cptr[0]; return -1; } -if (sw & SWMASK ('R')) return SCPE_ARG; /* radix 50 */ +if (sw & SWMASK ('R')) /* radix 50 */ + return SCPE_ARG; cptr = get_glyph (cptr, gbuf, 0); /* get opcode */ n1 = n2 = pflag = 0; for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ; -if (opcode[i] == NULL) return SCPE_ARG; +if (opcode[i] == NULL) + return SCPE_ARG; val[0] = opc_val[i] & 0177777; /* get value */ j = (opc_val[i] >> I_V_CL) & I_M_CL; /* get class */ @@ -958,26 +1010,30 @@ switch (j) { /* case on class */ case I_V_REG: /* register */ cptr = get_glyph (cptr, gbuf, 0); /* get glyph */ - if ((reg = get_reg (gbuf, rname, 0)) < 0) return SCPE_ARG; + if ((reg = get_reg (gbuf, rname, 0)) < 0) + return SCPE_ARG; val[0] = val[0] | reg; break; case I_V_3B: case I_V_6B: case I_V_8B: /* xb literal */ cptr = get_glyph (cptr, gbuf, 0); /* get literal */ d = get_uint (gbuf, 8, (1 << j) - 1, &r); - if (r != SCPE_OK) return SCPE_ARG; + if (r != SCPE_OK) + return SCPE_ARG; val[0] = val[0] | d; /* put in place */ break; case I_V_BR: /* cond br */ cptr = get_glyph (cptr, gbuf, 0); /* get address */ tptr = get_addr (gbuf, &disp, &pflag); /* parse */ - if ((tptr == NULL) || (*tptr != 0)) return SCPE_ARG; + if ((tptr == NULL) || (*tptr != 0)) + return SCPE_ARG; if ((pflag & A_REL) == 0) { if (cflag) disp = (disp - addr) & 0177777; else return SCPE_ARG; } - if ((disp & 1) || (disp > 0400) && (disp < 0177402)) return SCPE_ARG; + if ((disp & 1) || (disp > 0400) && (disp < 0177402)) + return SCPE_ARG; val[0] = val[0] | (((disp - 2) >> 1) & 0377); break; @@ -987,18 +1043,21 @@ switch (j) { /* case on class */ val[0] = val[0] | (reg << 6); cptr = get_glyph (cptr, gbuf, 0); /* get address */ tptr = get_addr (gbuf, &disp, &pflag); /* parse */ - if ((tptr == NULL) || (*tptr != 0)) return SCPE_ARG; + if ((tptr == NULL) || (*tptr != 0)) + return SCPE_ARG; if ((pflag & A_REL) == 0) { if (cflag) disp = (disp - addr) & 0177777; else return SCPE_ARG; } - if ((disp & 1) || ((disp > 2) && (disp < 0177604))) return SCPE_ARG; + if ((disp & 1) || ((disp > 2) && (disp < 0177604))) + return SCPE_ARG; val[0] = val[0] | (((2 - disp) >> 1) & 077); break; case I_V_RSOP: /* reg, sop */ cptr = get_glyph (cptr, gbuf, ','); /* get glyph */ - if ((reg = get_reg (gbuf, rname, 0)) < 0) return SCPE_ARG; + if ((reg = get_reg (gbuf, rname, 0)) < 0) + return SCPE_ARG; val[0] = val[0] | (reg << 6); /* fall through */ case I_V_SOP: /* sop */ cptr = get_glyph (cptr, gbuf, 0); /* get glyph */ @@ -1013,19 +1072,23 @@ switch (j) { /* case on class */ return SCPE_ARG; val[0] = val[0] | spec; cptr = get_glyph (cptr, gbuf, 0); /* get glyph */ - if ((reg = get_reg (gbuf, rname, 0)) < 0) return SCPE_ARG; + if ((reg = get_reg (gbuf, rname, 0)) < 0) + return SCPE_ARG; val[0] = val[0] | (reg << 6); break; case I_V_AFOP: case I_V_ASOP: case I_V_ASMD: /* fac, (s)fop */ cptr = get_glyph (cptr, gbuf, ','); /* get glyph */ - if ((reg = get_reg (gbuf, fname, 0)) < 0) return SCPE_ARG; - if (reg > 3) return SCPE_ARG; + if ((reg = get_reg (gbuf, fname, 0)) < 0) + return SCPE_ARG; + if (reg > 3) + return SCPE_ARG; val[0] = val[0] | (reg << 6); /* fall through */ case I_V_FOP: /* fop */ cptr = get_glyph (cptr, gbuf, 0); /* get glyph */ if ((n1 = get_spec (gbuf, addr, 0, &spec, &val[1], cflag, - (j == I_V_ASOP) || (j == I_V_ASMD))) > 0) return SCPE_ARG; + (j == I_V_ASOP) || (j == I_V_ASMD))) > 0) + return SCPE_ARG; val[0] = val[0] | spec; break; @@ -1036,7 +1099,8 @@ switch (j) { /* case on class */ val[0] = val[0] | (spec << 6); cptr = get_glyph (cptr, gbuf, 0); /* get glyph */ if ((n2 = get_spec (gbuf, addr, n1, &spec, &val[1 - n1], - cflag, TRUE)) > 0) return SCPE_ARG; + cflag, TRUE)) > 0) + return SCPE_ARG; val[0] = val[0] | spec; break; @@ -1046,7 +1110,8 @@ switch (j) { /* case on class */ for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ; if ((((opc_val[i] >> I_V_CL) & I_M_CL) != j) || - (opcode[i] == NULL)) return SCPE_ARG; + (opcode[i] == NULL)) + return SCPE_ARG; val[0] = val[0] | (opc_val[i] & 0177777); } break; @@ -1055,6 +1120,7 @@ switch (j) { /* case on class */ return SCPE_ARG; } -if (*cptr != 0) return SCPE_ARG; /* junk at end? */ +if (*cptr != 0) /* junk at end? */ + return SCPE_ARG; return ((n1 + n2) * 2) - 1; } diff --git a/PDP8/pdp8_fpp.c b/PDP8/pdp8_fpp.c new file mode 100644 index 00000000..fb2e5865 --- /dev/null +++ b/PDP8/pdp8_fpp.c @@ -0,0 +1,1387 @@ +/* pdp8_fpp.c: PDP-8 floating point processor (FPP8A) + + Copyright (c) 2007, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + fpp FPP8A floating point processor + + Floating point formats: + + 00 01 02 03 04 05 06 07 08 09 10 11 + +--+--+--+--+--+--+--+--+--+--+--+--+ + | S| hi integer | : double precision + +--+--+--+--+--+--+--+--+--+--+--+--+ + | lo integer | + +--+--+--+--+--+--+--+--+--+--+--+--+ + + 00 01 02 03 04 05 06 07 08 09 10 11 + +--+--+--+--+--+--+--+--+--+--+--+--+ + | S| exponent | : floating point + +--+--+--+--+--+--+--+--+--+--+--+--+ + | S| hi fraction | + +--+--+--+--+--+--+--+--+--+--+--+--+ + | lo fraction | + +--+--+--+--+--+--+--+--+--+--+--+--+ + + + 00 01 02 03 04 05 06 07 08 09 10 11 + +--+--+--+--+--+--+--+--+--+--+--+--+ + | S| exponent | : extended precision + +--+--+--+--+--+--+--+--+--+--+--+--+ + | S| hi fraction | + +--+--+--+--+--+--+--+--+--+--+--+--+ + | next fraction | + +--+--+--+--+--+--+--+--+--+--+--+--+ + | next fraction | + +--+--+--+--+--+--+--+--+--+--+--+--+ + | next fraction | + +--+--+--+--+--+--+--+--+--+--+--+--+ + | lo fraction | + +--+--+--+--+--+--+--+--+--+--+--+--+ + + Exponents are 2's complement, as are fractions. Normalized numbers have + the form: + + 0.0...0 + 0. + 1. + 1.1...0 + + Note that 1.0...0 is normalized but considered illegal, since it cannot + be represented as a positive number. When a result is normalized, 1.0...0 + is converted to 1.1...0 with exp+1. +*/ + +#include "pdp8_defs.h" + +extern int32 int_req; +extern int32 sim_switches; +extern int32 sim_interval; +extern uint16 M[]; +extern int32 stop_inst; +extern UNIT cpu_unit; + +#define SEXT12(x) (((x) & 04000)? (x) | ~07777: (x) & 03777) + +/* Index registers are in memory */ + +#define fpp_read_xr(xr) fpp_read (fpp_xra + xr) +#define fpp_write_xr(xr,d) fpp_write (fpp_xra +xr, d) + +/* Command register */ + +#define FPC_DP 04000 /* integer double */ +#define FPC_UNFX 02000 /* exit on fl undf */ +#define FPC_FIXF 01000 /* lock mem field */ +#define FPC_IE 00400 /* int enable */ +#define FPC_V_FAST 4 /* startup bits */ +#define FPC_M_FAST 017 +#define FPC_LOCK 00010 /* lockout */ +#define FPC_V_APTF 0 +#define FPC_M_APTF 07 /* apta field */ +#define FPC_STA (FPC_DP|FPC_LOCK) +#define FPC_GETFAST(x) (((x) >> FPC_V_FAST) & FPC_M_FAST) +#define FPC_GETAPTF(x) (((x) >> FPC_V_APTF) & FPC_M_APTF) + +/* Status register */ + +#define FPS_DP (FPC_DP) /* integer double */ +#define FPS_TRPX 02000 /* trap exit */ +#define FPS_HLTX 01000 /* halt exit */ +#define FPS_DVZX 00400 /* div zero exit */ +#define FPS_IOVX 00200 /* int ovf exit */ +#define FPS_FOVX 00100 /* flt ovf exit */ +#define FPS_UNF 00040 /* underflow */ +#define FPS_UNFX 00020 /* undf exit */ +#define FPS_XXXM 00010 /* FADDM/FMULM */ +#define FPS_LOCK (FPC_LOCK) /* lockout */ +#define FPS_EP 00004 /* ext prec */ +#define FPS_PAUSE 00002 /* paused */ +#define FPS_RUN 00001 /* running */ + +/* Floating point number: 3-6 words */ + +#define FPN_FRSIGN 04000 +#define FPN_NFR_FP 2 /* std precision */ +#define FPN_NFR_EP 5 /* ext precision */ +#define EXACT (uint32)((fpp_sta & FPS_EP)? FPN_NFR_EP: FPN_NFR_FP) +#define EXTEND ((uint32) FPN_NFR_EP) + +typedef struct { + int32 exp; + uint32 fr[FPN_NFR_EP]; + } FPN; + +uint32 fpp_apta; /* APT pointer */ +uint32 fpp_aptsvf; /* APT saved field */ +uint32 fpp_opa; /* operand pointer */ +uint32 fpp_fpc; /* FP PC */ +uint32 fpp_bra; /* base reg pointer */ +uint32 fpp_xra; /* indx reg pointer */ +uint32 fpp_cmd; /* command */ +uint32 fpp_sta; /* status */ +uint32 fpp_flag; /* flag */ +FPN fpp_ac; /* FAC */ +static FPN fpp_zero = { 0, { 0, 0, 0, 0, 0 } }; +static FPN fpp_one = { 1, { 02000, 0, 0, 0, 0 } }; + +DEVICE fpp_dev; +int32 fpp55 (int32 IR, int32 AC); +int32 fpp56 (int32 IR, int32 AC); +void fpp_load_apt (uint32 apta); +void fpp_dump_apt (uint32 apta, uint32 sta); +uint32 fpp_1wd_dir (uint32 ir); +uint32 fpp_2wd_dir (uint32 ir); +uint32 fpp_indir (uint32 ir); +uint32 fpp_ad15 (uint32 hi); +uint32 fpp_adxr (uint32 ir, uint32 base_ad); +t_bool fpp_add (FPN *a, FPN *b, uint32 sub); +t_bool fpp_mul (FPN *a, FPN *b); +t_bool fpp_div (FPN *a, FPN *b); +t_bool fpp_imul (FPN *a, FPN *b); +uint32 fpp_fr_add (uint32 *c, uint32 *a, uint32 *b); +void fpp_fr_sub (uint32 *c, uint32 *a, uint32 *b); +void fpp_fr_mul (uint32 *c, uint32 *a, uint32 *b); +t_bool fpp_fr_div (uint32 *c, uint32 *a, uint32 *b); +uint32 fpp_fr_neg (uint32 *a, uint32 cnt); +int32 fpp_fr_cmp (uint32 *a, uint32 *b, uint32 cnt); +int32 fpp_fr_test (uint32 *a, uint32 v0, uint32 cnt); +uint32 fpp_fr_abs (uint32 *a, uint32 *b, uint32 cnt); +void fpp_fr_fill (uint32 *a, uint32 v, uint32 cnt); +void fpp_fr_lshn (uint32 *a, uint32 sc, uint32 cnt); +void fpp_fr_lsh12 (uint32 *a, uint32 cnt); +void fpp_fr_lsh1 (uint32 *a, uint32 cnt); +void fpp_fr_rsh1 (uint32 *a, uint32 sign, uint32 cnt); +void fpp_fr_algn (uint32 *a, uint32 sc, uint32 cnt); +t_bool fpp_cond_met (uint32 cond); +t_bool fpp_norm (FPN *a, uint32 cnt); +uint32 fpp_round (FPN *a); +t_bool fpp_test_xp (FPN *a); +void fpp_copy (FPN *a, FPN *b); +void fpp_zcopy (FPN *a, FPN *b); +void fpp_read_op (uint32 ea, FPN *a); +void fpp_write_op (uint32 ea, FPN *a); +uint32 fpp_read (uint32 ea); +void fpp_write (uint32 ea, uint32 val); +uint32 apt_read (uint32 ea); +void apt_write (uint32 ea, uint32 val); +t_stat fpp_svc (UNIT *uptr); +t_stat fpp_reset (DEVICE *dptr); + +/* FPP data structures + + fpp_dev FPP device descriptor + fpp_unit FPP unit descriptor + fpp_reg FPP register list +*/ + +DIB fpp_dib = { DEV_FPP, 2, { &fpp55, &fpp56 } }; + +UNIT fpp_unit = { UDATA (&fpp_svc, 0, 0) }; + +REG fpp_reg[] = { + { ORDATA (FPACE, fpp_ac.exp, 12) }, + { ORDATA (FPAC0, fpp_ac.fr[0], 12) }, + { ORDATA (FPAC1, fpp_ac.fr[1], 12) }, + { ORDATA (FPAC2, fpp_ac.fr[2], 12) }, + { ORDATA (FPAC3, fpp_ac.fr[3], 12) }, + { ORDATA (FPAC4, fpp_ac.fr[4], 12) }, + { ORDATA (CMD, fpp_cmd, 12) }, + { ORDATA (STA, fpp_sta, 12) }, + { ORDATA (APTA, fpp_apta, 15) }, + { GRDATA (APTSVF, fpp_aptsvf, 8, 3, 12) }, + { ORDATA (FPC, fpp_fpc, 15) }, + { ORDATA (BRA, fpp_bra, 15) }, + { ORDATA (XRA, fpp_xra, 15) }, + { ORDATA (OPA, fpp_opa, 15) }, + { FLDATA (FLAG, fpp_flag, 0) }, + { NULL } + }; + +DEVICE fpp_dev = { + "FPP", &fpp_unit, fpp_reg, NULL, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &fpp_reset, + NULL, NULL, NULL, + &fpp_dib, DEV_DISABLE | DEV_DIS + }; + +/* IOT routines */ + +int32 fpp55 (int32 IR, int32 AC) +{ +switch (IR & 07) { /* decode IR<9:11> */ + + case 1: /* FPINT */ + return (fpp_flag? IOT_SKP | AC: AC); /* skip on flag */ + + case 2: /* FPICL */ + fpp_reset (&fpp_dev); /* reset device */ + break; + + case 3: /* FPCOM */ + if (!fpp_flag && !(fpp_sta & FPS_RUN)) { /* flag clr, !run? */ + fpp_cmd = AC; /* load cmd */ + fpp_sta = (fpp_sta & ~FPC_STA) | /* copy flags */ + (fpp_cmd & FPC_STA); /* to status */ + } + break; + + case 4: /* FPHLT */ + if (fpp_sta & FPS_RUN) { /* running? */ + if (fpp_sta & FPS_PAUSE) /* paused? */ + fpp_fpc = (fpp_fpc - 1) & ADDRMASK; /* decr FPC */ + sim_cancel (&fpp_unit); /* stop execution */ + fpp_dump_apt (fpp_apta, FPS_HLTX); /* dump APT */ + } + else sim_activate (&fpp_unit, 0); /* single step */ + break; + + case 5: /* FPST */ + if (!fpp_flag && !(fpp_sta & FPS_RUN)) { /* flag clr, !run? */ + fpp_apta = (FPC_GETAPTF (fpp_cmd) << 12) | AC; + fpp_load_apt (fpp_apta); /* load APT */ + sim_activate (&fpp_unit, 0); /* start unit */ + return IOT_SKP | AC; + } + if ((fpp_sta & (FPS_RUN|FPS_PAUSE)) == (FPS_RUN|FPS_PAUSE)) { + fpp_sta &= ~FPS_PAUSE; /* continue */ + sim_activate (&fpp_unit, 0); /* start unit */ + return (IOT_SKP | AC); + } + break; + + case 6: /* FPRST */ + return fpp_sta; + + case 7: /* FPIST */ + if (fpp_flag) { /* if flag set */ + uint32 old_sta = fpp_sta; + fpp_flag = 0; /* clr flag, status */ + fpp_sta = 0; + int_req &= ~INT_FPP; /* clr int req */ + return IOT_SKP | old_sta; /* ret old status */ + } + break; + + default: + return (stop_inst << IOT_V_REASON) | AC; + } /* end switch */ + +return AC; +} + +int32 fpp56 (int32 IR, int32 AC) +{ +switch (IR & 07) { /* decode IR<9:11> */ + + case 7: /* FPEP */ + if ((AC & 04000) && !(fpp_sta & FPS_RUN)) /* if AC0, not run, */ + fpp_sta = (fpp_sta | FPS_EP) & ~FPS_DP; /* set ep */ + break; + + default: + return (stop_inst << IOT_V_REASON) | AC; + } /* end switch */ + +return AC; +} + +/* Service routine */ + +t_stat fpp_svc (UNIT *uptr) +{ +FPN x; +uint32 ir, op, op2, op3, ad, ea, wd; +uint32 i; + +fpp_ac.exp = SEXT12 (fpp_ac.exp); /* sext AC exp */ +do { /* repeat */ + ir = fpp_read (fpp_fpc); /* get instr */ + fpp_fpc = (fpp_fpc + 1) & ADDRMASK; /* incr FP PC */ + op = (ir >> 7) & 037; /* get op+mode */ + op2 = (ir >> 3) & 017; /* get subop */ + op3 = ir & 07; /* get field/xr */ + fpp_sta &= ~FPS_XXXM; /* not mem op */ + + switch (op) { /* case on op+mode */ + case 000: /* operates */ + + switch (op2) { /* case on subop */ + case 000: /* no-operands */ + switch (op3) { /* case on subsubop */ + + case 0: /* FEXIT */ + fpp_dump_apt (fpp_apta, 0); + break; + + case 1: /* FPAUSE */ + fpp_sta |= FPS_PAUSE; + break; + + case 2: /* FCLA */ + fpp_copy (&fpp_ac, &fpp_zero); /* clear FAC */ + break; + + case 3: /* FNEG */ + fpp_fr_neg (fpp_ac.fr, EXACT); /* do exact length */ + break; + + case 4: /* FNORM */ + if (!(fpp_sta & FPS_DP)) { /* fp or ep only */ + fpp_copy (&x, &fpp_ac); /* copy AC */ + fpp_norm (&x, EXACT); /* do exact length */ + if (!fpp_test_xp (&x)) /* no trap? */ + fpp_copy (&fpp_ac, &x); /* copy back */ + } + break; + + case 5: /* STARTF */ + if (fpp_sta & FPS_EP) { /* if ep, */ + fpp_copy (&x, &fpp_ac); /* copy AC */ + fpp_round (&x); /* round */ + if (!fpp_test_xp (&x)) /* no trap? */ + fpp_copy (&fpp_ac, &x); /* copy back */ + } + fpp_sta &= ~(FPS_DP|FPS_EP); + break; + + case 6: /* STARTD */ + fpp_sta = (fpp_sta | FPS_DP) & ~FPS_EP; + break; + + case 7: /* JAC */ + fpp_fpc = ((fpp_ac.fr[0] & 07) << 12) | fpp_ac.fr[1]; + break; + } + break; + + case 001: /* ALN */ + if (op3 != 0) /* if xr, */ + wd = fpp_read_xr (op3); /* use val */ + else wd = 027; /* else 23 */ + if (!(fpp_sta & FPS_DP)) { /* fp or ep? */ + int32 t = wd - fpp_ac.exp; /* alignment */ + fpp_ac.exp = SEXT12 (wd); /* new exp */ + wd = t & 07777; + } + if (wd & 04000) /* left? */ + fpp_fr_lshn (fpp_ac.fr, 04000 - wd, EXACT); + else fpp_fr_algn (fpp_ac.fr, wd, EXACT); + break; + + case 002: /* ATX */ + if (fpp_sta & FPS_DP) /* dp? */ + fpp_write_xr (op3, fpp_ac.fr[1]); /* xr<-FAC<12:23> */ + else { + fpp_copy (&x, &fpp_ac); /* copy AC */ + wd = (fpp_ac.exp - 027) & 07777; /* shift amt */ + if (wd & 04000) /* left? */ + fpp_fr_lshn (x.fr, 04000 - wd, EXACT); + else fpp_fr_algn (x.fr, wd, EXACT); + fpp_write_xr (op3, x.fr[1]); /* xr<-val<12:23> */ + } + break; + + case 003: /* XTA */ + for (i = FPN_NFR_FP; i < FPN_NFR_EP; i++) + x.fr[i] = 0; /* clear FOP2-4 */ + x.fr[1] = fpp_read_xr (op3); /* get XR value */ + x.fr[0] = (x.fr[1] & 04000)? 07777: 0; + x.exp = 027; /* standard exp */ + if (!(fpp_sta & FPS_DP)) { /* fp or ep? */ + fpp_norm (&x, EXACT); /* normalize */ + if (fpp_test_xp (&x)) /* exception? */ + break; + } + fpp_copy (&fpp_ac, &x); /* result to AC */ + break; + + case 004: /* NOP */ + break; + + case 005: /* STARTE */ + if (!(fpp_sta & FPS_EP)) { + fpp_sta = (fpp_sta | FPS_EP) & ~FPS_DP; + for (i = FPN_NFR_FP; i < FPN_NFR_EP; i++) + fpp_ac.fr[i] = 0; /* clear FAC2-4 */ + } + break; + + case 010: /* LDX */ + wd = fpp_ad15 (0); /* load XR immed */ + fpp_write_xr (op3, wd); + break; + + case 011: /* ADDX */ + wd = fpp_ad15 (0); + wd = wd + fpp_read_xr (op3); /* add to XR immed */ + fpp_write_xr (op3, wd); /* trims to 12b */ + break; + + default: + return stop_inst; + } /* end case subop */ + break; + + case 001: /* FLDA */ + ea = fpp_1wd_dir (ir); + fpp_read_op (ea, &fpp_ac); + break; + + case 002: + ea = fpp_2wd_dir (ir); + fpp_read_op (ea, &fpp_ac); + break; + + case 003: + ea = fpp_indir (ir); + fpp_read_op (ea, &fpp_ac); + break; + + case 004: /* jumps and sets */ + ad = fpp_ad15 (op3); /* get 15b address */ + switch (op2) { /* case on subop */ + + case 000: case 001: case 002: case 003: /* cond jump */ + case 004: case 005: case 006: case 007: + if (fpp_cond_met (op2)) /* br if cond */ + fpp_fpc = ad; + break; + + case 010: /* SETX */ + fpp_xra = ad; + break; + + case 011: /* SETB */ + fpp_bra = ad; + break; + + case 012: /* JSA */ + fpp_write (ad, 01030 + (fpp_fpc >> 12)); /* save return */ + fpp_write (ad + 1, fpp_fpc); /* trims to 12b */ + fpp_fpc = (ad + 2) & ADDRMASK; + break; + + case 013: /* JSR */ + fpp_write (fpp_bra + 1, 01030 + (fpp_fpc >> 12)); + fpp_write (fpp_bra + 2, fpp_fpc); /* trims to 12b */ + fpp_fpc = ad; + break; + + default: + return stop_inst; + } /* end case subop */ + break; + + case 005: /* FADD */ + ea = fpp_1wd_dir (ir); + fpp_read_op (ea, &x); + fpp_add (&fpp_ac, &x, 0); + break; + + case 006: + ea = fpp_2wd_dir (ir); + fpp_read_op (ea, &x); + fpp_add (&fpp_ac, &x, 0); + break; + + case 007: + ea = fpp_indir (ir); + fpp_read_op (ea, &x); + fpp_add (&fpp_ac, &x, 0); + break; + + case 010: /* JNX */ + ad = fpp_ad15 (op3); /* get 15b addr */ + wd = fpp_read_xr (op2 & 07); /* read xr */ + if (ir & 00100) { /* inc? */ + wd = (wd + 1) & 07777; + fpp_write_xr (op2 & 07, wd); /* ++xr */ + } + if (wd != 0) /* xr != 0? */ + fpp_fpc = ad; /* jump */ + break; + + case 011: /* FSUB */ + ea = fpp_1wd_dir (ir); + fpp_read_op (ea, &x); + fpp_add (&fpp_ac, &x, 1); + break; + + case 012: + ea = fpp_2wd_dir (ir); + fpp_read_op (ea, &x); + fpp_add (&fpp_ac, &x, 1); + break; + + case 013: + ea = fpp_indir (ir); + fpp_read_op (ea, &x); + fpp_add (&fpp_ac, &x, 1); + break; + + case 014: /* TRAP3 */ + case 020: /* TRAP4 */ + fpp_opa = fpp_ad15 (op3); + fpp_dump_apt (fpp_apta, FPS_TRPX); + break; + + case 015: /* FDIV */ + ea = fpp_1wd_dir (ir); + fpp_read_op (ea, &x); + fpp_div (&fpp_ac, &x); + break; + + case 016: + ea = fpp_2wd_dir (ir); + fpp_read_op (ea, &x); + fpp_div (&fpp_ac, &x); + break; + + case 017: + ea = fpp_indir (ir); + fpp_read_op (ea, &x); + fpp_div (&fpp_ac, &x); + break; + + case 021: /* FMUL */ + ea = fpp_1wd_dir (ir); + fpp_read_op (ea, &x); + fpp_mul (&fpp_ac, &x); + break; + + case 022: + ea = fpp_2wd_dir (ir); + fpp_read_op (ea, &x); + fpp_mul (&fpp_ac, &x); + break; + + case 023: + ea = fpp_indir (ir); + fpp_read_op (ea, &x); + fpp_mul (&fpp_ac, &x); + break; + + case 024: /* LTR */ + fpp_copy (&fpp_ac, (fpp_cond_met (op2 & 07)? &fpp_one: &fpp_zero)); + break; + + case 025: /* FADDM */ + fpp_sta |= FPS_XXXM; + ea = fpp_1wd_dir (ir); + fpp_read_op (ea, &x); + if (!fpp_add (&x, &fpp_ac, 0)) /* no trap? */ + fpp_write_op (ea, &x); /* store result */ + break; + + case 026: + fpp_sta |= FPS_XXXM; + ea = fpp_2wd_dir (ir); + fpp_read_op (ea, &x); + if (!fpp_add (&x, &fpp_ac, 0)) /* no trap? */ + fpp_write_op (ea, &x); /* store result */ + break; + + case 027: + fpp_sta |= FPS_XXXM; + ea = fpp_indir (ir); + fpp_read_op (ea, &x); + if (!fpp_add (&x, &fpp_ac, 0)) /* no trap? */ + fpp_write_op (ea, &x); /* store result */ + break; + + case 030: /* IMUL/LEA */ + ea = fpp_2wd_dir (ir); /* 2-word direct */ + if (fpp_sta & FPS_DP) { /* dp? */ + fpp_read_op (ea, &x); /* IMUL */ + fpp_imul (&fpp_ac, &x); + } + else { /* LEA */ + fpp_sta = (fpp_sta | FPS_DP) & ~FPS_EP; /* set dp */ + fpp_ac.fr[0] = (ea >> 12) & 07; + fpp_ac.fr[1] = ea & 07777; + } + break; + + case 031: /* FSTA */ + ea = fpp_1wd_dir (ir); + fpp_write_op (ea, &fpp_ac); + break; + + case 032: + ea = fpp_2wd_dir (ir); + fpp_write_op (ea, &fpp_ac); + break; + + case 033: + ea = fpp_indir (ir); + fpp_write_op (ea, &fpp_ac); + break; + + case 034: /* IMULI/LEAI */ + ea = fpp_indir (ir); /* 1-word indir */ + if (fpp_sta & FPS_DP) { /* dp? */ + fpp_read_op (ea, &x); /* IMUL */ + fpp_imul (&fpp_ac, &x); + } + else { /* LEA */ + fpp_sta = (fpp_sta | FPS_DP) & ~FPS_EP; /* set dp */ + fpp_ac.fr[0] = (ea >> 12) & 07; + fpp_ac.fr[1] = ea & 07777; + } + break; + + case 035: /* FMULM */ + fpp_sta |= FPS_XXXM; + ea = fpp_1wd_dir (ir); + fpp_read_op (ea, &x); + if (!fpp_mul (&x, &fpp_ac)) /* no trap? */ + fpp_write_op (ea, &x); /* store result */ + break; + + case 036: + fpp_sta |= FPS_XXXM; + ea = fpp_2wd_dir (ir); + fpp_read_op (ea, &x); + if (!fpp_mul (&x, &fpp_ac)) /* no trap? */ + fpp_write_op (ea, &x); /* store result */ + break; + + case 037: + fpp_sta |= FPS_XXXM; + ea = fpp_indir (ir); + fpp_read_op (ea, &x); + if (!fpp_mul (&x, &fpp_ac)) /* no trap? */ + fpp_write_op (ea, &x); /* store result */ + break; + } /* end sw op+mode */ + + if (sim_interval) + sim_interval = sim_interval - 1; + } while ((sim_interval > 0) && + ((fpp_sta & (FPS_RUN|FPS_PAUSE|FPS_LOCK)) == (FPS_RUN|FPS_LOCK))); +if ((fpp_sta & (FPS_RUN|FPS_PAUSE)) == FPS_RUN) + sim_activate (uptr, 1); +fpp_ac.exp &= 07777; /* mask AC exp */ +return SCPE_OK; +} + +/* Address decoding routines */ + +uint32 fpp_1wd_dir (uint32 ir) +{ +uint32 ad; + +ad = fpp_bra + ((ir & 0177) * 3); /* base + 3*7b off */ +if (fpp_sta & FPS_DP) /* dp? skip exp */ + ad = ad + 1; +return ad & ADDRMASK; +} + +uint32 fpp_2wd_dir (uint32 ir) +{ +uint32 ad; + +ad = fpp_ad15 (ir); /* get 15b addr */ +return fpp_adxr (ir, ad); /* do indexing */ +} + +uint32 fpp_indir (uint32 ir) +{ +uint32 ad, iad, wd1, wd2; + +ad = fpp_bra + ((ir & 07) * 3); /* base + 3*3b off */ +iad = fpp_adxr (ir, ad); /* do indexing */ +wd1 = fpp_read (iad + 1); /* read wds 2,3 */ +wd2 = fpp_read (iad + 2); +return ((wd1 & 07) << 12) | wd2; /* return addr */ +} + +uint32 fpp_ad15 (uint32 hi) +{ +uint32 ad; + +ad = ((hi & 07) << 12) | fpp_read (fpp_fpc); /* 15b addr */ +fpp_fpc = (fpp_fpc + 1) & ADDRMASK; /* incr FPC */ +return ad; /* return addr */ +} + +uint32 fpp_adxr (uint32 ir, uint32 base_ad) +{ +uint32 xr, wd; + +xr = (ir >> 3) & 07; +wd = fpp_read_xr (xr); /* get xr */ +if (ir & 0100) { /* increment? */ + wd = (wd + 1) & 07777; /* inc, rewrite */ + fpp_write_xr (xr, wd); + } +if (xr != 0) { /* indexed? */ + if (fpp_sta & FPS_EP) wd = wd * 6; /* scale by len */ + else if (fpp_sta & FPS_DP) wd = wd * 2; + else wd = wd * 3; + return (base_ad + wd) & ADDRMASK; /* return index */ + } +else return base_ad & ADDRMASK; /* return addr */ +} + +/* Computation routines */ + +/* Fraction/floating add - return true if overflow */ + +t_bool fpp_add (FPN *a, FPN *b, uint32 sub) +{ +FPN x, y, z; +uint32 ediff, c; + +fpp_zcopy (&x, a); /* copy opnds */ +fpp_zcopy (&y, b); +if (sub) /* subtract? */ + fpp_fr_neg (y.fr, EXACT); /* neg B, exact */ +if (fpp_sta & FPS_DP) { /* dp? */ + fpp_fr_add (z.fr, x.fr, y.fr); /* z = a + b */ + if ((~x.fr[0] ^ y.fr[0]) & (x.fr[0] ^ z.fr[0]) & FPN_FRSIGN) { + fpp_dump_apt (fpp_apta, FPS_IOVX); /* int ovf? */ + return TRUE; + } + } +else { /* fp or ep */ + if (fpp_fr_test (b->fr, 0, EXACT) == 0) /* B == 0? */ + z = x; /* result is A */ + else if (fpp_fr_test (a->fr, 0, EXACT) == 0) /* A == 0? */ + z = y; /* result is B */ + else { /* fp or ep */ + if (x.exp < y.exp) { /* |a| < |b|? */ + z = x; /* exchange ops */ + x = y; + y = z; + } + ediff = x.exp - y.exp; /* exp diff */ + z.exp = x.exp; /* result exp */ + if (ediff <= (fpp_sta & FPS_EP)? 59: 24) { /* any add? */ + if (ediff != 0) /* any align? */ + fpp_fr_algn (y.fr, ediff, EXTEND); /* align, 60b */ + c = fpp_fr_add (z.fr, x.fr, y.fr); /* add fractions */ + if ((((x.fr[0] ^ y.fr[0]) & FPN_FRSIGN) == 0) && /* same signs? */ + (c || /* carry out? */ + ((~x.fr[0] & z.fr[0] & FPN_FRSIGN)))) { /* + to - change? */ + fpp_fr_rsh1 (z.fr, c << 11, EXTEND); /* rsh, insert cout */ + z.exp = z.exp + 1; /* incr exp */ + } /* end same signs */ + } /* end in range */ + } /* end ops != 0 */ + if (fpp_norm (&z, EXTEND)) /* norm, !exact? */ + fpp_round (&z); /* round */ + if (fpp_test_xp (&z)) /* ovf, unf? */ + return TRUE; + } /* end else */ +fpp_copy (a, &z); /* result is z */ +return FALSE; +} + +/* Fraction/floating multiply - return true if overflow */ + +t_bool fpp_mul (FPN *a, FPN *b) +{ +FPN x, y, z; + +fpp_zcopy (&x, a); /* copy opnds */ +fpp_zcopy (&y, b); +if (fpp_sta & FPS_DP) /* dp? */ + fpp_fr_mul (z.fr, x.fr, y.fr); /* mult frac */ +else { /* fp or ep */ + z.exp = x.exp + y.exp; /* add exp */ + fpp_fr_mul (z.fr, x.fr, y.fr); /* mult frac */ + if (fpp_norm (&z, EXTEND)) /* norm, !exact? */ + fpp_round (&z); /* round */ + if (fpp_test_xp (&z)) /* ovf, unf? */ + return TRUE; + } +fpp_copy (a, &z); /* result is z */ +return FALSE; +} + +/* Fraction/floating divide - return true if div by zero or overflow */ + +t_bool fpp_div (FPN *a, FPN *b) +{ +FPN x, y, z; + +if (fpp_fr_test (b->fr, 0, EXACT) == 0) { /* divisor 0? */ + fpp_dump_apt (fpp_apta, FPS_DVZX); /* error */ + return TRUE; + } +if (fpp_fr_test (a->fr, 0, EXACT) == 0) /* dividend 0? */ + return FALSE; /* quotient is 0 */ +fpp_zcopy (&x, a); /* copy opnds */ +fpp_zcopy (&y, b); +if (fpp_sta & FPS_DP) { /* dp? */ + if (fpp_fr_div (z.fr, x.fr, y.fr)) { /* fr div, ovflo? */ + fpp_dump_apt (fpp_apta, FPS_IOVX); /* error */ + return TRUE; + } + } +else { /* fp or ep */ + fpp_norm (&y, EXACT); /* norm divisor */ + if (fpp_fr_test (x.fr, 04000, EXACT) == 0) { /* divd 1.000...? */ + x.fr[0] = 06000; /* fix */ + x.exp = x.exp + 1; + } + z.exp = x.exp - y.exp; /* calc exp */ + if (fpp_fr_div (z.fr, x.fr, y.fr)) { /* fr div, ovflo? */ + uint32 cin = (a->fr[0] ^ b->fr[0]) & FPN_FRSIGN; + fpp_fr_rsh1 (z.fr, cin, EXTEND); /* rsh, insert sign */ + z.exp = z.exp + 1; /* incr exp */ + } + if (fpp_norm (&z, EXTEND)) /* norm, !exact? */ + fpp_round (&z); /* round */ + if (fpp_test_xp (&z)) /* ovf, unf? */ + return TRUE; + } +fpp_copy (a, &z); /* result is z */ +return FALSE; +} + +/* Integer multiply - returns true if overflow */ + +t_bool fpp_imul (FPN *a, FPN *b) +{ +uint32 sext; +FPN x, y, z; + +fpp_zcopy (&x, a); /* copy args */ +fpp_zcopy (&y, b); +fpp_fr_mul (z.fr, x.fr, y.fr); /* mult fracs */ +sext = (z.fr[2] & FPN_FRSIGN)? 07777: 0; +if (((z.fr[0] | z.fr[1] | sext) != 0) && /* hi 25b == 0 */ + ((z.fr[0] & z.fr[1] & sext) != 07777)) { /* or 777777774? */ + fpp_dump_apt (fpp_apta, FPS_IOVX); + return TRUE; + } +a->fr[0] = z.fr[2]; /* low 24b */ +a->fr[1] = z.fr[3]; +return FALSE; +} + +/* Auxiliary floating point routines */ + +t_bool fpp_cond_met (uint32 cond) +{ +switch (cond) { + + case 0: + return (fpp_fr_test (fpp_ac.fr, 0, EXACT) == 0); + + case 1: + return (fpp_fr_test (fpp_ac.fr, 0, EXACT) >= 0); + + case 2: + return (fpp_fr_test (fpp_ac.fr, 0, EXACT) <= 0); + + case 3: + return 1; + + case 4: + return (fpp_fr_test (fpp_ac.fr, 0, EXACT) != 0); + + case 5: + return (fpp_fr_test (fpp_ac.fr, 0, EXACT) < 0); + + case 6: + return (fpp_fr_test (fpp_ac.fr, 0, EXACT) > 0); + + case 7: + return (fpp_ac.exp > 027); + } +return 0; +} + +/* Normalization - returns TRUE if rounding possible, FALSE if exact */ + +t_bool fpp_norm (FPN *a, uint32 cnt) +{ +if (fpp_fr_test (a->fr, 0, cnt) == 0) { /* zero? */ + a->exp = 0; /* clean exp */ + return FALSE; /* don't round */ + } +while (((a->fr[0] == 0) && !(a->fr[1] & 04000)) || /* lead 13b same? */ + ((a->fr[0] = 07777) & (a->fr[1] & 04000))) { + fpp_fr_lsh12 (a->fr, cnt); /* move word */ + a->exp = a->exp - 12; + } +while (((a->fr[0] ^ (a->fr[0] << 1)) & FPN_FRSIGN) == 0) { /* until norm */ + fpp_fr_lsh1 (a->fr, cnt); /* shift 1b */ + a->exp = a->exp - 1; + } +if (fpp_fr_test (a->fr, 04000, EXACT) == 0) { /* 4000...0000? */ + a->fr[0] = 06000; /* chg to 6000... */ + a->exp = a->exp + 1; /* with exp+1 */ + return FALSE; /* don't round */ + } +return TRUE; +} + +/* Exact fp number copy */ + +void fpp_copy (FPN *a, FPN *b) +{ +uint32 i; + +if (!(fpp_sta & FPS_DP)) + a->exp = b->exp; +for (i = 0; i < EXACT; i++) + a->fr[i] = b->fr[i]; +return; +} + +/* Zero extended fp number copy (60b) */ + +void fpp_zcopy (FPN *a, FPN *b) +{ +uint32 i; + +a->exp = b->exp; +for (i = 0; i < FPN_NFR_EP; i++) { + if ((i < FPN_NFR_FP) || (fpp_sta & FPS_EP)) + a->fr[i] = b->fr[i]; + else a->fr[i] = 0; + } +return; +} + +/* Test exp for overflow or underflow, returns TRUE on trap */ + +t_bool fpp_test_xp (FPN *a) +{ +if (a->exp > 2047) { /* overflow? */ + fpp_dump_apt (fpp_apta, FPS_FOVX); /* trap */ + return TRUE; + } +if (a->exp < -2048) { /* underflow? */ + fpp_sta |= FPS_UNF; /* set flag */ + if (fpp_sta & FPS_UNFX) { /* trap? */ + fpp_dump_apt (fpp_apta, FPS_UNFX); + return TRUE; + } + fpp_copy (a, &fpp_zero); /* flush to 0 */ + } +return FALSE; +} + +/* Round dp/fp value, returns carry out */ + +uint32 fpp_round (FPN *a) +{ +int32 i; +uint32 cin, afr0_sign; + +if (fpp_sta & FPS_EP) /* ep? */ + return FALSE; /* don't round */ +afr0_sign = a->fr[0] & FPN_FRSIGN; /* save input sign */ +cin = afr0_sign? 03777: 04000; +for (i = FPN_NFR_FP; i >= 0; i--) { /* 3 words */ + a->fr[i] = a->fr[i] + cin; /* add in carry */ + cin = (a->fr[i] >> 12) & 1; + a->fr[i] = a->fr[i] & 07777; + } +if (!(fpp_sta & FPS_DP) && /* fp? */ + (afr0_sign ^ (a->fr[0] & FPN_FRSIGN))) { /* sign change? */ + fpp_fr_rsh1 (a->fr, afr0_sign, EXACT); /* rsh, insert sign */ + a->exp = a->exp + 1; + } +return cin; +} + +/* N-precision integer routines */ + +/* Fraction add/sub - always carried out to 60b */ + +uint32 fpp_fr_add (uint32 *c, uint32 *a, uint32 *b) +{ +uint32 i, cin; + +for (i = FPN_NFR_EP, cin = 0; i > 0; i--) { + c[i - 1] = a[i - 1] + b[i - 1] + cin; + cin = (c[i - 1] >> 12) & 1; + c[i - 1] = c[i - 1] & 07777; + } +return cin; +} + +void fpp_fr_sub (uint32 *c, uint32 *a, uint32 *b) +{ +uint32 i, cin; + +for (i = FPN_NFR_EP, cin = 0; i > 0; i--) { + c[i - 1] = a[i - 1] - b[i - 1] - cin; + cin = (c[i - 1] >> 12) & 1; + c[i - 1] = c[i - 1] & 07777; + } +return; +} + +/* Fraction multiply - always develop 60b, multiply is + either 24b*24b or 60b*60b + + This is a signed multiply. The shift in for signed multiply is + technically ALU_N XOR ALU_V. This can be simplified as follows: + + a-sign c-sign result-sign cout overflow N XOR V = shift in + + 0 0 0 0 0 0 + 0 0 1 0 1 0 + 0 1 0 1 0 0 + 0 1 1 0 0 1 + 1 0 0 1 0 0 + 1 0 1 0 0 1 + 1 1 0 1 1 1 + 1 1 1 1 0 1 + + If a-sign == c-sign, shift-in = a-sign + If a-sign != c-sign, shift-in = result-sign + */ + +void fpp_fr_mul (uint32 *c, uint32 *a, uint32 *b) +{ +uint32 i, cnt, lo, c_old, cin; + +fpp_fr_fill (c, 0, EXTEND); /* clr answer */ +if (fpp_sta & FPS_EP) /* ep? */ + lo = FPN_NFR_EP - 1; /* test <59> */ +else lo = FPN_NFR_FP - 1; /* sp, test <23> */ +cnt = (lo + 1) * 12; /* # iterations */ +for (i = 0; i < cnt; i++) { /* loop thru mpcd */ + c_old = c[0]; + if (b[lo] & 1) /* mpcd bit set? */ + fpp_fr_add (c, a, c); /* add mpyr */ + cin = (((a[0] ^ c_old) & FPN_FRSIGN)? c[0]: a[0]) & FPN_FRSIGN; + fpp_fr_rsh1 (c, cin, EXTEND); /* shift answer */ + fpp_fr_rsh1 (b, 0, EXACT); /* shift mpcd */ + } +if (a[0] & FPN_FRSIGN) /* mpyr negative? */ + fpp_fr_sub (c, c, a); /* adjust result */ +return; +} + +/* Fraction divide */ + +t_bool fpp_fr_div (uint32 *c, uint32 *a, uint32 *b) +{ +uint32 i, old_c, lo, cnt, sign; + +fpp_fr_fill (c, 0, EXTEND); /* clr answer */ +sign = (a[0] ^ b[0]) & FPN_FRSIGN; /* sign of result */ +if (a[0] & FPN_FRSIGN) /* |a| */ + fpp_fr_neg (a, EXACT); +if (b[0] & FPN_FRSIGN); /* |b| */ + fpp_fr_neg (b, EXACT); +if (fpp_sta & FPS_EP) /* ep? 5 words */ + lo = FPN_NFR_EP - 1; +else lo = FPN_NFR_FP; /* fp, dp? 3 words */ +cnt = (lo + 1) * 12; +for (i = 0; i < cnt; i++) { /* loop */ + fpp_fr_lsh1 (c, EXTEND); /* shift quotient */ + if (fpp_fr_cmp (a, b, EXTEND) >= 0) { /* sub work? */ + fpp_fr_sub (a, a, b); /* divd - divr */ + if (a[0] & FPN_FRSIGN) /* sign flip? */ + return TRUE; /* no, overflow */ + c[lo] |= 1; /* set quo bit */ + } + fpp_fr_lsh1 (a, EXTEND); /* shift dividend */ + } +old_c = c[0]; /* save ho quo */ +if (sign) /* expect neg ans? */ + fpp_fr_neg (c, EXTEND); /* -quo */ +if (old_c & FPN_FRSIGN) /* sign set before */ + return TRUE; /* neg? */ +return FALSE; +} + +/* Negate - 24b or 60b */ + +uint32 fpp_fr_neg (uint32 *a, uint32 cnt) +{ +uint32 i, cin; + +for (i = cnt, cin = 1; i > 0; i--) { + a[i - 1] = (~a[i - 1] + cin) & 07777; + cin = (a[i - 1] == 0); + } +return cin; +} + +/* Test (compare to x'0...0) - 24b or 60b */ + +int32 fpp_fr_test (uint32 *a, uint32 v0, uint32 cnt) +{ +uint32 i; + +if (a[0] != v0) + return (a[0] & FPN_FRSIGN)? -1: +1; +for (i = 1; i < cnt; i++) { + if (a[i] != 0) + return (a[0] & FPN_FRSIGN)? -1: +1; + } +return 0; +} + +/* Fraction compare - 24b or 60b */ + +int32 fpp_fr_cmp (uint32 *a, uint32 *b, uint32 cnt) +{ +uint32 i; + +if ((a[0] ^ b[0]) & FPN_FRSIGN) + return (b[0] & FPN_FRSIGN)? +1: -1; +for (i = 0; i < cnt; i++) { + if (a[i] > b[i]) + return (b[0] & FPN_FRSIGN)? +1: -1; + if (a[i] < b[i]) + return (b[0] & FPN_FRSIGN)? -1: +1; + } +return 0; +} + +/* Fraction fill */ + +void fpp_fr_fill (uint32 *a, uint32 v, uint32 cnt) +{ +uint32 i; + +for (i = 0; i < cnt; i++) + a[i] = v; +return; +} + +/* Left shift n (unsigned) */ + +void fpp_fr_lshn (uint32 *a, uint32 sc, uint32 cnt) +{ +uint32 i; + +if (sc >= (cnt * 12)) { /* out of range? */ + fpp_fr_fill (a, 0, cnt); + return; + } +while (sc >= 12) { /* word shift? */ + fpp_fr_lsh12 (a, cnt); + sc = sc - 12; + } +if (sc == 0) /* any more? */ + return; +for (i = 1; i < cnt; i++) /* bit shift */ + a[i - 1] = ((a[i - 1] << sc) | (a[i] >> (12 - sc))) & 07777; +a[cnt - 1] = (a[cnt - 1] << sc) & 07777; +return; +} + +/* Left shift 12b (unsigned) */ + +void fpp_fr_lsh12 (uint32 *a, uint32 cnt) +{ +uint32 i; + +for (i = 1; i < cnt; i++) + a[i - 1] = a[i]; +a[cnt - 1] = 0; +return; +} + +/* Left shift 1b (unsigned) */ + +void fpp_fr_lsh1 (uint32 *a, uint32 cnt) +{ +uint32 i; + +for (i = 1; i < cnt; i++) + a[i - 1] = ((a[i - 1] << 1) | (a[i] >> 11)) & 07777; +a[cnt - 1] = (a[cnt - 1] << 1) & 07777; +return; +} + +/* Right shift 1b, with shift in */ + +void fpp_fr_rsh1 (uint32 *a, uint32 sign, uint32 cnt) +{ +uint32 i; + +for (i = cnt - 1; i > 0; i--) + a[i] = ((a[i] >> 1) | (a[i - 1] << 11)) & 07777; +a[0] = (a[0] >> 1) | sign; +return; +} + +/* Right shift n (signed) */ + +void fpp_fr_algn (uint32 *a, uint32 sc, uint32 cnt) +{ +uint32 i, sign; + +sign = (a[0] & FPN_FRSIGN)? 07777: 0; +if (sc >= (cnt * 12)) { /* out of range? */ + fpp_fr_fill (a, sign, cnt); + return; + } +while (sc >= 12) { + for (i = cnt - 1; i > 0; i++) + a[i] = a[i - 1]; + a[0] = sign; + sc = sc - 12; + } +if (sc == 0) + return; +for (i = cnt - 1; i > 0; i--) + a[i] = ((a[i] >> sc) | (a[i - 1] << (12 - sc))) & 07777; +a[0] = ((a[0] >> sc) | (sign << (12 - sc))) & 07777; +return; +} + +/* Read/write routines */ + +void fpp_read_op (uint32 ea, FPN *a) +{ +uint32 i; + +fpp_opa = ea; +if (!(fpp_sta & FPS_DP)) { + a->exp = fpp_read (ea++); + a->exp = SEXT12 (a->exp); + } +for (i = 0; i < EXACT; i++) + a->fr[i] = fpp_read (ea + i); +return; +} + +void fpp_write_op (uint32 ea, FPN *a) +{ +uint32 i; + +fpp_opa = ea; +if (!(fpp_sta & FPS_DP)) + fpp_write (ea++, a->exp); +for (i = 0; i < EXACT; i++) + fpp_write (ea + i, a->fr[i]); +return; +} + +uint32 fpp_read (uint32 ea) +{ +ea = ea & ADDRMASK; +if (fpp_cmd & FPC_FIXF) + ea = fpp_aptsvf | (ea & 07777); +return M[ea]; +} + +void fpp_write (uint32 ea, uint32 val) +{ +ea = ea & ADDRMASK; +if (fpp_cmd & FPC_FIXF) + ea = fpp_aptsvf | (ea & 07777); +if (MEM_ADDR_OK (ea)) + M[ea] = val & 07777; +return; +} + +uint32 apt_read (uint32 ea) +{ +ea = ea & ADDRMASK; +return M[ea]; +} + +void apt_write (uint32 ea, uint32 val) +{ +ea = ea & ADDRMASK; +if (MEM_ADDR_OK (ea)) + M[ea] = val & 07777; +return; +} + +/* Utility routines */ + +void fpp_load_apt (uint32 ad) +{ +uint32 wd0, i; + +wd0 = apt_read (ad++); +fpp_fpc = ((wd0 & 07) << 12) | apt_read (ad++); +if (FPC_GETFAST (fpp_cmd) != 017) { + fpp_xra = ((wd0 & 00070) << 9) | apt_read (ad++); + fpp_bra = ((wd0 & 00700) << 6) | apt_read (ad++); + ad++; + fpp_ac.exp = apt_read (ad++); + for (i = 0; i < EXACT; i++) + fpp_ac.fr[i] = apt_read (ad++); + } +fpp_aptsvf = (ad - 1) & 070000; +fpp_sta |= FPS_RUN; +return; +} + +void fpp_dump_apt (uint32 ad, uint32 sta) +{ +uint32 wd0, i; + +wd0 = (fpp_fpc >> 12) & 07; +if (FPC_GETFAST (fpp_cmd) != 017) + wd0 = wd0 | + ((fpp_opa >> 3) & 07000) | + ((fpp_bra >> 6) & 00700) | + ((fpp_xra >> 9) & 00070); +apt_write (ad++, wd0); +apt_write (ad++, fpp_fpc); +if (FPC_GETFAST (fpp_cmd) != 017) { + apt_write (ad++, fpp_xra); + apt_write (ad++, fpp_bra); + apt_write (ad++, fpp_opa); + apt_write (ad++, fpp_ac.exp); + for (i = 0; i < EXACT; i++) + apt_write (ad++, fpp_ac.fr[i]); + } +fpp_sta = (fpp_sta | sta) & ~FPS_RUN; +fpp_flag = 1; +if (fpp_cmd & FPC_IE) + int_req |= INT_FPP; +return; +} + +/* Reset routine */ + +t_stat fpp_reset (DEVICE *dptr) +{ +sim_cancel (&fpp_unit); +fpp_sta = 0; +fpp_cmd = 0; +fpp_flag = 0; +int_req &= ~INT_FPP; +if (sim_switches & SWMASK ('P')) { + fpp_apta = 0; + fpp_aptsvf = 0; + fpp_fpc = 0; + fpp_bra = 0; + fpp_xra = 0; + fpp_opa = 0; + fpp_ac = fpp_zero; + } +return SCPE_OK; +} diff --git a/PDP8/pdp8_sys.c b/PDP8/pdp8_sys.c index 5405702d..c8ffa520 100644 --- a/PDP8/pdp8_sys.c +++ b/PDP8/pdp8_sys.c @@ -1,6 +1,6 @@ /* pdp8_sys.c: PDP-8 simulator interface - Copyright (c) 1993-2006, Robert M Supnik + Copyright (c) 1993-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,10 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 24-Jun-08 RMS Fixed bug in new rim loader (found by Don North) + 24-May-08 RMS Fixed signed/unsigned declaration inconsistency + 03-Sep-07 RMS Added FPP8 support + Rewrote rim and binary loaders 15-Dec-06 RMS Added TA8E support, IOT disambiguation 30-Oct-06 RMS Added infinite loop stop 18-Oct-06 RMS Re-ordered device list @@ -61,6 +65,12 @@ extern REG cpu_reg[]; extern uint16 M[]; extern int32 sim_switches; +t_stat fprint_sym_fpp (FILE *of, t_value *val); +t_stat parse_sym_fpp (char *cptr, t_value *val); +char *parse_field (char *cptr, uint32 max, uint32 *val, uint32 c); +char *parse_fpp_xr (char *cptr, uint32 *xr, t_bool inc); +int32 test_fpp_addr (uint32 ad, uint32 max); + /* SCP data structures and interface routines sim_name simulator name string @@ -124,100 +134,100 @@ DEVICE *amb_dev[] = { #define AMB_CT (2 << 12) #define AMB_TD (3 << 12) -/* Binary loader - - Two loader formats are supported: RIM loader (-r) and BIN (-b) loader. - - RIM loader format consists of alternating pairs of addresses and 12-bit +/* RIM loader format consists of alternating pairs of addresses and 12-bit words. It can only operate in field 0 and is not checksummed. +*/ - BIN loader format consists of a string of 12-bit words (made up from +t_stat sim_load_rim (FILE *fi) +{ +int32 origin, hi, lo, wd; + +origin = 0200; +do { /* skip leader */ + if ((hi = getc (fi)) == EOF) + return SCPE_FMT; + } while ((hi == 0) || (hi >= 0200)); +do { /* data block */ + if ((lo = getc (fi)) == EOF) + return SCPE_FMT; + wd = (hi << 6) | lo; + if (wd > 07777) origin = wd & 07777; + else M[origin++ & 07777] = wd; + if ((hi = getc (fi)) == EOF) + return SCPE_FMT; + } while (hi < 0200); /* until trailer */ +return SCPE_OK; +} + +/* BIN loader format consists of a string of 12-bit words (made up from 7-bit characters) between leader and trailer (200). The last word on tape is the checksum. A word with the "link" bit set is a new origin; a character > 0200 indicates a change of field. */ +int32 sim_bin_getc (FILE *fi, uint32 *newf) +{ +int32 c, rubout; + +rubout = 0; /* clear toggle */ +while ((c = getc (fi)) != EOF) { /* read char */ + if (rubout) /* toggle set? */ + rubout = 0; /* clr, skip */ + else if (c == 0377) /* rubout? */ + rubout = 1; /* set, skip */ + else if (c > 0200) /* channel 8 set? */ + *newf = (c & 070) << 9; /* change field */ + else return c; /* otherwise ok */ + } +return EOF; +} + +t_stat sim_load_bin (FILE *fi) +{ +int32 hi, lo, wd, csum, t; +uint32 field, newf, origin; + +do { /* skip leader */ + if ((hi = sim_bin_getc (fi, &newf)) == EOF) + return SCPE_FMT; + } while ((hi == 0) || (hi >= 0200)); +csum = origin = field = newf = 0; /* init */ +for (;;) { /* data blocks */ + if ((lo = sim_bin_getc (fi, &newf)) == EOF) /* low char */ + return SCPE_FMT; + wd = (hi << 6) | lo; /* form word */ + t = hi; /* save for csum */ + if ((hi = sim_bin_getc (fi, &newf)) == EOF) /* next char */ + return SCPE_FMT; + if (hi == 0200) { /* end of tape? */ + if ((csum - wd) & 07777) /* valid csum? */ + return SCPE_CSUM; + return SCPE_OK; + } + csum = csum + t + lo; /* add to csum */ + if (wd > 07777) /* chan 7 set? */ + origin = wd & 07777; /* new origin */ + else { /* no, data */ + if ((field | origin) >= MEMSIZE) + return SCPE_NXM; + M[field | origin] = wd; + origin = (origin + 1) & 07777; + } + field = newf; /* update field */ + } +return SCPE_IERR; +} + +/* Binary loader + Two loader formats are supported: RIM loader (-r) and BIN (-b) loader. */ + t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) { -int32 rubout, word, low, high, csum, newf, state, i; -uint32 origin, field; - if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; -rubout = state = field = newf = origin = csum = 0; if ((sim_switches & SWMASK ('R')) || /* RIM format? */ - (match_ext (fnam, "RIM") && !(sim_switches & SWMASK ('B')))) { - while ((i = getc (fileref)) != EOF) { - switch (state) { - - case 0: /* leader */ - if ((i != 0) && (i < 0200)) state = 1; - high = i; - break; - - case 1: /* low byte */ - word = (high << 6) | i; /* form word */ - if (word > 07777) origin = word & 07777; - else M[origin] = word; - state = 2; - break; - - case 2: /* high byte */ - if (i >= 0200) return SCPE_OK; /* end of tape? */ - high = i; /* save high */ - state = 1; - break; - } /* end switch */ - } /* end while */ - } /* end if */ - -else { - while ((i = getc (fileref)) != EOF) { /* BIN format */ - if (rubout) { - rubout = 0; - continue; - } - if (i == 0377) { - rubout = 1; - continue; - } - if (i > 0200) { - newf = (i & 070) << 9; - continue; - } - switch (state) { - - case 0: /* leader */ - if ((i != 0) && (i != 0200)) state = 1; - high = i; /* save as high */ - break; - - case 1: /* low byte */ - low = i; - state = 2; - break; - - case 2: /* high with test */ - word = (high << 6) | low; - if (i == 0200) { /* end of tape? */ - if ((csum - word) & 07777) return SCPE_CSUM; - return SCPE_OK; - } - csum = csum + low + high; - if (word >= 010000) origin = word & 07777; - else { - if ((field | origin) >= MEMSIZE) - return SCPE_NXM; - M[field | origin] = word & 07777; - origin = (origin + 1) & 07777; - } - field = newf; - high = i; - state = 1; - break; - } /* end switch */ - } /* end while */ - } /* end else */ -return SCPE_FMT; /* eof? error */ + (match_ext (fnam, "RIM") && !(sim_switches & SWMASK ('B')))) + return sim_load_rim (fileref); +else return sim_load_bin (fileref); /* no, BIN */ } /* Symbol tables */ @@ -242,9 +252,9 @@ return SCPE_FMT; /* eof? error */ #define I_IOA (I_V_IOA << I_V_FL) static const int32 masks[] = { - 07777, 07707, 07000, 07000, - 07416, 07571, 017457, 077777, - }; + 07777, 07707, 07000, 07000, + 07416, 07571, 017457, 077777, + }; /* Ambiguous device mnemonics must precede default mnemonics */ @@ -289,6 +299,10 @@ static const char *opcode[] = { "DTSF", "DTRB", "DTLB", "ETDS", "ESKP", "ECTF", "ECDF", /* TSC75 */ "ERTB", "ESME", "ERIOT", "ETEN", + "FFST", "FPINT", "FPICL", "FPCOM", /* FPP8 */ + "FPHLT", "FPST", "FPRST", "FPIST", + "FMODE", "FMRB", + "FMRP", "FMDO", "FPEP", "CDF", "CIF", "CIF CDF", "AND", "TAD", "ISZ", "DCA", "JMS", "JMP", "IOT", @@ -353,6 +367,10 @@ static const int32 opc_val[] = { 06771+I_NPN, 06772+I_NPN, 06774+I_NPN, 06360+I_NPN, 06361+I_NPN, 06362+I_NPN, 06363+I_NPN, /* TSC */ 06364+I_NPN, 06365+I_NPN, 06366+I_NPN, 06367+I_NPN, + 06550+I_NPN, 06551+I_NPN, 06552+I_NPN, 06553+I_NPN, /* FPP8 */ + 06554+I_NPN, 06555+I_NPN, 06556+I_NPN, 06557+I_NPN, + 06561+I_NPN, 06563+I_NPN, + 06564+I_NPN, 06565+I_NPN, 06567+I_NPN, 06201+I_FLD, 06202+I_FLD, 06203+I_FLD, 00000+I_MRF, 01000+I_MRF, 02000+I_MRF, 03000+I_MRF, @@ -380,6 +398,100 @@ static const int32 opc_val[] = { -1 }; +/* Symbol tables for FPP-8 */ + +#define F_V_FL 18 /* flag start */ +#define F_M_FL 017 /* flag mask */ +#define F_V_NOP12 0 /* no opnd 12b */ +#define F_V_NOP9 1 /* no opnd 9b */ +#define F_V_AD15 2 /* 15b dir addr */ +#define F_V_AD15X 3 /* 15b dir addr indx */ +#define F_V_IMMX 4 /* 12b immm indx */ +#define F_V_X 5 /* index */ +#define F_V_MRI 6 /* mem ref ind */ +#define F_V_MR1D 7 /* mem ref dir 1 word */ +#define F_V_MR2D 8 /* mem ref dir 2 word */ +#define F_V_LEMU 9 /* LEA/IMUL */ +#define F_V_LEMUI 10 /* LEAI/IMULI */ +#define F_V_LTR 11 /* LTR */ +#define F_V_MRD 12 /* mem ref direct (enc) */ +#define F_NOP12 (F_V_NOP12 << F_V_FL) +#define F_NOP9 (F_V_NOP9 << F_V_FL) +#define F_AD15 (F_V_AD15 << F_V_FL) +#define F_AD15X (F_V_AD15X << F_V_FL) +#define F_IMMX (F_V_IMMX << F_V_FL) +#define F_X (F_V_X << F_V_FL) +#define F_MRI (F_V_MRI << F_V_FL) +#define F_MR1D (F_V_MR1D << F_V_FL) +#define F_MR2D (F_V_MR2D << F_V_FL) +#define F_LEMU (F_V_LEMU << F_V_FL) +#define F_LEMUI (F_V_LEMUI << F_V_FL) +#define F_LTR (F_V_LTR << F_V_FL) +#define F_MRD (F_V_MRD << F_V_FL) + +static const uint32 fmasks[] = { + 07777, 07770, 07770, 07600, + 07770, 07770, 07600, 07600, + 07600, 017600, 017600, 07670, + 07777 + }; + +/* Memory references are encode dir / decode 1D / decode 2D / indirect */ + +static const char *fopcode[] = { + "FEXIT", "FPAUSE", "FCLA", "FNEG", + "FNORM", "STARTF", "STARTD", "JAC", + "ALN", "ATX", "XTA", + "FNOP", "STARTE", + "LDX", "ADDX", + "FLDA", "FLDA", "FLDA", "FLDAI", + "JEQ", "JGE", "JLE", "JA", + "JNE", "JLT", "JGT", "JAL", + "SETX", "SETB", "JSA", "JSR", + "FADD", "FADD", "FADD", "FADDI", + "JNX", + "FSUB", "FSUB", "FSUB", "FSUBI", + "TRAP3", + "FDIV", "FDIV", "FDIV", "FDIVI", + "TRAP4", + "FMUL", "FMUL", "FMUL", "FMULI", + "LTREQ", "LTRGE", "LTRLE", "LTRA", + "LTRNE", "LTRLT", "LTRGT", "LTRAL", + "FADDM", "FADDM", "FADDM", "FADDMI", + "IMUL", "LEA", + "FSTA", "FSTA", "FSTA", "FSTAI", + "IMULI", "LEAI", + "FMULM", "FMULM", "FMULM", "FMULMI", + NULL + }; + +static const int32 fop_val[] = { + 00000+F_NOP12, 00001+F_NOP12, 00002+F_NOP12, 00003+F_NOP12, + 00004+F_NOP12, 00005+F_NOP12, 00006+F_NOP12, 00007+F_NOP12, + 00010+F_X, 00020+F_X, 00030+F_X, + 00040+F_NOP9, 00050+F_NOP9, + 00100+F_IMMX, 00110+F_IMMX, + 00000+F_MRD, 00200+F_MR1D, 00400+F_MR2D, 00600+F_MRI, + 01000+F_AD15, 01010+F_AD15, 01020+F_AD15, 01030+F_AD15, + 01040+F_AD15, 01050+F_AD15, 01060+F_AD15, 01070+F_AD15, + 01100+F_AD15, 01110+F_AD15, 01120+F_AD15, 01130+F_AD15, + 01000+F_MRD, 01200+F_MR1D, 01400+F_MR2D, 01600+F_MRI, + 02000+F_AD15X, + 02000+F_MRD, 02200+F_MR1D, 02400+F_MR2D, 02600+F_MRI, + 03000+F_AD15, + 03000+F_MRD, 03200+F_MR1D, 03400+F_MR2D, 03600+F_MRI, + 04000+F_AD15, + 04000+F_MRD, 04200+F_MR1D, 04400+F_MR2D, 04600+F_MRI, + 05000+F_LTR, 05010+F_LTR, 05020+F_LTR, 05030+F_LTR, + 05040+F_LTR, 05050+F_LTR, 05060+F_LTR, 05070+F_LTR, + 05000+F_MRD, 05200+F_MR1D, 05400+F_MR2D, 05600+F_MRI, + 016000+F_LEMU, 006000+F_LEMU, + 06000+F_MRD, 06200+F_MR1D, 06400+F_MR2D, 06600+F_MRI, + 017000+F_LEMUI, 007000+F_LEMUI, + 07000+F_MRD, 07200+F_MR1D, 07400+F_MR2D, 07600+F_MRI, + -1 + }; + /* Operate decode Inputs: @@ -427,6 +539,7 @@ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, { int32 cflag, i, j, sp, inst, disp, opc; extern int32 emode; +t_stat r; cflag = (uptr == NULL) || (uptr == &cpu_unit); inst = val[0]; @@ -445,6 +558,9 @@ if (sw & SWMASK ('T')) { /* TSS8 packed? */ fprintf (of, "%c", TSSTOASC (inst & 077)); return SCPE_OK; } +if ((sw & SWMASK ('F')) && /* FPP8? */ + ((r = fprint_sym_fpp (of, val)) != SCPE_ARG)) + return r; if (!(sw & SWMASK ('M'))) return SCPE_ARG; /* Instruction decode */ @@ -532,7 +648,7 @@ return SCPE_ARG; t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) { -int32 cflag, d, i, j, k; +uint32 cflag, d, i, j, k; t_stat r; char gbuf[CBUFSIZE]; @@ -555,6 +671,8 @@ if ((sw & SWMASK ('T')) || ((*cptr == '"') && cptr++)) { /* TSS8 string? */ ((t_value) (cptr[1] - 040) & 077); return SCPE_OK; } +if ((r = parse_sym_fpp (cptr, val)) != SCPE_ARG) /* FPP8 inst? */ + return r; /* Instruction parse */ @@ -567,9 +685,8 @@ j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */ switch (j) { /* case on class */ case I_V_IOT: /* IOT */ - cptr = get_glyph (cptr, gbuf, 0); /* get dev+pulse */ - d = get_uint (gbuf, 8, 0777, &r); - if (r != SCPE_OK) return SCPE_ARG; + if ((cptr = parse_field (cptr, 0777, &d, 0)) == NULL) + return SCPE_ARG; /* get dev+pulse */ val[0] = val[0] | d; break; @@ -599,9 +716,8 @@ switch (j) { /* case on class */ cptr = get_glyph (cptr, gbuf, 0); } if ((k = (strcmp (gbuf, "C") == 0)) || (strcmp (gbuf, "Z") == 0)) { - cptr = get_glyph (cptr, gbuf, 0); - d = get_uint (gbuf, 8, 0177, &r); - if (r != SCPE_OK) return SCPE_ARG; + if ((cptr = parse_field (cptr, 0177, &d, 0)) == NULL) + return SCPE_ARG; val[0] = val[0] | d | (k? 0200: 0); } else { @@ -631,3 +747,233 @@ switch (j) { /* case on class */ if (*cptr != 0) return SCPE_ARG; /* junk at end? */ return SCPE_OK; } + +/* FPP8 instruction decode */ + +t_stat fprint_sym_fpp (FILE *of, t_value *val) +{ +uint32 wd1, wd2, xr4b, xr3b, ad15; +uint32 i, j; +extern uint32 fpp_bra, fpp_cmd; + +wd1 = (uint32) val[0] | ((fpp_cmd & 04000) << 1); +wd2 = (uint32) val[1]; +xr4b = (wd1 >> 3) & 017; +xr3b = wd1 & 07; +ad15 = (xr3b << 12) | wd2; + +for (i = 0; fop_val[i] >= 0; i++) { /* loop thru ops */ + j = (fop_val[i] >> F_V_FL) & F_M_FL; /* get class */ + if ((fop_val[i] & 017777) == (wd1 & fmasks[j])) { /* match? */ + + switch (j) { /* case on class */ + case F_V_NOP12: + case F_V_NOP9: + case F_V_LTR: /* no operands */ + fprintf (of, "%s", fopcode[i]); + break; + + case F_V_X: /* index */ + fprintf (of, "%s %o", fopcode[i], xr3b); + break; + + case F_V_IMMX: /* index imm */ + fprintf (of, "%s %-o,%o", fopcode[i], wd2, xr3b); + return -1; /* extra word */ + + case F_V_AD15: /* 15b address */ + fprintf (of, "%s %-o", fopcode[i], ad15); + return -1; /* extra word */ + + case F_V_AD15X: /* 15b addr, indx */ + fprintf (of, "%s %-o", fopcode[i], ad15); + if (xr4b >= 010) + fprintf (of, ",%o+", xr4b & 7); + else fprintf (of, ",%o", xr4b); + return -1; /* extra word */ + + case F_V_MR1D: /* 1 word direct */ + ad15 = (fpp_bra + (3 * (wd1 & 0177))) & ADDRMASK; + fprintf (of, "%s %-o", fopcode[i], ad15); + break; + + case F_V_LEMU: + case F_V_MR2D: /* 2 word direct */ + fprintf (of, "%s %-o", fopcode[i], ad15); + if (xr4b >= 010) + fprintf (of, ",%o+", xr4b & 7); + else if (xr4b != 0) + fprintf (of, ",%o", xr4b); + return -1; /* extra word */ + + case F_V_LEMUI: + case F_V_MRI: /* indirect */ + ad15 = (fpp_bra + (3 * xr3b)) & ADDRMASK; + fprintf (of, "%s %-o", fopcode[i], ad15); + if (xr4b >= 010) + fprintf (of, ",%o+", xr4b & 7); + else if (xr4b != 0) + fprintf (of, ",%o", xr4b); + break; + + case F_V_MRD: /* encode only */ + return SCPE_IERR; + } + + return SCPE_OK; + } /* end if */ + } /* end for */ +return SCPE_ARG; +} + +/* FPP8 instruction parse */ + +t_stat parse_sym_fpp (char *cptr, t_value *val) +{ +uint32 i, j, ad, xr; +int32 broff, nwd; +char gbuf[CBUFSIZE]; + +cptr = get_glyph (cptr, gbuf, 0); /* get opcode */ +for (i = 0; (fopcode[i] != NULL) && (strcmp (fopcode[i], gbuf) != 0) ; i++) ; +if (fopcode[i] == NULL) return SCPE_ARG; +val[0] = fop_val[i] & 07777; /* get value */ +j = (fop_val[i] >> F_V_FL) & F_M_FL; /* get class */ +xr = 0; +nwd = 0; + +switch (j) { /* case on class */ + + case F_V_NOP12: + case F_V_NOP9: + case F_V_LTR: /* no operands */ + break; + + case F_V_X: /* 3b XR */ + if ((cptr = parse_field (cptr, 07, &xr, 0)) == NULL) + return SCPE_ARG; + val[0] |= xr; + break; + + case F_V_IMMX: /* 12b, XR */ + if ((cptr = parse_field (cptr, 07777, &ad, ',')) == NULL) + return SCPE_ARG; + if ((*cptr == 0) || + ((cptr = parse_fpp_xr (cptr, &xr, FALSE)) == NULL)) + return SCPE_ARG; + val[0] |= xr; + val[++nwd] = ad; + break; + + case F_V_AD15: /* 15b addr */ + if ((cptr = parse_field (cptr, 077777, &ad, 0)) == NULL) + return SCPE_ARG; + val[0] |= (ad >> 12) & 07; + val[++nwd] = ad & 07777; + break; + + case F_V_AD15X: /* 15b addr, idx */ + if ((cptr = parse_field (cptr, 077777, &ad, ',')) == NULL) + return SCPE_ARG; + if ((*cptr == 0) || + ((cptr = parse_fpp_xr (cptr, &xr, FALSE)) == NULL)) + return SCPE_ARG; + val[0] |= ((xr << 3) | ((ad >> 12) & 07)); + val[++nwd] = ad & 07777; + break; + + case F_V_LEMUI: + case F_V_MRI: /* indirect */ + if ((cptr = parse_field (cptr, 077777, &ad, ',')) == NULL) + return SCPE_ARG; + if ((*cptr != 0) && + ((cptr = parse_fpp_xr (cptr, &xr, TRUE)) == NULL)) + return SCPE_ARG; + if ((broff = test_fpp_addr (ad, 07)) < 0) + return SCPE_ARG; + val[0] |= ((xr << 3) | broff); + break; + + case F_V_MRD: /* direct */ + if ((cptr = parse_field (cptr, 077777, &ad, ',')) == NULL) + return SCPE_ARG; + if (((broff = test_fpp_addr (ad, 0177)) < 0) || + (*cptr != 0)) { + if ((*cptr != 0) && + ((cptr = parse_fpp_xr (cptr, &xr, TRUE)) == NULL)) + return SCPE_ARG; + val[0] |= (00400 | (xr << 3) | ((ad >> 12) & 07)); + val[++nwd] = ad & 07777; + } + else val[0] |= (00200 | broff); + break; + + case F_V_LEMU: + if ((cptr = parse_field (cptr, 077777, &ad, ',')) == NULL) + return SCPE_ARG; + if ((*cptr != 0) && + ((cptr = parse_fpp_xr (cptr, &xr, TRUE)) == NULL)) + return SCPE_ARG; + val[0] |= ((xr << 3) | ((ad >> 12) & 07)); + val[++nwd] = ad & 07777; + break; + + case F_V_MR1D: + case F_V_MR2D: + return SCPE_IERR; + } /* end case */ + +if (*cptr != 0) return SCPE_ARG; /* junk at end? */ +return -nwd; +} + +/* Parse field */ + +char *parse_field (char *cptr, uint32 max, uint32 *val, uint32 c) +{ +char gbuf[CBUFSIZE]; +t_stat r; + +cptr = get_glyph (cptr, gbuf, c); /* get field */ +*val = get_uint (gbuf, 8, max, &r); +if (r != SCPE_OK) + return NULL; +return cptr; +} + +/* Parse index register */ + +char *parse_fpp_xr (char *cptr, uint32 *xr, t_bool inc) +{ +char gbuf[CBUFSIZE]; +uint32 len; +t_stat r; + +cptr = get_glyph (cptr, gbuf, 0); /* get field */ +len = strlen (gbuf); +if (gbuf[len - 1] == '+') { + if (!inc) + return NULL; + gbuf[len - 1] = 0; + *xr = 010; + } +else *xr = 0; +*xr += get_uint (gbuf, 8, 7, &r); +if (r != SCPE_OK) + return NULL; +return cptr; +} + +/* Test address in range of base register */ + +int32 test_fpp_addr (uint32 ad, uint32 max) +{ +uint32 off; +extern uint32 fpp_bra; + +off = ad - fpp_bra; +if (((off % 3) != 0) || + (off > (max * 3))) + return -1; +return ((int32) off / 3); +} diff --git a/VAX/ka655_patch.com b/VAX/ka655_patch.com new file mode 100644 index 00000000..e35cb744 --- /dev/null +++ b/VAX/ka655_patch.com @@ -0,0 +1,509 @@ +$! +$! This procedure patches the base KA655.BIN Boot ROM image to work under +$! the SIMH simulator +$ +$! The second part of the patch adds support for Extended Memory in the +$! simulator. A simulated system can have up to 512MB of RAM. +$! +$ PATCH /ABSOLUTE /NEW_VERSION /OUTPUT=cp$exe:KA655.BIN cp$src:ka655_orig.BIN +! CVAX Bootstrap Notes +! +! [2004c87e] - de$read_script +! [2004c916] - launch next test, r2 = test #, r4 = header, r5 = offset to main routine +! +! Script BA +! --------- +! +! Test 9D - Utility - ok +! Test 42 - Wait for interrupt - ok +! Test C6 - SSC register check - ok +! Test 60 [2004de37] - Serial line - requires diagnostic loopback mode and +! break detection - bypass +! 2004de99/ brw 2004e0a7 +Replace/Instruction 0DE99 = 'MOVB #03,B^76(R9)' +'BRW 0000E0A7' +Exit +! Test 62 - QDSS disable - ok +! +! Script BC +! --------- +! +! 40. Test 91 - CQBIC init check - ok +! 39. Test 90 [2004d748] - CQBIC registers - ok +! 38. Test 33 [2004d54e] - CMCTL init check - ok +! 37. Test 32 [2004d5b0] - CMCTL registers - ok +! 36. Test 31 [200512d0] - CMCTL CSR setup to map memory - ok +! 35. Test 49 [20052a4b] - CMCTL FDM test - requires fast diagnostic mode +! and XMX counters - bypass +! 20052a55:20052a58/ nop +Delete/Instruction 12A55 = 'BBC #26,(R9),00012A5C' +! 34. Test 30 [20051909] - init map - ok +! +! Script BD +! --------- +! +! 33. Test 52 [2004e656] - prog timer 0 - ok +! 32. Test 52 [2004e656] - prog timer 1 - ok +! 31. Test 53 [2004e918] - toy clock - ok +! 30. Test C1 [2004f8f1] - SSC RAM - ok +! 29. Test 34 [2004d4a0] - ROM - checksum off due to other patches - patch +! 2004d52c:2004d52d/ nop +Delete/Instruction 0D52C = 'BNEQ 0000D531' ! 2004D52C +! 28. Test C5 [2004fc0e] - SSC registers - ok +! 27. Test 55 [2004ea8c] - interval timer - ok +! 26. Test 51 [2004e42d] - CFPA - ok +! 25. Test C7 [2004D3D3] - CBTCR<31:30> - ok +! 24. Test 46 [2004ef1a] - L1 cache diagnostic mode - bypass +! 2004ef80/ brw 2004f47a +Replace/Instruction 0EF80 = 'MOVB #06,B^76(R9)' +'BRW 0000F47A' ! 2004FE80 +Exit +! 23. Test 35 [20050554] - L2 cache integrity test - bypass +! 20050554/ brw 20050a48 +Replace/Instruction 10554 = 'INSV #00,#10,#02,(R9)' +'BRW 00010A48' ! 20050554 +Exit +! 22. Test 43 [20050d65] - L1 with L2 test - bypass +! 20050d65/ brw 20050fca +Replace/Instruction 10D65 = 'MOVAL B^00010D65,W^0080(R9)' +'BRW 00010FCA' ! 20050D65 +Exit +! 21. (Rerun of C2) +! 20. Test 4F [20051d4f] - memory data - bypass, run from ROM +! 20055205/ 0 +Replace/Byte 15205 = 3 +0 ! 20055205 +Exit +! 20051d4f/ brw 2005163a +Replace/Instruction 11D4F = 'MOVAL B^00011D4F,W^0080(R9)' +'BRW 0001163A' ! 20051D4F +Exit +! 19. Test 4E [20051edb] - memory byte write - ok, run from ROM +! 2005521c/ 0 +Replace/Byte 1521C = 3 +0 ! 2005521C +Exit +! 18. Test 4D [20051ff3] - memory addressing - ok, run from ROM +! 20055233/ 0 +Replace/Byte 15233 = 3 +0 ! 20055233 +Exit +! 17. Test 4C [20052190] - ECC test - bypass, run from ROM +! 2005524a/ 0 +Replace/Byte 1524A = 3 +0 ! 2005524A +Exit +! 20052190/ brw 2005163a +Replace/Instruction 12190 = 'MOVAL B^00012190,W^0080(R9)' +'BRW 0001163A' ! 20052190 +Exit +! 16. Test 4B [2005264e] - masked writes with errors - bypass, run from ROM +! 20055261/ 0 +Replace/Byte 15261 = 3 +0 ! 20055261 +Exit +! 2005264e/ brw 2005163a +Replace/Instruction 1264E = 'MOVAL B^0001264E,W^0080(R9)' +'BRW 0001163A' ! 2005264E +Exit +! 15. Test 4A [20052823] - single bit correction - bypass, run from ROM +! 20055278/ 0 +Replace/Byte 15278 = 3 +0 ! 20055278 +Exit +! 20052823/ brw 2005163a +Replace/Instruction 12823 = 'MOVAL B^00012823,W^0080(R9)' +'BRW 0001163A' ! 20052823 +Exit +! 14. Test 48 [20053062] - memory address shorts - bypass, run from ROM +! 2005528f/ 0 +Replace/Byte 1528F = 3 +0 ! 2005528F +Exit +! 20053062/ brw 2005163a +Replace/Instruction 13062 = 'MOVAL B^00013062,W^0080(R9)' +'BRW 0001163A' ! 20053062 +Exit +! 13. Test 47 [200536c3] - verify refresh - run from ROM +! 200552aa/ 0 +Replace/Byte 152AA = 3 +0 ! 200552AA +Exit +! 12. Test 41 [] - count bad pages, relocate bit map +! 11. Test 44 [20050d34] - L1 with memory - bypass +! 20050d34/ brw 20050fca +Replace/Instruction 10D34 = 'MOVAL B^00010D34,W^0080(R9)' +'BRW 00010FCA' ! 20050D34 +Exit +! 10. Test 36 [2004ffdf] - L2 with memory - bypass +! 2004ffdf/ brw 20050428 +Replace/Instruction 0FFDF = 'JSB L^0000CEFD' +'BRW 00010428' ! 2004FFDF +Exit +! 9. Test 80 [2004d7de] - CQBIC memory - bypass last 2 subtests, run from ROM +! 2004dbc0/ brw 2004dd8a +Replace/Instruction 0DBC0 = 'MOVB #1B,B^76(R9)' +'BRW 0000DD8A' ! 2004DBC0 +Exit +! 200552f6/ 0 +Replace/Byte 152F6 = 3 +0 ! 200552F6 +Exit +! 8. Test 54 [] - virtual mode - ok +! 7. Test 34 [] - ROM in virtual mode - see previous notes +! 6. Test C5 [] - SSC registers in virtual mode - ok +! 5. Test 45 [2004ec5d] - cache, memory, CQBIC - bypass +! 2004ec5d/ brw 2004ee90 +Replace/Instruction 0EC5D = 'BICL2 #03,B^28(R9)' +'BRW 0000EE90' ! 2004EC5D +Exit +! 4. Test 5A [2004eb5f] - CVAX CMCTL DAL drivers - ok +! 3. Test 41 [20051096] - reset board +! +! =========================================================================== +! +! +! All of the above patches were done against the base ROM image extracted +! from a genuine MicroVAX 3900. These were all part of SIMH prior to +! extended memory support. +! +! The Diagnostic State Variable DST$W_BITMAP_LENGTH, being 16 bits, can only +! describe a PFN Bitmap describing up to, but NOT including 256MB of RAM. To +! get to 256MB and beyond, we must correctly determine a correct bitmap size. +! all of the Diagnostic state space is in use, either since it is already +! defined, and the space beyond that is used for stack. So, we change the +! references to DST$W_BITMAP_LENGTH to call a subroutine to properly determine +! the PFN BITMAP size. +! +! Most of the code which references DST$W_BITMAP_LENGTH are done from a +! diagnostic test routine which may be relocated to RAM before execution. +! The assumption of such relocating activity is that none of the relocated code +! references any other instructions or data in the ROM image via any PC +! relative addressing modes. Given this requirement, each of the above +! patches must be done with a JSB to an explicit ROM address. As a +! consequence, the patched instruction will generally be longer than the +! instruction which is being replaced. To cleanly affect this +! we must overwrite multiple instructions and incorporate the activities of +! each of the overwritten instructions into the target subroutine. +! Additionally, even without the relocation concerns, numerous places which +! reference these extra routines may be beyond a PC relative displacement +! due to the size of the ROM. +! +! The KA655 ROM size is 128KB. As it turns out, the ROM image is only using +! approximately 105,136 bytes of the total 131072 bytes. We use this unused +! ROM space to store code which implements the required extra functionality +! +Define PATCH_BASE = 00019C00 +Define P$END = PATCH_BASE +Define CP$K_MEMSIZE = 20080148 +Define CP$K_QBMBR = 20080010 +Define DST_BASE = 20140758 +Define CTX_BASE = 201404B2 +Define CTX$L_R2 = 8 +Define CTX$A_GPTR = 66 +Define CTX$L_ERROR_COUNT = 54 +Define CTX$L_ERROR_STATUS = 58 +Define DST$W_BITMAP_LENGTH = 20 +Define DST$A_BITMAP = 1C +Define DST$A_BUSMAP = 24 +Define DST$W_BITMAP_CHECKSUM = 22 +Define CP$CHECKSUM_RTN = 20041C6A +Define GUARD$S_GUARD_BLOCK = 12 +Define GUARD$l_pc = 0 +Define GUARD$a_gptr = 4 +Define GUARD$w_rmask = 8 +Define GUARD$l_save_error_count = 0A +Define GUARD$l_save_error_status = 0E +! +! This routine determines the memory size of the current system. This is +! done by referencing the CMCTL18 memory size register. On an older simulator +! or one with less than 64MB of RAM configured, this register may not exist. +! If it doesn't exist the machine check generated by the reference to the +! non-existant register is caught, and the appropriate memory size is +! determined from the existing PFN Bitmap size. +! +DEFINE GETMEMSIZE_R0 = P$End+1 +Deposit/Instruction GETMEMSIZE_R0 +' pushr #0 ' +' subl2 #guard$s_guard_block, sp' +' movw #0, B^guard$w_rmask (sp)' +' movab B^G$ERR, B^guard$l_pc (sp)' +' movl @#, B^guard$a_gptr (sp)' +' movl @#, B^guard$l_save_error_count (sp)' +' movl @#, B^guard$l_save_error_status (sp)' +' movl sp, @#' +' brb G$RD ' +'G$ERR: movzwl @#,R0' +' clrl @#' +' clrl @#' +' ashl #^d12,r0,r0 ' +' brb G$DON ' +'G$RD: movl @#CP$K_MEMSIZE,R0 ' +'G$DON: movl @#, sp' +' movl B^guard$a_gptr (sp), @#' +' movl B^guard$l_save_error_count (sp), @#' +' movl B^guard$l_save_error_status (sp), @#' +' addl2 #guard$s_guard_block - 2, sp' +' popr (sp)+ ' +'P$End: rsb ' +Exit +! +Define GETMAPENDADDR_R6 = P$End+1 +Deposit/Instruction GETMAPENDADDR_R6 +' MOVZWL @#,R6' +' BNEQ X$1 ' +' MOVL R0, -(SP) ' +' JSB GETMEMSIZE_R0 ' +' ashl #-^D12,R0,R6 ' +' MOVL (SP)+, R0 ' +'X$1: addl @#,R6' +'P$End: rsb ' +Exit + +! DE_QDSS_ANY [2004E2A8] Uses R6 for BitMap Size +! 2004E390/ BSBW GETMAPSIZE_R6 +Replace/Instruction 0E390 +' MOVZWL B^20(R9),R6 ' +' ADDL3 R6,B^1C(R9),R6 ' +Exit +' JSB GETMAPENDADDR_R6 ' +Exit +! +! +DEFINE GETMAPSIZEMAPADDR_STACK = P$End+1 +Deposit/Instruction GETMAPSIZEMAPADDR_STACK +' PUSHL @#,' +' MOVL B^4(SP),-(SP) ' +' MOVZWL @#,B^8(SP)' +' BNEQ X$2' +' MOVL R0, -(SP) ' +' JSB GETMEMSIZE_R0 ' +' ASHL #-^D12,R0,B^0C(SP) ' +' MOVL (SP)+, R0 ' +'X$2: NOP ' +'P$END: RSB' +Exit + +! CP_FIND [200419E8] Uses (SP) for BitMap Size R1 Scratch +! 20041A16/ BSBW GETMAPSIZE_STACK +Replace/Instruction 01A16 +' MOVZWL B^20(R0),-(SP) ' +' PUSHL B^1C(R0) ' +Exit +' JSB GETMAPSIZEMAPADDR_STACK ' +Exit +! +! CP_SCAN [200459D0] Uses R3 for BitMap Size +DEFINE GETMBMEMSIZE_STACK = P$End+1 +Deposit/Instruction GETMBMEMSIZE_STACK +' MOVAB L^0000AACF,-(SP) ' +' MOVL B^4(SP),-(SP) ' +' MOVL R0, -(SP) ' +' JSB GETMEMSIZE_R0 ' +' ASHL #-^D20,R0,B^0C(SP) ' +' MOVL (SP)+, R0 ' +' RSB ' +'GETMAPSIZE_R3: MOVZWL @#,R3' +' BNEQ X$3' +' MOVL R0, -(SP) ' +' JSB GETMEMSIZE_R0 ' +' ASHL #-^D12,R0,R3 ' +' MOVL (SP)+, R0 ' +'X$3: RSB' +'P$END: NOP' +Exit +! 20045B05/ BSBW GETMBMEMSIZE_STACK +Replace/Instruction 05B05 +' MOVL R8,-(SP) ' +' MOVAB L^0000AACF,-(SP) ' +Exit +' JSB GETMBMEMSIZE_STACK ' +Exit +! 20045B80/ BSBW GETMAPSIZE_R3 +Replace/Instruction 05B80 +' MOVZWL @#20140778,R3 ' +Exit +' JSB GETMAPSIZE_R3 ' +Exit +! DE_CQBIC_MEMORY [2004D7B2] +DEFINE GETBITMAPPAGES_R5 = P$End+1 +Deposit/Instruction GETBITMAPPAGES_R5 +' MOVZWL @#,R5' +' BNEQ X$4 ' +' MOVL R0,-(SP) ' +' JSB GETMEMSIZE_R0 ' +' ASHL #-^D12,R0,R5 ' +' MOVL (SP)+,R0 ' +'X$4: ASHL #3,R5,R5 ' +' RSB ' +'GETBITMAPMEMSIZE_R3: MOVZWL @#,R3' +' BNEQ X$5 ' +' MOVL R0,-(SP) ' +' JSB GETMEMSIZE_R0 ' +' ASHL #-^D12,R0,R3 ' +' MOVL (SP)+,R0 ' +'X$5: ASHL #^D12,R3,R3 ' +'P$END: RSB' +Exit +! 2004D8A5/ BSBW GETMAPSIZE_R5 +Replace/Instruction 0D8A5 +' MOVZWL B^20(R9),R5 ' +' ASHL #03,R5,R5 ' +Exit +' JSB GETBITMAPPAGES_R5 ' +Exit +! 2004DA41/ BSBW GETMAPSIZE_R5 +Replace/Instruction 0DA41 +' MOVZWL B^20(R9),R5 ' +' ASHL #03,R5,R5 ' +Exit +' JSB GETBITMAPPAGES_R5 ' +Exit +! 2004DA8C/ BSBW GETMAPSIZE_R5 +Replace/Instruction 0DA8C +' MOVZWL B^20(R9),R5 ' +' ASHL #03,R5,R5 ' +Exit +' JSB GETBITMAPPAGES_R5 ' +Exit +! DE_CACHE_MEM_CQBIC [2004EBF0] +! 2004ECD0/ BSBW GETMAPSIZE_R3 +Replace/Instruction 0ECD0 +' MOVZWL B^20(R9),R3 ' +' ASHL #0C,R3,R3 ' +Exit +' JSB GETBITMAPMEMSIZE_R3 ' +Exit +! CP_BOOTSTRAP +DEFINE GET_X_PFNMAP_SIZEADDR_STACK = P$End+1 +Deposit/Instruction GET_X_PFNMAP_SIZEADDR_STACK +' movl B^dst$a_bitmap (r11), r2' +' movzwl B^dst$w_bitmap_length (r11), r1' +' bneq X$20 ' ! Zero Bitmap size means extended mem +' ashl #-^D12, @#CP$K_MEMSIZE, r1' ! Map Size = MEMSIZE/512/8 +'X$10: brw X$70 ' ! already fixed +'X$20: cmpl r1, #^D16384 ' ! Original Map of 64MB? +' blss X$10 ' ! Too Small For Extended +' JSB GETMEMSIZE_R0 ' +' ashl #-^D12, R0, r1 ' ! Map Size = MEMSIZE/512/8 +' cmpl r1, #^D16384 ' +' beql X$10 ' ! Normal 64MB map +!; +!; First move the Console Scratch Area (16KB), and the Qbus Map (32KB) +!; to the end of physical memory. +!; +' movl @#CP$K_MEMSIZE, r1 ' ! MEMSIZE +' subl3 #^D48*^D1024, r1, r3 ' ! New Destination Address +' addl #^D16384, r2 ' ! Point at end of prior Map +' clrl r0 ' ! Index +'X$63: movb (r2)[r0], (r3)[r0] ' ! Move the Console Scratch Pad and QBMRs +' aoblss #^D48*^D1024, r0, X$63 ' +' movab W^4000(r3), B^DST$A_BUSMAP(r11)' ! Save Qbus Map Register Space +' movab W^4000(r3), @#CP$K_QBMBR' ! Save Qbus Map Register Space +!; +!; Fixup the boot device descriptor previously saved in the scratchpad RAM +!; +' subl3 #^D512, B^DST$A_BUSMAP (r11), r1' +' movab B^8(r1), B^4(r1)' +!; +!; Now we build a new bitmap, with all bits set except for the reserved +!; area containing the bitmap itself, and the console scratch area and +!; the Qbus Map. +!; +' ashl #-^D12, @#CP$K_MEMSIZE, r1' ! Map Size = MEMSIZE/512/8 +' subl3 r1, r3, r2 ' ! Point at new Destination Address +' movl r2, B^dst$a_bitmap (r11)' ! Save Bitmap address +' ashl #-9, @#CP$K_MEMSIZE, r1 ' ! PFN count = MEMSIZE/512 +' ashl #-^D12, @#CP$K_MEMSIZE, r0' ! Map Size = MEMSIZE/512/8 +' addl #^D48*^D1024+^D511, r0 ' ! Plus other reserved page size +' ashl #-9, r0, r0 ' +' subl r0, r1 ' ! Adjust for bitmap of reserved pages +' clrl r0 ' +' pushl r1 ' ! Save total Bit Count +' ashl #-5, r1, r1 ' ! Convert limit to Longword Count +'X$632: movl #-1,(r2)[r0] ' ! Set bitmap entry for 32 pages +' aoblss r1, r0, X$632 ' +' ashl #5, r0, r0 ' ! Convert back to Bit Count +' movl (SP)+, r1 ' ! Restore total Bit Count +' cmpl r0, r1' +' bgeq X$651' +'X$64: bbss r0, (r2), X$65 ' ! Set page bitmap entry +'X$65: aoblss r1, r0, X$64 ' ! Done ? +'X$651: ashl #-9, @#CP$K_MEMSIZE, r1 ' ! PFN count = MEMSIZE/512 +'X$66: bbcc r0, (r2), X$67 ' ! Clear reserved page bitmap entry +'X$67: aoblss r1, r0, X$66 ' ! Done? +' clrl r0 ' ! Zero Initial checksum value +' ashl #-^D12, @#CP$K_MEMSIZE, r1' ! Map Size = MEMSIZE/512/8 +' jsb @#cp$checksum_rtn ' ! Compute checksum for revised bitmap +' movw r0, B^dst$w_bitmap_checksum (r11)' ! save it +' clrw B^dst$w_bitmap_length (r11)' ! Mark as extended bitmap +' ashl #-^D12, @#CP$K_MEMSIZE, r1' ! Map Size = MEMSIZE/512/8 +' movl B^dst$a_bitmap (r11), r2' +'X$70: jmp GETMAPSIZEMAPADDR_STACK' +! +'GETMAPSIZE_CTX_R2: movzwl @#,@#' +' bneq X$71' +' MOVL R0, -(SP) ' +' JSB GETMEMSIZE_R0 ' +' ASHL #-^D12,R0,@#' +' MOVL (SP)+, R0 ' +'X$71: rsb' +Exit +Replace/Instruction 517F = 'movzwl B^20(r11), @#201404BA' +' jsb GETMAPSIZE_CTX_R2 ' +Exit +Replace/Instruction 514B +' MOVZWL B^20(R11),-(SP) ' +' PUSHL B^1C(R11) ' +Exit +' JSB GET_X_PFNMAP_SIZEADDR_STACK' +Exit +! +! DE_MEMORY [200512AC] +! CP_UTIL [] +! +! Identify the Extended Memory Mode in the Console Banner +! (i.e. KA655X-B vs KA655-B) +! +Replace 83D8 = 00303436 +58353536 +Exit +Replace/Byte 83DC = 4B +0 +Exit +Deposit/Instruction 1C04 +' PUSHAB L^000083E2 ' +' JSB GETMEMSIZE_R0 ' +' CMPL R0, #<^D64*^D1024*^D1024>' +' BLEQ B$1 ' +' MOVAB L^000083D6,(SP) ' +'B$1: NOP ' +' NOP ' +' NOP ' +' NOP ' +' NOP ' +' NOP ' +' NOP ' +' NOP ' +' NOP ' +Exit +! +! Extended Memory Patches: +! 9. Test 80 [2004d7de] - CQBIC memory - bypass last 2 subtests, run from ROM +! MP Revised to bypass tests starting at test of NXM reference through MAP +! 2004db2e/ brw 2004dd8a +Replace/Instruction 0db2e = 'MOVB #17,B^76(R9)' +'BRW 0DD8A' +EXIT +! +! Interval Timer Patch +! In operational environments, Test 82 subtests 17 and 20 have been observed +! to ocaisionally fail. Disable the timer portion of the interval timer tests. +! 2004e7c1/ brw 2004e870 +Replace/Instruction 0e7c1 = 'MOVB #10,B^76(R9)' +'BRW 0e870' +EXIT +! +UPDATE +EXIT +$ diff --git a/VAX/ka655x.bin b/VAX/ka655x.bin index d15f41da..ade93ab7 100644 Binary files a/VAX/ka655x.bin and b/VAX/ka655x.bin differ diff --git a/VAX/ka655x.bin_old b/VAX/ka655x.bin_old new file mode 100644 index 00000000..d15f41da Binary files /dev/null and b/VAX/ka655x.bin_old differ diff --git a/VAX/vax780_bugs.txt b/VAX/vax780_bug_history.txt similarity index 96% rename from VAX/vax780_bugs.txt rename to VAX/vax780_bug_history.txt index 9c75193b..a8f4aa32 100644 --- a/VAX/vax780_bugs.txt +++ b/VAX/vax780_bug_history.txt @@ -1,3 +1,5 @@ +Bugs Found And Fixed During Simulator Debug + 1. RP: drive clear does not clear RPDA. 2. TU: default formatter must be TM03. 3. SBI: drive 'letter' is actually a 1-based number. diff --git a/VAX/vax780_defs.h b/VAX/vax780_defs.h index b5abed71..82c03931 100644 --- a/VAX/vax780_defs.h +++ b/VAX/vax780_defs.h @@ -404,6 +404,22 @@ typedef struct { #define BOOT_UDA 17 #define BOOT_TK 18 +/* Function prototypes for virtual memory interface */ + +int32 Read (uint32 va, int32 lnt, int32 acc); +void Write (uint32 va, int32 val, int32 lnt, int32 acc); + +/* Function prototypes for physical memory interface (inlined) */ + +SIM_INLINE int32 ReadB (uint32 pa); +SIM_INLINE int32 ReadW (uint32 pa); +SIM_INLINE int32 ReadL (uint32 pa); +SIM_INLINE int32 ReadLP (uint32 pa); +SIM_INLINE void WriteB (uint32 pa, int32 val); +SIM_INLINE void WriteW (uint32 pa, int32 val); +SIM_INLINE void WriteL (uint32 pa, int32 val); +void WriteLP (uint32 pa, int32 val); + /* Function prototypes for I/O */ int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf); diff --git a/VAX/vax780_fload.c b/VAX/vax780_fload.c index c4a444dd..c74e3f93 100644 --- a/VAX/vax780_fload.c +++ b/VAX/vax780_fload.c @@ -1,6 +1,6 @@ /* vax780_fload.c: VAX780 FLOAD command - Copyright (c) 2006, Robert M Supnik + Copyright (c) 2006-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -37,6 +37,8 @@ -- Assebmbly language routines added for BIOS calls etc. Thanks to Phil Budne for the original adaptation of RT11 to SimH. + + 28-May-08 RMS Inlined physical memory routines */ #include "vax_defs.h" @@ -84,8 +86,6 @@ uint32 rtfile_ator50 (uint32 ascii); t_bool rtfile_read (uint32 block, uint32 count, uint16 *buffer); uint32 rtfile_find (uint32 block, uint32 sector); -extern void WriteW (uint32 pa, int32 val); - /* FLOAD file_name {file_origin} */ t_stat vax780_fload (int flag, char *cptr) diff --git a/VAX/vax780_mba.c b/VAX/vax780_mba.c index 9a05a68d..b7cd550c 100644 --- a/VAX/vax780_mba.c +++ b/VAX/vax780_mba.c @@ -1,6 +1,6 @@ /* vax780_mba.c: VAX 11/780 Massbus adapter - Copyright (c) 2004-2005, Robert M Supnik + Copyright (c) 2004-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -24,6 +24,8 @@ in this Software without prior written authorization from Robert M Supnik. mba0, mba1 RH780 Massbus adapter + + 28-May-08 RMS Inlined physical memory routines */ #include "vax_defs.h" @@ -171,13 +173,6 @@ void mba_clr_int (uint32 mb); void mba_upd_sr (uint32 set, uint32 clr, uint32 mb); DIB mba0_dib, mba1_dib; -extern int32 ReadB (uint32 pa); -extern int32 ReadW (uint32 pa); -extern int32 ReadL (uint32 pa); -extern void WriteB (uint32 pa, int32 val); -extern void WriteW (uint32 pa, int32 val); -extern void WriteL (uint32 pa, int32 val); - /* Massbus register dispatches */ static t_stat (*mbregR[MBA_NUM])(int32 *dat, int32 ad, int32 md); diff --git a/VAX/vax780_sbi.c b/VAX/vax780_sbi.c index 6738caea..be7088fb 100644 --- a/VAX/vax780_sbi.c +++ b/VAX/vax780_sbi.c @@ -1,6 +1,6 @@ /* vax780_sbi.c: VAX 11/780 SBI - Copyright (c) 2004-2006, Robert M Supnik + Copyright (c) 2004-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -27,7 +27,9 @@ sbi bus controller + 31-May-2008 RMS Fixed machine_check calling sequence (found by Peter Schorn) 03-May-2006 RMS Fixed writes to ACCS + 28-May-08 RMS Inlined physical memory routines */ #include "vax_defs.h" @@ -132,7 +134,6 @@ void uba_eval_int (void); t_stat vax780_boot (int32 flag, char *ptr); extern t_stat vax780_fload (int flag, char *cptr); -extern void Write (uint32 va, int32 val, int32 lnt, int32 acc); extern int32 intexc (int32 vec, int32 cc, int32 ipl, int ei); extern int32 iccs_rd (void); extern int32 nicr_rd (void); @@ -151,7 +152,6 @@ extern void init_mbus_tab (void); extern void init_ubus_tab (void); extern t_stat build_mbus_tab (DEVICE *dptr, DIB *dibp); extern t_stat build_ubus_tab (DEVICE *dptr, DIB *dibp); -extern void WriteLP (uint32 pa, int32 val); /* SBI data structures @@ -548,7 +548,7 @@ return; Rest will be zero */ -int32 machine_check (int32 p1, int32 opc, int32 cc) +int32 machine_check (int32 p1, int32 opc, int32 cc, int32 delta) { int32 acc, err; diff --git a/VAX/vax780_uba.c b/VAX/vax780_uba.c index 02822129..206e059a 100644 --- a/VAX/vax780_uba.c +++ b/VAX/vax780_uba.c @@ -1,6 +1,6 @@ /* vax780_uba.c: VAX 11/780 Unibus adapter - Copyright (c) 2004-2005, Robert M Supnik + Copyright (c) 2004-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -24,6 +24,9 @@ in this Software without prior written authorization from Robert M Supnik. uba DW780 Unibus adapter + + 28-May-08 RMS Inlined physical memory routines + 25-Jan-08 RMS Fixed declarations (from Mark Pizzolato) */ #include "vax_defs.h" @@ -200,12 +203,6 @@ t_stat show_autocon (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat uba_show_virt (FILE *st, UNIT *uptr, int32 val, void *desc); -extern int32 ReadB (uint32 pa); -extern int32 ReadW (uint32 pa); -extern int32 ReadL (uint32 pa); -extern void WriteB (uint32 pa, int32 val); -extern void WriteW (uint32 pa, int32 val); -extern void WriteL (uint32 pa, int32 val); extern int32 eval_int (void); extern t_stat build_dib_tab (void); @@ -513,7 +510,7 @@ return; longword of data */ -int32 ReadIO (int32 pa, int32 lnt) +int32 ReadIO (uint32 pa, int32 lnt) { uint32 iod; @@ -541,7 +538,7 @@ return iod; none */ -void WriteIO (int32 pa, int32 val, int32 lnt) +void WriteIO (uint32 pa, int32 val, int32 lnt) { if (lnt == L_BYTE) WriteUb (pa, val, WRITEB); /* byte? DATOB */ else if ((lnt == L_WORD) && ((pa & 1) == 0)) /* aligned word? */ diff --git a/VAX/vax_cis.c b/VAX/vax_cis.c index a481cea5..e8b3c90d 100644 --- a/VAX/vax_cis.c +++ b/VAX/vax_cis.c @@ -1,6 +1,6 @@ /* vax_cis.c: VAX CIS instructions - Copyright (c) 2004-2005, Robert M Supnik + Copyright (c) 2004-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,7 @@ On a full VAX, this module simulates the VAX commercial instruction set (CIS). On a subset VAX, this module implements the emulated instruction fault. + 28-May-08 RMS Inlined physical memory routines 16-May-06 RMS Fixed bug in length calculation (found by Tim Stark) 03-May-06 RMS Fixed MOVTC, MOVTUC to preserve cc's through page faults Fixed MOVTUC to stop on translated == escape @@ -99,8 +100,6 @@ int32 edit_read_src (int32 inc, int32 acc); void edit_adv_src (int32 inc); int32 edit_read_sign (int32 acc); -extern int32 Read (uint32 va, int32 lnt, int32 acc); -extern void Write (uint32 va, int32 val, int32 lnt, int32 acc); extern int32 eval_int (void); /* CIS emulator */ @@ -1614,10 +1613,6 @@ extern int32 pcq[PCQ_SIZE]; extern int32 pcq_p; extern jmp_buf save_env; -extern int32 Read (uint32 va, int32 lnt, int32 acc); -extern void Write (uint32 va, int32 val, int32 lnt, int32 acc); -extern int32 ReadLP (uint32 pa); - /* CIS instructions - invoke emulator interface opnd[0:5] = six operands to be pushed (if PSL = 0) diff --git a/VAX/vax_cmode.c b/VAX/vax_cmode.c index a8e7a3dc..b48fb7ea 100644 --- a/VAX/vax_cmode.c +++ b/VAX/vax_cmode.c @@ -1,6 +1,6 @@ /* vax_cmode.c: VAX compatibility mode - Copyright (c) 2004-2006, Robert M Supnik + Copyright (c) 2004-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,8 @@ On a full VAX, this module implements PDP-11 compatibility mode. On a subset VAX, this module forces a fault if REI attempts to set PSL. + 28-May-08 RMS Inlined physical memory routines + 25-Jan-08 RMS Fixed declaration (from Mark Pizzolato) 03-May-06 RMS Fixed omission of SXT Fixed order of operand fetching in XOR 24-Aug-04 RMS Cloned from PDP-11 CPU @@ -58,10 +60,7 @@ extern int32 pcq[]; extern int32 pcq_p; extern int32 ibcnt, ppc; extern int32 sim_interval; -extern int32 sim_brk_summ; - -extern int32 Read (uint32 va, int32 lnt, int32 access); -extern void Write (uint32 va, int32 val, int32 lnt, int32 access); +extern uint32 sim_brk_summ; extern jmp_buf save_env; int32 GeteaB (int32 spec); diff --git a/VAX/vax_cpu.c b/VAX/vax_cpu.c index bb333c03..ec0e4ba7 100644 --- a/VAX/vax_cpu.c +++ b/VAX/vax_cpu.c @@ -1,6 +1,6 @@ /* vax_cpu.c: VAX CPU - Copyright (c) 1998-2007, Robert M Supnik + Copyright (c) 1998-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ cpu VAX central processor + 28-May-08 RMS Inlined instruction prefetch, physical memory routines 13-Aug-07 RMS Fixed bug in read access g-format indexed specifiers 28-Apr-07 RMS Removed clock initialization 29-Oct-06 RMS Added idle support @@ -350,11 +351,6 @@ extern int32 op_cmode (int32 cc); extern int32 op_cis (int32 *opnd, int32 cc, int32 opc, int32 acc); extern int32 op_octa (int32 *opnd, int32 cc, int32 opc, int32 acc, int32 spec, int32 va); extern int32 intexc (int32 vec, int32 cc, int32 ipl, int ei); -extern int32 Read (uint32 va, int32 lnt, int32 acc); -extern void Write (uint32 va, int32 val, int32 lnt, int32 acc); -extern int32 ReadB (uint32 pa); -extern void WriteB (uint32 pa, int32 val); -extern int32 ReadLP (uint32 pa); extern int32 Test (uint32 va, int32 acc, int32 *status); extern int32 BadCmPSL (int32 newpsl); extern int32 eval_int (void); @@ -376,7 +372,7 @@ t_stat cpu_show_virt (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat cpu_set_idle (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cpu_show_idle (FILE *st, UNIT *uptr, int32 val, void *desc); int32 cpu_get_vsw (int32 sw); -int32 get_istr (int32 lnt, int32 acc); +SIM_INLINE int32 get_istr (int32 lnt, int32 acc); int32 ReadOcta (int32 va, int32 *opnd, int32 j, int32 acc); t_bool cpu_show_opnd (FILE *st, InstHistory *h, int32 line); int32 cpu_psl_ipl_idle (int32 newpsl); @@ -2919,7 +2915,7 @@ ABORT (STOP_UNKNOWN); so any translation errors are real. */ -int32 get_istr (int32 lnt, int32 acc) +SIM_INLINE int32 get_istr (int32 lnt, int32 acc) { int32 bo = PC & 3; int32 sc, val, t; diff --git a/VAX/vax_cpu1.c b/VAX/vax_cpu1.c index 186f6dbb..d0ba90cf 100644 --- a/VAX/vax_cpu1.c +++ b/VAX/vax_cpu1.c @@ -1,6 +1,6 @@ /* vax_cpu1.c: VAX complex instructions - Copyright (c) 1998-2007, Robert M Supnik + Copyright (c) 1998-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 28-May-08 RMS Inlined physical memory routines 29-Apr-07 RMS Separated base register access checks for 11/780 10-May-06 RMS Added access check on system PTE for 11/780 Added mbz check in LDPCTX for 11/780 @@ -100,11 +101,7 @@ extern int32 ibcnt, ppc; extern FILE *sim_deb; extern DEVICE cpu_dev; -extern int32 Read (uint32 va, int32 lnt, int32 acc); -extern void Write (uint32 va, int32 val, int32 lnt, int32 acc); extern int32 Test (uint32 va, int32 acc, int32 *status); -extern int32 ReadLP (uint32 pa); -extern void WriteLP (uint32 pa, int32 val); extern void set_map_reg (void); extern void zap_tb (int stb); extern void zap_tb_ent (uint32 va); diff --git a/VAX/vax_fpa.c b/VAX/vax_fpa.c index b43416b3..5dea5ad2 100644 --- a/VAX/vax_fpa.c +++ b/VAX/vax_fpa.c @@ -1,6 +1,6 @@ /* vax_fpa.c - VAX f_, d_, g_floating instructions - Copyright (c) 1998-2006, Robert M Supnik + Copyright (c) 1998-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 28-May-08 RMS Inlined physical memory routines 16-May-06 RMS Fixed bug in 32b floating multiply routine Fixed bug in 64b extended modulus routine 03-May-06 RMS Fixed POLYD, POLYG to clear R4, R5 @@ -59,8 +60,6 @@ extern int32 PSL; extern int32 p1; extern jmp_buf save_env; -extern int32 Read (uint32 va, int32 size, int32 acc); - #if defined (USE_INT64) #define M64 0xFFFFFFFFFFFFFFFF /* 64b */ diff --git a/VAX/vax_io.c b/VAX/vax_io.c index b385a7a9..c8ebf2d4 100644 --- a/VAX/vax_io.c +++ b/VAX/vax_io.c @@ -1,6 +1,6 @@ /* vax_io.c: VAX 3900 Qbus IO simulator - Copyright (c) 1998-2005, Robert M Supnik + Copyright (c) 1998-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,8 @@ qba Qbus adapter + 28-May-08 RMS Inlined physical memory routines + 25-Jan-08 RMS Fixed declarations (from Mark Pizzolato) 03-Dec-05 RMS Added SHOW QBA VIRT and ex/dep via map 05-Oct-05 RMS Fixed bug in autoconfiguration (missing XU) 25-Jul-05 RMS Revised autoconfiguration algorithm and interface @@ -116,13 +118,6 @@ extern int32 ssc_bto; extern jmp_buf save_env; extern int32 sim_switches; extern DEVICE *sim_devices[]; - -extern int32 ReadB (uint32 pa); -extern int32 ReadW (uint32 pa); -extern int32 ReadL (uint32 pa); -extern void WriteB (uint32 pa, int32 val); -extern void WriteW (uint32 pa, int32 val); -extern void WriteL (uint32 pa, int32 val); extern FILE *sim_log; t_stat dbl_rd (int32 *data, int32 addr, int32 access); @@ -243,7 +238,7 @@ return; longword of data */ -int32 ReadIO (int32 pa, int32 lnt) +int32 ReadIO (uint32 pa, int32 lnt) { int32 iod; @@ -264,7 +259,7 @@ return iod; none */ -void WriteIO (int32 pa, int32 val, int32 lnt) +void WriteIO (uint32 pa, int32 val, int32 lnt) { if (lnt == L_BYTE) WriteQb (pa, val, WRITEB); else if (lnt == L_WORD) WriteQb (pa, val, WRITE); diff --git a/VAX/vax_mmu.c b/VAX/vax_mmu.c index 1a4be293..be4ff63c 100644 --- a/VAX/vax_mmu.c +++ b/VAX/vax_mmu.c @@ -1,6 +1,6 @@ /* vax_mmu.c - VAX memory management - Copyright (c) 1998-2007, Robert M Supnik + Copyright (c) 1998-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 28-May-08 RMS Inlined physical memory routines 29-Apr-07 RMS Added address masking for system page table reads 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) 30-Sep-04 RMS Comment and formating changes @@ -101,14 +102,6 @@ t_stat tlb_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat tlb_reset (DEVICE *dptr); TLBENT fill (uint32 va, int32 lnt, int32 acc, int32 *stat); -int32 ReadB (uint32 pa); -void WriteB (uint32 pa, int32 val); -int32 ReadW (uint32 pa); -void WriteW (uint32 pa, int32 val); -int32 ReadL (uint32 pa); -void WriteL (uint32 pa, int32 val); -int32 ReadLP (uint32 pa); -void WriteLP (uint32 pa, int32 val); extern int32 ReadIO (uint32 pa, int32 lnt); extern void WriteIO (uint32 pa, int32 val, int32 lnt); extern int32 ReadReg (uint32 pa, int32 lnt); @@ -313,7 +306,7 @@ return va & PAMASK; /* ret phys addr */ returned data, right justified in 32b longword */ -int32 ReadB (uint32 pa) +SIM_INLINE int32 ReadB (uint32 pa) { int32 dat; @@ -326,7 +319,7 @@ else { return ((dat >> ((pa & 3) << 3)) & BMASK); } -int32 ReadW (uint32 pa) +SIM_INLINE int32 ReadW (uint32 pa) { int32 dat; @@ -339,7 +332,7 @@ else { return ((dat >> ((pa & 2)? 16: 0)) & WMASK); } -int32 ReadL (uint32 pa) +SIM_INLINE int32 ReadL (uint32 pa) { if (ADDR_IS_MEM (pa)) return M[pa >> 2]; mchk_ref = REF_V; @@ -347,7 +340,7 @@ if (ADDR_IS_IO (pa)) return ReadIO (pa, L_LONG); return ReadReg (pa, L_LONG); } -int32 ReadLP (uint32 pa) +SIM_INLINE int32 ReadLP (uint32 pa) { if (ADDR_IS_MEM (pa)) return M[pa >> 2]; mchk_va = pa; @@ -365,7 +358,7 @@ return ReadReg (pa, L_LONG); none */ -void WriteB (uint32 pa, int32 val) +SIM_INLINE void WriteB (uint32 pa, int32 val) { if (ADDR_IS_MEM (pa)) { int32 id = pa >> 2; @@ -381,7 +374,7 @@ else { return; } -void WriteW (uint32 pa, int32 val) +SIM_INLINE void WriteW (uint32 pa, int32 val) { if (ADDR_IS_MEM (pa)) { int32 id = pa >> 2; @@ -396,7 +389,7 @@ else { return; } -void WriteL (uint32 pa, int32 val) +SIM_INLINE void WriteL (uint32 pa, int32 val) { if (ADDR_IS_MEM (pa)) M[pa >> 2] = val; else { diff --git a/VAX/vax_octa.c b/VAX/vax_octa.c index 65e37f55..bbed2a7d 100644 --- a/VAX/vax_octa.c +++ b/VAX/vax_octa.c @@ -1,6 +1,6 @@ /* vax_octa.c - VAX octaword and h_floating instructions - Copyright (c) 2004-2006, Robert M Supnik + Copyright (c) 2004-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ This module simulates the VAX h_floating instruction set. + 28-May-08 RMS Inlined physical memory routines 10-May-06 RMS Fixed bug in reported VA on faulting cross-page write 03-May-06 RMS Fixed MNEGH to test negated sign, clear C Fixed carry propagation in qp_inc, qp_neg, qp_add @@ -50,8 +51,6 @@ extern int32 trpirq; extern int32 p1; extern jmp_buf save_env; -extern int32 Read (uint32 va, int32 size, int32 acc); -extern void Write (uint32 va, int32 val, int32 lnt, int32 acc); extern int32 Test (uint32 va, int32 acc, int32 *status); #define WORDSWAP(x) ((((x) & WMASK) << 16) | (((x) >> 16) & WMASK)) diff --git a/VAX/vax_sysdev.c b/VAX/vax_sysdev.c index a5896e58..3940f925 100644 --- a/VAX/vax_sysdev.c +++ b/VAX/vax_sysdev.c @@ -254,7 +254,6 @@ int32 tmr1_inta (void); int32 parity (int32 val, int32 odd); t_stat sysd_powerup (void); -extern void Write (uint32 va, int32 val, int32 lnt, int32 acc); extern int32 intexc (int32 vec, int32 cc, int32 ipl, int ei); extern int32 cqmap_rd (int32 pa); extern void cqmap_wr (int32 pa, int32 val, int32 lnt); diff --git a/VAX/vaxmod_defs.h b/VAX/vaxmod_defs.h index f808c396..6dc06dae 100644 --- a/VAX/vaxmod_defs.h +++ b/VAX/vaxmod_defs.h @@ -441,6 +441,22 @@ typedef struct { #define LOG_CPU_R 0x2 /* REI */ #define LOG_CPU_P 0x4 /* context */ +/* Function prototypes for virtual memory interface */ + +int32 Read (uint32 va, int32 lnt, int32 acc); +void Write (uint32 va, int32 val, int32 lnt, int32 acc); + +/* Function prototypes for physical memory interface (inlined) */ + +SIM_INLINE int32 ReadB (uint32 pa); +SIM_INLINE int32 ReadW (uint32 pa); +SIM_INLINE int32 ReadL (uint32 pa); +SIM_INLINE int32 ReadLP (uint32 pa); +SIM_INLINE void WriteB (uint32 pa, int32 val); +SIM_INLINE void WriteW (uint32 pa, int32 val); +SIM_INLINE void WriteL (uint32 pa, int32 val); +void WriteLP (uint32 pa, int32 val); + /* Function prototypes for I/O */ int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf); diff --git a/descrip.mms b/descrip.mms index 8691cadb..6f92ee2e 100644 --- a/descrip.mms +++ b/descrip.mms @@ -183,12 +183,20 @@ ALTAIR_OPTIONS = /INCL=($(SIMH_DIR),$(ALTAIR_DIR))/DEF=($(CC_DEFS)) # ALTAIRZ80_DIR = SYS$DISK:[.ALTAIRZ80] ALTAIRZ80_LIB = $(LIB_DIR)ALTAIRZ80-$(ARCH).OLB -ALTAIRZ80_SOURCE = $(ALTAIRZ80_DIR)ALTAIRZ80_CPU.C,\ - $(ALTAIRZ80_DIR)ALTAIRZ80_DSK.C,\ - $(ALTAIRZ80_DIR)ALTAIRZ80_SIO.C,\ - $(ALTAIRZ80_DIR)ALTAIRZ80_SYS.C,\ - $(ALTAIRZ80_DIR)ALTAIRZ80_HDSK.C,\ - $(ALTAIRZ80_DIR)ALTAIRZ80_NET.C +ALTAIRZ80_SOURCE = $(ALTAIRZ80_DIR)/ALTAIRZ80_CPU.C,$(ALTAIRZ80_DIR)/ALTAIRZ80_CPU_NOMMU.C,\ + $(ALTAIRZ80_DIR)/ALTAIRZ80_DSK.C,$(ALTAIRZ80_DIR)/DISASM.C,\ + $(ALTAIRZ80_DIR)/ALTAIRZ80_SIO.C,$(ALTAIRZ80_DIR)/ALTAIRZ80_SYS.C,\ + $(ALTAIRZ80_DIR)/ALTAIRZ80_HDSK.C,$(ALTAIRZ80_DIR)/ALTAIRZ80_NET.C,\ + $(ALTAIRZ80_DIR)/FLASHWRITER2.C,$(ALTAIRZ80_DIR)/I86_DECODE.C,\ + $(ALTAIRZ80_DIR)/I86_OPS.C,$(ALTAIRZ80_DIR)/I86_PRIM_OPS.C,\ + $(ALTAIRZ80_DIR)/I8272.C,$(ALTAIRZ80_DIR)/INSNSA.C,$(ALTAIRZ80_DIR)/INSNSD.C,\ + $(ALTAIRZ80_DIR)/MFDC.C,$(ALTAIRZ80_DIR)/N8VEM.C,$(ALTAIRZ80_DIR)/VFDHD.C,\ + $(ALTAIRZ80_DIR)/S100_DISK1A.C,$(ALTAIRZ80_DIR)/S100_DISK2.C,\ + $(ALTAIRZ80_DIR)/S100_FIF.C,$(ALTAIRZ80_DIR)/S100_MDRIVEH.C,\ + $(ALTAIRZ80_DIR)/S100_MDSAD.C,$(ALTAIRZ80_DIR)/S100_SELCHAN.C,\ + $(ALTAIRZ80_DIR)/S100_SS1.C,$(ALTAIRZ80_DIR)/S100_64FDC.C,\ + $(ALTAIRZ80_DIR)/S100_SCP300F.C,$(ALTAIRZ80_DIR)/SIM_IMD.C,\ + $(ALTAIRZ80_DIR)/WD179X.C ALTAIRZ80_OPTIONS = /INCL=($(SIMH_DIR),$(ALTAIRZ80_DIR))/DEF=($(CC_DEFS)) # @@ -258,7 +266,9 @@ HP2100_SOURCE = $(HP2100_DIR)HP2100_STDDEV.C,$(HP2100_DIR)HP2100_DP.C,\ $(HP2100_DIR)HP2100_IPL.C,$(HP2100_DIR)HP2100_DS.C,\ $(HP2100_DIR)HP2100_CPU0.C,$(HP2100_DIR)HP2100_CPU1.C,\ $(HP2100_DIR)HP2100_CPU2.C,$(HP2100_DIR)HP2100_CPU3.C,\ - $(HP2100_DIR)HP2100_CPU4.C,$(HP2100_DIR)HP2100_FP1.C + $(HP2100_DIR)HP2100_CPU4.C,$(HP2100_DIR)HP2100_CPU5.C,\ + $(HP2100_DIR)HP2100_CPU6.C,$(HP2100_DIR)HP2100_CPU7.C,\ + $(HP2100_DIR)HP2100_FP1.C,$(HP2100_DIR)HP2100_BACI.C .IF ALPHA_OR_IA64 HP2100_OPTIONS = /INCL=($(SIMH_DIR),$(HP2100_DIR))\ /DEF=($(CC_DEFS),"HAVE_INT64=1") @@ -394,7 +404,9 @@ PDP11_SOURCE2 = $(PDP11_DIR)PDP11_TM.C,$(PDP11_DIR)PDP11_TS.C,\ $(PDP11_DIR)PDP11_HK.C,$(PDP11_DIR)PDP11_XQ.C,\ $(PDP11_DIR)PDP11_VH.C,$(PDP11_DIR)PDP11_RH.C,\ $(PDP11_DIR)PDP11_XU.C,$(PDP11_DIR)PDP11_TU.C,\ - $(PDP11_DIR)PDP11_DL.C,$(PDP11_DIR)PDP11_RF.C + $(PDP11_DIR)PDP11_DL.C,$(PDP11_DIR)PDP11_RF.C, \ + $(PDP11_DIR)PDP11_RC.C,$(PDP11_DIR)PDP11_KG.C,\ + $(PDP11_DIR)PDP11_KE.C,$(PDP11_DIR)PDP11_DC.C PDP11_OPTIONS = /INCL=($(SIMH_DIR),$(PDP11_DIR)$(PCAP_INC))\ /DEF=($(CC_DEFS),"VM_PDP11=1"$(PCAP_DEFS)) diff --git a/makefile b/makefile index 4973273d..fd2501c8 100644 --- a/makefile +++ b/makefile @@ -1,33 +1,31 @@ +# # CC Command # -# Note: -O2 is sometimes broken in GCC when setjump/longjump is being -# used. Try -O2 only with released simulators. -# ifeq ($(WIN32),) -#Unix Environments -ifeq ($(OSTYPE),solaris) -OS_CCDEFS = -lsocket -lnsl -lpthread -D_GNU_SOURCE + #Unix Environments + ifneq (,$(findstring solaris,$(OSTYPE))) + OS_CCDEFS = -lm -lsocket -lnsl -lrt -lpthread -D_GNU_SOURCE + else + ifneq (,$(findstring darwin,$(OSTYPE))) + OS_CCDEFS = -D_GNU_SOURCE + else + OS_CCDEFS = -lrt -lm -D_GNU_SOURCE + endif + endif + CC = gcc -std=c99 -U__STRICT_ANSI__ -g $(OS_CCDEFS) -I . + ifeq ($(USE_NETWORK),) + else + NETWORK_OPT = -DUSE_NETWORK -isystem /usr/local/include /usr/local/lib/libpcap.a + endif else -OS_CCDEFS = -D_GNU_SOURCE -endif -ifeq ($(OSTYPE),macos) -CC = gcc -std=c99 -O2 -U__STRICT_ANSI__ -g -lm -lrt $(OS_CCDEFS) -I . -else -CC = gcc -std=c99 -O2 -U__STRICT_ANSI__ -g -lm $(OS_CCDEFS) -I . -endif -ifeq ($(USE_NETWORK),) -else -NETWORK_OPT = -DUSE_NETWORK -isystem /usr/local/include /usr/local/lib/libpcap.a -endif -else -#Win32 Environments -LDFLAGS = -lm -lwsock32 -lwinmm -CC = gcc -std=c99 -U__STRICT_ANSI__ -O0 -I. -EXE = .exe -ifeq ($(USE_NETWORK),) -else -NETWORK_OPT = -DUSE_NETWORK -lwpcap -lpacket -endif + #Win32 Environments + LDFLAGS = -lm -lwsock32 -lwinmm + CC = gcc -std=c99 -U__STRICT_ANSI__ -O2 -I. + EXE = .exe + ifeq ($(USE_NETWORK),) + else + NETWORK_OPT = -DUSE_NETWORK -lwpcap -lpacket + endif endif # @@ -85,7 +83,8 @@ PDP11 = ${PDP11D}/pdp11_fp.c ${PDP11D}/pdp11_cpu.c ${PDP11D}/pdp11_dz.c \ ${PDP11D}/pdp11_xq.c ${PDP11D}/pdp11_xu.c ${PDP11D}/pdp11_vh.c \ ${PDP11D}/pdp11_rh.c ${PDP11D}/pdp11_tu.c ${PDP11D}/pdp11_cpumod.c \ ${PDP11D}/pdp11_cr.c ${PDP11D}/pdp11_rf.c ${PDP11D}/pdp11_dl.c \ - ${PDP11D}/pdp11_ta.c + ${PDP11D}/pdp11_ta.c ${PDP11D}/pdp11_rc.c ${PDP11D}/pdp11_kg.c \ + ${PDP11D}/pdp11_ke.c ${PDP11D}/pdp11_dc.c PDP11_OPT = -DVM_PDP11 -I ${PDP11D} ${NETWORK_OPT} @@ -125,13 +124,13 @@ PDP10_OPT = -DVM_PDP10 -DUSE_INT64 -I ${PDP10D} -I ${PDP11D} ${NETWORK_OPT} -PDP8D = PDP8/ +PDP8D = PDP8 PDP8 = ${PDP8D}/pdp8_cpu.c ${PDP8D}/pdp8_clk.c ${PDP8D}/pdp8_df.c \ ${PDP8D}/pdp8_dt.c ${PDP8D}/pdp8_lp.c ${PDP8D}/pdp8_mt.c \ ${PDP8D}/pdp8_pt.c ${PDP8D}/pdp8_rf.c ${PDP8D}/pdp8_rk.c \ ${PDP8D}/pdp8_rx.c ${PDP8D}/pdp8_sys.c ${PDP8D}/pdp8_tt.c \ ${PDP8D}/pdp8_ttx.c ${PDP8D}/pdp8_rl.c ${PDP8D}/pdp8_tsc.c \ - ${PDP8D}/pdp8_td.c ${PDP8D}/pdp8_ct.c + ${PDP8D}/pdp8_td.c ${PDP8D}/pdp8_ct.c ${PDP8D}/pdp8_fpp.c PDP8_OPT = -I ${PDP8D} @@ -149,7 +148,8 @@ HP2100 = ${HP2100D}/hp2100_stddev.c ${HP2100D}/hp2100_dp.c ${HP2100D}/hp2100_dq. ${HP2100D}/hp2100_fp.c ${HP2100D}/hp2100_sys.c ${HP2100D}/hp2100_lpt.c \ ${HP2100D}/hp2100_ipl.c ${HP2100D}/hp2100_ds.c ${HP2100D}/hp2100_cpu0.c \ ${HP2100D}/hp2100_cpu1.c ${HP2100D}/hp2100_cpu2.c ${HP2100D}/hp2100_cpu3.c \ - ${HP2100D}/hp2100_cpu4.c ${HP2100D}/hp2100_fp1.c + ${HP2100D}/hp2100_cpu4.c ${HP2100D}/hp2100_cpu5.c ${HP2100D}/hp2100_cpu6.c \ + ${HP2100D}/hp2100_cpu7.c ${HP2100D}/hp2100_fp1.c ${HP2100D}/hp2100_baci.c HP2100_OPT = -DHAVE_INT64 -I ${HP2100D} @@ -215,9 +215,20 @@ ALTAIR_OPT = -I ${ALTAIRD} ALTAIRZ80D = AltairZ80 -ALTAIRZ80 = ${ALTAIRZ80D}/altairz80_cpu.c ${ALTAIRZ80D}/altairz80_dsk.c \ +ALTAIRZ80 = ${ALTAIRZ80D}/altairz80_cpu.c ${ALTAIRZ80D}/altairz80_cpu_nommu.c \ + ${ALTAIRZ80D}/altairz80_dsk.c ${ALTAIRZ80D}/disasm.c \ ${ALTAIRZ80D}/altairz80_sio.c ${ALTAIRZ80D}/altairz80_sys.c \ - ${ALTAIRZ80D}/altairz80_hdsk.c ${ALTAIRZ80D}/altairz80_net.c + ${ALTAIRZ80D}/altairz80_hdsk.c ${ALTAIRZ80D}/altairz80_net.c \ + ${ALTAIRZ80D}/flashwriter2.c ${ALTAIRZ80D}/i86_decode.c \ + ${ALTAIRZ80D}/i86_ops.c ${ALTAIRZ80D}/i86_prim_ops.c \ + ${ALTAIRZ80D}/i8272.c ${ALTAIRZ80D}/insnsa.c ${ALTAIRZ80D}/insnsd.c \ + ${ALTAIRZ80D}/mfdc.c ${ALTAIRZ80D}/n8vem.c ${ALTAIRZ80D}/vfdhd.c \ + ${ALTAIRZ80D}/s100_disk1a.c ${ALTAIRZ80D}/s100_disk2.c \ + ${ALTAIRZ80D}/s100_fif.c ${ALTAIRZ80D}/s100_mdriveh.c \ + ${ALTAIRZ80D}/s100_mdsad.c ${ALTAIRZ80D}/s100_selchan.c \ + ${ALTAIRZ80D}/s100_ss1.c ${ALTAIRZ80D}/s100_64fdc.c \ + ${ALTAIRZ80D}/s100_scp300f.c ${ALTAIRZ80D}/sim_imd.c \ + ${ALTAIRZ80D}/wd179x.c ALTAIRZ80_OPT = -I ${ALTAIRZ80D} diff --git a/scp.c b/scp.c index 3108c739..c28b7280 100644 --- a/scp.c +++ b/scp.c @@ -1,6 +1,6 @@ /* scp.c: simulator control program - Copyright (c) 1993-2007, Robert M Supnik + Copyright (c) 1993-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,9 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 31-Mar-08 RMS Fixed bug in local/global register search (found by Mark Pizzolato) + Fixed bug in restore of RO units (from Mark Pizzolato) + 06-Feb-08 RMS Added SET/SHO/NO BR with default argument 18-Jul-07 RMS Modified match_ext for VMS ext;version support 28-Apr-07 RMS Modified sim_instr invocation to call sim_rtcn_init_all Fixed bug in get_sim_opt @@ -173,11 +176,6 @@ #include #include -#if defined (HAVE_READLINE) -#include -#include -#endif - #define EX_D 0 /* deposit */ #define EX_E 1 /* examine */ #define EX_I 2 /* interactive */ @@ -329,6 +327,7 @@ t_stat attach_err (UNIT *uptr, t_stat stat); t_stat detach_all (int32 start_device, t_bool shutdown); t_stat assign_device (DEVICE *dptr, char *cptr); t_stat deassign_device (DEVICE *dptr); +t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, char *aptr); t_stat run_boot_prep (void); t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, char *cptr, REG *lowr, REG *highr, uint32 lows, uint32 highs); @@ -352,6 +351,7 @@ FILE *sim_ofile = NULL; SCHTAB *sim_schptr = FALSE; DEVICE *sim_dfdev = NULL; UNIT *sim_dfunit = NULL; +int32 sim_opt_out = 0; int32 sim_is_running = 0; uint32 sim_brk_summ = 0; uint32 sim_brk_types = 0; @@ -525,7 +525,7 @@ static CTAB cmd_table[] = { "set console arg{,arg...} set console options\n" "set break set breakpoints\n" "set nobreak clear breakpoints\n" - "set throttle x{M|K|%} set simulation rate\n" + "set throttle x{M|K|%%} set simulation rate\n" "set nothrottle set simulation rate to maximum\n" "set OCT|DEC|HEX set device display radix\n" "set ENABLED enable device\n" @@ -1372,10 +1372,11 @@ return; t_stat show_version (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) { -int32 vmaj = SIM_MAJOR, vmin = SIM_MINOR, vpat = SIM_PATCH; +int32 vmaj = SIM_MAJOR, vmin = SIM_MINOR, vpat = SIM_PATCH, vdelt = SIM_DELTA; if (cptr && (*cptr != 0)) return SCPE_2MARG; fprintf (st, "%s simulator V%d.%d-%d", sim_name, vmaj, vmin, vpat); +if (vdelt) fprintf (st, "(%d)", vdelt); if (flag) fprintf (st, " [%s, %s, %s]", sim_si64, sim_sa64, sim_snet); fprintf (st, "\n"); return SCPE_OK; @@ -1585,13 +1586,16 @@ t_stat r; t_addr lo, hi, max = uptr->capac - 1; int32 cnt; -if (*cptr == 0) return SCPE_2FARG; if (sim_brk_types == 0) return SCPE_NOFNC; if ((dptr == NULL) || (uptr == NULL)) return SCPE_IERR; if (aptr = strchr (cptr, ';')) { /* ;action? */ if (flg != SSH_ST) return SCPE_ARG; /* only on SET */ *aptr++ = 0; /* separate strings */ } +if (*cptr == 0) { /* no argument? */ + lo = (t_addr) get_rval (sim_PC, 0); /* use PC */ + return ssh_break_one (st, flg, lo, 0, aptr); + } while (*cptr) { cptr = get_glyph (cptr, gbuf, ','); tptr = get_range (dptr, gbuf, &lo, &hi, dptr->aradix, max, 0); @@ -1611,24 +1615,7 @@ while (*cptr) { } else { for ( ; lo <= hi; lo = lo + 1) { - switch (flg) { - - case SSH_ST: - r = sim_brk_set (lo, sim_switches, cnt, aptr); - break; - - case SSH_CL: - r = sim_brk_clr (lo, sim_switches); - break; - - case SSH_SH: - r = sim_brk_show (st, lo, sim_switches); - break; - - default: - return SCPE_ARG; - } - + r = ssh_break_one (st, flg, lo, cnt, aptr); if (r != SCPE_OK) return r; } } @@ -1636,6 +1623,27 @@ while (*cptr) { return SCPE_OK; } +t_stat ssh_break_one (FILE *st, int32 flg, t_addr lo, int32 cnt, char *aptr) +{ +switch (flg) { + + case SSH_ST: + return sim_brk_set (lo, sim_switches, cnt, aptr); + break; + + case SSH_CL: + return sim_brk_clr (lo, sim_switches); + break; + + case SSH_SH: + return sim_brk_show (st, lo, sim_switches); + break; + + default: + return SCPE_ARG; + } +} + /* Reset command and routines re[set] reset all devices @@ -2176,7 +2184,6 @@ if (v32) { /* [V3.2+] time as strin else READ_I (sim_time); /* sim time */ READ_I (sim_rtime); /* [V2.6+] sim rel time */ -sim_switches = SIM_SW_REST; /* flag restore */ for ( ;; ) { /* device loop */ READ_S (buf); /* read device name */ if (buf[0] == 0) break; /* last? */ @@ -2194,6 +2201,7 @@ for ( ;; ) { /* device loop */ dptr->flags = (dptr->flags & ~DEV_RFLAGS) | /* restore ctlr flags */ (flg & DEV_RFLAGS); for ( ;; ) { /* unit loop */ + sim_switches = SIM_SW_REST; /* flag rstr, clr RO */ READ_I (unitno); /* unit number */ if (unitno < 0) break; /* end units? */ if ((uint32) unitno >= dptr->numunits) { /* too big? */ @@ -2551,8 +2559,9 @@ for (gptr = gbuf, reason = SCPE_OK; continue; } - if ((lowr = find_reg (gptr, &tptr, tdptr)) || - (lowr = find_reg_glob (gptr, &tptr, &tdptr))) { + if ((lowr = find_reg (gptr, &tptr, tdptr)) || /* local reg or */ + (!(sim_opt_out & CMD_OPT_DFT) && /* no dflt, global? */ + (lowr = find_reg_glob (gptr, &tptr, &tdptr)))) { low = high = 0; if ((*tptr == '-') || (*tptr == ':')) { highr = find_reg (tptr + 1, &tptr, tdptr); @@ -2705,7 +2714,7 @@ sz = SZ_R (rptr); if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) { idx = idx + rptr->qptr; if (idx >= rptr->depth) idx = idx - rptr->depth; - } + } if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) { uptr = ((UNIT *) rptr->loc) + idx; #if defined (USE_INT64) @@ -3051,21 +3060,7 @@ char *read_line (char *cptr, int32 size, FILE *stream) { char *tptr; -#if !defined (HAVE_READLINE) cptr = fgets (cptr, size, stream); /* get cmd line */ - -#else -if (stream != stdin) cptr = fgets (cptr, size, stream); -else { - char *tmpc = readline (NULL); - if (tmpc == NULL) cptr = NULL; - else { - strncpy (cptr, tmpc, size); - free (tmpc); - } - } -#endif - if (cptr == NULL) { clearerr (stream); /* clear error */ return NULL; /* ignore EOF */ @@ -3503,7 +3498,6 @@ return cptr; char *get_sim_opt (int32 opt, char *cptr, t_stat *st) { int32 t; -t_bool dfdu; char *svptr, gbuf[CBUFSIZE]; DEVICE *tdptr; UNIT *tuptr; @@ -3517,7 +3511,7 @@ sim_stab.mask = 0; sim_stab.comp = 0; sim_dfdev = sim_dflt_dev; sim_dfunit = sim_dfdev->units; -dfdu = FALSE; /* no default yet */ +sim_opt_out = 0; /* no options yet */ *st = SCPE_OK; while (*cptr) { /* loop through modifiers */ svptr = cptr; /* save current position */ @@ -3526,12 +3520,15 @@ while (*cptr) { /* loop through modifier fclose (sim_ofile); /* one per customer */ *st = SCPE_ARG; return NULL; - } + } cptr = get_glyph_nc (cptr + 1, gbuf, 0); sim_ofile = sim_fopen (gbuf, "a"); /* open for append */ - if (sim_ofile) continue; /* if ok, look for more */ - *st = SCPE_OPENERR; /* open failed */ - return NULL; + if (sim_ofile == NULL) { /* open failed? */ + *st = SCPE_OPENERR; + return NULL; + } + sim_opt_out |= CMD_OPT_OF; /* got output file */ + continue; } cptr = get_glyph (cptr, gbuf, 0); if ((t = get_switches (gbuf)) != 0) { /* try for switches */ @@ -3542,14 +3539,17 @@ while (*cptr) { /* loop through modifier sim_switches = sim_switches | t; /* or in new switches */ } else if ((opt & CMD_OPT_SCH) && /* if allowed, */ - get_search (gbuf, sim_dfdev->dradix, &sim_stab)) /* try for search */ + get_search (gbuf, sim_dfdev->dradix, &sim_stab)) { /* try for search */ sim_schptr = &sim_stab; /* set search */ - else if ((opt & CMD_OPT_DFT) && !dfdu && /* if allowed, none yet*/ + sim_opt_out |= CMD_OPT_SCH; /* got search */ + } + else if ((opt & CMD_OPT_DFT) && /* default allowed? */ + ((sim_opt_out & CMD_OPT_DFT) == 0) && /* none yet? */ (tdptr = find_unit (gbuf, &tuptr)) && /* try for default */ (tuptr != NULL)) { sim_dfdev = tdptr; /* set as default */ sim_dfunit = tuptr; - dfdu = TRUE; /* indicate dflt seen */ + sim_opt_out |= CMD_OPT_DFT; /* got default */ } else return svptr; /* not rec, break out */ } @@ -3575,11 +3575,11 @@ pptr = strrchr (fnam, '.'); /* find last . */ if (pptr) { /* any? */ for (fptr = pptr + 1, eptr = ext; /* match characters */ #if defined (VMS) /* VMS: stop at ; or null */ - (*fptr != 0) && (*fptr != ';'); + (*fptr != 0) && (*fptr != ';'); #else - *fptr != 0; /* others: stop at null */ + *fptr != 0; /* others: stop at null */ #endif - fptr++, eptr++) { + fptr++, eptr++) { if (toupper (*fptr) != toupper (*eptr)) return NULL; } diff --git a/sim_console.c b/sim_console.c index 6388c2c4..9a0044d4 100644 --- a/sim_console.c +++ b/sim_console.c @@ -640,7 +640,7 @@ t_stat sim_ttcmd (void) if (sim_log) { fflush (sim_log); _setmode (_fileno (sim_log), _O_TEXT); - } + } SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_NORMAL); if (!SetConsoleMode(std_input, saved_mode)) return SCPE_TTYERR; return SCPE_OK; @@ -731,7 +731,7 @@ if (c != 0177) { putch (c); #endif fflush (stdout); - } + } return SCPE_OK; } diff --git a/sim_defs.h b/sim_defs.h index 7866bb4d..c26c4ee8 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -1,6 +1,6 @@ /* sim_defs.h: simulator definitions - Copyright (c) 1993-2007, Robert M Supnik + Copyright (c) 1993-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 28-May-08 RMS Added inlining support 28-Jun-07 RMS Added IA64 VMS support (from Norm Lastovica) 18-Jun-07 RMS Added UNIT_IDLE flag 18-Mar-07 RMS Added UNIT_TEXT flag @@ -160,6 +161,16 @@ typedef uint32 t_addr; #define T_ADDR_W 32 #endif /* end 64b address */ +/* Inlining */ + +#if defined (__GNUC__) /* GCC */ +#define SIM_INLINE inline +#elif defined (_MSC_VER) /* Microsoft C Compilers */ +#define SIM_INLINE __inline +#else /* default */ +#define SIM_INLINE +#endif + /* System independent definitions */ #define FLIP_SIZE (1 << 16) /* flip buf size */ diff --git a/sim_ether.c b/sim_ether.c index e8942a9e..09bd134b 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -49,8 +49,8 @@ networking is needed - there may be known workarounds. Define one of the two macros below to enable networking: - USE_NETWORK - Create statically linked network code - USE_SHARED - Create dynamically linked network code (_WIN32 only) + USE_NETWORK - Create statically linked network code + USE_SHARED - Create dynamically linked network code (_WIN32 only) ------------------------------------------------------------------------------ @@ -140,9 +140,9 @@ 17-May-07 DTH Fixed non-ethernet device removal loop (from Naoki Hamada) 15-May-07 DTH Added dynamic loading of wpcap.dll; - Corrected exceed max index bug in ethX lookup + Corrected exceed max index bug in ethX lookup 04-May-07 DTH Corrected failure to look up ethernet device names in - the registry on Windows XP x64 + the registry on Windows XP x64 10-Jul-06 RMS Fixed linux conditionalization (from Chaskiel Grundman) 02-Jun-06 JDB Fixed compiler warning for incompatible sscanf parameter 15-Dec-05 DTH Patched eth_host_devices [remove non-ethernet devices] @@ -623,7 +623,7 @@ t_stat eth_filter (ETH_DEV* dev, int addr_count, ETH_MAC* addresses, {return SCPE_NOFNC;} int eth_devices (int max, ETH_LIST* dev) {return -1;} -#else /* endif unimplemented */ +#else /* endif unimplemented */ /*============================================================================*/ /* WIN32, Linux, and xBSD routines use WinPcap and libpcap packages */ @@ -648,8 +648,8 @@ int eth_devices (int max, ETH_LIST* dev) Etherial/WireShark capture_pcap.c */ /* Dynamic DLL load variables */ -static HINSTANCE hDll = 0; /* handle to DLL */ -static int dll_loaded = 0; /* 0=not loaded, 1=loaded, 2=DLL load failed, 3=Func load failed */ +static HINSTANCE hDll = 0; /* handle to DLL */ +static int dll_loaded = 0; /* 0=not loaded, 1=loaded, 2=DLL load failed, 3=Func load failed */ static char* no_wpcap = "wpcap load failure"; /* define pointers to pcap functions needed */ @@ -669,158 +669,158 @@ static char* (*p_pcap_lib_version) (void); /* load function pointer from DLL */ void load_function(char* function, void** func_ptr) { - *func_ptr = GetProcAddress(hDll, function); - if (*func_ptr == 0) { - char* msg = "Eth: Failed to find function '%s' in wpcap.dll\r\n"; - printf (msg, function); - if (sim_log) fprintf (sim_log, msg, function); - dll_loaded = 3; - } + *func_ptr = GetProcAddress(hDll, function); + if (*func_ptr == 0) { + char* msg = "Eth: Failed to find function '%s' in wpcap.dll\r\n"; + printf (msg, function); + if (sim_log) fprintf (sim_log, msg, function); + dll_loaded = 3; + } } /* load wpcap.dll as required */ int load_wpcap(void) { - switch(dll_loaded) { - case 0: /* not loaded */ - /* attempt to load DLL */ - hDll = LoadLibrary(TEXT("wpcap.dll")); - if (hDll == 0) { - /* failed to load DLL */ - char* msg = "Eth: Failed to load wpcap.dll\r\n"; - char* msg2 = "Eth: You must install WinPcap 4.x to use networking\r\n"; - printf (msg); - printf (msg2); - if (sim_log) { - fprintf (sim_log, msg); - fprintf (sim_log, msg2); - } - dll_loaded = 2; - break; - } else { - /* DLL loaded OK */ - dll_loaded = 1; - } + switch(dll_loaded) { + case 0: /* not loaded */ + /* attempt to load DLL */ + hDll = LoadLibrary(TEXT("wpcap.dll")); + if (hDll == 0) { + /* failed to load DLL */ + char* msg = "Eth: Failed to load wpcap.dll\r\n"; + char* msg2 = "Eth: You must install WinPcap 4.x to use networking\r\n"; + printf (msg); + printf (msg2); + if (sim_log) { + fprintf (sim_log, msg); + fprintf (sim_log, msg2); + } + dll_loaded = 2; + break; + } else { + /* DLL loaded OK */ + dll_loaded = 1; + } - /* load required functions; sets dll_load=3 on error */ - load_function("pcap_close", (void**) &p_pcap_close); - load_function("pcap_compile", (void**) &p_pcap_compile); - load_function("pcap_datalink", (void**) &p_pcap_datalink); - load_function("pcap_dispatch", (void**) &p_pcap_dispatch); - load_function("pcap_findalldevs", (void**) &p_pcap_findalldevs); - load_function("pcap_freealldevs", (void**) &p_pcap_freealldevs); - load_function("pcap_freecode", (void**) &p_pcap_freecode); - load_function("pcap_geterr", (void**) &p_pcap_geterr); - load_function("pcap_lookupnet", (void**) &p_pcap_lookupnet); - load_function("pcap_open_live", (void**) &p_pcap_open_live); - load_function("pcap_sendpacket", (void**) &p_pcap_sendpacket); - load_function("pcap_setfilter", (void**) &p_pcap_setfilter); - load_function("pcap_lib_version", (void**) &p_pcap_lib_version); + /* load required functions; sets dll_load=3 on error */ + load_function("pcap_close", (void**) &p_pcap_close); + load_function("pcap_compile", (void**) &p_pcap_compile); + load_function("pcap_datalink", (void**) &p_pcap_datalink); + load_function("pcap_dispatch", (void**) &p_pcap_dispatch); + load_function("pcap_findalldevs", (void**) &p_pcap_findalldevs); + load_function("pcap_freealldevs", (void**) &p_pcap_freealldevs); + load_function("pcap_freecode", (void**) &p_pcap_freecode); + load_function("pcap_geterr", (void**) &p_pcap_geterr); + load_function("pcap_lookupnet", (void**) &p_pcap_lookupnet); + load_function("pcap_open_live", (void**) &p_pcap_open_live); + load_function("pcap_sendpacket", (void**) &p_pcap_sendpacket); + load_function("pcap_setfilter", (void**) &p_pcap_setfilter); + load_function("pcap_lib_version", (void**) &p_pcap_lib_version); - if (dll_loaded == 1) { - /* log successful load */ - char* version = p_pcap_lib_version(); - printf("%s\n", version); - if (sim_log) - fprintf(sim_log, "%s\n", version); - } - break; - default: /* loaded or failed */ - break; - } - return (dll_loaded == 1) ? 1 : 0; + if (dll_loaded == 1) { + /* log successful load */ + char* version = p_pcap_lib_version(); + printf("%s\n", version); + if (sim_log) + fprintf(sim_log, "%s\n", version); + } + break; + default: /* loaded or failed */ + break; + } + return (dll_loaded == 1) ? 1 : 0; } /* define functions with dynamic revectoring */ void pcap_close(pcap_t* a) { - if (load_wpcap() != 0) { - p_pcap_close(a); - } + if (load_wpcap() != 0) { + p_pcap_close(a); + } } int pcap_compile(pcap_t* a, struct bpf_program* b, char* c, int d, bpf_u_int32 e) { - if (load_wpcap() != 0) { - return p_pcap_compile(a, b, c, d, e); - } else { - return 0; - } + if (load_wpcap() != 0) { + return p_pcap_compile(a, b, c, d, e); + } else { + return 0; + } } int pcap_datalink(pcap_t* a) { - if (load_wpcap() != 0) { - return p_pcap_datalink(a); - } else { - return 0; - } + if (load_wpcap() != 0) { + return p_pcap_datalink(a); + } else { + return 0; + } } int pcap_dispatch(pcap_t* a, int b, pcap_handler c, u_char* d) { - if (load_wpcap() != 0) { - return p_pcap_dispatch(a, b, c, d); - } else { - return 0; - } + if (load_wpcap() != 0) { + return p_pcap_dispatch(a, b, c, d); + } else { + return 0; + } } int pcap_findalldevs(pcap_if_t** a, char* b) { - if (load_wpcap() != 0) { - return p_pcap_findalldevs(a, b); - } else { - *a = 0; - strcpy(b, no_wpcap); - return -1; - } + if (load_wpcap() != 0) { + return p_pcap_findalldevs(a, b); + } else { + *a = 0; + strcpy(b, no_wpcap); + return -1; + } } void pcap_freealldevs(pcap_if_t* a) { - if (load_wpcap() != 0) { - p_pcap_freealldevs(a); - } + if (load_wpcap() != 0) { + p_pcap_freealldevs(a); + } } void pcap_freecode(struct bpf_program* a) { - if (load_wpcap() != 0) { - p_pcap_freecode(a); - } + if (load_wpcap() != 0) { + p_pcap_freecode(a); + } } char* pcap_geterr(pcap_t* a) { - if (load_wpcap() != 0) { - return p_pcap_geterr(a); - } else { - return (char*) 0; - } + if (load_wpcap() != 0) { + return p_pcap_geterr(a); + } else { + return (char*) 0; + } } int pcap_lookupnet(const char* a, bpf_u_int32* b, bpf_u_int32* c, char* d) { - if (load_wpcap() != 0) { - return p_pcap_lookupnet(a, b, c, d); - } else { - return 0; - } + if (load_wpcap() != 0) { + return p_pcap_lookupnet(a, b, c, d); + } else { + return 0; + } } pcap_t* pcap_open_live(const char* a, int b, int c, int d, char* e) { - if (load_wpcap() != 0) { - return p_pcap_open_live(a, b, c, d, e); - } else { - return (pcap_t*) 0; - } + if (load_wpcap() != 0) { + return p_pcap_open_live(a, b, c, d, e); + } else { + return (pcap_t*) 0; + } } int pcap_sendpacket(pcap_t* a, const u_char* b, int c) { - if (load_wpcap() != 0) { - return p_pcap_sendpacket(a, b, c); - } else { - return 0; - } + if (load_wpcap() != 0) { + return p_pcap_sendpacket(a, b, c); + } else { + return 0; + } } int pcap_setfilter(pcap_t* a, struct bpf_program* b) { - if (load_wpcap() != 0) { - return p_pcap_setfilter(a, b); - } else { - return 0; - } + if (load_wpcap() != 0) { + return p_pcap_setfilter(a, b); + } else { + return 0; + } } #endif @@ -1387,40 +1387,40 @@ int eth_host_devices(int used, int max, ETH_LIST* list) #if defined(_WIN32) /* replace device description with user-defined adapter name (if defined) */ for (i=0; i sizeof(regval))) { - RegCloseKey (reghnd); - continue; - } + if((regtype != REG_SZ) || (reglen > sizeof(regval))) { + RegCloseKey (reghnd); + continue; + } /* registry value seems OK, finish up and replace description */ - RegCloseKey (reghnd ); + RegCloseKey (reghnd ); sprintf (list[i].desc, "%s", regval); } } /* for */ diff --git a/sim_ether.h b/sim_ether.h index e6a1beb9..371ee3ba 100644 --- a/sim_ether.h +++ b/sim_ether.h @@ -169,7 +169,7 @@ struct eth_device { DEVICE* dptr; /* device ethernet is attached to */ uint32 dbit; /* debugging bit */ int reflections; /* packet reflections on interface */ - int need_crc; /* device needs CRC (Cyclic Redundancy Check) */ + int need_crc; /* device needs CRC (Cyclic Redundancy Check) */ #if defined (USE_READER_THREAD) ETH_QUE read_queue; pthread_mutex_t lock; diff --git a/sim_rev.h b/sim_rev.h index 10ac292d..9cda3321 100644 --- a/sim_rev.h +++ b/sim_rev.h @@ -28,13 +28,188 @@ #define _SIM_REV_H_ 0 #define SIM_MAJOR 3 -#define SIM_MINOR 7 -#define SIM_PATCH 3 +#define SIM_MINOR 8 +#define SIM_PATCH 0 +#define SIM_DELTA 0 -/* V3.7 revision history +/* V3.8 revision history patch date module(s) and fix(es) + 0 tbd scp.c: + - fixed bug in local/global register search (found by Mark Pizzolato) + - fixed bug in restore of RO units (from Mark Pizzolato) + - added SET/SHO/NO BR with default argument (from Dave Bryan) + + sim_tmxr.c + - worked around Telnet negotiation problem with QCTerm (from Dave Bryan) + + gri_defs.h, gri_cpu.c, gri_sys.c: + - added GRI-99 support + + hp2100_baci.c (from Dave Bryan): + - Implemented 12966A Buffered Asynchronous Communications Interface simulator + + hp2100_cpu.c (from Dave Bryan): + - Memory ex/dep and bkpt type default to current map mode + - Added SET CPU DEBUG and OS/VMA flags, enabled OS/VMA + - Corrected MP W5 (JSB) jumper action, SET/SHOW reversal, + mp_mevff clear on interrupt with I/O instruction in trap cell + - Removed DBI support from 1000-M (was temporary for RTE-6/VM) + - Enabled EMA and VIS, added EMA, VIS, and SIGNAL debug flags + - Enabled SIGNAL instructions, SIG debug flag + - Fixed single stepping through interrupts + + hp2100_cpu0.c (from Dave Bryan and Holger Veit): + - Removed and implemented "cpu_rte_vma" and "cpu_rte_os" + - Removed and implemented "cpu_vis" and "cpu_signal" + - Removed and implemented "cpu_rte_ema" + + hp2100_cpu1.c (from Dave Bryan): + - Added fprint_ops, fprint_regs for debug printouts + - Enabled DIAG as NOP on 1000 F-Series + - Fixed VIS and SIGNAL to depend on the FPP and HAVE_INT64 + + hp2100_cpu3.c (from Dave Bryan): + - Fixed unsigned divide bug in .DDI + - Fixed unsigned multiply bug in .DMP + - Added implementation of DBI self-test + + hp2100_cpu4.c (from Dave Bryan): + - Fixed B register return bug in /CMRT + + hp2100_cpu5.c (from Holger Veit): + - Implemented RTE-6/VM Virtual Memory Area firmware + - Implemented RTE-IV Extended Memory Area firmware + + hp2100_cpu6.c (from Dave Bryan): + - Implemented RTE-6/VM OS accelerator firmware + + hp2100_cpu7.c (from Holger Veit): + - Implemented Vector Instruction Set and SIGNAL/1000 firmware + + hp2100_ds.c (from Dave Bryan): + - Corrected and verified ioCRS action + - Corrected DPTR register definition from FLDATA to DRDATA + + hp2100_fp.c (from Mark Pizzolato) + - Corrected fp_unpack mantissa high-word return + + hp2100_fp1.c (from Dave Bryan): + - Reworked "complement" to avoid inlining bug in gcc-4.x + - Fixed uninitialized return in fp_accum when setting + + hp2100_mux.c (from Dave Bryan): + - Sync mux poll with console poll for idle compatibility + + hp2100_stddev.c (from Dave Bryan): + - Fixed PTR trailing null counter for tape re-read + - Added IPTICK register to CLK to display CPU instr/tick + - Corrected and verified ioCRS actions + - Changed TTY console poll to 10 msec. real time + - Synchronized CLK with TTY if set for 10 msec. + - Added UNIT_IDLE to TTY and CLK + - Removed redundant control char handling definitions + - Changed TTY output wait from 100 to 200 for MSU BASIC + + hp2100_sys.c (from Dave Bryan): + - Added BACI device + - Added RTE OS/VMA/EMA mnemonics + - Changed fprint_sym to handle step with irq pending + + hp2100_cpu.h (from Dave Bryan): + - Added calc_defer() prototype + - Added extern sim_deb, cpu_dev, DEB flags for debug printouts + - Added extern intaddr, mp_viol, mp_mevff, calc_int, dev_ctl, + ReadIO, WriteIO for RTE-6/VM microcode support + + hp2100_cpu1.h (from Dave Bryan): + - Corrected OP_AFF to OP_AAFF for SIGNAL/1000 + - Removed unused operand patterns + - Added fprint_ops, fprint_regs for debug printouts + - Revised OP_KKKAKK operand profile to OP_CCCACC for $LOC + + hp2100_defs.h (from Dave Bryan): + - Added BACI device + - Added 16/32-bit unsigned-to-signed conversions + - Changed TMR_MUX to TMR_POLL for idle support + - Added POLLMODE, sync_poll() declaration + - Added I_MRG, I_ISZ, I_IOG, I_STF, and I_SFS instruction masks + - Added I_MRG_I, I_JSB, I_JSB_I, and I_JMP instruction masks + + nova_defs.h (from Bruce Ray): + - added support for third-party 64KW memory + + nova_clk.c (from Bruce Ray): + - renamed to RTC, to match DG literature + + nova_cpu.c (from Bruce Ray): + - added support for third-party 64KW memory + - added Nova 3 "secret" instructions + - added CPU history support + + nova_dkp.c (from Bruce Ray): + - renamed to DKP, to match DG literature + - fixed numerous bugs in both documented and undocumented behavior + - changed bootstrap code to DG official sequence + + nova_dsk.c (from Bruce Ray): + - renamed to DSK, to match DG literature + - added support for undocumented behavior + - changed bootstrap code to DG official sequence + + nova_mta.c (from Bruce Ray): + - renamed to MTA, to match DG literature + - changed bootstrap code to DG official sequence + + nova_plt.c, nova_pt.c (from Bruce Ray): + - added 7B/8B support + + nova_sys.c (from Bruce Ray): + - fixed mistaken instruction mnemonics + + pdp11_cpu.c, pdp11_io.c, pdp11_rh.c: + - fixed DMA memory address limit test (found by John Dundas) + - fixed MMR0 treatment in RESET (found by Walter Mueller) + + pdp11_cpumod.h, pdp11_cpumod.c: + - fixed write behavior of 11/70 MBRK, LOSIZE, HISIZE (found by Walter Mueller) + - added support to set default state of KDJ11B,E clock control register + + pdp11_dc.c: + - added support for DC11 + + pdp11_defs.h: + - added KE, KG, RC, DC support + - renamed DL11 devices + + pdp11_dl.c: + - renamed devices to DLI/DLO, to match DC11 + - added modem control + + pdp11_io.c: + - added autoconfigure support for DC11 + + pdp11_ke.c: + - added support for KE11A + + pdp11_kg.c (from John Dundas): + - added support for KG11A + + pdp11_rc.c (from John Dundas): + - added support for RC11 + + pdp11_sys.c: + - modified to allow -A, -B use with 8b devices + - added KE, KG, RC, DC support + - renamed DL11 devices + + vax_cmode.c, vax_io.c, vax780_uba.c: + - fixed declarations (from Mark Pizzolato) + + +/* V3.7 revision history + 3 02-Sep-07 scp.c: - fixed bug in SET THROTTLE command diff --git a/sim_sock.h b/sim_sock.h index fd38f516..9ac90e34 100644 --- a/sim_sock.h +++ b/sim_sock.h @@ -1,6 +1,6 @@ /* sim_sock.h: OS-dependent socket routines header file - Copyright (c) 2001-2005, Robert M Supnik + Copyright (c) 2001-2009, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 04-Jun-08 RMS Addes sim_create_sock, for IBM 1130 14-Apr-05 RMS Added WSAEINPROGRESS (from Tim Riker) 20-Aug-04 HV Added missing definition for OS/2 (from Holger Veit) 22-Oct-03 MP Changed WIN32 winsock include to use winsock2.h to @@ -76,6 +77,7 @@ SOCKET sim_master_sock (int32 port); SOCKET sim_connect_sock (int32 ip, int32 port); +SOCKET sim_create_sock (void); SOCKET sim_accept_conn (SOCKET master, uint32 *ipaddr); int32 sim_check_conn (SOCKET sock, t_bool rd); int32 sim_read_sock (SOCKET sock, char *buf, int32 nbytes); diff --git a/sim_timer.c b/sim_timer.c index 2e035e4a..d2dbfa7e 100644 --- a/sim_timer.c +++ b/sim_timer.c @@ -1,6 +1,6 @@ /* sim_timer.c: simulator timer library - Copyright (c) 1993-2007, Robert M Supnik + Copyright (c) 1993-2008, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 27-May-08 RMS Fixed bug in Linux idle routines (from Walter Mueller) 18-Jun-07 RMS Modified idle to exclude counted delays 22-Mar-07 RMS Added sim_rtcn_init_all 17-Oct-06 RMS Added idle support (based on work by Mark Pizzolato) @@ -204,7 +205,7 @@ void sim_os_sleep (unsigned int sec) return; } -t_bool sim_os_ms_sleep_init (void) +uint32 sim_os_ms_sleep_init (void) { return FALSE; } @@ -271,7 +272,7 @@ return sim_os_msec () - stime; #include #define NANOS_PER_MILLI 1000000 #define MILLIS_PER_SEC 1000 -#define sleep1Samples 100 +#define sleep1Samples 100 const t_bool rtc_avail = TRUE; @@ -301,7 +302,7 @@ uint32 msec; if (clock_getres (CLOCK_REALTIME, &treq) != 0) return 0; -msec = (treq.tv_nsec + (NANOS_PER_MILLI >> 1)) / NANOS_PER_MILLI; +msec = (treq.tv_nsec + (NANOS_PER_MILLI - 1)) / NANOS_PER_MILLI; if (msec > SIM_IDLE_MAX) return 0; return msec; @@ -432,7 +433,7 @@ return (sim_idle_rate_ms != 0); /* sim_idle - idle simulator until next event or for specified interval Inputs: - tmr = calibrated timer to use + tmr = calibrated timer to use Must solve the linear equation diff --git a/sim_tmxr.c b/sim_tmxr.c index 91cd3b59..16b958a0 100644 --- a/sim_tmxr.c +++ b/sim_tmxr.c @@ -1,6 +1,6 @@ /* sim_tmxr.c: Telnet terminal multiplexor library - Copyright (c) 2001-2005, Robert M Supnik + Copyright (c) 2001-2007, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,7 @@ Based on the original DZ11 simulator by Thord Nilson, as updated by Arthur Krewat. + 11-Apr-07 JDB Worked around Telnet negotiation problem with QCTerm 16-Aug-05 RMS Fixed C++ declaration and cast problems 29-Jun-05 RMS Extended tmxr_dscln to support unit array devices Fixed bug in SET LOG/NOLOG @@ -88,6 +89,8 @@ #define TN_SGA 3 /* sga */ #define TN_LINE 34 /* line mode */ #define TN_CR 015 /* carriage return */ +#define TN_LF 012 /* line feed */ +#define TN_NUL 000 /* null */ /* Telnet line states */ @@ -95,7 +98,8 @@ #define TNS_IAC 001 /* IAC seen */ #define TNS_WILL 002 /* WILL seen */ #define TNS_WONT 003 /* WONT seen */ -#define TNS_SKIP 004 /* skip next */ +#define TNS_SKIP 004 /* skip next cmd */ +#define TNS_CRPAD 005 /* CR padding */ void tmxr_rmvrc (TMLN *lp, int32 p); int32 tmxr_send_buffered_data (TMLN *lp); @@ -247,9 +251,9 @@ for (i = 0; i < mp->lines; i++) { /* loop thru lines */ lp->tsta = TNS_IAC; /* change state */ tmxr_rmvrc (lp, j); /* remove char */ break; - } + } if ((tmp == TN_CR) && lp->dstb) /* CR, no bin */ - lp->tsta = TNS_SKIP; /* skip next */ + lp->tsta = TNS_CRPAD; /* skip pad char */ j = j + 1; /* advance j */ break; @@ -278,7 +282,28 @@ for (i = 0; i < mp->lines; i++) { /* loop thru lines */ if (tmp == TN_BIN) { /* BIN? */ if (lp->tsta == TNS_WILL) lp->dstb = 0; else lp->dstb = 1; - } + } + + /* Negotiation with the HP terminal emulator "QCTerm" is not working. + QCTerm says "WONT BIN" but sends bare CRs. RFC 854 says: + + Note that "CR LF" or "CR NUL" is required in both directions + (in the default ASCII mode), to preserve the symmetry of the + NVT model. ...The protocol requires that a NUL be inserted + following a CR not followed by a LF in the data stream. + + Until full negotiation is implemented, we work around the problem + by checking the character following the CR in non-BIN mode and + strip it only if it is LF or NUL. This should not affect + conforming clients. + */ + + case TNS_CRPAD: /* only LF or NUL should follow CR */ + lp->tsta = TNS_NORM; /* next normal */ + if ((tmp == TN_LF) || /* CR + LF ? */ + (tmp == TN_NUL)) /* CR + NUL? */ + tmxr_rmvrc (lp, j); /* remove it */ + break; case TNS_SKIP: default: /* skip char */ lp->tsta = TNS_NORM; /* next normal */ @@ -335,8 +360,8 @@ if (tmxr_tqln (lp) < (TMXR_MAXBUF - 1)) { /* room for char (+ IAC) if ((char) chr == TN_IAC) { /* IAC? */ lp->txb[lp->txbpi] = (char) chr; /* IAC + IAC */ lp->txbpi = lp->txbpi + 1; /* adv pointer */ - if (lp->txbpi >= TMXR_MAXBUF) lp->txbpi = 0; /* wrap? */ - } + if (lp->txbpi >= TMXR_MAXBUF) lp->txbpi = 0; /* wrap? */ + } if (tmxr_tqln (lp) > (TMXR_MAXBUF - TMXR_GUARD)) /* near full? */ lp->xmte = 0; /* disable line */ return SCPE_OK; /* char sent */