diff --git a/0readme_37.txt b/0readme_37.txt index 5c571c79..37d95680 100644 --- a/0readme_37.txt +++ b/0readme_37.txt @@ -1,4 +1,4 @@ -Notes For V3.7-0 +Notes For V3.7 1. New Features diff --git a/AltairZ80/altairZ80_cpu.c b/AltairZ80/altairZ80_cpu.c index b1a79969..8483f81b 100644 --- a/AltairZ80/altairZ80_cpu.c +++ b/AltairZ80/altairZ80_cpu.c @@ -1,6271 +1,6264 @@ -/* 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 void PutBYTEForced(uint32 Addr, const uint32 Value); -static int32 addressIsInROM(const uint32 Addr); -static int32 addressExists(const uint32 Addr); -static void printROMMessage(const uint32 cntROM); -static void warnUnsuccessfulWriteAttempt(const uint32 Addr); -static uint8 warnUnsuccessfulReadAttempt(const uint32 Addr); -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); -static void prepareMemoryAccessMessage(t_addr loc); -static void checkROMBoundaries(void); -static void reset_memory(void); -static uint32 in(const uint32 Port); -static void out(const uint32 Port, const uint32 Value); -static void PutBYTE(register uint32 Addr, const register uint32 Value); -static void PutWORD(register uint32 Addr, const register uint32 Value); -static t_bool sim_brk_lookup (const t_addr bloc, const int32 btyp); -static void resetCell(const int32 address, const int32 bank); - -/* 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; /* 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 -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 */ - -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 Read Only Memory */ -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))); -} - -/* determine whether Addr points to a valid memory address */ -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; - 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; - 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); - 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); - 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; - 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; - 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); - 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); - 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 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; -} - -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 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 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-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; +} diff --git a/AltairZ80/altairZ80_defs.h b/AltairZ80/altairZ80_defs.h index 00153c84..af4cc163 100644 --- a/AltairZ80/altairZ80_defs.h +++ b/AltairZ80/altairZ80_defs.h @@ -14,7 +14,7 @@ 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 + 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. diff --git a/AltairZ80/altairZ80_dsk.c b/AltairZ80/altairZ80_dsk.c index 0a9c2898..e02ccd90 100644 --- a/AltairZ80/altairZ80_dsk.c +++ b/AltairZ80/altairZ80_dsk.c @@ -1,566 +1,559 @@ -/* 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_DSKWLK (UNIT_V_UF + 0) /* write locked */ -#define UNIT_DSKWLK (1 << UNIT_V_DSKWLK) -#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 int32 dskseek(const UNIT *xptr); -static t_stat dsk_boot(int32 unitno, DEVICE *dptr); -static t_stat dsk_reset(DEVICE *dptr); -static void writebuf(void); -static t_stat dsk_set_verbose(UNIT *uptr, int32 value, char *cptr, void *desc); -static void resetDSKWarningFlags(void); -static int32 hasVerbose(void); -static char* selectInOut(const int32 io); - -extern int32 PCX; -extern int32 saved_PC; -extern FILE *sim_log; -extern char messageBuffer[]; -extern UNIT cpu_unit; - -extern void printMessage(void); -extern int32 install_bootrom(void); - -/* global data on status */ - -static int32 current_disk = NUM_OF_DSK; /* 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_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_DSKWLK, 0, "write enabled", "WRITEENABLED", NULL }, - { UNIT_DSKWLK, UNIT_DSKWLK, "write locked", "LOCKED", 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)) { - if (install_bootrom()) { - printf("ALTAIR boot ROM installed.\n"); - } - /* 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; - } - } - saved_PC = DEFAULT_ROM_LOW; - return SCPE_OK; -} - -/* 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 */ - -static int32 dskseek(const UNIT *xptr) { - return fseek(xptr -> fileref, DSK_TRACSIZE * current_track[current_disk] + - DSK_SECTSIZE * current_sector[current_disk], SEEK_SET); -} - -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 */ - } -} - -/* 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_DSKWLK) == 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; -} +/* 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 */ + } +} diff --git a/AltairZ80/altairZ80_sio.c b/AltairZ80/altairZ80_sio.c index eaba1c69..dad8838b 100644 --- a/AltairZ80/altairZ80_sio.c +++ b/AltairZ80/altairZ80_sio.c @@ -1,1290 +1,1277 @@ -/* altairz80_sio.c: MITS Altair serial I/O card - - 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 - - These functions support a simulated MITS 2SIO interface card. - The card had two physical I/O ports which could be connected - to any serial I/O device that would connect to a current loop, - RS232, or TTY interface. Available baud rates were jumper - selectable for each port from 110 to 9600. - - All I/O is via programmed I/O. Each device has a status port - and a data port. A write to the status port can select - some options for the device (0x03 will reset the port). - A read of the status port gets the port status: - - +---+---+---+---+---+---+---+---+ - | X | X | X | X | X | X | O | I | - +---+---+---+---+---+---+---+---+ - - I - A 1 in this bit position means a character has been received - on the data port and is ready to be read. - O - A 1 in this bit means the port is ready to receive a character - on the data port and transmit it out over the serial line. - - A read to the data port gets the buffered character, a write - to the data port writes the character to the device. -*/ - -#include - -#include "altairz80_defs.h" -#include "sim_sock.h" -#include "sim_tmxr.h" -#include -#include -#if UNIX_PLATFORM -#include -#elif defined (_WIN32) -#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_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_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 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 BACKSPACE_CHAR 0x08 /* backspace character */ -#define DELETE_CHAR 0x7f /* delete character */ -#define CONTROLC_CHAR 0x03 /* control C character */ -#define CONTROLG_CHAR 0x07 /* control G char., rings bell when displayed */ -#define CONTROLZ_CHAR 0x1a /* control Z character */ - -static void resetSIOWarningFlags(void); -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); -static t_stat sio_reset(DEVICE *dptr); -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); -int32 nulldev (const int32 port, const int32 io, const int32 data); -int32 sr_dev (const int32 port, const int32 io, const int32 data); -int32 simh_dev (const int32 port, const int32 io, const int32 data); -int32 sio0d (const int32 port, const int32 io, const int32 data); -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); -static int32 mapCharacter(int32 ch); -static void pollConnection(void); -static t_stat simh_dev_reset(DEVICE *dptr); -static t_stat simh_svc(UNIT *uptr); -static int32 simh_in(const int32 port); -static int32 simh_out(const int32 port, const int32 data); -static void createCPMCommandLine(void); -static void attachCPM(UNIT *uptr); -static void setClockZSDOS(void); -static void setClockCPM3(void); -static time_t mkCPM3Origin(void); -static int32 toBCD(const int32 x); -static int32 fromBCD(const int32 x); -void printMessage(void); -static void warnNoRealTimeClock(void); - -extern int32 getBankSelect(void); -extern void setBankSelect(const int32 b); -extern uint32 getCommon(void); -extern uint8 GetBYTEWrapper(const uint32 Addr); - -extern t_bool rtc_avail; -extern FILE *sim_log; -extern int32 PCX; -extern int32 sim_switches; -extern const char *scp_error_messages[]; -extern int32 SR; -extern UNIT cpu_unit; -extern volatile int32 stop_cpu; -extern int32 sim_interval; - -/* SIMH pseudo device status registers */ -/* ZSDOS clock definitions */ -static time_t ClockZSDOSDelta = 0; /* delta between real clock and Altair clock */ -static int32 setClockZSDOSPos = 0; /* determines state for receiving address of parameter block */ -static int32 setClockZSDOSAdr = 0; /* address in M of 6 byte parameter block for setting time */ -static int32 getClockZSDOSPos = 0; /* determines state for sending clock information */ - -/* CPM3 clock definitions */ -static time_t ClockCPM3Delta = 0; /* delta between real clock and Altair clock */ -static int32 setClockCPM3Pos = 0; /* determines state for receiving address of parameter block */ -static int32 setClockCPM3Adr = 0; /* address in M of 5 byte parameter block for setting time */ -static int32 getClockCPM3Pos = 0; /* determines state for sending clock information */ -static int32 daysCPM3SinceOrg = 0; /* days since 1 Jan 1978 */ - -/* interrupt related */ -static uint32 timeOfNextInterrupt; /* time when next interrupt is scheduled */ - int32 timerInterrupt = FALSE; /* timer interrupt pending */ - int32 timerInterruptHandler = 0x0fc00; /* default address of interrupt handling routine */ -static int32 setTimerInterruptAdrPos= 0; /* determines state for receiving timerInterruptHandler */ -static int32 timerDelta = 100; /* interrupt every 100 ms */ -static int32 setTimerDeltaPos = 0; /* determines state for receiving timerDelta */ - -/* stop watch and timer related */ -static uint32 stopWatchDelta = 0; /* stores elapsed time of stop watch */ -static int32 getStopWatchDeltaPos = 0; /* determines the state for receiving stopWatchDelta */ -static uint32 stopWatchNow = 0; /* stores starting time of stop watch */ -static int32 markTimeSP = 0; /* stack pointer for timer stack */ - - /* default time in microseconds to sleep for SIMHSleepCmd */ -#if defined (_WIN32) -static uint32 SIMHSleep = 1000; /* Sleep uses milliseconds */ -#elif defined (__MWERKS__) && defined (macintosh) -static uint32 SIMHSleep = 0; /* No sleep on Macintosh OS9 */ -#else -static uint32 SIMHSleep = 100; /* on other platforms 100 micro seconds is good enough */ -#endif - -/* miscellaneous */ -static int32 versionPos = 0; /* determines state for sending device identifier */ -static int32 lastCPMStatus = 0; /* result of last attachCPM command */ -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 */ -#if UNIX_PLATFORM -static glob_t globS; -static int32 globPosNameList = 0; -static int32 globPosName = 0; -static int32 globValid = FALSE; -static int32 globError = 0; -#elif defined (_WIN32) -static WIN32_FIND_DATA FindFileData; -static HANDLE hFind = INVALID_HANDLE_VALUE; -static int32 globFinished = FALSE; -static int32 globValid = FALSE; -static int32 globPosName = 0; -#endif - -/* SIO status registers */ -static int32 warnLevelSIO = 3; /* display at most 'warnLevelSIO' times the same warning */ -static int32 warnUnattachedPTP = 0; /* display a warning message if < warnLevel and SIO set to - VERBOSE and output to PTP without an attached file */ -static int32 warnUnattachedPTR = 0; /* display a warning message if < warnLevel and SIO set to - VERBOSE and attempt to read from PTR without an attached file */ -static int32 warnPTREOF = 0; /* display a warning message if < warnLevel and SIO set to - VERBOSE and attempt to read from PTR past EOF */ -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 */ - -static TMLN TerminalLines[TERMINALS] = { /* four terminals */ - { 0 } -}; - -static TMXR altairTMXR = { /* mux descriptor */ - TERMINALS, 0, 0, TerminalLines -}; - -static UNIT sio_unit = { - UDATA (NULL, UNIT_ATTABLE + UNIT_MAP, 0), - 0, /* wait = 0 */ - 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 */ - 0 /* u6 = 0, not used */ -}; - -static REG sio_reg[] = { - { DRDATA (SIOWLEV, warnLevelSIO, 32) }, - { DRDATA (WRNUPTP, warnUnattachedPTP, 32) }, - { DRDATA (WRNUPTR, warnUnattachedPTR, 32) }, - { DRDATA (WRNPTRE, warnPTREOF, 32) }, - { DRDATA (WRUPORT, warnUnassignedPort, 32) }, - { HRDATA (FILEATT, sio_unit.u4, 8), REG_RO }, /* TRUE iff terminal input is attached to a file */ - { 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 */ - { 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 */ - { 0 } -}; - -DEVICE sio_dev = { - "SIO", &sio_unit, sio_reg, sio_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &sio_reset, - NULL, &sio_attach, &sio_detach, - NULL, 0, 0, - NULL, NULL, NULL }; - -static UNIT ptr_unit = { - UDATA (NULL, UNIT_SEQ + UNIT_ATTABLE + UNIT_ROABLE, 0) -}; - -static REG ptr_reg[] = { - { HRDATA (STAT, ptr_unit.u3, 8) }, - { NULL } -}; - -DEVICE ptr_dev = { - "PTR", &ptr_unit, ptr_reg, NULL, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ptr_reset, - NULL, NULL, NULL, - NULL, 0, 0, - NULL, NULL, NULL -}; - -static UNIT ptp_unit = { - UDATA (NULL, UNIT_SEQ + UNIT_ATTABLE, 0) -}; - -DEVICE ptp_dev = { - "PTP", &ptp_unit, NULL, NULL, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ptp_reset, - NULL, NULL, NULL, - NULL, 0, 0, - NULL, NULL, NULL -}; - -/* Synthetic device SIMH for communication - between Altair and SIMH environment using port 0xfe */ -static UNIT simh_unit = { - UDATA (&simh_svc, 0, 0), KBD_POLL_WAIT -}; - -static REG simh_reg[] = { - { DRDATA (CZD, ClockZSDOSDelta, 32) }, - { DRDATA (SCZP, setClockZSDOSPos, 8), REG_RO }, - { HRDATA (SCZA, setClockZSDOSAdr, 16), REG_RO }, - { DRDATA (GCZP, getClockZSDOSPos, 8), REG_RO }, - - { DRDATA (CC3D, ClockCPM3Delta, 32) }, - { DRDATA (SC3DP, setClockCPM3Pos, 8), REG_RO }, - { HRDATA (SC3DA, setClockCPM3Adr, 16), REG_RO }, - { DRDATA (GC3DP, getClockCPM3Pos, 8), REG_RO }, - { DRDATA (D3DO, daysCPM3SinceOrg, 32), REG_RO }, - - { DRDATA (TOFNI, timeOfNextInterrupt, 32), REG_RO }, - { DRDATA (TIMI, timerInterrupt, 3) }, - { HRDATA (TIMH, timerInterruptHandler, 16) }, - { DRDATA (STIAP, setTimerInterruptAdrPos,8), REG_RO }, - { DRDATA (TIMD, timerDelta, 32) }, - { DRDATA (STDP, setTimerDeltaPos, 8), REG_RO }, - { DRDATA (SLEEP, SIMHSleep, 32) }, - - { DRDATA (STPDT, stopWatchDelta, 32), REG_RO }, - { DRDATA (STPOS, getStopWatchDeltaPos, 8), REG_RO }, - { DRDATA (STPNW, stopWatchNow, 32), REG_RO }, - { DRDATA (MTSP, markTimeSP, 8), REG_RO }, - - { DRDATA (VPOS, versionPos, 8), REG_RO }, - { DRDATA (LCPMS, lastCPMStatus, 8), REG_RO }, - { DRDATA (LCMD, lastCommand, 8), REG_RO }, - { DRDATA (CPOS, getCommonPos, 8), REG_RO }, - { NULL } -}; - -static MTAB simh_mod[] = { - /* quiet, no warning messages */ - { UNIT_SIMH_VERBOSE, 0, "QUIET", "QUIET", NULL }, - /* verbose, display warning messages */ - { UNIT_SIMH_VERBOSE, UNIT_SIMH_VERBOSE, "VERBOSE", "VERBOSE", NULL }, - /* timer generated interrupts are off */ - { UNIT_SIMH_TIMERON, 0, "TIMEROFF", "TIMEROFF", &simh_dev_set_timeroff }, - /* timer generated interrupts are on */ - { UNIT_SIMH_TIMERON, UNIT_SIMH_TIMERON, "TIMERON", "TIMERON", &simh_dev_set_timeron }, - { 0 } -}; - -DEVICE simh_device = { - "SIMH", &simh_unit, simh_reg, simh_mod, - 1, 10, 31, 1, 16, 4, - NULL, NULL, &simh_dev_reset, - NULL, NULL, NULL, - NULL, 0, 0, - NULL, NULL, NULL -}; - -char messageBuffer[256]; - -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 - if (sim_log) { - fprintf(sim_log, messageBuffer); - fprintf(sim_log,"\n"); - } -} - -static void resetSIOWarningFlags(void) { - warnUnattachedPTP = warnUnattachedPTR = warnPTREOF = warnUnassignedPort = 0; -} - -static t_stat sio_set_verbose(UNIT *uptr, int32 value, char *cptr, void *desc) { - resetSIOWarningFlags(); - return SCPE_OK; -} - -static t_stat sio_attach(UNIT *uptr, char *cptr) { - t_stat r = SCPE_IERR; - sio_unit.u3 = FALSE; /* no character in terminal input buffer */ - get_uint(cptr, 10, 65535, &r); /* attempt to get port, discard result */ - if (r == SCPE_OK) { /* string can be interpreted as port number */ - sio_unit.u4 = FALSE; /* terminal input is not attached to a file */ - return tmxr_attach(&altairTMXR, uptr, cptr); /* attach mux */ - } - sio_unit.u4 = TRUE; /* terminal input is attached to a file */ - sio_unit.u5 = FALSE; /* EOF not yet reached */ - return attach_unit(uptr, cptr); -} - -static t_stat sio_detach(UNIT *uptr) { - sio_unit.u3 = FALSE; /* no character in terminal input buffer */ - if (sio_unit.u4) { /* is terminal input attached to a file? */ - sio_unit.u4 = FALSE; /* not anymore, detach */ - return detach_unit(uptr); - } - return tmxr_detach(&altairTMXR, uptr); -} - -static void pollConnection(void) { - if (sio_unit.flags & UNIT_ATT) { - int32 temp = tmxr_poll_conn(&altairTMXR); /* poll connection */ - if (temp >= 0) - TerminalLines[temp].rcve = 1; /* enable receive */ - tmxr_poll_rx(&altairTMXR); /* poll input */ - tmxr_poll_tx(&altairTMXR); /* poll output */ - } -} - -/* reset routines */ -static t_stat sio_reset(DEVICE *dptr) { - int32 i; - sio_unit.u3 = FALSE; /* no character in terminal input buffer */ - resetSIOWarningFlags(); - if (sio_unit.u4) { /* is terminal input attached to a file? */ - rewind(sio_unit.fileref); /* yes, rewind input */ - sio_unit.u5 = FALSE; /* EOF not yet reached */ - } - else if (sio_unit.flags & UNIT_ATT) - for (i = 0; i < TERMINALS; i++) - if (TerminalLines[i].conn) - tmxr_reset_ln(&TerminalLines[i]); - return SCPE_OK; -} - -static t_stat ptr_reset(DEVICE *dptr) { - resetSIOWarningFlags(); - ptr_unit.u3 = FALSE; /* End Of File not yet reached */ - if (ptr_unit.flags & UNIT_ATT) /* attached? */ - rewind(ptr_unit.fileref); - return SCPE_OK; -} - -static t_stat ptp_reset(DEVICE *dptr) { - resetSIOWarningFlags(); - return SCPE_OK; -} - - -/* 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. - - Port 1 controls console I/O. We distinguish three cases: - 1) SIO attached to a file (i.e. input taken from a file ) - 2) SIO attached to a port (i.e. Telnet console I/O ) - 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); - } - if (io == 0) { /* IN */ - 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; - } - 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); - /* write possible if connected and transmit - enabled */ - } - if (sio_unit.u3) /* character available? */ - return SIO_CAN_READ | 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 */ - } - sio_unit.u3 = TRUE; /* indicate character available */ - sio_unit.buf = ch; /* store character in buffer */ - return SIO_CAN_READ | SIO_CAN_WRITE; - } - return SIO_CAN_WRITE; - } /* OUT follows */ - if (data == 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; -} - -int32 sio0d(const int32 port, const int32 io, const int32 data) { - int32 ti = 0, ch; - 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? */ - sio_detach(&sio_unit); /* detach file and switch to keyboard input */ - return CONTROLC_CHAR; /* this time return ^C after all */ - } - if ((ch = getc(sio_unit.fileref)) == EOF) { /* end of file? */ - sio_unit.u5 = TRUE; /* terminal input file has reached EOF */ - return CONTROLC_CHAR; /* result is ^C (= CP/M interrupt) */ - } - return mapCharacter(ch); /* return mapped character */ - } - if (sio_unit.flags & UNIT_ATT) - return mapCharacter(tmxr_getc_ln(&TerminalLines[ti])); - 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); - return 0x00; /* ignored since OUT */ -} - -/* PTR/PTP status port */ -int32 sio1s(const int32 port, const int32 io, const int32 data) { - if (io == 0) { /* IN */ - /* reset I bit iff PTR unit not attached or - no more data available. O bit is always - set since write always possible. */ - 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."); - } - return SIO_CAN_WRITE; - } - /* if EOF then SIO_CAN_WRITE else - (SIO_CAN_WRITE and SIO_CAN_READ) */ - return ptr_unit.u3 ? SIO_CAN_WRITE : (SIO_CAN_READ | SIO_CAN_WRITE); - } /* OUT follows */ - if (data == SIO_RESET) - ptr_unit.u3 = FALSE; /* reset EOF indicator */ - return 0x00; /* ignored since OUT */ -} - -/* PTR/PTP data port */ -int32 sio1d(const int32 port, const int32 io, const int32 data) { - int32 ch; - if (io == 0) { /* IN */ - 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."); - } - 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."); - } - return 0x00; - } - if ((ch = getc(ptr_unit.fileref)) == EOF) { /* end of file? */ - ptr_unit.u3 = TRUE; /* remember EOF reached */ - return CONTROLZ_CHAR; /* ^Z denotes end of text file in CP/M */ - } - return ch & 0xff; - } /* OUT follows */ - if (ptp_unit.flags & UNIT_ATT) /* unit must be attached */ - putc(data, ptp_unit.fileref); - /* 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); - } - return 0x00; /* ignored since OUT */ -} - -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); - } - else { - MESSAGE_3("Unassigned OUT(%2xh) -> %2xh - ignored.", port, data); - } - } - return io == 0 ? 0xff : 0; -} - -int32 sr_dev(const int32 port, const int32 io, const int32 data) { - return io == 0 ? SR : 0; -} - -static int32 toBCD(const int32 x) { - return (x / 10) * 16 + (x % 10); -} - -static int32 fromBCD(const int32 x) { - return 10 * ((0xf0 & x) >> 4) + (0x0f & x); -} - -/* Z80 or 8080 programs communicate with the SIMH pseudo device via port 0xfe. - The following principles apply: - - 1) For commands that do not require parameters and do not return results - ld a, - out (0feh),a - Special case is the reset command which needs to be send 128 times to make - sure that the internal state is properly reset. - - 2) For commands that require parameters and do not return results - ld a, - out (0feh),a - ld a, - out (0feh),a - ld a, - out (0feh),a - ... - Note: The calling program must send all parameter bytes. Otherwise - the pseudo device is left in an undefined state. - - 3) For commands that do not require parameters and return results - ld a, - out (0feh),a - in a,(0feh) ; contains first byte of result - in a,(0feh) ; contains second byte of result - ... - Note: The calling program must request all bytes of the result. Otherwise - the pseudo device is left in an undefined state. - - 4) Commands requiring parameters and returning results do not exist currently. - -*/ - -enum simhPseudoDeviceCommands { /* do not change order or remove commands, add only at the end */ - printTimeCmd, /* 0 print the current time in milliseconds */ - startTimerCmd, /* 1 start a new timer on the top of the timer stack */ - stopTimerCmd, /* 2 stop timer on top of timer stack and show time difference */ - resetPTRCmd, /* 3 reset the PTR device */ - attachPTRCmd, /* 4 attach the PTR device */ - detachPTRCmd, /* 5 detach the PTR device */ - getSIMHVersionCmd, /* 6 get the current version of the SIMH pseudo device */ - getClockZSDOSCmd, /* 7 get the current time in ZSDOS format */ - setClockZSDOSCmd, /* 8 set the current time in ZSDOS format */ - getClockCPM3Cmd, /* 9 get the current time in CP/M 3 format */ - setClockCPM3Cmd, /* 10 set the current time in CP/M 3 format */ - getBankSelectCmd, /* 11 get the selected bank */ - setBankSelectCmd, /* 12 set the selected bank */ - getCommonCmd, /* 13 get the base address of the common memory segment */ - resetSIMHInterfaceCmd, /* 14 reset the SIMH pseudo device */ - showTimerCmd, /* 15 show time difference to timer on top of stack */ - attachPTPCmd, /* 16 attach PTP to the file with name at beginning of CP/M command line*/ - detachPTPCmd, /* 17 detach PTP */ - hasBankedMemoryCmd, /* 18 determines whether machine has banked memory */ - setZ80CPUCmd, /* 19 set the CPU to a Z80 */ - set8080CPUCmd, /* 20 set the CPU to an 8080 */ - startTimerInterruptsCmd, /* 21 start timer interrupts */ - stopTimerInterruptsCmd, /* 22 stop timer interrupts */ - setTimerDeltaCmd, /* 23 set the timer interval in which interrupts occur */ - setTimerInterruptAdrCmd, /* 24 set the address to call by timer interrupts */ - resetStopWatchCmd, /* 25 reset the millisecond stop watch */ - readStopWatchCmd, /* 26 read the millisecond stop watch */ - SIMHSleepCmd, /* 27 let SIMH sleep for SIMHSleep microseconds */ - getHostOSPathSeparator, /* 28 obtain the file path separator of the OS under which SIMH runs */ - getHostFilenames /* 29 perform wildcard expansion and obtain list of file names */ -}; - -#define CPM_COMMAND_LINE_LENGTH 128 -#define TIMER_STACK_LIMIT 10 /* stack depth of timer stack */ -static uint32 markTime[TIMER_STACK_LIMIT]; /* timer stack */ -static struct tm currentTime; -static int32 currentTimeValid = FALSE; -static char version[] = "SIMH003"; - -static t_stat simh_dev_reset(DEVICE *dptr) { - currentTimeValid = FALSE; - ClockZSDOSDelta = 0; - setClockZSDOSPos = 0; - getClockZSDOSPos = 0; - ClockCPM3Delta = 0; - setClockCPM3Pos = 0; - getClockCPM3Pos = 0; - getStopWatchDeltaPos = 0; - getCommonPos = 0; - setTimerDeltaPos = 0; - setTimerInterruptAdrPos = 0; - markTimeSP = 0; - versionPos = 0; - lastCommand = 0; - lastCPMStatus = SCPE_OK; - timerInterrupt = FALSE; - if (simh_unit.flags & UNIT_SIMH_TIMERON) - simh_dev_set_timeron(NULL, 0, NULL, NULL); - return SCPE_OK; -} - -static void warnNoRealTimeClock(void) { - if (simh_unit.flags & UNIT_SIMH_VERBOSE) - printf("Sorry - no real time clock available.\n"); -} - -static t_stat simh_dev_set_timeron(UNIT *uptr, int32 value, char *cptr, void *desc) { - if (rtc_avail) { - timeOfNextInterrupt = sim_os_msec() + timerDelta; - return sim_activate(&simh_unit, simh_unit.wait); /* activate unit */ - } - warnNoRealTimeClock(); - return SCPE_ARG; -} - -static t_stat simh_dev_set_timeroff(UNIT *uptr, int32 value, char *cptr, void *desc) { - timerInterrupt = FALSE; - sim_cancel(&simh_unit); - return SCPE_OK; -} - -static t_stat simh_svc(UNIT *uptr) { - uint32 n = sim_os_msec(); - if (n >= timeOfNextInterrupt) { - timerInterrupt = TRUE; - timeOfNextInterrupt += timerDelta; - if (n >= timeOfNextInterrupt) /* time of next interrupt is not in the future */ - timeOfNextInterrupt = n + timerDelta; /* make sure it is in the future! */ - } - if (simh_unit.flags & UNIT_SIMH_TIMERON) - sim_activate(&simh_unit, simh_unit.wait); /* activate unit */ - return SCPE_OK; -} - -static char cpmCommandLine[CPM_COMMAND_LINE_LENGTH]; -static void createCPMCommandLine(void) { - int32 i, len = (GetBYTEWrapper(0x80) & 0x7f); /* 0x80 contains length of command line, discard first char */ - for (i = 0; i < len - 1; i++) - cpmCommandLine[i] = (char)GetBYTEWrapper(0x82 + i); /* the first char, typically ' ', is discarded */ - cpmCommandLine[i] = 0; /* make C string */ -} - -/* The CP/M command line is used as the name of a file and UNIT* uptr is attached to it. */ -static void attachCPM(UNIT *uptr) { - createCPMCommandLine(); - if (uptr == &ptr_unit) - sim_switches = SWMASK('R'); - else if (uptr == &ptp_unit) - sim_switches = SWMASK('W') | SWMASK('C'); /* 'C' option makes sure that file is properly truncated - if it had existed before */ - 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 */ - } -} - -/* setClockZSDOSAdr points to 6 byte block in M: YY MM DD HH MM SS in BCD notation */ -static void setClockZSDOS(void) { - struct tm newTime; - int32 year = fromBCD(GetBYTEWrapper(setClockZSDOSAdr)); - newTime.tm_year = year < 50 ? year + 100 : year; - newTime.tm_mon = fromBCD(GetBYTEWrapper(setClockZSDOSAdr + 1)) - 1; - newTime.tm_mday = fromBCD(GetBYTEWrapper(setClockZSDOSAdr + 2)); - newTime.tm_hour = fromBCD(GetBYTEWrapper(setClockZSDOSAdr + 3)); - newTime.tm_min = fromBCD(GetBYTEWrapper(setClockZSDOSAdr + 4)); - newTime.tm_sec = fromBCD(GetBYTEWrapper(setClockZSDOSAdr + 5)); - ClockZSDOSDelta = mktime(&newTime) - time(NULL); -} - -#define SECONDS_PER_MINUTE 60 -#define SECONDS_PER_HOUR (60 * SECONDS_PER_MINUTE) -#define SECONDS_PER_DAY (24 * SECONDS_PER_HOUR) -static time_t mkCPM3Origin(void) { - struct tm date; - date.tm_year = 77; - date.tm_mon = 11; - date.tm_mday = 31; - date.tm_hour = 0; - date.tm_min = 0; - date.tm_sec = 0; - return mktime(&date); -} - -/* setClockCPM3Adr points to 5 byte block in M: - 0 - 1 int16: days since 31 Dec 77 - 2 BCD byte: HH - 3 BCD byte: MM - 4 BCD byte: SS */ -static void setClockCPM3(void) { - ClockCPM3Delta = mkCPM3Origin() + - (GetBYTEWrapper(setClockCPM3Adr) + GetBYTEWrapper(setClockCPM3Adr + 1) * 256) * SECONDS_PER_DAY + - fromBCD(GetBYTEWrapper(setClockCPM3Adr + 2)) * SECONDS_PER_HOUR + - fromBCD(GetBYTEWrapper(setClockCPM3Adr + 3)) * SECONDS_PER_MINUTE + - fromBCD(GetBYTEWrapper(setClockCPM3Adr + 4)) - time(NULL); -} - -static int32 simh_in(const int32 port) { - int32 result = 0; - switch(lastCommand) { - - case getHostFilenames: -#if UNIX_PLATFORM - if (globValid) - if (globPosNameList < globS.gl_pathc) { - if (!(result = globS.gl_pathv[globPosNameList][globPosName++])) { - globPosNameList++; - globPosName = 0; - } - } - else { - globValid = FALSE; - lastCommand = 0; - globfree(&globS); - } -#elif defined (_WIN32) - if (globValid) { - if (globFinished) { - globValid = FALSE; - } - else if (!(result = FindFileData.cFileName[globPosName++])) { - globPosName = 0; - if (!FindNextFile(hFind, &FindFileData)) { - globFinished = TRUE; - FindClose(hFind); - hFind = INVALID_HANDLE_VALUE; - } - } - } -#else - lastCommand = 0; -#endif - break; - - case attachPTRCmd: - - case attachPTPCmd: - result = lastCPMStatus; - lastCommand = 0; - break; - - case getClockZSDOSCmd: - if (currentTimeValid) { - switch(getClockZSDOSPos) { - - case 0: - result = toBCD(currentTime.tm_year > 99 ? - currentTime.tm_year - 100 : currentTime.tm_year); - getClockZSDOSPos = 1; - break; - - case 1: - result = toBCD(currentTime.tm_mon + 1); - getClockZSDOSPos = 2; - break; - - case 2: - result = toBCD(currentTime.tm_mday); - getClockZSDOSPos = 3; - break; - - case 3: - result = toBCD(currentTime.tm_hour); - getClockZSDOSPos = 4; - break; - - case 4: - result = toBCD(currentTime.tm_min); - getClockZSDOSPos = 5; - break; - - case 5: - result = toBCD(currentTime.tm_sec); - getClockZSDOSPos = lastCommand = 0; - break; - } - } - else { - result = getClockZSDOSPos = lastCommand = 0; - } - break; - - case getClockCPM3Cmd: - if (currentTimeValid) { - switch(getClockCPM3Pos) { - case 0: - result = daysCPM3SinceOrg & 0xff; - getClockCPM3Pos = 1; - break; - - case 1: - result = (daysCPM3SinceOrg >> 8) & 0xff; - getClockCPM3Pos = 2; - break; - - case 2: - result = toBCD(currentTime.tm_hour); - getClockCPM3Pos = 3; - break; - - case 3: - result = toBCD(currentTime.tm_min); - getClockCPM3Pos = 4; - break; - - case 4: - result = toBCD(currentTime.tm_sec); - getClockCPM3Pos = lastCommand = 0; - break; - } - } - else { - result = getClockCPM3Pos = lastCommand = 0; - } - break; - - case getSIMHVersionCmd: - result = version[versionPos++]; - if (result == 0) { - versionPos = lastCommand = 0; - } - break; - - case getBankSelectCmd: - if (cpu_unit.flags & UNIT_BANKED) { - result = getBankSelect(); - } - else { - result = 0; - if (simh_unit.flags & UNIT_SIMH_VERBOSE) { - MESSAGE_1("Get selected bank ignored for non-banked memory."); - } - } - lastCommand = 0; - break; - - case getCommonCmd: - if (getCommonPos == 0) { - result = getCommon() & 0xff; - getCommonPos = 1; - } - else { - result = (getCommon() >> 8) & 0xff; - getCommonPos = lastCommand = 0; - } - break; - - case hasBankedMemoryCmd: - result = cpu_unit.flags & UNIT_BANKED ? MAXBANKS : 0; - lastCommand = 0; - break; - - case readStopWatchCmd: - if (getStopWatchDeltaPos == 0) { - result = stopWatchDelta & 0xff; - getStopWatchDeltaPos = 1; - } - else { - result = (stopWatchDelta >> 8) & 0xff; - getStopWatchDeltaPos = lastCommand = 0; - } - break; - - case getHostOSPathSeparator: -#if defined (__MWERKS__) && defined (macintosh) - result = ':'; /* colon on Macintosh OS 9 */ -#elif defined (_WIN32) - result = '\\'; /* back slash in Windows */ -#else - result = '/'; /* slash in UNIX */ -#endif - break; - - default: - if (simh_unit.flags & UNIT_SIMH_VERBOSE) { - MESSAGE_2("Undefined IN from SIMH pseudo device on port %03xh ignored.", - port); - } - result = lastCommand = 0; - } - return result; -} - -static int32 simh_out(const int32 port, const int32 data) { - time_t now; - switch(lastCommand) { - - case setClockZSDOSCmd: - if (setClockZSDOSPos == 0) { - setClockZSDOSAdr = data; - setClockZSDOSPos = 1; - } - else { - setClockZSDOSAdr |= (data << 8); - setClockZSDOS(); - setClockZSDOSPos = lastCommand = 0; - } - break; - - case setClockCPM3Cmd: - if (setClockCPM3Pos == 0) { - setClockCPM3Adr = data; - setClockCPM3Pos = 1; - } - else { - setClockCPM3Adr |= (data << 8); - setClockCPM3(); - setClockCPM3Pos = lastCommand = 0; - } - break; - - case setBankSelectCmd: - if (cpu_unit.flags & UNIT_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); - } - lastCommand = 0; - break; - - case setTimerDeltaCmd: - if (setTimerDeltaPos == 0) { - timerDelta = data; - setTimerDeltaPos = 1; - } - else { - timerDelta |= (data << 8); - setTimerDeltaPos = lastCommand = 0; - } - break; - - case setTimerInterruptAdrCmd: - if (setTimerInterruptAdrPos == 0) { - timerInterruptHandler = data; - setTimerInterruptAdrPos = 1; - } - else { - timerInterruptHandler |= (data << 8); - setTimerInterruptAdrPos = lastCommand = 0; - } - break; - - default: - lastCommand = data; - switch(data) { - - case getHostFilenames: -#if UNIX_PLATFORM - if (!globValid) { - globValid = TRUE; - globPosNameList = globPosName = 0; - createCPMCommandLine(); - globError = glob(cpmCommandLine, GLOB_ERR, NULL, &globS); - if (globError) { - if (simh_unit.flags & UNIT_SIMH_VERBOSE) { - MESSAGE_3("Cannot expand '%s'. Error is %i.", cpmCommandLine, globError); - } - globfree(&globS); - globValid = FALSE; - } - } -#elif defined (_WIN32) - if (!globValid) { - globValid = TRUE; - globPosName = 0; - globFinished = FALSE; - createCPMCommandLine(); - hFind = FindFirstFile(cpmCommandLine, &FindFileData); - if (hFind == INVALID_HANDLE_VALUE) { - if (simh_unit.flags & UNIT_SIMH_VERBOSE) { - MESSAGE_3("Cannot expand '%s'. Error is %u.", cpmCommandLine, GetLastError()); - } - globValid = FALSE; - } - } -#endif - 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 - break; - - case printTimeCmd: /* print time */ - if (rtc_avail) { - MESSAGE_2("Current time in milliseconds = %d.", sim_os_msec()); - } - else { - warnNoRealTimeClock(); - } - break; - - case startTimerCmd: /* create a new timer on top of stack */ - if (rtc_avail) { - if (markTimeSP < TIMER_STACK_LIMIT) { - markTime[markTimeSP++] = sim_os_msec(); - } - else { - MESSAGE_1("Timer stack overflow."); - } - } - else { - warnNoRealTimeClock(); - } - break; - - case stopTimerCmd: /* stop timer on top of stack and show time difference */ - if (rtc_avail) { - if (markTimeSP > 0) { - uint32 delta = sim_os_msec() - markTime[--markTimeSP]; - MESSAGE_2("Timer stopped. Elapsed time in milliseconds = %d.", delta); - } - else { - MESSAGE_1("No timer active."); - } - } - else { - warnNoRealTimeClock(); - } - break; - - case resetPTRCmd: /* reset ptr device */ - ptr_reset(NULL); - break; - - case attachPTRCmd: /* attach ptr to the file with name at beginning of CP/M command line */ - attachCPM(&ptr_unit); - break; - - case detachPTRCmd: /* detach ptr */ - detach_unit(&ptr_unit); - break; - - case getSIMHVersionCmd: - versionPos = 0; - break; - - case getClockZSDOSCmd: - time(&now); - now += ClockZSDOSDelta; - currentTime = *localtime(&now); - currentTimeValid = TRUE; - getClockZSDOSPos = 0; - break; - - case setClockZSDOSCmd: - setClockZSDOSPos = 0; - break; - - case getClockCPM3Cmd: - time(&now); - now += ClockCPM3Delta; - currentTime = *localtime(&now); - currentTimeValid = TRUE; - daysCPM3SinceOrg = (int32) ((now - mkCPM3Origin()) / SECONDS_PER_DAY); - getClockCPM3Pos = 0; - break; - - case setClockCPM3Cmd: - setClockCPM3Pos = 0; - break; - - case getBankSelectCmd: - case setBankSelectCmd: - case getCommonCmd: - case hasBankedMemoryCmd: - case getHostOSPathSeparator: - break; - - case resetSIMHInterfaceCmd: - markTimeSP = 0; - lastCommand = 0; -#if UNIX_PLATFORM - if (globValid) { - globValid = FALSE; - globfree(&globS); - } -#elif defined (_WIN32) - if (globValid) { - globValid = FALSE; - if (hFind != INVALID_HANDLE_VALUE) { - FindClose(hFind); - } - } -#endif - break; - - case showTimerCmd: /* show time difference to timer on top of stack */ - if (rtc_avail) { - if (markTimeSP > 0) { - uint32 delta = sim_os_msec() - markTime[markTimeSP - 1]; - MESSAGE_2("Timer running. Elapsed in milliseconds = %d.", delta); - } - else { - MESSAGE_1("No timer active."); - } - } - else { - warnNoRealTimeClock(); - } - break; - - case attachPTPCmd: /* attach ptp to the file with name at beginning of CP/M command line */ - attachCPM(&ptp_unit); - break; - - case detachPTPCmd: /* detach ptp */ - detach_unit(&ptp_unit); - break; - - case setZ80CPUCmd: - cpu_unit.flags |= UNIT_CHIP; - break; - - case set8080CPUCmd: - cpu_unit.flags &= ~UNIT_CHIP; - break; - - case startTimerInterruptsCmd: - if (simh_dev_set_timeron(NULL, 0, NULL, NULL) == SCPE_OK) { - timerInterrupt = FALSE; - simh_unit.flags |= UNIT_SIMH_TIMERON; - } - break; - - case stopTimerInterruptsCmd: - simh_unit.flags &= ~UNIT_SIMH_TIMERON; - simh_dev_set_timeroff(NULL, 0, NULL, NULL); - break; - - case setTimerDeltaCmd: - setTimerDeltaPos = 0; - break; - - case setTimerInterruptAdrCmd: - setTimerInterruptAdrPos = 0; - break; - - case resetStopWatchCmd: - stopWatchNow = rtc_avail ? sim_os_msec() : 0; - break; - - case readStopWatchCmd: - getStopWatchDeltaPos = 0; - stopWatchDelta = rtc_avail ? sim_os_msec() - stopWatchNow : 0; - break; - - default: - if (simh_unit.flags & UNIT_SIMH_VERBOSE) { - MESSAGE_3("Unknown command (%i) to SIMH pseudo device on port %03xh ignored.", - data, port); - } - } - } - return 0x00; /* ignored, since OUT */ -} - -/* port 0xfe is a device for communication SIMH <--> Altair machine */ -int32 simh_dev(const int32 port, const int32 io, const int32 data) { - return io == 0 ? simh_in(port) : simh_out(port, data); -} +/* altairz80_sio.c: MITS Altair serial I/O card + + 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 + + These functions support a simulated MITS 2SIO interface card. + The card had two physical I/O ports which could be connected + to any serial I/O device that would connect to a current loop, + RS232, or TTY interface. Available baud rates were jumper + selectable for each port from 110 to 9600. + + All I/O is via programmed I/O. Each device has a status port + and a data port. A write to the status port can select + some options for the device (0x03 will reset the port). + A read of the status port gets the port status: + + +---+---+---+---+---+---+---+---+ + | X | X | X | X | X | X | O | I | + +---+---+---+---+---+---+---+---+ + + I - A 1 in this bit position means a character has been received + on the data port and is ready to be read. + O - A 1 in this bit means the port is ready to receive a character + on the data port and transmit it out over the serial line. + + A read to the data port gets the buffered character, a write + to the data port writes the character to the device. +*/ + +#include + +#include "altairz80_defs.h" +#include "sim_sock.h" +#include "sim_tmxr.h" +#include +#include +#if UNIX_PLATFORM +#include +#elif defined (_WIN32) +#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_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_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 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 BACKSPACE_CHAR 0x08 /* backspace character */ +#define DELETE_CHAR 0x7f /* delete character */ +#define CONTROLC_CHAR 0x03 /* control C character */ +#define CONTROLG_CHAR 0x07 /* control G char., rings bell when displayed */ +#define CONTROLZ_CHAR 0x1a /* control Z character */ + +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); +static t_stat sio_reset(DEVICE *dptr); +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 simh_dev_reset(DEVICE *dptr); +static t_stat simh_svc(UNIT *uptr); +int32 nulldev (const int32 port, const int32 io, const int32 data); +int32 sr_dev (const int32 port, const int32 io, const int32 data); +int32 simh_dev (const int32 port, const int32 io, const int32 data); +int32 sio0d (const int32 port, const int32 io, const int32 data); +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); + +extern int32 getBankSelect(void); +extern void setBankSelect(const int32 b); +extern uint32 getCommon(void); +extern uint8 GetBYTEWrapper(const uint32 Addr); + +extern t_bool rtc_avail; +extern FILE *sim_log; +extern int32 PCX; +extern int32 sim_switches; +extern const char *scp_error_messages[]; +extern int32 SR; +extern UNIT cpu_unit; +extern volatile int32 stop_cpu; +extern int32 sim_interval; + +/* SIMH pseudo device status registers */ +/* ZSDOS clock definitions */ +static time_t ClockZSDOSDelta = 0; /* delta between real clock and Altair clock */ +static int32 setClockZSDOSPos = 0; /* determines state for receiving address of parameter block */ +static int32 setClockZSDOSAdr = 0; /* address in M of 6 byte parameter block for setting time */ +static int32 getClockZSDOSPos = 0; /* determines state for sending clock information */ + +/* CPM3 clock definitions */ +static time_t ClockCPM3Delta = 0; /* delta between real clock and Altair clock */ +static int32 setClockCPM3Pos = 0; /* determines state for receiving address of parameter block */ +static int32 setClockCPM3Adr = 0; /* address in M of 5 byte parameter block for setting time */ +static int32 getClockCPM3Pos = 0; /* determines state for sending clock information */ +static int32 daysCPM3SinceOrg = 0; /* days since 1 Jan 1978 */ + +/* interrupt related */ +static uint32 timeOfNextInterrupt; /* time when next interrupt is scheduled */ + int32 timerInterrupt = FALSE; /* timer interrupt pending */ + int32 timerInterruptHandler = 0x0fc00; /* default address of interrupt handling routine */ +static int32 setTimerInterruptAdrPos= 0; /* determines state for receiving timerInterruptHandler */ +static int32 timerDelta = 100; /* interrupt every 100 ms */ +static int32 setTimerDeltaPos = 0; /* determines state for receiving timerDelta */ + +/* stop watch and timer related */ +static uint32 stopWatchDelta = 0; /* stores elapsed time of stop watch */ +static int32 getStopWatchDeltaPos = 0; /* determines the state for receiving stopWatchDelta */ +static uint32 stopWatchNow = 0; /* stores starting time of stop watch */ +static int32 markTimeSP = 0; /* stack pointer for timer stack */ + + /* default time in microseconds to sleep for SIMHSleepCmd */ +#if defined (_WIN32) +static uint32 SIMHSleep = 1000; /* Sleep uses milliseconds */ +#elif defined (__MWERKS__) && defined (macintosh) +static uint32 SIMHSleep = 0; /* No sleep on Macintosh OS9 */ +#else +static uint32 SIMHSleep = 100; /* on other platforms 100 micro seconds is good enough */ +#endif + +/* miscellaneous */ +static int32 versionPos = 0; /* determines state for sending device identifier */ +static int32 lastCPMStatus = 0; /* result of last attachCPM command */ +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 */ +#if UNIX_PLATFORM +static glob_t globS; +static int32 globPosNameList = 0; +static int32 globPosName = 0; +static int32 globValid = FALSE; +static int32 globError = 0; +#elif defined (_WIN32) +static WIN32_FIND_DATA FindFileData; +static HANDLE hFind = INVALID_HANDLE_VALUE; +static int32 globFinished = FALSE; +static int32 globValid = FALSE; +static int32 globPosName = 0; +#endif + +/* SIO status registers */ +static int32 warnLevelSIO = 3; /* display at most 'warnLevelSIO' times the same warning */ +static int32 warnUnattachedPTP = 0; /* display a warning message if < warnLevel and SIO set to + VERBOSE and output to PTP without an attached file */ +static int32 warnUnattachedPTR = 0; /* display a warning message if < warnLevel and SIO set to + VERBOSE and attempt to read from PTR without an attached file */ +static int32 warnPTREOF = 0; /* display a warning message if < warnLevel and SIO set to + VERBOSE and attempt to read from PTR past EOF */ +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 */ + +static TMLN TerminalLines[TERMINALS] = { /* four terminals */ + { 0 } +}; + +static TMXR altairTMXR = { /* mux descriptor */ + TERMINALS, 0, 0, TerminalLines +}; + +static UNIT sio_unit = { + UDATA (NULL, UNIT_ATTABLE + UNIT_MAP, 0), + 0, /* wait = 0 */ + 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 */ + 0 /* u6 = 0, not used */ +}; + +static REG sio_reg[] = { + { DRDATA (SIOWLEV, warnLevelSIO, 32) }, + { DRDATA (WRNUPTP, warnUnattachedPTP, 32) }, + { DRDATA (WRNUPTR, warnUnattachedPTR, 32) }, + { DRDATA (WRNPTRE, warnPTREOF, 32) }, + { DRDATA (WRUPORT, warnUnassignedPort, 32) }, + { HRDATA (FILEATT, sio_unit.u4, 8), REG_RO }, /* TRUE iff terminal input is attached to a file */ + { 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 */ + { 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 */ + { 0 } +}; + +DEVICE sio_dev = { + "SIO", &sio_unit, sio_reg, sio_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &sio_reset, + NULL, &sio_attach, &sio_detach, + NULL, 0, 0, + NULL, NULL, NULL }; + +static UNIT ptr_unit = { + UDATA (NULL, UNIT_SEQ + UNIT_ATTABLE + UNIT_ROABLE, 0) +}; + +static REG ptr_reg[] = { + { HRDATA (STAT, ptr_unit.u3, 8) }, + { NULL } +}; + +DEVICE ptr_dev = { + "PTR", &ptr_unit, ptr_reg, NULL, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &ptr_reset, + NULL, NULL, NULL, + NULL, 0, 0, + NULL, NULL, NULL +}; + +static UNIT ptp_unit = { + UDATA (NULL, UNIT_SEQ + UNIT_ATTABLE, 0) +}; + +DEVICE ptp_dev = { + "PTP", &ptp_unit, NULL, NULL, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &ptp_reset, + NULL, NULL, NULL, + NULL, 0, 0, + NULL, NULL, NULL +}; + +/* Synthetic device SIMH for communication + between Altair and SIMH environment using port 0xfe */ +static UNIT simh_unit = { + UDATA (&simh_svc, 0, 0), KBD_POLL_WAIT +}; + +static REG simh_reg[] = { + { DRDATA (CZD, ClockZSDOSDelta, 32) }, + { DRDATA (SCZP, setClockZSDOSPos, 8), REG_RO }, + { HRDATA (SCZA, setClockZSDOSAdr, 16), REG_RO }, + { DRDATA (GCZP, getClockZSDOSPos, 8), REG_RO }, + + { DRDATA (CC3D, ClockCPM3Delta, 32) }, + { DRDATA (SC3DP, setClockCPM3Pos, 8), REG_RO }, + { HRDATA (SC3DA, setClockCPM3Adr, 16), REG_RO }, + { DRDATA (GC3DP, getClockCPM3Pos, 8), REG_RO }, + { DRDATA (D3DO, daysCPM3SinceOrg, 32), REG_RO }, + + { DRDATA (TOFNI, timeOfNextInterrupt, 32), REG_RO }, + { DRDATA (TIMI, timerInterrupt, 3) }, + { HRDATA (TIMH, timerInterruptHandler, 16) }, + { DRDATA (STIAP, setTimerInterruptAdrPos,8), REG_RO }, + { DRDATA (TIMD, timerDelta, 32) }, + { DRDATA (STDP, setTimerDeltaPos, 8), REG_RO }, + { DRDATA (SLEEP, SIMHSleep, 32) }, + + { DRDATA (STPDT, stopWatchDelta, 32), REG_RO }, + { DRDATA (STPOS, getStopWatchDeltaPos, 8), REG_RO }, + { DRDATA (STPNW, stopWatchNow, 32), REG_RO }, + { DRDATA (MTSP, markTimeSP, 8), REG_RO }, + + { DRDATA (VPOS, versionPos, 8), REG_RO }, + { DRDATA (LCPMS, lastCPMStatus, 8), REG_RO }, + { DRDATA (LCMD, lastCommand, 8), REG_RO }, + { DRDATA (CPOS, getCommonPos, 8), REG_RO }, + { NULL } +}; + +static MTAB simh_mod[] = { + /* quiet, no warning messages */ + { UNIT_SIMH_VERBOSE, 0, "QUIET", "QUIET", NULL }, + /* verbose, display warning messages */ + { UNIT_SIMH_VERBOSE, UNIT_SIMH_VERBOSE, "VERBOSE", "VERBOSE", NULL }, + /* timer generated interrupts are off */ + { UNIT_SIMH_TIMERON, 0, "TIMEROFF", "TIMEROFF", &simh_dev_set_timeroff }, + /* timer generated interrupts are on */ + { UNIT_SIMH_TIMERON, UNIT_SIMH_TIMERON, "TIMERON", "TIMERON", &simh_dev_set_timeron }, + { 0 } +}; + +DEVICE simh_device = { + "SIMH", &simh_unit, simh_reg, simh_mod, + 1, 10, 31, 1, 16, 4, + NULL, NULL, &simh_dev_reset, + NULL, NULL, NULL, + NULL, 0, 0, + NULL, NULL, NULL +}; + +char messageBuffer[256] = {}; + +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 + if (sim_log) { + fprintf(sim_log, messageBuffer); + fprintf(sim_log,"\n"); + } +} + +static void resetSIOWarningFlags(void) { + warnUnattachedPTP = warnUnattachedPTR = warnPTREOF = warnUnassignedPort = 0; +} + +static t_stat sio_set_verbose(UNIT *uptr, int32 value, char *cptr, void *desc) { + resetSIOWarningFlags(); + return SCPE_OK; +} + +static t_stat sio_attach(UNIT *uptr, char *cptr) { + t_stat r = SCPE_IERR; + sio_unit.u3 = FALSE; /* no character in terminal input buffer */ + get_uint(cptr, 10, 65535, &r); /* attempt to get port, discard result */ + if (r == SCPE_OK) { /* string can be interpreted as port number */ + sio_unit.u4 = FALSE; /* terminal input is not attached to a file */ + return tmxr_attach(&altairTMXR, uptr, cptr); /* attach mux */ + } + sio_unit.u4 = TRUE; /* terminal input is attached to a file */ + sio_unit.u5 = FALSE; /* EOF not yet reached */ + return attach_unit(uptr, cptr); +} + +static t_stat sio_detach(UNIT *uptr) { + sio_unit.u3 = FALSE; /* no character in terminal input buffer */ + if (sio_unit.u4) { /* is terminal input attached to a file? */ + sio_unit.u4 = FALSE; /* not anymore, detach */ + return detach_unit(uptr); + } + return tmxr_detach(&altairTMXR, uptr); +} + +static void pollConnection(void) { + if (sio_unit.flags & UNIT_ATT) { + int32 temp = tmxr_poll_conn(&altairTMXR); /* poll connection */ + if (temp >= 0) + TerminalLines[temp].rcve = 1; /* enable receive */ + tmxr_poll_rx(&altairTMXR); /* poll input */ + tmxr_poll_tx(&altairTMXR); /* poll output */ + } +} + +/* reset routines */ +static t_stat sio_reset(DEVICE *dptr) { + int32 i; + sio_unit.u3 = FALSE; /* no character in terminal input buffer */ + resetSIOWarningFlags(); + if (sio_unit.u4) { /* is terminal input attached to a file? */ + rewind(sio_unit.fileref); /* yes, rewind input */ + sio_unit.u5 = FALSE; /* EOF not yet reached */ + } + else if (sio_unit.flags & UNIT_ATT) + for (i = 0; i < TERMINALS; i++) + if (TerminalLines[i].conn) + tmxr_reset_ln(&TerminalLines[i]); + return SCPE_OK; +} + +static t_stat ptr_reset(DEVICE *dptr) { + resetSIOWarningFlags(); + ptr_unit.u3 = FALSE; /* End Of File not yet reached */ + if (ptr_unit.flags & UNIT_ATT) /* attached? */ + rewind(ptr_unit.fileref); + return SCPE_OK; +} + +static t_stat ptp_reset(DEVICE *dptr) { + resetSIOWarningFlags(); + return SCPE_OK; +} + + +/* 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. + + Port 1 controls console I/O. We distinguish three cases: + 1) SIO attached to a file (i.e. input taken from a file ) + 2) SIO attached to a port (i.e. Telnet console I/O ) + 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); + } + if (io == 0) { /* IN */ + 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; + } + 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); + /* write possible if connected and transmit + enabled */ + } + if (sio_unit.u3) /* character available? */ + return SIO_CAN_READ | 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 */ + } + sio_unit.u3 = TRUE; /* indicate character available */ + sio_unit.buf = ch; /* store character in buffer */ + return SIO_CAN_READ | SIO_CAN_WRITE; + } + return SIO_CAN_WRITE; + } /* OUT follows */ + if (data == 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; +} + +int32 sio0d(const int32 port, const int32 io, const int32 data) { + int32 ti = 0, ch; + 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? */ + sio_detach(&sio_unit); /* detach file and switch to keyboard input */ + return CONTROLC_CHAR; /* this time return ^C after all */ + } + if ((ch = getc(sio_unit.fileref)) == EOF) { /* end of file? */ + sio_unit.u5 = TRUE; /* terminal input file has reached EOF */ + return CONTROLC_CHAR; /* result is ^C (= CP/M interrupt) */ + } + return mapCharacter(ch); /* return mapped character */ + } + if (sio_unit.flags & UNIT_ATT) + return mapCharacter(tmxr_getc_ln(&TerminalLines[ti])); + 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); + return 0x00; /* ignored since OUT */ +} + +/* PTR/PTP status port */ +int32 sio1s(const int32 port, const int32 io, const int32 data) { + if (io == 0) { /* IN */ + /* reset I bit iff PTR unit not attached or + no more data available. O bit is always + set since write always possible. */ + 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."); + } + return SIO_CAN_WRITE; + } + /* if EOF then SIO_CAN_WRITE else + (SIO_CAN_WRITE and SIO_CAN_READ) */ + return ptr_unit.u3 ? SIO_CAN_WRITE : (SIO_CAN_READ | SIO_CAN_WRITE); + } /* OUT follows */ + if (data == SIO_RESET) + ptr_unit.u3 = FALSE; /* reset EOF indicator */ + return 0x00; /* ignored since OUT */ +} + +/* PTR/PTP data port */ +int32 sio1d(const int32 port, const int32 io, const int32 data) { + int32 ch; + if (io == 0) { /* IN */ + 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."); + } + 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."); + } + return 0x00; + } + if ((ch = getc(ptr_unit.fileref)) == EOF) { /* end of file? */ + ptr_unit.u3 = TRUE; /* remember EOF reached */ + return CONTROLZ_CHAR; /* ^Z denotes end of text file in CP/M */ + } + return ch & 0xff; + } /* OUT follows */ + if (ptp_unit.flags & UNIT_ATT) /* unit must be attached */ + putc(data, ptp_unit.fileref); + /* 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); + } + return 0x00; /* ignored since OUT */ +} + +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); + } + else { + MESSAGE_3("Unassigned OUT(%2xh) -> %2xh - ignored.", port, data); + } + } + return io == 0 ? 0xff : 0; +} + +int32 sr_dev(const int32 port, const int32 io, const int32 data) { + return io == 0 ? SR : 0; +} + +static int32 toBCD(const int32 x) { + return (x / 10) * 16 + (x % 10); +} + +static int32 fromBCD(const int32 x) { + return 10 * ((0xf0 & x) >> 4) + (0x0f & x); +} + +/* Z80 or 8080 programs communicate with the SIMH pseudo device via port 0xfe. + The following principles apply: + + 1) For commands that do not require parameters and do not return results + ld a, + out (0feh),a + Special case is the reset command which needs to be send 128 times to make + sure that the internal state is properly reset. + + 2) For commands that require parameters and do not return results + ld a, + out (0feh),a + ld a, + out (0feh),a + ld a, + out (0feh),a + ... + Note: The calling program must send all parameter bytes. Otherwise + the pseudo device is left in an undefined state. + + 3) For commands that do not require parameters and return results + ld a, + out (0feh),a + in a,(0feh) ; contains first byte of result + in a,(0feh) ; contains second byte of result + ... + Note: The calling program must request all bytes of the result. Otherwise + the pseudo device is left in an undefined state. + + 4) Commands requiring parameters and returning results do not exist currently. + +*/ + +enum simhPseudoDeviceCommands { /* do not change order or remove commands, add only at the end */ + printTimeCmd, /* 0 print the current time in milliseconds */ + startTimerCmd, /* 1 start a new timer on the top of the timer stack */ + stopTimerCmd, /* 2 stop timer on top of timer stack and show time difference */ + resetPTRCmd, /* 3 reset the PTR device */ + attachPTRCmd, /* 4 attach the PTR device */ + detachPTRCmd, /* 5 detach the PTR device */ + getSIMHVersionCmd, /* 6 get the current version of the SIMH pseudo device */ + getClockZSDOSCmd, /* 7 get the current time in ZSDOS format */ + setClockZSDOSCmd, /* 8 set the current time in ZSDOS format */ + getClockCPM3Cmd, /* 9 get the current time in CP/M 3 format */ + setClockCPM3Cmd, /* 10 set the current time in CP/M 3 format */ + getBankSelectCmd, /* 11 get the selected bank */ + setBankSelectCmd, /* 12 set the selected bank */ + getCommonCmd, /* 13 get the base address of the common memory segment */ + resetSIMHInterfaceCmd, /* 14 reset the SIMH pseudo device */ + showTimerCmd, /* 15 show time difference to timer on top of stack */ + attachPTPCmd, /* 16 attach PTP to the file with name at beginning of CP/M command line*/ + detachPTPCmd, /* 17 detach PTP */ + hasBankedMemoryCmd, /* 18 determines whether machine has banked memory */ + setZ80CPUCmd, /* 19 set the CPU to a Z80 */ + set8080CPUCmd, /* 20 set the CPU to an 8080 */ + startTimerInterruptsCmd, /* 21 start timer interrupts */ + stopTimerInterruptsCmd, /* 22 stop timer interrupts */ + setTimerDeltaCmd, /* 23 set the timer interval in which interrupts occur */ + setTimerInterruptAdrCmd, /* 24 set the address to call by timer interrupts */ + resetStopWatchCmd, /* 25 reset the millisecond stop watch */ + readStopWatchCmd, /* 26 read the millisecond stop watch */ + SIMHSleepCmd, /* 27 let SIMH sleep for SIMHSleep microseconds */ + getHostOSPathSeparator, /* 28 obtain the file path separator of the OS under which SIMH runs */ + getHostFilenames /* 29 perform wildcard expansion and obtain list of file names */ +}; + +#define CPM_COMMAND_LINE_LENGTH 128 +#define TIMER_STACK_LIMIT 10 /* stack depth of timer stack */ +static uint32 markTime[TIMER_STACK_LIMIT]; /* timer stack */ +static struct tm currentTime; +static int32 currentTimeValid = FALSE; +static char version[] = "SIMH003"; + +static t_stat simh_dev_reset(DEVICE *dptr) { + currentTimeValid = FALSE; + ClockZSDOSDelta = 0; + setClockZSDOSPos = 0; + getClockZSDOSPos = 0; + ClockCPM3Delta = 0; + setClockCPM3Pos = 0; + getClockCPM3Pos = 0; + getStopWatchDeltaPos = 0; + getCommonPos = 0; + setTimerDeltaPos = 0; + setTimerInterruptAdrPos = 0; + markTimeSP = 0; + versionPos = 0; + lastCommand = 0; + lastCPMStatus = SCPE_OK; + timerInterrupt = FALSE; + if (simh_unit.flags & UNIT_SIMH_TIMERON) + simh_dev_set_timeron(NULL, 0, NULL, NULL); + return SCPE_OK; +} + +static void warnNoRealTimeClock(void) { + if (simh_unit.flags & UNIT_SIMH_VERBOSE) + printf("Sorry - no real time clock available.\n"); +} + +static t_stat simh_dev_set_timeron(UNIT *uptr, int32 value, char *cptr, void *desc) { + if (rtc_avail) { + timeOfNextInterrupt = sim_os_msec() + timerDelta; + return sim_activate(&simh_unit, simh_unit.wait); /* activate unit */ + } + warnNoRealTimeClock(); + return SCPE_ARG; +} + +static t_stat simh_dev_set_timeroff(UNIT *uptr, int32 value, char *cptr, void *desc) { + timerInterrupt = FALSE; + sim_cancel(&simh_unit); + return SCPE_OK; +} + +static t_stat simh_svc(UNIT *uptr) { + uint32 n = sim_os_msec(); + if (n >= timeOfNextInterrupt) { + timerInterrupt = TRUE; + timeOfNextInterrupt += timerDelta; + if (n >= timeOfNextInterrupt) /* time of next interrupt is not in the future */ + timeOfNextInterrupt = n + timerDelta; /* make sure it is in the future! */ + } + if (simh_unit.flags & UNIT_SIMH_TIMERON) + sim_activate(&simh_unit, simh_unit.wait); /* activate unit */ + return SCPE_OK; +} + +static char cpmCommandLine[CPM_COMMAND_LINE_LENGTH]; +static void createCPMCommandLine(void) { + int32 i, len = (GetBYTEWrapper(0x80) & 0x7f); /* 0x80 contains length of command line, discard first char */ + for (i = 0; i < len - 1; i++) + cpmCommandLine[i] = (char)GetBYTEWrapper(0x82 + i); /* the first char, typically ' ', is discarded */ + cpmCommandLine[i] = 0; /* make C string */ +} + +/* The CP/M command line is used as the name of a file and UNIT* uptr is attached to it. */ +static void attachCPM(UNIT *uptr) { + createCPMCommandLine(); + if (uptr == &ptr_unit) + sim_switches = SWMASK('R'); + else if (uptr == &ptp_unit) + sim_switches = SWMASK('W') | SWMASK('C'); /* 'C' option makes sure that file is properly truncated + if it had existed before */ + 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 */ + } +} + +/* setClockZSDOSAdr points to 6 byte block in M: YY MM DD HH MM SS in BCD notation */ +static void setClockZSDOS(void) { + struct tm newTime; + int32 year = fromBCD(GetBYTEWrapper(setClockZSDOSAdr)); + newTime.tm_year = year < 50 ? year + 100 : year; + newTime.tm_mon = fromBCD(GetBYTEWrapper(setClockZSDOSAdr + 1)) - 1; + newTime.tm_mday = fromBCD(GetBYTEWrapper(setClockZSDOSAdr + 2)); + newTime.tm_hour = fromBCD(GetBYTEWrapper(setClockZSDOSAdr + 3)); + newTime.tm_min = fromBCD(GetBYTEWrapper(setClockZSDOSAdr + 4)); + newTime.tm_sec = fromBCD(GetBYTEWrapper(setClockZSDOSAdr + 5)); + ClockZSDOSDelta = mktime(&newTime) - time(NULL); +} + +#define SECONDS_PER_MINUTE 60 +#define SECONDS_PER_HOUR (60 * SECONDS_PER_MINUTE) +#define SECONDS_PER_DAY (24 * SECONDS_PER_HOUR) +static time_t mkCPM3Origin(void) { + struct tm date; + date.tm_year = 77; + date.tm_mon = 11; + date.tm_mday = 31; + date.tm_hour = 0; + date.tm_min = 0; + date.tm_sec = 0; + return mktime(&date); +} + +/* setClockCPM3Adr points to 5 byte block in M: + 0 - 1 int16: days since 31 Dec 77 + 2 BCD byte: HH + 3 BCD byte: MM + 4 BCD byte: SS */ +static void setClockCPM3(void) { + ClockCPM3Delta = mkCPM3Origin() + + (GetBYTEWrapper(setClockCPM3Adr) + GetBYTEWrapper(setClockCPM3Adr + 1) * 256) * SECONDS_PER_DAY + + fromBCD(GetBYTEWrapper(setClockCPM3Adr + 2)) * SECONDS_PER_HOUR + + fromBCD(GetBYTEWrapper(setClockCPM3Adr + 3)) * SECONDS_PER_MINUTE + + fromBCD(GetBYTEWrapper(setClockCPM3Adr + 4)) - time(NULL); +} + +static int32 simh_in(const int32 port) { + int32 result = 0; + switch(lastCommand) { + + case getHostFilenames: +#if UNIX_PLATFORM + if (globValid) + if (globPosNameList < globS.gl_pathc) { + if (!(result = globS.gl_pathv[globPosNameList][globPosName++])) { + globPosNameList++; + globPosName = 0; + } + } + else { + globValid = FALSE; + lastCommand = 0; + globfree(&globS); + } +#elif defined (_WIN32) + if (globValid) { + if (globFinished) { + globValid = FALSE; + } + else if (!(result = FindFileData.cFileName[globPosName++])) { + globPosName = 0; + if (!FindNextFile(hFind, &FindFileData)) { + globFinished = TRUE; + FindClose(hFind); + hFind = INVALID_HANDLE_VALUE; + } + } + } +#else + lastCommand = 0; +#endif + break; + + case attachPTRCmd: + + case attachPTPCmd: + result = lastCPMStatus; + lastCommand = 0; + break; + + case getClockZSDOSCmd: + if (currentTimeValid) { + switch(getClockZSDOSPos) { + + case 0: + result = toBCD(currentTime.tm_year > 99 ? + currentTime.tm_year - 100 : currentTime.tm_year); + getClockZSDOSPos = 1; + break; + + case 1: + result = toBCD(currentTime.tm_mon + 1); + getClockZSDOSPos = 2; + break; + + case 2: + result = toBCD(currentTime.tm_mday); + getClockZSDOSPos = 3; + break; + + case 3: + result = toBCD(currentTime.tm_hour); + getClockZSDOSPos = 4; + break; + + case 4: + result = toBCD(currentTime.tm_min); + getClockZSDOSPos = 5; + break; + + case 5: + result = toBCD(currentTime.tm_sec); + getClockZSDOSPos = lastCommand = 0; + break; + } + } + else { + result = getClockZSDOSPos = lastCommand = 0; + } + break; + + case getClockCPM3Cmd: + if (currentTimeValid) { + switch(getClockCPM3Pos) { + case 0: + result = daysCPM3SinceOrg & 0xff; + getClockCPM3Pos = 1; + break; + + case 1: + result = (daysCPM3SinceOrg >> 8) & 0xff; + getClockCPM3Pos = 2; + break; + + case 2: + result = toBCD(currentTime.tm_hour); + getClockCPM3Pos = 3; + break; + + case 3: + result = toBCD(currentTime.tm_min); + getClockCPM3Pos = 4; + break; + + case 4: + result = toBCD(currentTime.tm_sec); + getClockCPM3Pos = lastCommand = 0; + break; + } + } + else { + result = getClockCPM3Pos = lastCommand = 0; + } + break; + + case getSIMHVersionCmd: + result = version[versionPos++]; + if (result == 0) { + versionPos = lastCommand = 0; + } + break; + + case getBankSelectCmd: + if (cpu_unit.flags & UNIT_BANKED) { + result = getBankSelect(); + } + else { + result = 0; + if (simh_unit.flags & UNIT_SIMH_VERBOSE) { + MESSAGE_1("Get selected bank ignored for non-banked memory."); + } + } + lastCommand = 0; + break; + + case getCommonCmd: + if (getCommonPos == 0) { + result = getCommon() & 0xff; + getCommonPos = 1; + } + else { + result = (getCommon() >> 8) & 0xff; + getCommonPos = lastCommand = 0; + } + break; + + case hasBankedMemoryCmd: + result = cpu_unit.flags & UNIT_BANKED ? MAXBANKS : 0; + lastCommand = 0; + break; + + case readStopWatchCmd: + if (getStopWatchDeltaPos == 0) { + result = stopWatchDelta & 0xff; + getStopWatchDeltaPos = 1; + } + else { + result = (stopWatchDelta >> 8) & 0xff; + getStopWatchDeltaPos = lastCommand = 0; + } + break; + + case getHostOSPathSeparator: +#if defined (__MWERKS__) && defined (macintosh) + result = ':'; /* colon on Macintosh OS 9 */ +#elif defined (_WIN32) + result = '\\'; /* back slash in Windows */ +#else + result = '/'; /* slash in UNIX */ +#endif + break; + + default: + if (simh_unit.flags & UNIT_SIMH_VERBOSE) { + MESSAGE_2("Undefined IN from SIMH pseudo device on port %03xh ignored.", + port); + } + result = lastCommand = 0; + } + return result; +} + +static int32 simh_out(const int32 port, const int32 data) { + time_t now; + switch(lastCommand) { + + case setClockZSDOSCmd: + if (setClockZSDOSPos == 0) { + setClockZSDOSAdr = data; + setClockZSDOSPos = 1; + } + else { + setClockZSDOSAdr |= (data << 8); + setClockZSDOS(); + setClockZSDOSPos = lastCommand = 0; + } + break; + + case setClockCPM3Cmd: + if (setClockCPM3Pos == 0) { + setClockCPM3Adr = data; + setClockCPM3Pos = 1; + } + else { + setClockCPM3Adr |= (data << 8); + setClockCPM3(); + setClockCPM3Pos = lastCommand = 0; + } + break; + + case setBankSelectCmd: + if (cpu_unit.flags & UNIT_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); + } + lastCommand = 0; + break; + + case setTimerDeltaCmd: + if (setTimerDeltaPos == 0) { + timerDelta = data; + setTimerDeltaPos = 1; + } + else { + timerDelta |= (data << 8); + setTimerDeltaPos = lastCommand = 0; + } + break; + + case setTimerInterruptAdrCmd: + if (setTimerInterruptAdrPos == 0) { + timerInterruptHandler = data; + setTimerInterruptAdrPos = 1; + } + else { + timerInterruptHandler |= (data << 8); + setTimerInterruptAdrPos = lastCommand = 0; + } + break; + + default: + lastCommand = data; + switch(data) { + + case getHostFilenames: +#if UNIX_PLATFORM + if (!globValid) { + globValid = TRUE; + globPosNameList = globPosName = 0; + createCPMCommandLine(); + globError = glob(cpmCommandLine, GLOB_ERR, NULL, &globS); + if (globError) { + if (simh_unit.flags & UNIT_SIMH_VERBOSE) { + MESSAGE_3("Cannot expand '%s'. Error is %i.", cpmCommandLine, globError); + } + globfree(&globS); + globValid = FALSE; + } + } +#elif defined (_WIN32) + if (!globValid) { + globValid = TRUE; + globPosName = 0; + globFinished = FALSE; + createCPMCommandLine(); + hFind = FindFirstFile(cpmCommandLine, &FindFileData); + if (hFind == INVALID_HANDLE_VALUE) { + if (simh_unit.flags & UNIT_SIMH_VERBOSE) { + MESSAGE_3("Cannot expand '%s'. Error is %lu.", cpmCommandLine, GetLastError()); + } + globValid = FALSE; + } + } +#endif + 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 + break; + + case printTimeCmd: /* print time */ + if (rtc_avail) { + MESSAGE_2("Current time in milliseconds = %d.", sim_os_msec()); + } + else { + warnNoRealTimeClock(); + } + break; + + case startTimerCmd: /* create a new timer on top of stack */ + if (rtc_avail) { + if (markTimeSP < TIMER_STACK_LIMIT) { + markTime[markTimeSP++] = sim_os_msec(); + } + else { + MESSAGE_1("Timer stack overflow."); + } + } + else { + warnNoRealTimeClock(); + } + break; + + case stopTimerCmd: /* stop timer on top of stack and show time difference */ + if (rtc_avail) { + if (markTimeSP > 0) { + uint32 delta = sim_os_msec() - markTime[--markTimeSP]; + MESSAGE_2("Timer stopped. Elapsed time in milliseconds = %d.", delta); + } + else { + MESSAGE_1("No timer active."); + } + } + else { + warnNoRealTimeClock(); + } + break; + + case resetPTRCmd: /* reset ptr device */ + ptr_reset(NULL); + break; + + case attachPTRCmd: /* attach ptr to the file with name at beginning of CP/M command line */ + attachCPM(&ptr_unit); + break; + + case detachPTRCmd: /* detach ptr */ + detach_unit(&ptr_unit); + break; + + case getSIMHVersionCmd: + versionPos = 0; + break; + + case getClockZSDOSCmd: + time(&now); + now += ClockZSDOSDelta; + currentTime = *localtime(&now); + currentTimeValid = TRUE; + getClockZSDOSPos = 0; + break; + + case setClockZSDOSCmd: + setClockZSDOSPos = 0; + break; + + case getClockCPM3Cmd: + time(&now); + now += ClockCPM3Delta; + currentTime = *localtime(&now); + currentTimeValid = TRUE; + daysCPM3SinceOrg = (int32) ((now - mkCPM3Origin()) / SECONDS_PER_DAY); + getClockCPM3Pos = 0; + break; + + case setClockCPM3Cmd: + setClockCPM3Pos = 0; + break; + + case getBankSelectCmd: + case setBankSelectCmd: + case getCommonCmd: + case hasBankedMemoryCmd: + case getHostOSPathSeparator: + break; + + case resetSIMHInterfaceCmd: + markTimeSP = 0; + lastCommand = 0; +#if UNIX_PLATFORM + if (globValid) { + globValid = FALSE; + globfree(&globS); + } +#elif defined (_WIN32) + if (globValid) { + globValid = FALSE; + if (hFind != INVALID_HANDLE_VALUE) { + FindClose(hFind); + } + } +#endif + break; + + case showTimerCmd: /* show time difference to timer on top of stack */ + if (rtc_avail) { + if (markTimeSP > 0) { + uint32 delta = sim_os_msec() - markTime[markTimeSP - 1]; + MESSAGE_2("Timer running. Elapsed in milliseconds = %d.", delta); + } + else { + MESSAGE_1("No timer active."); + } + } + else { + warnNoRealTimeClock(); + } + break; + + case attachPTPCmd: /* attach ptp to the file with name at beginning of CP/M command line */ + attachCPM(&ptp_unit); + break; + + case detachPTPCmd: /* detach ptp */ + detach_unit(&ptp_unit); + break; + + case setZ80CPUCmd: + cpu_unit.flags |= UNIT_CHIP; + break; + + case set8080CPUCmd: + cpu_unit.flags &= ~UNIT_CHIP; + break; + + case startTimerInterruptsCmd: + if (simh_dev_set_timeron(NULL, 0, NULL, NULL) == SCPE_OK) { + timerInterrupt = FALSE; + simh_unit.flags |= UNIT_SIMH_TIMERON; + } + break; + + case stopTimerInterruptsCmd: + simh_unit.flags &= ~UNIT_SIMH_TIMERON; + simh_dev_set_timeroff(NULL, 0, NULL, NULL); + break; + + case setTimerDeltaCmd: + setTimerDeltaPos = 0; + break; + + case setTimerInterruptAdrCmd: + setTimerInterruptAdrPos = 0; + break; + + case resetStopWatchCmd: + stopWatchNow = rtc_avail ? sim_os_msec() : 0; + break; + + case readStopWatchCmd: + getStopWatchDeltaPos = 0; + stopWatchDelta = rtc_avail ? sim_os_msec() - stopWatchNow : 0; + break; + + default: + if (simh_unit.flags & UNIT_SIMH_VERBOSE) { + MESSAGE_3("Unknown command (%i) to SIMH pseudo device on port %03xh ignored.", + data, port); + } + } + } + return 0x00; /* ignored, since OUT */ +} + +/* port 0xfe is a device for communication SIMH <--> Altair machine */ +int32 simh_dev(const int32 port, const int32 io, const int32 data) { + return io == 0 ? simh_in(port) : simh_out(port, data); +} diff --git a/AltairZ80/altairZ80_sys.c b/AltairZ80/altairZ80_sys.c index d7e1ca7e..45496edb 100644 --- a/AltairZ80/altairZ80_sys.c +++ b/AltairZ80/altairZ80_sys.c @@ -1,738 +1,728 @@ -/* altairz80_sys.c: MITS Altair system interface - - 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 - Disassembler from Marat Fayzullin ((c) 1995, 1996, 1997 - Commercial use prohibited) -*/ - -#include -#include "altairz80_defs.h" - -extern DEVICE cpu_dev; -extern DEVICE dsk_dev; -extern DEVICE hdsk_dev; -extern UNIT cpu_unit; -extern REG cpu_reg[]; -extern DEVICE sio_dev; -extern DEVICE simh_device; -extern DEVICE ptr_dev; -extern DEVICE ptp_dev; -extern DEVICE net_dev; -extern int32 saved_PC; - -int32 fprint_sym(FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw); -static int32 checkbase(char ch, const char *numString); -static int32 numok(char ch, const char **numString, const int32 minvalue, - const int32 maxvalue, const int32 requireSign, int32 *result); -static int32 match(const char *pattern, const char *input, char *xyFirst, char *xy, int32 *number, int32 *star, int32 *at, - int32 *hat, int32 *dollar); -static int32 parse_X80(const char *cptr, const int32 addr, uint32 *val, char *const Mnemonics[]); -int32 parse_sym(char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw); -static int32 DAsm(char *S, const uint32 *val, const int32 useZ80Mnemonics, const int32 addr); -static int32 checkXY(const char xy); - -/* SCP data structures - sim_name simulator name string - sim_PC pointer to saved PC register descriptor - sim_emax number of words needed for examine - sim_devices array of pointers to simulated devices - sim_stop_messages array of pointers to stop messages - sim_load binary loader -*/ - -char sim_name[] = "Altair 8800 (Z80)"; -REG *sim_PC = &cpu_reg[0]; -int32 sim_emax = 4; -DEVICE *sim_devices[] = { - &cpu_dev, &sio_dev, &simh_device, &ptr_dev, &ptp_dev, &dsk_dev, &hdsk_dev, &net_dev, NULL -}; - -char memoryAccessMessage[80]; -const char *sim_stop_messages[] = { - "HALT instruction", - "Breakpoint", - memoryAccessMessage, - "Invalid Opcode" -}; - -static char *const Mnemonics8080[] = { -/* 0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ - "NOP", "LXI B,#h", "STAX B", "INX B", "INR B", "DCR B", "MVI B,*h", "RLC", /* 00-07 */ - "DB 09h", "DAD B", "LDAX B", "DCX B", "INR C", "DCR C", "MVI C,*h", "RRC", /* 08-0f */ - "DB 10h", "LXI D,#h", "STAX D", "INX D", "INR D", "DCR D", "MVI D,*h", "RAL", /* 10-17 */ - "DB 18h", "DAD D", "LDAX D", "DCX D", "INR E", "DCR E", "MVI E,*h", "RAR", /* 18-1f */ - "DB 20h", "LXI H,#h", "SHLD #h", "INX H", "INR H", "DCR H", "MVI H,*h", "DAA", /* 20-27 */ - "DB 28h", "DAD H", "LHLD #h", "DCX H", "INR L", "DCR L", "MVI L,*h", "CMA", /* 28-2f */ - "DB 30h", "LXI SP,#h", "STA #h", "INX SP", "INR M", "DCR M", "MVI M,*h", "STC", /* 30-37 */ - "DB 38h", "DAD SP", "LDA #h", "DCX SP", "INR A", "DCR A", "MVI A,*h", "CMC", /* 38-3f */ - "MOV B,B", "MOV B,C", "MOV B,D", "MOV B,E", "MOV B,H", "MOV B,L", "MOV B,M", "MOV B,A", /* 40-47 */ - "MOV C,B", "MOV C,C", "MOV C,D", "MOV C,E", "MOV C,H", "MOV C,L", "MOV C,M", "MOV C,A", /* 48-4f */ - "MOV D,B", "MOV D,C", "MOV D,D", "MOV D,E", "MOV D,H", "MOV D,L", "MOV D,M", "MOV D,A", /* 50-57 */ - "MOV E,B", "MOV E,C", "MOV E,D", "MOV E,E", "MOV E,H", "MOV E,L", "MOV E,M", "MOV E,A", /* 58-5f */ - "MOV H,B", "MOV H,C", "MOV H,D", "MOV H,E", "MOV H,H", "MOV H,L", "MOV H,M", "MOV H,A", /* 60-67 */ - "MOV L,B", "MOV L,C", "MOV L,D", "MOV L,E", "MOV L,H", "MOV L,L", "MOV L,M", "MOV L,A", /* 68-6f */ - "MOV M,B", "MOV M,C", "MOV M,D", "MOV M,E", "MOV M,H", "MOV M,L", "HLT", "MOV M,A", /* 70-77 */ - "MOV A,B", "MOV A,C", "MOV A,D", "MOV A,E", "MOV A,H", "MOV A,L", "MOV A,M", "MOV A,A", /* 78-7f */ - "ADD B", "ADD C", "ADD D", "ADD E", "ADD H", "ADD L", "ADD M", "ADD A", /* 80-87 */ - "ADC B", "ADC C", "ADC D", "ADC E", "ADC H", "ADC L", "ADC M", "ADC A", /* 88-8f */ - "SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB M", "SUB A", /* 90-97 */ - "SBB B", "SBB C", "SBB D", "SBB E", "SBB H", "SBB L", "SBB M", "SBB A", /* 98-9f */ - "ANA B", "ANA C", "ANA D", "ANA E", "ANA H", "ANA L", "ANA M", "ANA A", /* a0-a7 */ - "XRA B", "XRA C", "XRA D", "XRA E", "XRA H", "XRA L", "XRA M", "XRA A", /* a8-af */ - "ORA B", "ORA C", "ORA D", "ORA E", "ORA H", "ORA L", "ORA M", "ORA A", /* b0-b7 */ - "CMP B", "CMP C", "CMP D", "CMP E", "CMP H", "CMP L", "CMP M", "CMP A", /* b8-bf */ - "RNZ", "POP B", "JNZ #h", "JMP #h", "CNZ #h", "PUSH B", "ADI *h", "RST 0", /* c0-c7 */ - "RZ", "RET", "JZ #h", "DB CBh", "CZ #h", "CALL #h", "ACI *h", "RST 1", /* c8-cf */ - "RNC", "POP D", "JNC #h", "OUT *h", "CNC #h", "PUSH D", "SUI *h", "RST 2", /* d0-d7 */ - "RC", "DB D9h", "JC #h", "IN *h", "CC #h", "DB DDh", "SBI *h", "RST 3", /* d8-df */ - "RPO", "POP H", "JPO #h", "XTHL", "CPO #h", "PUSH H", "ANI *h", "RST 4", /* e0-e7 */ - "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 */ - "NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA", /* 00-07 */ - "EX AF,AF'", "ADD HL,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA", /* 08-0f */ - "DJNZ $h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA", /* 10-17 */ - "JR $h", "ADD HL,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA", /* 18-1f */ - "JR NZ,$h", "LD HL,#h", "LD (#h),HL", "INC HL", "INC H", "DEC H", "LD H,*h", "DAA", /* 20-27 */ - "JR Z,$h", "ADD HL,HL", "LD HL,(#h)", "DEC HL", "INC L", "DEC L", "LD L,*h", "CPL", /* 28-2f */ - "JR NC,$h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (HL)", "DEC (HL)", "LD (HL),*h", "SCF", /* 30-37 */ - "JR C,$h", "ADD HL,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF", /* 38-3f */ - "LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,H", "LD B,L", "LD B,(HL)", "LD B,A", /* 40-47 */ - "LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,H", "LD C,L", "LD C,(HL)", "LD C,A", /* 48-4f */ - "LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,H", "LD D,L", "LD D,(HL)", "LD D,A", /* 50-57 */ - "LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,H", "LD E,L", "LD E,(HL)", "LD E,A", /* 58-5f */ - "LD H,B", "LD H,C", "LD H,D", "LD H,E", "LD H,H", "LD H,L", "LD H,(HL)", "LD H,A", /* 60-67 */ - "LD L,B", "LD L,C", "LD L,D", "LD L,E", "LD L,H", "LD L,L", "LD L,(HL)", "LD L,A", /* 68-6f */ - "LD (HL),B", "LD (HL),C", "LD (HL),D", "LD (HL),E", "LD (HL),H", "LD (HL),L", "HALT", "LD (HL),A", /* 70-77 */ - "LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,H", "LD A,L", "LD A,(HL)", "LD A,A", /* 78-7f */ - "ADD A,B", "ADD A,C", "ADD A,D", "ADD A,E", "ADD A,H", "ADD A,L", "ADD A,(HL)", "ADD A,A", /* 80-87 */ - "ADC A,B", "ADC A,C", "ADC A,D", "ADC A,E", "ADC A,H", "ADC A,L", "ADC A,(HL)", "ADC A,A", /* 88-8f */ - "SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB (HL)", "SUB A", /* 90-97 */ - "SBC A,B", "SBC A,C", "SBC A,D", "SBC A,E", "SBC A,H", "SBC A,L", "SBC A,(HL)", "SBC A,A", /* 98-9f */ - "AND B", "AND C", "AND D", "AND E", "AND H", "AND L", "AND (HL)", "AND A", /* a0-a7 */ - "XOR B", "XOR C", "XOR D", "XOR E", "XOR H", "XOR L", "XOR (HL)", "XOR A", /* a8-af */ - "OR B", "OR C", "OR D", "OR E", "OR H", "OR L", "OR (HL)", "OR A", /* b0-b7 */ - "CP B", "CP C", "CP D", "CP E", "CP H", "CP L", "CP (HL)", "CP A", /* b8-bf */ - "RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD A,*h", "RST 00h", /* c0-c7 */ - "RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC A,*h", "RST 08h", /* c8-cf */ - "RET NC", "POP DE", "JP NC,#h", "OUT (*h),A", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h", /* d0-d7 */ - "RET C", "EXX", "JP C,#h", "IN A,(*h)", "CALL C,#h", "PFX_DD", "SBC A,*h", "RST 18h", /* d8-df */ - "RET PO", "POP HL", "JP PO,#h", "EX (SP),HL", "CALL PO,#h", "PUSH HL", "AND *h", "RST 20h", /* e0-e7 */ - "RET PE", "LD PC,HL", "JP PE,#h", "EX DE,HL", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h", /* e8-ef */ - "RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h", /* f0-f7 */ - "RET M", "LD SP,HL", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h" /* f8-ff */ -}; - -static char *const MnemonicsCB[256] = { -/* 0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ - "RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (HL)", "RLC A", /* 00-07 */ - "RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (HL)", "RRC A", /* 08-0f */ - "RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (HL)", "RL A", /* 10-17 */ - "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (HL)", "RR A", /* 18-1f */ - "SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (HL)", "SLA A", /* 20-27 */ - "SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (HL)", "SRA A", /* 28-2f */ - "SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (HL)", "SLL A", /* 30-37 */ - "SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (HL)", "SRL A", /* 38-3f */ - "BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(HL)", "BIT 0,A", /* 40-47 */ - "BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(HL)", "BIT 1,A", /* 48-4f */ - "BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(HL)", "BIT 2,A", /* 50-57 */ - "BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(HL)", "BIT 3,A", /* 58-5f */ - "BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(HL)", "BIT 4,A", /* 60-67 */ - "BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(HL)", "BIT 5,A", /* 68-6f */ - "BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(HL)", "BIT 6,A", /* 70-77 */ - "BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(HL)", "BIT 7,A", /* 78-7f */ - "RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(HL)", "RES 0,A", /* 80-87 */ - "RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(HL)", "RES 1,A", /* 88-8f */ - "RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(HL)", "RES 2,A", /* 90-97 */ - "RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(HL)", "RES 3,A", /* 98-9f */ - "RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(HL)", "RES 4,A", /* a0-a7 */ - "RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(HL)", "RES 5,A", /* a8-af */ - "RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(HL)", "RES 6,A", /* b0-b7 */ - "RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(HL)", "RES 7,A", /* b8-bf */ - "SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(HL)", "SET 0,A", /* c0-c7 */ - "SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(HL)", "SET 1,A", /* c8-cf */ - "SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(HL)", "SET 2,A", /* d0-d7 */ - "SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(HL)", "SET 3,A", /* d8-df */ - "SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(HL)", "SET 4,A", /* e0-e7 */ - "SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(HL)", "SET 5,A", /* e8-ef */ - "SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(HL)", "SET 6,A", /* f0-f7 */ - "SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(HL)", "SET 7,A" /* f8-ff */ -}; - -static char *const MnemonicsED[256] = { -/* 0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ - "DB EDh,00h", "DB EDh,01h", "DB EDh,02h", "DB EDh,03h", "DB EDh,04h", "DB EDh,05h", "DB EDh,06h", "DB EDh,07h", /* 00-07 */ - "DB EDh,08h", "DB EDh,09h", "DB EDh,0Ah", "DB EDh,0Bh", "DB EDh,0Ch", "DB EDh,0Dh", "DB EDh,0Eh", "DB EDh,0Fh", /* 08-0f */ - "DB EDh,10h", "DB EDh,11h", "DB EDh,12h", "DB EDh,13h", "DB EDh,14h", "DB EDh,15h", "DB EDh,16h", "DB EDh,17h", /* 10-17 */ - "DB EDh,18h", "DB EDh,19h", "DB EDh,1Ah", "DB EDh,1Bh", "DB EDh,1Ch", "DB EDh,1Dh", "DB EDh,1Eh", "DB EDh,1Fh", /* 18-1f */ - "DB EDh,20h", "DB EDh,21h", "DB EDh,22h", "DB EDh,23h", "DB EDh,24h", "DB EDh,25h", "DB EDh,26h", "DB EDh,27h", /* 20-27 */ - "DB EDh,28h", "DB EDh,29h", "DB EDh,2Ah", "DB EDh,2Bh", "DB EDh,2Ch", "DB EDh,2Dh", "DB EDh,2Eh", "DB EDh,2Fh", /* 28-2f */ - "DB EDh,30h", "DB EDh,31h", "DB EDh,32h", "DB EDh,33h", "DB EDh,34h", "DB EDh,35h", "DB EDh,36h", "DB EDh,37h", /* 30-37 */ - "DB EDh,38h", "DB EDh,39h", "DB EDh,3Ah", "DB EDh,3Bh", "DB EDh,3Ch", "DB EDh,3Dh", "DB EDh,3Eh", "DB EDh,3Fh", /* 38-3f */ - "IN B,(C)", "OUT (C),B", "SBC HL,BC", "LD (#h),BC", "NEG", "RETN", "IM 0", "LD I,A", /* 40-47 */ - "IN C,(C)", "OUT (C),C", "ADC HL,BC", "LD BC,(#h)", "DB EDh,4Ch", "RETI", "DB EDh,4Eh", "LD R,A", /* 48-4f */ - "IN D,(C)", "OUT (C),D", "SBC HL,DE", "LD (#h),DE", "DB EDh,54h", "DB EDh,55h", "IM 1", "LD A,I", /* 50-57 */ - "IN E,(C)", "OUT (C),E", "ADC HL,DE", "LD DE,(#h)", "DB EDh,5Ch", "DB EDh,5Dh", "IM 2", "LD A,R", /* 58-5f */ - "IN H,(C)", "OUT (C),H", "SBC HL,HL", "LD (#h),HL", "DB EDh,64h", "DB EDh,65h", "DB EDh,66h", "RRD", /* 60-67 */ - "IN L,(C)", "OUT (C),L", "ADC HL,HL", "LD HL,(#h)", "DB EDh,6Ch", "DB EDh,6Dh", "DB EDh,6Eh", "RLD", /* 68-6f */ - "IN F,(C)", "DB EDh,71h", "SBC HL,SP", "LD (#h),SP", "DB EDh,74h", "DB EDh,75h", "DB EDh,76h", "DB EDh,77h", /* 70-77 */ - "IN A,(C)", "OUT (C),A", "ADC HL,SP", "LD SP,(#h)", "DB EDh,7Ch", "DB EDh,7Dh", "DB EDh,7Eh", "DB EDh,7Fh", /* 78-7f */ - "DB EDh,80h", "DB EDh,81h", "DB EDh,82h", "DB EDh,83h", "DB EDh,84h", "DB EDh,85h", "DB EDh,86h", "DB EDh,87h", /* 80-87 */ - "DB EDh,88h", "DB EDh,89h", "DB EDh,8Ah", "DB EDh,8Bh", "DB EDh,8Ch", "DB EDh,8Dh", "DB EDh,8Eh", "DB EDh,8Fh", /* 88-8f */ - "DB EDh,90h", "DB EDh,91h", "DB EDh,92h", "DB EDh,93h", "DB EDh,94h", "DB EDh,95h", "DB EDh,96h", "DB EDh,97h", /* 90-97 */ - "DB EDh,98h", "DB EDh,99h", "DB EDh,9Ah", "DB EDh,9Bh", "DB EDh,9Ch", "DB EDh,9Dh", "DB EDh,9Eh", "DB EDh,9Fh", /* 98-9f */ - "LDI", "CPI", "INI", "OUTI", "DB EDh,A4h", "DB EDh,A5h", "DB EDh,A6h", "DB EDh,A7h", /* a0-a7 */ - "LDD", "CPD", "IND", "OUTD", "DB EDh,ACh", "DB EDh,ADh", "DB EDh,AEh", "DB EDh,AFh", /* a8-af */ - "LDIR", "CPIR", "INIR", "OTIR", "DB EDh,B4h", "DB EDh,B5h", "DB EDh,B6h", "DB EDh,B7h", /* b0-b7 */ - "LDDR", "CPDR", "INDR", "OTDR", "DB EDh,BCh", "DB EDh,BDh", "DB EDh,BEh", "DB EDh,BFh", /* b8-bf */ - "DB EDh,C0h", "DB EDh,C1h", "DB EDh,C2h", "DB EDh,C3h", "DB EDh,C4h", "DB EDh,C5h", "DB EDh,C6h", "DB EDh,C7h", /* c0-c7 */ - "DB EDh,C8h", "DB EDh,C9h", "DB EDh,CAh", "DB EDh,CBh", "DB EDh,CCh", "DB EDh,CDh", "DB EDh,CEh", "DB EDh,CFh", /* c8-cf */ - "DB EDh,D0h", "DB EDh,D1h", "DB EDh,D2h", "DB EDh,D3h", "DB EDh,D4h", "DB EDh,D5h", "DB EDh,D6h", "DB EDh,D7h", /* d0-d7 */ - "DB EDh,D8h", "DB EDh,D9h", "DB EDh,DAh", "DB EDh,DBh", "DB EDh,DCh", "DB EDh,DDh", "DB EDh,DEh", "DB EDh,DFh", /* d8-df */ - "DB EDh,E0h", "DB EDh,E1h", "DB EDh,E2h", "DB EDh,E3h", "DB EDh,E4h", "DB EDh,E5h", "DB EDh,E6h", "DB EDh,E7h", /* e0-e7 */ - "DB EDh,E8h", "DB EDh,E9h", "DB EDh,EAh", "DB EDh,EBh", "DB EDh,ECh", "DB EDh,EDh", "DB EDh,EEh", "DB EDh,EFh", /* e8-ef */ - "DB EDh,F0h", "DB EDh,F1h", "DB EDh,F2h", "DB EDh,F3h", "DB EDh,F4h", "DB EDh,F5h", "DB EDh,F6h", "DB EDh,F7h", /* f0-f7 */ - "DB EDh,F8h", "DB EDh,F9h", "DB EDh,FAh", "DB EDh,FBh", "DB EDh,FCh", "DB EDh,FDh", "DB EDh,FEh", "DB EDh,FFh" /* f8-ff */ -}; - -static char *const MnemonicsXX[256] = { -/* 0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ - "NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA", /* 00-07 */ - "EX AF,AF'", "ADD I%,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA", /* 08-0f */ - "DJNZ $h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA", /* 10-17 */ - "JR $h", "ADD I%,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA", /* 18-1f */ - "JR NZ,$h", "LD I%,#h", "LD (#h),I%", "INC I%", "INC I%H", "DEC I%H", "LD I%H,*h", "DAA", /* 20-27 */ - "JR Z,$h", "ADD I%,I%", "LD I%,(#h)", "DEC I%", "INC I%L", "DEC I%L", "LD I%L,*h", "CPL", /* 28-2f */ - "JR NC,$h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (I%+^h)", "DEC (I%+^h)", "LD (I%+^h),*h","SCF", /* 30-37 */ - "JR C,$h", "ADD I%,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF", /* 38-3f */ - "LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,I%H", "LD B,I%L", "LD B,(I%+^h)", "LD B,A", /* 40-47 */ - "LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,I%H", "LD C,I%L", "LD C,(I%+^h)", "LD C,A", /* 48-4f */ - "LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,I%H", "LD D,I%L", "LD D,(I%+^h)", "LD D,A", /* 50-57 */ - "LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,I%H", "LD E,I%L", "LD E,(I%+^h)", "LD E,A", /* 58-5f */ - "LD I%H,B", "LD I%H,C", "LD I%H,D", "LD I%H,E", "LD I%H,I%H", "LD I%H,I%L", "LD H,(I%+^h)", "LD I%H,A", /* 60-67 */ - "LD I%L,B", "LD I%L,C", "LD I%L,D", "LD I%L,E", "LD I%L,I%H", "LD I%L,I%L", "LD L,(I%+^h)", "LD I%L,A", /* 68-6f */ - "LD (I%+^h),B", "LD (I%+^h),C", "LD (I%+^h),D", "LD (I%+^h),E", "LD (I%+^h),H", "LD (I%+^h),L", "HALT", "LD (I%+^h),A", /* 70-77 */ - "LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,I%H", "LD A,I%L", "LD A,(I%+^h)", "LD A,A", /* 78-7f */ - "ADD A,B", "ADD A,C", "ADD A,D", "ADD A,E", "ADD A,I%H", "ADD A,I%L", "ADD A,(I%+^h)","ADD A,A", /* 80-87 */ - "ADC A,B", "ADC A,C", "ADC A,D", "ADC A,E", "ADC A,I%H", "ADC A,I%L", "ADC A,(I%+^h)","ADC A,A", /* 88-8f */ - "SUB B", "SUB C", "SUB D", "SUB E", "SUB I%H", "SUB I%L", "SUB (I%+^h)", "SUB A", /* 90-97 */ - "SBC A,B", "SBC A,C", "SBC A,D", "SBC A,E", "SBC A,I%H", "SBC A,I%L", "SBC A,(I%+^h)","SBC A,A", /* 98-9f */ - "AND B", "AND C", "AND D", "AND E", "AND I%H", "AND I%L", "AND (I%+^h)", "AND A", /* a0-a7 */ - "XOR B", "XOR C", "XOR D", "XOR E", "XOR I%H", "XOR I%L", "XOR (I%+^h)", "XOR A", /* a8-af */ - "OR B", "OR C", "OR D", "OR E", "OR I%H", "OR I%L", "OR (I%+^h)", "OR A", /* b0-b7 */ - "CP B", "CP C", "CP D", "CP E", "CP I%H", "CP I%L", "CP (I%+^h)", "CP A", /* b8-bf */ - "RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD A,*h", "RST 00h", /* c8-cf */ - "RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC A,*h", "RST 08h", /* c8-cf */ - "RET NC", "POP DE", "JP NC,#h", "OUT (*h),A", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h", /* d0-d7 */ - "RET C", "EXX", "JP C,#h", "IN A,(*h)", "CALL C,#h", "PFX_DD", "SBC A,*h", "RST 18h", /* d8-df */ - "RET PO", "POP I%", "JP PO,#h", "EX (SP),I%", "CALL PO,#h", "PUSH I%", "AND *h", "RST 20h", /* e0-e7 */ - "RET PE", "LD PC,I%", "JP PE,#h", "EX DE,I%", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h", /* e8-ef */ - "RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h", /* f0-f7 */ - "RET M", "LD SP,I%", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h" /* f8-ff */ -}; - -static char *const MnemonicsXCB[256] = { -/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ - "RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (I%@h)", "RLC A", /* 00-07 */ - "RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (I%@h)", "RRC A", /* 08-0f */ - "RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (I%@h)", "RL A", /* 10-17 */ - "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (I%@h)", "RR A", /* 18-1f */ - "SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (I%@h)", "SLA A", /* 20-27 */ - "SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (I%@h)", "SRA A", /* 28-2f */ - "SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (I%@h)", "SLL A", /* 30-37 */ - "SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (I%@h)", "SRL A", /* 38-3f */ - "BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(I%@h)", "BIT 0,A", /* 40-47 */ - "BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(I%@h)", "BIT 1,A", /* 48-4f */ - "BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(I%@h)", "BIT 2,A", /* 50-57 */ - "BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(I%@h)", "BIT 3,A", /* 58-5f */ - "BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(I%@h)", "BIT 4,A", /* 60-67 */ - "BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(I%@h)", "BIT 5,A", /* 68-6f */ - "BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(I%@h)", "BIT 6,A", /* 70-77 */ - "BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(I%@h)", "BIT 7,A", /* 78-7f */ - "RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(I%@h)", "RES 0,A", /* 80-87 */ - "RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(I%@h)", "RES 1,A", /* 88-8f */ - "RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(I%@h)", "RES 2,A", /* 90-97 */ - "RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(I%@h)", "RES 3,A", /* 98-9f */ - "RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(I%@h)", "RES 4,A", /* a0-a7 */ - "RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(I%@h)", "RES 5,A", /* a8-af */ - "RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(I%@h)", "RES 6,A", /* b0-b7 */ - "RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(I%@h)", "RES 7,A", /* b8-bf */ - "SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(I%@h)", "SET 0,A", /* c0-c7 */ - "SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(I%@h)", "SET 1,A", /* c8-cf */ - "SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(I%@h)", "SET 2,A", /* d0-d7 */ - "SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(I%@h)", "SET 3,A", /* d8-df */ - "SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(I%@h)", "SET 4,A", /* e0-e7 */ - "SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(I%@h)", "SET 5,A", /* e8-ef */ - "SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(I%@h)", "SET 6,A", /* f0-f7 */ - "SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(I%@h)", "SET 7,A" /* f8-ff */ -}; - -/* Symbolic disassembler - - Inputs: - *val = instructions to disassemble - useZ80Mnemonics = > 0 iff Z80 mnemonics are to be used - addr = current PC - Outputs: - *S = output text - - DAsm is Copyright (C) Marat Fayzullin 1995,1996,1997 - You are not allowed to distribute this software - commercially. - -*/ - -static int32 DAsm(char *S, const uint32 *val, const int32 useZ80Mnemonics, const int32 addr) { - char R[128], H[10], C = '\0', *T, *P; - uint8 J = 0, Offset = 0; - uint16 B = 0; - - if (useZ80Mnemonics) { - switch(val[B]) { - - case 0xcb: - B++; - T = MnemonicsCB[val[B++]]; - break; - - case 0xed: - B++; - T = MnemonicsED[val[B++]]; - break; - - case 0xdd: - - case 0xfd: - C = (val[B++] == 0xdd) ? 'X' : 'Y'; - if (val[B] == 0xcb) { - B++; - Offset = val[B++]; - J = 1; - T = MnemonicsXCB[val[B++]]; - } - else { - T = MnemonicsXX[val[B++]]; - } - break; - - default: - T = MnemonicsZ80[val[B++]]; - } - } - else { - T = Mnemonics8080[val[B++]]; - } - - if ( (P = strchr(T, '^')) ) { - strncpy(R, T, P - T); - R[P - T] = '\0'; - sprintf(H, "%02X", val[B++]); - strcat(R, H); - strcat(R, P + 1); - } - else { - strcpy(R, T); - } - if ( (P = strchr(R, '%')) ) { - *P = C; - if ( (P = strchr(P + 1, '%')) ) { - *P = C; - } - } - - if( (P = strchr(R, '*')) ) { - strncpy(S, R, P - R); - S[P - R] = '\0'; - sprintf(H, "%02X", val[B++]); - strcat(S, H); - strcat(S, P + 1); - } - else if ( (P = strchr(R, '@')) ) { - strncpy(S, R, P - R); - S[P - R] = '\0'; - if(!J) { - Offset = val[B++]; - } - strcat(S, Offset & 0x80 ? "-" : "+"); - J = Offset & 0x80 ? 256 - Offset : Offset; - sprintf(H, "%02X", J); - strcat(S, H); - strcat(S, P + 1); - } - else if ( (P = strchr(R, '$')) ) { - strncpy(S, R, P - R); - S[P - R] = '\0'; - Offset = val[B++]; - sprintf(H, "%04X", addr + 2 + (Offset & 0x80 ? (Offset - 256) : Offset)); - strcat(S, H); - strcat(S, P + 1); - } - else if ( (P = strchr(R, '#')) ) { - strncpy(S, R, P - R); - S[P - R] = '\0'; - sprintf(H, "%04X", val[B] + 256 * val[B + 1]); - strcat(S, H); - strcat(S, P + 1); - B += 2; - } - else { - strcpy(S, R); - } - return(B); -} - -/* Symbolic output - - Inputs: - *of = output stream - addr = current PC - *val = pointer to values - *uptr = pointer to unit - sw = switches - Outputs: - status = error code -*/ - -int32 fprint_sym(FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw) { - char disasm[128]; - int32 ch = val[0] & 0x7f; - 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; - } - ch = DAsm(disasm, val, cpu_unit.flags & UNIT_CHIP, addr); - fprintf(of, "%s", disasm); - return 1 - ch; /* need to return additional bytes */ -} - -/* 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; - } - } - 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)++; - } - else if (ch == '-') { - sign = -1; - ch = *(*numString)++; - } - 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)--; - } - *result = value * sign; - return (minvalue <= value) && (value <= maxvalue); -} - -static int32 match(const char *pattern, const char *input, char *xyFirst, char *xy, int32 *number, int32 *star, - int32 *at, int32 *hat, int32 *dollar) { - char pat = *pattern++; - char inp = *input++; - while ((pat) && (inp)) { - switch(pat) { - - case '_': /* patterns containing '_' should never match */ - return FALSE; - - case ',': - if (inp == ' ') { - inp = *input++; - continue; - } /* otherwise fall through */ - - case ' ': - if (inp != pat) { - return FALSE; - } - pat = *pattern++; - 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; - } - } - else { /* take note of first '%' for later */ - *xyFirst = inp; - *xy = inp; - } - } - else { - return FALSE; - } - break; - - case '#': - 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; - } - break; - - case '@': - 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; - } - break; - - case '^': - if (numok(inp, &input, 0, 255, FALSE, hat)) { - pattern++; /* skip h */ - } - else { - return FALSE; - } - break; - - default: - if (toupper(pat) != toupper(inp)) { - return FALSE; - } - } - pat = *pattern++; - inp = *input++; - } - while (inp == ' ') { - inp = *input++; - } - return (pat == 0) && (inp == 0); -} - -static int32 checkXY(const char xy) { - return xy == 'X' ? 0xdd : 0xfd; /* else is 'Y' */ -} - -static int32 parse_X80(const char *cptr, const int32 addr, uint32 *val, char *const Mnemonics[]) { - char xyFirst = 0, xy; - int32 op, number, star, at, hat, dollar; - for (op = 0; op < 256; op++) { - number = star = at = dollar = -129; - if (match(Mnemonics[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { - val[0] = op; - if (number >= 0) { - val[1] = (0xff) & number; - val[2] = (0xff) & (number >> 8); - return -2; /* two additional bytes returned */ - } - else if (star >= 0) { - val[1] = (0xff) & star; - return -1; /* one additional byte returned */ - } - else if (at > -129) { - if ((-128 <= at) && (at <= 127)) { - val[1] = (int8)(at); - return -1; /* one additional byte returned */ - } - 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; - } - } - } - if (Mnemonics == Mnemonics8080) { - return SCPE_ARG; - } - - 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; - if (match(MnemonicsED[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { - val[0] = 0xed; - val[1] = op; - if (number >= 0) { - val[2] = (0xff) & number; - val[3] = (0xff) & (number >> 8); - return -3; /* three additional bytes returned */ - } - else { - return -1; /* one additional byte returned */ - } - } - } - - for (op = 0; op < 256; op++) { - number = star = hat = -1; - 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; - } - val[1] = op; - if (number >= 0) { - val[2] = (0xff) & number; - val[3] = (0xff) & (number >> 8); - return -3; /* three additional bytes returned */ - } - else if ((star >= 0) && (hat >= 0)) { - val[2] = (0xff) & hat; - val[3] = (0xff) & star; - return -3; /* three additional bytes returned */ - } - else if (star >= 0) { - val[2] = (0xff) & star; - return -2; /* two additional bytes returned */ - } - else if (hat >= 0) { - val[2] = (0xff) & hat; - return -2; /* two additional bytes returned */ - } - else { - return -1; /* one additional byte returned */ - } - } - } - - for (op = 0; op < 256; op++) { - at = -129; - 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; - } - val[1] = 0xcb; - if (at > -129) { - val[2] = (int8) (at); - } - else { - printf("Offset expected.\n"); - return SCPE_ARG; - } - val[3] = op; - return -3; /* three additional bytes returned */ - } - } - return SCPE_ARG; -} - - -/* Symbolic input - - Inputs: - *cptr = pointer to input string - addr = current PC - *uptr = pointer to unit - *val = pointer to output values - sw = switches - Outputs: - status = error status -*/ -int32 parse_sym(char *cptr, int32 addr, UNIT *uptr, uint32 *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 */ - } - val[0] = (uint32) cptr[0]; - return SCPE_OK; - } - return parse_X80(cptr, addr, val, cpu_unit.flags & UNIT_CHIP ? MnemonicsZ80 : Mnemonics8080); -} +/* altairz80_sys.c: MITS Altair system interface + + 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 + Disassembler from Marat Fayzullin ((c) 1995, 1996, 1997 - Commercial use prohibited) +*/ + +#include +#include "altairz80_defs.h" + +extern UNIT cpu_unit; +extern REG cpu_reg[]; +extern DEVICE cpu_dev; +extern DEVICE sio_dev; +extern DEVICE simh_device; +extern DEVICE ptr_dev; +extern DEVICE ptp_dev; +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); + +/* SCP data structures + sim_name simulator name string + sim_PC pointer to saved PC register descriptor + sim_emax number of words needed for examine + sim_devices array of pointers to simulated devices + sim_stop_messages array of pointers to stop messages +*/ + +char sim_name[] = "Altair 8800 (Z80)"; +REG *sim_PC = &cpu_reg[0]; +int32 sim_emax = 4; +DEVICE *sim_devices[] = { + &cpu_dev, &sio_dev, &simh_device, &ptr_dev, &ptp_dev, &dsk_dev, &hdsk_dev, &net_dev, NULL +}; + +char memoryAccessMessage[80]; +const char *sim_stop_messages[] = { + "HALT instruction", + "Breakpoint", + memoryAccessMessage, + "Invalid Opcode" +}; + +static char *const Mnemonics8080[] = { +/* 0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ + "NOP", "LXI B,#h", "STAX B", "INX B", "INR B", "DCR B", "MVI B,*h", "RLC", /* 00-07 */ + "DB 09h", "DAD B", "LDAX B", "DCX B", "INR C", "DCR C", "MVI C,*h", "RRC", /* 08-0f */ + "DB 10h", "LXI D,#h", "STAX D", "INX D", "INR D", "DCR D", "MVI D,*h", "RAL", /* 10-17 */ + "DB 18h", "DAD D", "LDAX D", "DCX D", "INR E", "DCR E", "MVI E,*h", "RAR", /* 18-1f */ + "DB 20h", "LXI H,#h", "SHLD #h", "INX H", "INR H", "DCR H", "MVI H,*h", "DAA", /* 20-27 */ + "DB 28h", "DAD H", "LHLD #h", "DCX H", "INR L", "DCR L", "MVI L,*h", "CMA", /* 28-2f */ + "DB 30h", "LXI SP,#h", "STA #h", "INX SP", "INR M", "DCR M", "MVI M,*h", "STC", /* 30-37 */ + "DB 38h", "DAD SP", "LDA #h", "DCX SP", "INR A", "DCR A", "MVI A,*h", "CMC", /* 38-3f */ + "MOV B,B", "MOV B,C", "MOV B,D", "MOV B,E", "MOV B,H", "MOV B,L", "MOV B,M", "MOV B,A", /* 40-47 */ + "MOV C,B", "MOV C,C", "MOV C,D", "MOV C,E", "MOV C,H", "MOV C,L", "MOV C,M", "MOV C,A", /* 48-4f */ + "MOV D,B", "MOV D,C", "MOV D,D", "MOV D,E", "MOV D,H", "MOV D,L", "MOV D,M", "MOV D,A", /* 50-57 */ + "MOV E,B", "MOV E,C", "MOV E,D", "MOV E,E", "MOV E,H", "MOV E,L", "MOV E,M", "MOV E,A", /* 58-5f */ + "MOV H,B", "MOV H,C", "MOV H,D", "MOV H,E", "MOV H,H", "MOV H,L", "MOV H,M", "MOV H,A", /* 60-67 */ + "MOV L,B", "MOV L,C", "MOV L,D", "MOV L,E", "MOV L,H", "MOV L,L", "MOV L,M", "MOV L,A", /* 68-6f */ + "MOV M,B", "MOV M,C", "MOV M,D", "MOV M,E", "MOV M,H", "MOV M,L", "HLT", "MOV M,A", /* 70-77 */ + "MOV A,B", "MOV A,C", "MOV A,D", "MOV A,E", "MOV A,H", "MOV A,L", "MOV A,M", "MOV A,A", /* 78-7f */ + "ADD B", "ADD C", "ADD D", "ADD E", "ADD H", "ADD L", "ADD M", "ADD A", /* 80-87 */ + "ADC B", "ADC C", "ADC D", "ADC E", "ADC H", "ADC L", "ADC M", "ADC A", /* 88-8f */ + "SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB M", "SUB A", /* 90-97 */ + "SBB B", "SBB C", "SBB D", "SBB E", "SBB H", "SBB L", "SBB M", "SBB A", /* 98-9f */ + "ANA B", "ANA C", "ANA D", "ANA E", "ANA H", "ANA L", "ANA M", "ANA A", /* a0-a7 */ + "XRA B", "XRA C", "XRA D", "XRA E", "XRA H", "XRA L", "XRA M", "XRA A", /* a8-af */ + "ORA B", "ORA C", "ORA D", "ORA E", "ORA H", "ORA L", "ORA M", "ORA A", /* b0-b7 */ + "CMP B", "CMP C", "CMP D", "CMP E", "CMP H", "CMP L", "CMP M", "CMP A", /* b8-bf */ + "RNZ", "POP B", "JNZ #h", "JMP #h", "CNZ #h", "PUSH B", "ADI *h", "RST 0", /* c0-c7 */ + "RZ", "RET", "JZ #h", "DB CBh", "CZ #h", "CALL #h", "ACI *h", "RST 1", /* c8-cf */ + "RNC", "POP D", "JNC #h", "OUT *h", "CNC #h", "PUSH D", "SUI *h", "RST 2", /* d0-d7 */ + "RC", "DB D9h", "JC #h", "IN *h", "CC #h", "DB DDh", "SBI *h", "RST 3", /* d8-df */ + "RPO", "POP H", "JPO #h", "XTHL", "CPO #h", "PUSH H", "ANI *h", "RST 4", /* e0-e7 */ + "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 */ + "NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA", /* 00-07 */ + "EX AF,AF'", "ADD HL,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA", /* 08-0f */ + "DJNZ $h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA", /* 10-17 */ + "JR $h", "ADD HL,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA", /* 18-1f */ + "JR NZ,$h", "LD HL,#h", "LD (#h),HL", "INC HL", "INC H", "DEC H", "LD H,*h", "DAA", /* 20-27 */ + "JR Z,$h", "ADD HL,HL", "LD HL,(#h)", "DEC HL", "INC L", "DEC L", "LD L,*h", "CPL", /* 28-2f */ + "JR NC,$h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (HL)", "DEC (HL)", "LD (HL),*h", "SCF", /* 30-37 */ + "JR C,$h", "ADD HL,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF", /* 38-3f */ + "LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,H", "LD B,L", "LD B,(HL)", "LD B,A", /* 40-47 */ + "LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,H", "LD C,L", "LD C,(HL)", "LD C,A", /* 48-4f */ + "LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,H", "LD D,L", "LD D,(HL)", "LD D,A", /* 50-57 */ + "LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,H", "LD E,L", "LD E,(HL)", "LD E,A", /* 58-5f */ + "LD H,B", "LD H,C", "LD H,D", "LD H,E", "LD H,H", "LD H,L", "LD H,(HL)", "LD H,A", /* 60-67 */ + "LD L,B", "LD L,C", "LD L,D", "LD L,E", "LD L,H", "LD L,L", "LD L,(HL)", "LD L,A", /* 68-6f */ + "LD (HL),B", "LD (HL),C", "LD (HL),D", "LD (HL),E", "LD (HL),H", "LD (HL),L", "HALT", "LD (HL),A", /* 70-77 */ + "LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,H", "LD A,L", "LD A,(HL)", "LD A,A", /* 78-7f */ + "ADD A,B", "ADD A,C", "ADD A,D", "ADD A,E", "ADD A,H", "ADD A,L", "ADD A,(HL)", "ADD A,A", /* 80-87 */ + "ADC A,B", "ADC A,C", "ADC A,D", "ADC A,E", "ADC A,H", "ADC A,L", "ADC A,(HL)", "ADC A,A", /* 88-8f */ + "SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB (HL)", "SUB A", /* 90-97 */ + "SBC A,B", "SBC A,C", "SBC A,D", "SBC A,E", "SBC A,H", "SBC A,L", "SBC A,(HL)", "SBC A,A", /* 98-9f */ + "AND B", "AND C", "AND D", "AND E", "AND H", "AND L", "AND (HL)", "AND A", /* a0-a7 */ + "XOR B", "XOR C", "XOR D", "XOR E", "XOR H", "XOR L", "XOR (HL)", "XOR A", /* a8-af */ + "OR B", "OR C", "OR D", "OR E", "OR H", "OR L", "OR (HL)", "OR A", /* b0-b7 */ + "CP B", "CP C", "CP D", "CP E", "CP H", "CP L", "CP (HL)", "CP A", /* b8-bf */ + "RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD A,*h", "RST 00h", /* c0-c7 */ + "RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC A,*h", "RST 08h", /* c8-cf */ + "RET NC", "POP DE", "JP NC,#h", "OUT (*h),A", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h", /* d0-d7 */ + "RET C", "EXX", "JP C,#h", "IN A,(*h)", "CALL C,#h", "PFX_DD", "SBC A,*h", "RST 18h", /* d8-df */ + "RET PO", "POP HL", "JP PO,#h", "EX (SP),HL", "CALL PO,#h", "PUSH HL", "AND *h", "RST 20h", /* e0-e7 */ + "RET PE", "LD PC,HL", "JP PE,#h", "EX DE,HL", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h", /* e8-ef */ + "RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h", /* f0-f7 */ + "RET M", "LD SP,HL", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h" /* f8-ff */ +}; + +static char *const MnemonicsCB[256] = { +/* 0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ + "RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (HL)", "RLC A", /* 00-07 */ + "RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (HL)", "RRC A", /* 08-0f */ + "RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (HL)", "RL A", /* 10-17 */ + "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (HL)", "RR A", /* 18-1f */ + "SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (HL)", "SLA A", /* 20-27 */ + "SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (HL)", "SRA A", /* 28-2f */ + "SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (HL)", "SLL A", /* 30-37 */ + "SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (HL)", "SRL A", /* 38-3f */ + "BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(HL)", "BIT 0,A", /* 40-47 */ + "BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(HL)", "BIT 1,A", /* 48-4f */ + "BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(HL)", "BIT 2,A", /* 50-57 */ + "BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(HL)", "BIT 3,A", /* 58-5f */ + "BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(HL)", "BIT 4,A", /* 60-67 */ + "BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(HL)", "BIT 5,A", /* 68-6f */ + "BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(HL)", "BIT 6,A", /* 70-77 */ + "BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(HL)", "BIT 7,A", /* 78-7f */ + "RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(HL)", "RES 0,A", /* 80-87 */ + "RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(HL)", "RES 1,A", /* 88-8f */ + "RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(HL)", "RES 2,A", /* 90-97 */ + "RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(HL)", "RES 3,A", /* 98-9f */ + "RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(HL)", "RES 4,A", /* a0-a7 */ + "RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(HL)", "RES 5,A", /* a8-af */ + "RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(HL)", "RES 6,A", /* b0-b7 */ + "RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(HL)", "RES 7,A", /* b8-bf */ + "SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(HL)", "SET 0,A", /* c0-c7 */ + "SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(HL)", "SET 1,A", /* c8-cf */ + "SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(HL)", "SET 2,A", /* d0-d7 */ + "SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(HL)", "SET 3,A", /* d8-df */ + "SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(HL)", "SET 4,A", /* e0-e7 */ + "SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(HL)", "SET 5,A", /* e8-ef */ + "SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(HL)", "SET 6,A", /* f0-f7 */ + "SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(HL)", "SET 7,A" /* f8-ff */ +}; + +static char *const MnemonicsED[256] = { +/* 0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ + "DB EDh,00h", "DB EDh,01h", "DB EDh,02h", "DB EDh,03h", "DB EDh,04h", "DB EDh,05h", "DB EDh,06h", "DB EDh,07h", /* 00-07 */ + "DB EDh,08h", "DB EDh,09h", "DB EDh,0Ah", "DB EDh,0Bh", "DB EDh,0Ch", "DB EDh,0Dh", "DB EDh,0Eh", "DB EDh,0Fh", /* 08-0f */ + "DB EDh,10h", "DB EDh,11h", "DB EDh,12h", "DB EDh,13h", "DB EDh,14h", "DB EDh,15h", "DB EDh,16h", "DB EDh,17h", /* 10-17 */ + "DB EDh,18h", "DB EDh,19h", "DB EDh,1Ah", "DB EDh,1Bh", "DB EDh,1Ch", "DB EDh,1Dh", "DB EDh,1Eh", "DB EDh,1Fh", /* 18-1f */ + "DB EDh,20h", "DB EDh,21h", "DB EDh,22h", "DB EDh,23h", "DB EDh,24h", "DB EDh,25h", "DB EDh,26h", "DB EDh,27h", /* 20-27 */ + "DB EDh,28h", "DB EDh,29h", "DB EDh,2Ah", "DB EDh,2Bh", "DB EDh,2Ch", "DB EDh,2Dh", "DB EDh,2Eh", "DB EDh,2Fh", /* 28-2f */ + "DB EDh,30h", "DB EDh,31h", "DB EDh,32h", "DB EDh,33h", "DB EDh,34h", "DB EDh,35h", "DB EDh,36h", "DB EDh,37h", /* 30-37 */ + "DB EDh,38h", "DB EDh,39h", "DB EDh,3Ah", "DB EDh,3Bh", "DB EDh,3Ch", "DB EDh,3Dh", "DB EDh,3Eh", "DB EDh,3Fh", /* 38-3f */ + "IN B,(C)", "OUT (C),B", "SBC HL,BC", "LD (#h),BC", "NEG", "RETN", "IM 0", "LD I,A", /* 40-47 */ + "IN C,(C)", "OUT (C),C", "ADC HL,BC", "LD BC,(#h)", "DB EDh,4Ch", "RETI", "DB EDh,4Eh", "LD R,A", /* 48-4f */ + "IN D,(C)", "OUT (C),D", "SBC HL,DE", "LD (#h),DE", "DB EDh,54h", "DB EDh,55h", "IM 1", "LD A,I", /* 50-57 */ + "IN E,(C)", "OUT (C),E", "ADC HL,DE", "LD DE,(#h)", "DB EDh,5Ch", "DB EDh,5Dh", "IM 2", "LD A,R", /* 58-5f */ + "IN H,(C)", "OUT (C),H", "SBC HL,HL", "LD (#h),HL", "DB EDh,64h", "DB EDh,65h", "DB EDh,66h", "RRD", /* 60-67 */ + "IN L,(C)", "OUT (C),L", "ADC HL,HL", "LD HL,(#h)", "DB EDh,6Ch", "DB EDh,6Dh", "DB EDh,6Eh", "RLD", /* 68-6f */ + "IN F,(C)", "DB EDh,71h", "SBC HL,SP", "LD (#h),SP", "DB EDh,74h", "DB EDh,75h", "DB EDh,76h", "DB EDh,77h", /* 70-77 */ + "IN A,(C)", "OUT (C),A", "ADC HL,SP", "LD SP,(#h)", "DB EDh,7Ch", "DB EDh,7Dh", "DB EDh,7Eh", "DB EDh,7Fh", /* 78-7f */ + "DB EDh,80h", "DB EDh,81h", "DB EDh,82h", "DB EDh,83h", "DB EDh,84h", "DB EDh,85h", "DB EDh,86h", "DB EDh,87h", /* 80-87 */ + "DB EDh,88h", "DB EDh,89h", "DB EDh,8Ah", "DB EDh,8Bh", "DB EDh,8Ch", "DB EDh,8Dh", "DB EDh,8Eh", "DB EDh,8Fh", /* 88-8f */ + "DB EDh,90h", "DB EDh,91h", "DB EDh,92h", "DB EDh,93h", "DB EDh,94h", "DB EDh,95h", "DB EDh,96h", "DB EDh,97h", /* 90-97 */ + "DB EDh,98h", "DB EDh,99h", "DB EDh,9Ah", "DB EDh,9Bh", "DB EDh,9Ch", "DB EDh,9Dh", "DB EDh,9Eh", "DB EDh,9Fh", /* 98-9f */ + "LDI", "CPI", "INI", "OUTI", "DB EDh,A4h", "DB EDh,A5h", "DB EDh,A6h", "DB EDh,A7h", /* a0-a7 */ + "LDD", "CPD", "IND", "OUTD", "DB EDh,ACh", "DB EDh,ADh", "DB EDh,AEh", "DB EDh,AFh", /* a8-af */ + "LDIR", "CPIR", "INIR", "OTIR", "DB EDh,B4h", "DB EDh,B5h", "DB EDh,B6h", "DB EDh,B7h", /* b0-b7 */ + "LDDR", "CPDR", "INDR", "OTDR", "DB EDh,BCh", "DB EDh,BDh", "DB EDh,BEh", "DB EDh,BFh", /* b8-bf */ + "DB EDh,C0h", "DB EDh,C1h", "DB EDh,C2h", "DB EDh,C3h", "DB EDh,C4h", "DB EDh,C5h", "DB EDh,C6h", "DB EDh,C7h", /* c0-c7 */ + "DB EDh,C8h", "DB EDh,C9h", "DB EDh,CAh", "DB EDh,CBh", "DB EDh,CCh", "DB EDh,CDh", "DB EDh,CEh", "DB EDh,CFh", /* c8-cf */ + "DB EDh,D0h", "DB EDh,D1h", "DB EDh,D2h", "DB EDh,D3h", "DB EDh,D4h", "DB EDh,D5h", "DB EDh,D6h", "DB EDh,D7h", /* d0-d7 */ + "DB EDh,D8h", "DB EDh,D9h", "DB EDh,DAh", "DB EDh,DBh", "DB EDh,DCh", "DB EDh,DDh", "DB EDh,DEh", "DB EDh,DFh", /* d8-df */ + "DB EDh,E0h", "DB EDh,E1h", "DB EDh,E2h", "DB EDh,E3h", "DB EDh,E4h", "DB EDh,E5h", "DB EDh,E6h", "DB EDh,E7h", /* e0-e7 */ + "DB EDh,E8h", "DB EDh,E9h", "DB EDh,EAh", "DB EDh,EBh", "DB EDh,ECh", "DB EDh,EDh", "DB EDh,EEh", "DB EDh,EFh", /* e8-ef */ + "DB EDh,F0h", "DB EDh,F1h", "DB EDh,F2h", "DB EDh,F3h", "DB EDh,F4h", "DB EDh,F5h", "DB EDh,F6h", "DB EDh,F7h", /* f0-f7 */ + "DB EDh,F8h", "DB EDh,F9h", "DB EDh,FAh", "DB EDh,FBh", "DB EDh,FCh", "DB EDh,FDh", "DB EDh,FEh", "DB EDh,FFh" /* f8-ff */ +}; + +static char *const MnemonicsXX[256] = { +/* 0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ + "NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA", /* 00-07 */ + "EX AF,AF'", "ADD I%,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA", /* 08-0f */ + "DJNZ $h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA", /* 10-17 */ + "JR $h", "ADD I%,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA", /* 18-1f */ + "JR NZ,$h", "LD I%,#h", "LD (#h),I%", "INC I%", "INC I%H", "DEC I%H", "LD I%H,*h", "DAA", /* 20-27 */ + "JR Z,$h", "ADD I%,I%", "LD I%,(#h)", "DEC I%", "INC I%L", "DEC I%L", "LD I%L,*h", "CPL", /* 28-2f */ + "JR NC,$h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (I%+^h)", "DEC (I%+^h)", "LD (I%+^h),*h","SCF", /* 30-37 */ + "JR C,$h", "ADD I%,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF", /* 38-3f */ + "LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,I%H", "LD B,I%L", "LD B,(I%+^h)", "LD B,A", /* 40-47 */ + "LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,I%H", "LD C,I%L", "LD C,(I%+^h)", "LD C,A", /* 48-4f */ + "LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,I%H", "LD D,I%L", "LD D,(I%+^h)", "LD D,A", /* 50-57 */ + "LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,I%H", "LD E,I%L", "LD E,(I%+^h)", "LD E,A", /* 58-5f */ + "LD I%H,B", "LD I%H,C", "LD I%H,D", "LD I%H,E", "LD I%H,I%H", "LD I%H,I%L", "LD H,(I%+^h)", "LD I%H,A", /* 60-67 */ + "LD I%L,B", "LD I%L,C", "LD I%L,D", "LD I%L,E", "LD I%L,I%H", "LD I%L,I%L", "LD L,(I%+^h)", "LD I%L,A", /* 68-6f */ + "LD (I%+^h),B", "LD (I%+^h),C", "LD (I%+^h),D", "LD (I%+^h),E", "LD (I%+^h),H", "LD (I%+^h),L", "HALT", "LD (I%+^h),A", /* 70-77 */ + "LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,I%H", "LD A,I%L", "LD A,(I%+^h)", "LD A,A", /* 78-7f */ + "ADD A,B", "ADD A,C", "ADD A,D", "ADD A,E", "ADD A,I%H", "ADD A,I%L", "ADD A,(I%+^h)","ADD A,A", /* 80-87 */ + "ADC A,B", "ADC A,C", "ADC A,D", "ADC A,E", "ADC A,I%H", "ADC A,I%L", "ADC A,(I%+^h)","ADC A,A", /* 88-8f */ + "SUB B", "SUB C", "SUB D", "SUB E", "SUB I%H", "SUB I%L", "SUB (I%+^h)", "SUB A", /* 90-97 */ + "SBC A,B", "SBC A,C", "SBC A,D", "SBC A,E", "SBC A,I%H", "SBC A,I%L", "SBC A,(I%+^h)","SBC A,A", /* 98-9f */ + "AND B", "AND C", "AND D", "AND E", "AND I%H", "AND I%L", "AND (I%+^h)", "AND A", /* a0-a7 */ + "XOR B", "XOR C", "XOR D", "XOR E", "XOR I%H", "XOR I%L", "XOR (I%+^h)", "XOR A", /* a8-af */ + "OR B", "OR C", "OR D", "OR E", "OR I%H", "OR I%L", "OR (I%+^h)", "OR A", /* b0-b7 */ + "CP B", "CP C", "CP D", "CP E", "CP I%H", "CP I%L", "CP (I%+^h)", "CP A", /* b8-bf */ + "RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD A,*h", "RST 00h", /* c8-cf */ + "RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC A,*h", "RST 08h", /* c8-cf */ + "RET NC", "POP DE", "JP NC,#h", "OUT (*h),A", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h", /* d0-d7 */ + "RET C", "EXX", "JP C,#h", "IN A,(*h)", "CALL C,#h", "PFX_DD", "SBC A,*h", "RST 18h", /* d8-df */ + "RET PO", "POP I%", "JP PO,#h", "EX (SP),I%", "CALL PO,#h", "PUSH I%", "AND *h", "RST 20h", /* e0-e7 */ + "RET PE", "LD PC,I%", "JP PE,#h", "EX DE,I%", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h", /* e8-ef */ + "RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h", /* f0-f7 */ + "RET M", "LD SP,I%", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h" /* f8-ff */ +}; + +static char *const MnemonicsXCB[256] = { +/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ + "RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (I%@h)", "RLC A", /* 00-07 */ + "RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (I%@h)", "RRC A", /* 08-0f */ + "RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (I%@h)", "RL A", /* 10-17 */ + "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (I%@h)", "RR A", /* 18-1f */ + "SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (I%@h)", "SLA A", /* 20-27 */ + "SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (I%@h)", "SRA A", /* 28-2f */ + "SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (I%@h)", "SLL A", /* 30-37 */ + "SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (I%@h)", "SRL A", /* 38-3f */ + "BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(I%@h)", "BIT 0,A", /* 40-47 */ + "BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(I%@h)", "BIT 1,A", /* 48-4f */ + "BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(I%@h)", "BIT 2,A", /* 50-57 */ + "BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(I%@h)", "BIT 3,A", /* 58-5f */ + "BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(I%@h)", "BIT 4,A", /* 60-67 */ + "BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(I%@h)", "BIT 5,A", /* 68-6f */ + "BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(I%@h)", "BIT 6,A", /* 70-77 */ + "BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(I%@h)", "BIT 7,A", /* 78-7f */ + "RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(I%@h)", "RES 0,A", /* 80-87 */ + "RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(I%@h)", "RES 1,A", /* 88-8f */ + "RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(I%@h)", "RES 2,A", /* 90-97 */ + "RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(I%@h)", "RES 3,A", /* 98-9f */ + "RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(I%@h)", "RES 4,A", /* a0-a7 */ + "RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(I%@h)", "RES 5,A", /* a8-af */ + "RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(I%@h)", "RES 6,A", /* b0-b7 */ + "RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(I%@h)", "RES 7,A", /* b8-bf */ + "SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(I%@h)", "SET 0,A", /* c0-c7 */ + "SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(I%@h)", "SET 1,A", /* c8-cf */ + "SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(I%@h)", "SET 2,A", /* d0-d7 */ + "SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(I%@h)", "SET 3,A", /* d8-df */ + "SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(I%@h)", "SET 4,A", /* e0-e7 */ + "SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(I%@h)", "SET 5,A", /* e8-ef */ + "SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(I%@h)", "SET 6,A", /* f0-f7 */ + "SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(I%@h)", "SET 7,A" /* f8-ff */ +}; + +/* Symbolic disassembler + + Inputs: + *val = instructions to disassemble + useZ80Mnemonics = > 0 iff Z80 mnemonics are to be used + addr = current PC + Outputs: + *S = output text + + DAsm is Copyright (C) Marat Fayzullin 1995,1996,1997 + You are not allowed to distribute this software + commercially. + +*/ + +static int32 DAsm(char *S, const uint32 *val, const int32 useZ80Mnemonics, const int32 addr) { + char R[128], H[10], C = '\0', *T, *P; + uint8 J = 0, Offset = 0; + uint16 B = 0; + + if (useZ80Mnemonics) { + switch(val[B]) { + + case 0xcb: + B++; + T = MnemonicsCB[val[B++]]; + break; + + case 0xed: + B++; + T = MnemonicsED[val[B++]]; + break; + + case 0xdd: + + case 0xfd: + C = (val[B++] == 0xdd) ? 'X' : 'Y'; + if (val[B] == 0xcb) { + B++; + Offset = val[B++]; + J = 1; + T = MnemonicsXCB[val[B++]]; + } + else { + T = MnemonicsXX[val[B++]]; + } + break; + + default: + T = MnemonicsZ80[val[B++]]; + } + } + else { + T = Mnemonics8080[val[B++]]; + } + + if ( (P = strchr(T, '^')) ) { + strncpy(R, T, P - T); + R[P - T] = '\0'; + sprintf(H, "%02X", val[B++]); + strcat(R, H); + strcat(R, P + 1); + } + else { + strcpy(R, T); + } + if ( (P = strchr(R, '%')) ) { + *P = C; + if ( (P = strchr(P + 1, '%')) ) { + *P = C; + } + } + + if ( (P = strchr(R, '*')) ) { + strncpy(S, R, P - R); + S[P - R] = '\0'; + sprintf(H, "%02X", val[B++]); + strcat(S, H); + strcat(S, P + 1); + } + else if ( (P = strchr(R, '@')) ) { + strncpy(S, R, P - R); + S[P - R] = '\0'; + if (!J) { + Offset = val[B++]; + } + strcat(S, Offset & 0x80 ? "-" : "+"); + J = Offset & 0x80 ? 256 - Offset : Offset; + sprintf(H, "%02X", J); + strcat(S, H); + strcat(S, P + 1); + } + else if ( (P = strchr(R, '$')) ) { + strncpy(S, R, P - R); + S[P - R] = '\0'; + Offset = val[B++]; + sprintf(H, "%04X", addr + 2 + (Offset & 0x80 ? (Offset - 256) : Offset)); + strcat(S, H); + strcat(S, P + 1); + } + else if ( (P = strchr(R, '#')) ) { + strncpy(S, R, P - R); + S[P - R] = '\0'; + sprintf(H, "%04X", val[B] + 256 * val[B + 1]); + strcat(S, H); + strcat(S, P + 1); + B += 2; + } + else { + strcpy(S, R); + } + return(B); +} + +/* Symbolic output + + Inputs: + *of = output stream + addr = current PC + *val = pointer to values + *uptr = pointer to unit + sw = switches + Outputs: + status = error code +*/ + +int32 fprint_sym(FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw) { + char disasm[128]; + int32 ch = val[0] & 0x7f; + 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; + } + ch = DAsm(disasm, val, cpu_unit.flags & UNIT_CHIP, addr); + fprintf(of, "%s", disasm); + return 1 - ch; /* need to return additional bytes */ +} + +/* 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; + } + } + 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)++; + } + else if (ch == '-') { + sign = -1; + ch = *(*numString)++; + } + 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)--; + } + *result = value * sign; + return (minvalue <= value) && (value <= maxvalue); +} + +static int32 match(const char *pattern, const char *input, char *xyFirst, char *xy, int32 *number, int32 *star, + int32 *at, int32 *hat, int32 *dollar) { + char pat = *pattern++; + char inp = *input++; + while ((pat) && (inp)) { + switch(pat) { + + case '_': /* patterns containing '_' should never match */ + return FALSE; + + case ',': + if (inp == ' ') { + inp = *input++; + continue; + } /* otherwise fall through */ + + case ' ': + if (inp != pat) { + return FALSE; + } + pat = *pattern++; + 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; + } + } + else { /* take note of first '%' for later */ + *xyFirst = inp; + *xy = inp; + } + } + else { + return FALSE; + } + break; + + case '#': + 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; + } + break; + + case '@': + 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; + } + break; + + case '^': + if (numok(inp, &input, 0, 255, FALSE, hat)) { + pattern++; /* skip h */ + } + else { + return FALSE; + } + break; + + default: + if (toupper(pat) != toupper(inp)) { + return FALSE; + } + } + pat = *pattern++; + inp = *input++; + } + while (inp == ' ') { + inp = *input++; + } + return (pat == 0) && (inp == 0); +} + +static int32 checkXY(const char xy) { + return xy == 'X' ? 0xdd : 0xfd; /* else is 'Y' */ +} + +static int32 parse_X80(const char *cptr, const int32 addr, uint32 *val, char *const Mnemonics[]) { + char xyFirst = 0, xy; + int32 op, number, star, at, hat, dollar; + for (op = 0; op < 256; op++) { + number = star = at = dollar = -129; + if (match(Mnemonics[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { + val[0] = op; + if (number >= 0) { + val[1] = (0xff) & number; + val[2] = (0xff) & (number >> 8); + return -2; /* two additional bytes returned */ + } + else if (star >= 0) { + val[1] = (0xff) & star; + return -1; /* one additional byte returned */ + } + else if (at > -129) { + if ((-128 <= at) && (at <= 127)) { + val[1] = (int8)(at); + return -1; /* one additional byte returned */ + } + 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; + } + } + } + if (Mnemonics == Mnemonics8080) { + return SCPE_ARG; + } + + 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; + if (match(MnemonicsED[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { + val[0] = 0xed; + val[1] = op; + if (number >= 0) { + val[2] = (0xff) & number; + val[3] = (0xff) & (number >> 8); + return -3; /* three additional bytes returned */ + } + else { + return -1; /* one additional byte returned */ + } + } + } + + for (op = 0; op < 256; op++) { + number = star = hat = -1; + 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; + } + val[1] = op; + if (number >= 0) { + val[2] = (0xff) & number; + val[3] = (0xff) & (number >> 8); + return -3; /* three additional bytes returned */ + } + else if ((star >= 0) && (hat >= 0)) { + val[2] = (0xff) & hat; + val[3] = (0xff) & star; + return -3; /* three additional bytes returned */ + } + else if (star >= 0) { + val[2] = (0xff) & star; + return -2; /* two additional bytes returned */ + } + else if (hat >= 0) { + val[2] = (0xff) & hat; + return -2; /* two additional bytes returned */ + } + else { + return -1; /* one additional byte returned */ + } + } + } + + for (op = 0; op < 256; op++) { + at = -129; + 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; + } + val[1] = 0xcb; + if (at > -129) { + val[2] = (int8) (at); + } + else { + printf("Offset expected.\n"); + return SCPE_ARG; + } + val[3] = op; + return -3; /* three additional bytes returned */ + } + } + return SCPE_ARG; +} + + +/* Symbolic input + + Inputs: + *cptr = pointer to input string + addr = current PC + *uptr = pointer to unit + *val = pointer to output values + sw = switches + Outputs: + status = error status +*/ +int32 parse_sym(char *cptr, int32 addr, UNIT *uptr, uint32 *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 */ + } + val[0] = (uint32) cptr[0]; + return SCPE_OK; + } + return parse_X80(cptr, addr, val, cpu_unit.flags & UNIT_CHIP ? MnemonicsZ80 : Mnemonics8080); +} diff --git a/AltairZ80/altairz80_hdsk.c b/AltairZ80/altairz80_hdsk.c index 6724dbef..8fddc05c 100644 --- a/AltairZ80/altairz80_hdsk.c +++ b/AltairZ80/altairz80_hdsk.c @@ -14,7 +14,7 @@ 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 + 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. @@ -22,27 +22,28 @@ 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 provided courtesy of 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); +/* 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_HDSKWLK (UNIT_V_UF + 0) /* write locked */ -#define UNIT_HDSKWLK (1 << UNIT_V_HDSKWLK) +#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 /* size of sector */ +#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_MAX_TRACKS u3 /* number of tracks */ +#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 */ @@ -55,11 +56,11 @@ t_stat hdsk_attach (UNIT *uptr, char *cptr); #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 uint8 M[MAXMEMSIZE][MAXBANKS]; extern int32 saved_PC; extern int32 install_bootrom(void); @@ -71,14 +72,7 @@ extern uint8 GetBYTEWrapper(const uint32 Addr); extern int32 bootrom[BOOTROM_SIZE]; static t_stat hdsk_boot(int32 unitno, DEVICE *dptr); -static int32 hdsk_hasVerbose(void); int32 hdsk_io(const int32 port, const int32 io, const int32 data); -static int32 hdsk_in(const int32 port); -static int32 hdsk_out(const int32 data); -static int32 checkParameters(void); -static int32 doSeek(void); -static int32 doRead(void); -static int32 doWrite(void); static int32 hdskLastCommand = HDSK_NONE; static int32 hdskCommandPosition = 0; @@ -87,31 +81,33 @@ static int32 selectedDisk; static int32 selectedSector; static int32 selectedTrack; static int32 selectedDMA; -static int32 hdskTrace; +static int32 hdskTrace = FALSE; typedef struct { - char name[16]; - t_addr capac; - uint16 spt; - uint8 bsh; - uint8 blm; - uint8 exm; - uint16 dsm; - uint16 drm; - uint8 al0; - uint8 al1; - uint16 cks; - uint16 off; - uint8 psh; - uint8 phm; + 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, 0x8000, 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 */ +/* 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 } }; @@ -139,12 +135,12 @@ static REG hdsk_reg[] = { static MTAB hdsk_mod[] = { { MTAB_XTD|MTAB_VUN|MTAB_VAL, 0, "FORMAT", "FORMAT", &set_format, &show_format, NULL }, - { UNIT_HDSKWLK, 0, "WRTENB", "WRTENB", NULL }, - { UNIT_HDSKWLK, UNIT_HDSKWLK, "WRTLCK", "WRTLCK", 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 }, + { UNIT_HDSK_VERBOSE, 0, "QUIET", "QUIET", NULL }, /* verbose, show warning messages */ - { UNIT_HDSK_VERBOSE, UNIT_HDSK_VERBOSE, "VERBOSE", "VERBOSE", NULL }, + { UNIT_HDSK_VERBOSE, UNIT_HDSK_VERBOSE, "VERBOSE", "VERBOSE", NULL }, { MTAB_XTD|MTAB_VUN|MTAB_VAL, 0, "GEOM", "GEOM", &set_geom, &show_geom, NULL }, { 0 } }; @@ -159,102 +155,117 @@ DEVICE hdsk_dev = { }; /* Attach routine */ -t_stat hdsk_attach (UNIT *uptr, char *cptr) { - uint32 flen; +t_stat hdsk_attach(UNIT *uptr, char *cptr) { t_stat r; int32 i; + char unitChar; - r = attach_unit (uptr, cptr); /* attach unit */ - if (r != SCPE_OK) return r; /* error? */ - if ((flen = sim_fsize (uptr->fileref)) == 0) { /* new disk image? */ - if (uptr->flags & UNIT_RO) return SCPE_OK; /* if ro, done */ - return SCPE_OK; - } + r = attach_unit(uptr, cptr); /* attach unit */ + if ( r != SCPE_OK) /* error? */ + return r; - if(flen>0) { - uptr->capac = flen; + /* 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); - uptr->HDSK_FORMAT_TYPE = -1; /* Default to unknown format type */ - - for(i=0; dpb[i].spt != 0; i++) { - if(dpb[i].capac == uptr->capac) { - uptr->HDSK_FORMAT_TYPE = i; - break; - } + /* 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; } } - if(uptr->HDSK_FORMAT_TYPE == -1) { - uptr->HDSK_FORMAT_TYPE = 0; - uptr->capac = dpb[uptr->HDSK_FORMAT_TYPE].capac; - printf("HDSK: WARNING: Unsupported disk capacity, assuming HDSK type.\n"); - uptr->flags |= UNIT_HDSKWLK; - printf("HDSK: WARNING: Forcing WRTLCK.\n"); - if(uptr->capac != (uptr->HDSK_MAX_TRACKS * uptr->HDSK_SECTORS_PER_TRACK * uptr->HDSK_SECTOR_SIZE)) { - printf("HDSK: WARNING: Geometry may be incorrect.\n"); + /* 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); - 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_MAX_TRACKS = uptr->capac / (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( ((uptr -> HDSK_NUMBER_OF_TRACKS - 1) * uptr -> HDSK_SECTORS_PER_TRACK * + uptr -> HDSK_SECTOR_SIZE < uptr -> capac) && + (uptr -> capac <= 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) { - DEVICE *dptr; - - uint32 ncyl, nsect, ssize; +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; - dptr = find_dev_from_unit (uptr); - if (dptr == NULL) return SCPE_IERR; - - sscanf(cptr, "%d/%d/%d", &ncyl, &nsect, &ssize); - uptr->HDSK_MAX_TRACKS = ncyl; - uptr->HDSK_SECTORS_PER_TRACK = nsect; - uptr->HDSK_SECTOR_SIZE = ssize; - + 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) { - DEVICE *dptr; +t_stat show_geom(FILE *st, UNIT *uptr, int32 val, void *desc) { if (uptr == NULL) return SCPE_IERR; - dptr = find_dev_from_unit (uptr); - if (dptr == NULL) return SCPE_IERR; - fprintf (st, "T:%d/N:%d/S:%d", uptr->HDSK_MAX_TRACKS, uptr->HDSK_SECTORS_PER_TRACK, uptr->u5); - + 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) { - DEVICE *dptr; - - char fmtname[16]; +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; - dptr = find_dev_from_unit (uptr); - if (dptr == NULL) return SCPE_IERR; - - sscanf(cptr, "%s", fmtname); - - for(i=0;dpb[i].spt != 0;i++) { - if(!strncmp(fmtname, dpb[i].name, strlen(fmtname))) { - uptr->HDSK_FORMAT_TYPE = i; - uptr->capac = dpb[i].capac; /* Set capacity */ + 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_MAX_TRACKS = uptr->capac / (uptr->HDSK_SECTORS_PER_TRACK * uptr->HDSK_SECTOR_SIZE); + 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; } @@ -263,13 +274,9 @@ t_stat set_format (UNIT *uptr, int32 val, char *cptr, void *desc) { } /* Show disk format routine */ -t_stat show_format (FILE *st, UNIT *uptr, int32 val, void *desc) { - DEVICE *dptr; +t_stat show_format(FILE *st, UNIT *uptr, int32 val, void *desc) { if (uptr == NULL) return SCPE_IERR; - dptr = find_dev_from_unit (uptr); - if (dptr == NULL) return SCPE_IERR; - fprintf (st, "%s", dpb[uptr->HDSK_FORMAT_TYPE].name); - + fprintf(st, "%s", dpb[uptr -> HDSK_FORMAT_TYPE].name); return SCPE_OK; } @@ -315,9 +322,6 @@ static t_stat hdsk_boot(int32 unitno, DEVICE *dptr) { return SCPE_ARG; } if (cpu_unit.flags & (UNIT_ALTAIRROM | UNIT_BANKED)) { - if (install_bootrom()) { - printf("ALTAIR boot ROM installed.\n"); - } /* 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, */ @@ -326,6 +330,7 @@ static t_stat hdsk_boot(int32 unitno, DEVICE *dptr) { 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); @@ -339,7 +344,7 @@ static t_stat hdsk_boot(int32 unitno, DEVICE *dptr) { static int32 hdsk_hasVerbose(void) { int32 i; for (i = 0; i < HDSK_NUMBER; i++) { - if (((hdsk_dev.units + i) -> flags) & UNIT_HDSK_VERBOSE) { + if (hdsk_dev.units[i].flags & UNIT_HDSK_VERBOSE) { return TRUE; } } @@ -398,7 +403,7 @@ static int32 hdsk_hasVerbose(void) { /* check the parameters and return TRUE iff parameters are correct or have been repaired */ static int32 checkParameters(void) { - UNIT *uptr = hdsk_dev.units + selectedDisk; + UNIT *uptr = &hdsk_dev.units[selectedDisk]; int32 currentFlag; if ((selectedDisk < 0) || (selectedDisk >= HDSK_NUMBER)) { if (hdsk_hasVerbose()) { @@ -406,24 +411,24 @@ static int32 checkParameters(void) { } selectedDisk = 0; } - currentFlag = (hdsk_dev.units + selectedDisk) -> flags; + 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 ((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); + selectedDisk, selectedSector, uptr -> HDSK_SECTORS_PER_TRACK); } selectedSector = 0; } - if ((selectedTrack < 0) || (selectedTrack >= uptr->HDSK_MAX_TRACKS)) { + 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_MAX_TRACKS); + selectedDisk, selectedTrack, uptr -> HDSK_NUMBER_OF_TRACKS); } selectedTrack = 0; } @@ -431,15 +436,16 @@ static int32 checkParameters(void) { 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); + selectedDisk, selectedTrack, selectedSector, uptr -> HDSK_SECTOR_SIZE, selectedDMA); } return TRUE; } static int32 doSeek(void) { - UNIT *uptr = hdsk_dev.units + selectedDisk; + 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)) { + (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); @@ -451,17 +457,17 @@ static int32 doSeek(void) { } } -uint8 hdskbuf[HDSK_MAX_SECTOR_SIZE]; /* data buffer */ +uint8 hdskbuf[HDSK_MAX_SECTOR_SIZE] = {}; /* data buffer */ static int32 doRead(void) { int32 i; - UNIT *uptr = hdsk_dev.units + selectedDisk; + 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++) { + 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) { @@ -470,7 +476,7 @@ static int32 doRead(void) { } return CPM_OK; /* allows the creation of empty hard disks */ } - for (i = 0; i < uptr->HDSK_SECTOR_SIZE; i++) { + for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++) { PutBYTEWrapper(selectedDMA + i, hdskbuf[i]); } return CPM_OK; @@ -479,15 +485,15 @@ static int32 doRead(void) { static int32 doWrite(void) { int32 i; - UNIT *uptr = hdsk_dev.units + selectedDisk; - if (((uptr -> flags) & UNIT_HDSKWLK) == 0) { /* write enabled */ + 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++) { + 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 (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); @@ -506,7 +512,7 @@ static int32 doWrite(void) { } static int32 hdsk_in(const int32 port) { - UNIT *uptr = hdsk_dev.units + selectedDisk; + UNIT *uptr = &hdsk_dev.units[selectedDisk]; int32 result; if ((hdskCommandPosition == 6) && ((hdskLastCommand == HDSK_READ) || (hdskLastCommand == HDSK_WRITE))) { @@ -515,7 +521,7 @@ static int32 hdsk_in(const int32 port) { hdskCommandPosition = 0; return result; } else if (hdskLastCommand == HDSK_PARAM) { - DPB current = dpb[uptr->HDSK_FORMAT_TYPE]; + 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; @@ -535,9 +541,9 @@ static int32 hdsk_in(const int32 port) { if (paramcount <= 17) return params[paramcount - 1]; else if (paramcount == 18) - return (uptr->HDSK_SECTOR_SIZE & 0xff); + return (uptr -> HDSK_SECTOR_SIZE & 0xff); else if (paramcount == 19) - return (uptr->HDSK_SECTOR_SIZE >> 8); + return (uptr -> HDSK_SECTOR_SIZE >> 8); else MESSAGE_2("HDSK%d Get parameter error.", selectedDisk); diff --git a/AltairZ80/altairz80_net.c b/AltairZ80/altairz80_net.c index 1354cff2..b69dac6f 100644 --- a/AltairZ80/altairz80_net.c +++ b/AltairZ80/altairz80_net.c @@ -1,292 +1,292 @@ -/* 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-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; +} diff --git a/GRI/gri_cpu.c b/GRI/gri_cpu.c index cc64557e..c854828d 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-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"), @@ -25,6 +25,7 @@ cpu GRI-909 CPU + 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 @@ -380,14 +381,12 @@ t_stat sim_instr (void) { uint32 src, dst, op, t, jmp; t_stat reason; -extern UNIT rtc_unit; /* Restore register state */ SC = SC & AMASK; /* load local PC */ reason = 0; ao_update (); /* update AO */ -sim_rtc_init (rtc_unit.wait); /* init calibration */ /* Main instruction fetch/decode loop */ diff --git a/H316/h316_cpu.c b/H316/h316_cpu.c index 92be3e37..07778cb5 100644 --- a/H316/h316_cpu.c +++ b/H316/h316_cpu.c @@ -1,6 +1,6 @@ /* h316_cpu.c: Honeywell 316/516 CPU simulator - Copyright (c) 1999-2006, Robert M. Supnik + Copyright (c) 1999-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,6 +25,7 @@ cpu H316/H516 CPU + 28-Apr-07 RMS Removed clock initialization 03-Apr-06 RMS Fixed bugs in LLL, LRL (from Theo Engel) 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) 16-Aug-05 RMS Fixed C++ declaration and cast problems @@ -370,7 +371,6 @@ DEVICE cpu_dev = { t_stat sim_instr (void) { -extern UNIT clk_unit; int32 AR, BR, MB, Y, t1, t2, t3, skip, dev; uint32 ut; t_stat reason; @@ -399,7 +399,6 @@ BR = saved_BR & DMASK; XR = saved_XR & DMASK; PC = PC & ((cpu_unit.flags & UNIT_EXT)? X_AMASK: NX_AMASK); /* mask PC */ reason = 0; -sim_rtc_init (clk_unit.wait); /* init calibration */ /* Main instruction fetch/decode loop */ diff --git a/H316/h316_lp.c b/H316/h316_lp.c index 59d18784..9dc311c8 100644 --- a/H316/h316_lp.c +++ b/H316/h316_lp.c @@ -1,6 +1,6 @@ /* h316_lp.c: Honeywell 316/516 line printer - Copyright (c) 1999-2006, Robert M. Supnik + Copyright (c) 1999-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,6 +25,7 @@ lpt line printer + 19-Jan-06 RMS Added UNIT_TEXT flag 03-Apr-06 RMS Fixed bug in blanks backscanning (from Theo Engel) 01-Dec-04 RMS Fixed bug in DMA/DMC support 24-Oct-03 RMS Added DMA/DMC support @@ -105,7 +106,7 @@ t_stat lpt_reset (DEVICE *dptr); DIB lpt_dib = { LPT, IOBUS, 1, &lptio }; -UNIT lpt_unit = { UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0) }; +UNIT lpt_unit = { UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0) }; REG lpt_reg[] = { { DRDATA (WDPOS, lpt_wdpos, 6) }, diff --git a/HP2100/hp2100_cpu.c b/HP2100/hp2100_cpu.c index 50a9d122..8cca1782 100644 --- a/HP2100/hp2100_cpu.c +++ b/HP2100/hp2100_cpu.c @@ -28,6 +28,8 @@ DMA0,DMA1 12607B/12578A/12895A direct memory access controller DCPC0,DCPC1 12897B dual channel port controller + 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 28-Dec-06 JDB CLC 0 now sends CRS instead of CLC to devices 26-Dec-06 JDB Fixed improper IRQ deferral for 21xx CPUs @@ -378,7 +380,6 @@ #define UNIT_MP_INT (1 << UNIT_V_MP_INT) #define UNIT_MP_SEL1 (1 << UNIT_V_MP_SEL1) - #define ABORT(val) longjmp (save_env, (val)) #define DMAR0 1 @@ -521,8 +522,6 @@ void hp_post_cmd (t_bool from_scp); extern t_stat cpu_eau (uint32 IR, uint32 intrq); extern t_stat cpu_uig_0 (uint32 IR, uint32 intrq, uint32 iotrap); extern t_stat cpu_uig_1 (uint32 IR, uint32 intrq, uint32 iotrap); - -extern int32 clk_delay (int32 flg); extern void (*sim_vm_post) (t_bool from_scp); /* CPU data structures @@ -841,7 +840,6 @@ for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru dev */ dtab[dev] = dibp->iot; /* set I/O dispatch */ } } -sim_rtc_init (clk_delay (0)); /* recalibrate clock */ /* Configure interrupt deferral table */ @@ -2023,7 +2021,7 @@ return dat; - STC requested but not CLC: issue STC,C - CLC requested but not STC: issue CLC,C - STC and CLC both requested: issue STC,C and CLC,C, in that order - Either: issue EDT + Either: issue EDT (pass DMA channel number and I/O flag) */ void dma_cycle (uint32 ch, uint32 map) @@ -2101,7 +2099,7 @@ else { } /* end output */ setFLG (DMA0 + ch); /* set DMA flg */ clrCMD (DMA0 + ch); /* clr DMA cmd */ - devdisp (dev, ioEDT, dev, 0); /* do EDT */ + devdisp (dev, ioEDT, dev, inp | ch); /* do EDT */ } return; } diff --git a/HP2100/hp2100_diag.txt b/HP2100/hp2100_diag.txt index 236e7f45..a518d4af 100644 --- a/HP2100/hp2100_diag.txt +++ b/HP2100/hp2100_diag.txt @@ -1,6 +1,6 @@ SIMH/HP 21XX DIAGNOSTICS PERFORMANCE ==================================== - Last update: 2007-01-12 + Last update: 2007-03-05 The HP 24396 diagnostic suite has been run against the SIMH HP 21xx simulation. @@ -62,8 +62,8 @@ The results of the diagnostic runs are summarized below: 103122 59310 Interface Bus Interface 1728 - No simulation 103003 12587 Asynchronous Data Set Interface 1553 - No simulation -103110 12920 Asynchronous Multiplexer (Data) 1805 - Not tested -103011 12920 Asynchronous Multiplexer (Cntl) 1444 - Not tested +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 103116 12967 Synchronous Interface 1438 - No simulation @@ -114,11 +114,11 @@ not supported by the 24396 suite: Paper Tape Date SIMH Part Number DSN Diagnostic Name Code Vers. Result ----------- ------ --------------------------------------- ---- ----- ---------- -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 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 @@ -988,31 +988,71 @@ TEST RESULT: Passed. --------------------------------------------------- -DSN 103110 - 12920 Asynchronous Multiplexer (Data) --------------------------------------------------- +--------------------------------------------------- +DSN 103110 - 12920A Asynchronous Multiplexer (Data) +--------------------------------------------------- TESTED DEVICE: MUX, MUXL (hp2100_mux.c) -CONFIGURATION: +CONFIGURATION: sim> set MUX DIAG + sim> deposit S 004040 + sim> reset + sim> go 100 -TEST REPORT: + HALT instruction 102074 -TEST RESULT: Not tested. + sim> deposit S 000000 + sim> reset + sim> go + +TEST REPORT: ASYNC MULTIPLEXER DATA BOARD DIAGNOSTIC DSN 103110 + H024 PRESS PRESET (EXT&INT),RUN + + HALT instruction 102024 + + sim> reset + sim> go + + H025 BI-O COMP + PASS 000001 + + HALT instruction 102077 + +TEST RESULT: Passed. --------------------------------------------------- -DSN 103011 - 12920 Asynchronous Multiplexer (Cntl) --------------------------------------------------- +--------------------------------------------------- +DSN 103011 - 12920A Asynchronous Multiplexer (Cntl) +--------------------------------------------------- TESTED DEVICE: MUXM (hp2100_mux.c) -CONFIGURATION: +CONFIGURATION: sim> set MUX DIAG + sim> deposit S 004042 + sim> reset + sim> go 100 -TEST REPORT: + HALT instruction 102074 -TEST RESULT: Not tested. + sim> deposit S 000000 + sim> reset + sim> go + +TEST REPORT: ASYNC MULTIPLEXER CONTROL BOARD DIAGNOSTIC + H024 PRESS PRESET (EXT&INT),RUN + + HALT instruction 102024 + + sim> reset + sim> go + + H025 BI-O COMP + PASS 000001 + + HALT instruction 102077 + +TEST RESULT: Passed. @@ -3117,6 +3157,41 @@ TEST RESULT: Passed. +----------------------------------------------- +DSN (none) - 12875 Processor Interconnect Cable +----------------------------------------------- + +TESTED DEVICE: IPLI, IPLO (hp2100_ipl.c) + +BINARY TAPE: 24197-60001 Rev. B + +CONFIGURATION: sim> set IPLI DIAG + sim> set IPLO DIAG + sim> deposit S 003332 + sim> reset + sim> go 2 + + HALT instruction 107076 + + sim> deposit S 010000 + sim> reset + sim> go + + HALT instruction 107077 + + sim> deposit S 000000 + sim> reset + sim> go 100 + +TEST REPORT: H14. START 12875 CABLE DIAGNOSTIC + H77. END 12875 CABLE DIAGNOSTIC + + HALT instruction 102077 + +TEST RESULT: Passed. + + + -------------------------------------------- DSN (none) - HP 3030 Magnetic Tape Subsystem -------------------------------------------- diff --git a/HP2100/hp2100_ipl.c b/HP2100/hp2100_ipl.c index 95195010..48c27f98 100644 --- a/HP2100/hp2100_ipl.c +++ b/HP2100/hp2100_ipl.c @@ -1,6 +1,6 @@ /* hp2100_ipl.c: HP 2000 interprocessor link simulator - Copyright (c) 2002-2006, Robert M Supnik + Copyright (c) 2002-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"), @@ -23,9 +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. - ipli, iplo 12566B interprocessor link pair + ipli, iplo 12875A interprocessor link - 28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified) + 01-Mar-07 JDB IPLI EDT delays DMA completion interrupt for TSB + Added debug printouts + 28-Dec-06 JDB Added ioCRS state to I/O decoders 16-Aug-05 RMS Fixed C++ declaration and cast problems 07-Oct-04 JDB Fixed enable/disable from either device 26-Apr-04 RMS Fixed SFS x,C and SFC x,C @@ -33,6 +35,20 @@ 21-Dec-03 RMS Adjusted ipl_ptime for TSB (from Mike Gemeny) 09-May-03 RMS Added network device flag 31-Jan-03 RMS Links are full duplex (found by Mike Gemeny) + + The 12875A Processor Interconnect Kit consists four 12566A Microcircuit + Interface cards. Two are used in each processor. One card in each system is + used to initiate transmissions to the other, and the second card is used to + receive transmissions from the other. Each pair of cards forms a + bidirectional link, as the sixteen data lines are cross-connected, so that + data sent and status returned are supported. In each processor, data is sent + on the lower priority card and received on the higher priority card. Two + sets of cards are used to support simultaneous transmission in both + directions. + + Reference: + - 12875A Processor Interconnect Kit Operating and Service Manual + (12875-90002, Jan-1974) */ #include "hp2100_defs.h" @@ -52,9 +68,17 @@ #define DSOCKET u3 /* data socket */ #define LSOCKET u4 /* listening socket */ +/* Debug flags */ + +#define DEB_CMDS (1 << 0) /* Command initiation and completion */ +#define DEB_CPU (1 << 1) /* CPU I/O */ +#define DEB_XFER (1 << 2) /* Socket receive and transmit */ + extern uint32 PC; extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2]; extern FILE *sim_log; +extern FILE *sim_deb; +int32 ipl_edtdelay = 1; /* EDT delay (msec) */ int32 ipl_ptime = 31; /* polling interval */ int32 ipl_stopioe = 0; /* stop on error */ int32 ipl_hold[2] = { 0 }; /* holding character */ @@ -72,6 +96,14 @@ t_stat ipl_dscln (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat ipl_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc); t_bool ipl_check_conn (UNIT *uptr); +/* Debug flags table */ + +DEBTAB ipl_deb[] = { + { "CMDS", DEB_CMDS }, + { "CPU", DEB_CPU }, + { "XFER", DEB_XFER }, + { NULL, 0 } }; + /* IPLI data structures ipli_dev IPLI device descriptor @@ -125,7 +157,8 @@ DEVICE ipli_dev = { 1, 10, 31, 1, 16, 16, &tmxr_ex, &tmxr_dep, &ipl_reset, &ipl_boot, &ipl_attach, &ipl_detach, - &ipli_dib, DEV_NET | DEV_DISABLE | DEV_DIS + &ipli_dib, DEV_NET | DEV_DISABLE | DEV_DIS | DEV_DEBUG, + 0, ipl_deb, NULL, NULL }; /* IPLO data structures @@ -154,7 +187,8 @@ DEVICE iplo_dev = { 1, 10, 31, 1, 16, 16, &tmxr_ex, &tmxr_dep, &ipl_reset, &ipl_boot, &ipl_attach, &ipl_detach, - &iplo_dib, DEV_NET | DEV_DISABLE | DEV_DIS + &iplo_dib, DEV_NET | DEV_DISABLE | DEV_DIS | DEV_DEBUG, + 0, ipl_deb, NULL, NULL }; /* I/O instructions */ @@ -169,12 +203,61 @@ int32 iploio (int32 inst, int32 IR, int32 dat) return iplio (&iplo_unit, inst, IR, dat); } +/* I/O handler for the IPLI and IPLO devices. + + Implementation note: 2000 Access has a race condition that manifests itself + by an apparently normal boot and operational system console but no PLEASE LOG + IN response to terminals connected to the multiplexer. The frequency of + occurrence is higher on multiprocessor host systems, where the SP and IOP + instances may execute concurrently. + + The cause is this code in the SP disc loader source (2883.asm, 7900.asm, + 790X.asm, 79X3.asm, and 79XX.asm): + + LDA SDVTR REQUEST + JSB IOPMA,I DEVICE TABLE + [...] + STC DMAHS,C TURN ON DMA + SFS DMAHS WAIT FOR + JMP *-1 DEVICE TABLE + STC CH2,C SET CORRECT + CLC CH2 FLAG DIRECTION + + The STC/CLC normally would cause a second "request device table" command to + be recognized by the IOP, except that the IOP DMA setup routine "DMAXF" (in + D61.asm) has specified an end-of-block CLC that holds off the IPL interrupt, + and the completion interrupt routine "DMACP" ends with a STC,C that clears + the IPL flag. + + In hardware, the two CPUs are essentially interlocked by the DMA transfer, + and DMA completion interrupts occur almost simultaneously. Therefore, the + STC/CLC in the SP is guaranteed to occur before the STC,C in the IOP. Under + simulation, and especially on multiprocessor hosts, that guarantee does not + hold. If the STC/CLC occurs after the STC,C, then the IOP starts a second + device table DMA transfer, which the SP is not expecting. The IOP never + processes the subsequent "start timesharing" command, and the muxtiplexer is + non-reponsive. + + We employ a workaround that decreases the incidence of the problem: DMA + output completion interrupts are delayed to allow the other SIMH instance a + chance to process its own DMA completion. We do this by processing the EDT + (End Data Transfer) I/O backplane signal and "sleep"ing for a short time if + the transfer was an output transfer ("dat" contains the DMA channel number + and direction flag for EDT signals). +*/ + int32 iplio (UNIT *uptr, int32 inst, int32 IR, int32 dat) { uint32 u, dev, odev; int32 sta; -char msg[2]; +char msg[2], uc; +DEVICE *dbdev; /* device ptr for debug */ +static const char *iotype[] = { "Status", "Command" }; +uc = (uptr == &ipli_unit) ? 'I' : 'O'; /* identify unit for debug */ +dbdev = (uptr == &ipli_unit) ? &ipli_dev : &iplo_dev; /* identify device for debug */ + +u = (uptr - ipl_unit); /* get unit number */ dev = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ @@ -192,25 +275,42 @@ switch (inst) { /* case on opcode */ case ioOTX: /* output */ uptr->OBUF = dat; + + if (DEBUG_PRJ (dbdev, DEB_CPU)) + fprintf (sim_deb, ">>IPL%c OTx: %s = %06o\n", uc, iotype[u], dat); break; case ioLIX: /* load */ - dat = uptr->IBUF; /* return val */ - break; + dat = 0; case ioMIX: /* merge */ dat = dat | uptr->IBUF; /* get return data */ + + if (DEBUG_PRJ (dbdev, DEB_CPU)) + fprintf (sim_deb, ">>IPL%c LIx: %s = %06o\n", uc, iotype[u ^ 1], dat); + break; + + case ioCRS: /* control reset */ + clrCMD (dev); /* clear ctl, cmd */ + clrCTL (dev); break; - case ioCRS: /* control reset (action unverif) */ case ioCTL: /* control clear/set */ if (IR & I_CTL) { /* CLC */ clrCMD (dev); /* clear ctl, cmd */ clrCTL (dev); + + if (DEBUG_PRJ (dbdev, DEB_CMDS)) + fprintf (sim_deb, ">>IPL%c CLC: Command cleared\n", uc); } + else { /* STC */ setCMD (dev); /* set ctl, cmd */ setCTL (dev); + + if (DEBUG_PRJ (dbdev, DEB_CMDS)) + fprintf (sim_deb, ">>IPL%c STC: Command set\n", uc); + if (uptr->flags & UNIT_ATT) { /* attached? */ if ((uptr->flags & UNIT_ESTB) == 0) { /* established? */ if (!ipl_check_conn (uptr)) /* not established? */ @@ -220,6 +320,12 @@ switch (inst) { /* case on opcode */ msg[0] = (uptr->OBUF >> 8) & 0377; msg[1] = uptr->OBUF & 0377; sta = sim_write_sock (uptr->DSOCKET, msg, 2); + + if (DEBUG_PRJ (dbdev, DEB_XFER)) + fprintf (sim_deb, + ">>IPL%c STC: Socket write = %06o, status = %d\n", + uc, uptr->OBUF, sta); + if (sta == SOCKET_ERROR) { printf ("IPL: socket write error\n"); return SCPE_IOERR; @@ -236,6 +342,16 @@ switch (inst) { /* case on opcode */ } break; + case ioEDT: /* End of DMA data transfer */ + if ((dat & DMA2_OI) == 0) { /* output transfer? */ + if (DEBUG_PRJ (dbdev, DEB_CMDS)) + fprintf (sim_deb, + ">>IPL%c EDT: Delaying DMA completion interrupt for %d msec\n", + uc, ipl_edtdelay); + sim_os_ms_sleep (ipl_edtdelay); /* delay completion */ + } + break; + default: break; } @@ -249,7 +365,8 @@ return dat; t_stat ipl_svc (UNIT *uptr) { int32 u, nb, dev; -char msg[2]; +char msg[2], uc; +DEVICE *dbdev; /* device ptr for debug */ u = uptr - ipl_unit; /* get link number */ if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* not attached? */ @@ -277,6 +394,14 @@ else uptr->IBUF = ((((int32) msg[0]) & 0377) << 8) | dev = ipl_dib[u].devno; /* get device number */ clrCMD (dev); /* clr cmd, set flag */ setFSR (dev); + +uc = (uptr == &ipli_unit) ? 'I' : 'O'; /* identify unit for debug */ +dbdev = (uptr == &ipli_unit) ? &ipli_dev : &iplo_dev; /* identify device for debug */ + +if (DEBUG_PRJ (dbdev, DEB_XFER)) + fprintf (sim_deb, ">>IPL%c svc: Socket read = %06o, status = %d\n", + uc, uptr->IBUF, nb); + return SCPE_OK; } @@ -524,4 +649,3 @@ M[PC + IPL_DEVA] = devi; M[PC + PTR_DEVA] = devp; return SCPE_OK; } - diff --git a/HP2100/hp2100_lps.c b/HP2100/hp2100_lps.c index 9cf49cc6..9f26a28c 100644 --- a/HP2100/hp2100_lps.c +++ b/HP2100/hp2100_lps.c @@ -26,6 +26,7 @@ lps 12653A 2767 line printer 12566B microcircuit interface with loopback diagnostic connector + 10-May-07 RMS Added UNIT_TEXT flag 11-Jan-07 JDB CLC cancels I/O event if DIAG (jumper W9 in "A" pos) Added ioCRS state to I/O decoders 19-Nov-04 JDB Added restart when set online, etc. @@ -207,7 +208,7 @@ t_stat lps_show_timing (FILE *st, UNIT *uptr, int32 val, void *desc); DIB lps_dib = { LPS, 0, 0, 0, 0, 0, &lpsio }; UNIT lps_unit = { - UDATA (&lps_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_DISABLE, 0) + UDATA (&lps_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_DISABLE+UNIT_TEXT, 0) }; REG lps_reg[] = { diff --git a/HP2100/hp2100_lpt.c b/HP2100/hp2100_lpt.c index 9c17c86a..41f43cf2 100644 --- a/HP2100/hp2100_lpt.c +++ b/HP2100/hp2100_lpt.c @@ -1,6 +1,6 @@ /* hp2100_lpt.c: HP 2100 12845B line printer simulator - Copyright (c) 1993-2006, Robert M. Supnik + Copyright (c) 1993-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,6 +25,7 @@ lpt 12845B 2607 line printer + 22-Jan-07 RMS Added UNIT_TEXT flag 28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified) 19-Nov-04 JDB Added restart when set online, etc. 29-Sep-04 JDB Added SET OFFLINE/ONLINE, POWEROFF/POWERON @@ -113,7 +114,7 @@ t_stat lpt_attach (UNIT *uptr, char *cptr); DIB lpt_dib = { LPT, 0, 0, 0, 0, 0, &lptio }; UNIT lpt_unit = { - UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_DISABLE, 0) + UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_DISABLE+UNIT_TEXT, 0) }; REG lpt_reg[] = { diff --git a/HP2100/hp2100_mux.c b/HP2100/hp2100_mux.c index 9f15d1ea..1bb073ff 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-2006, Robert M Supnik + Copyright (c) 2002-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,19 @@ mux,muxl,muxc 12920A terminal multiplexor - 28-Dec-06 JDB Added ioCRS state to I/O decoders (action unverified) + 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 + Fixed control card OTx to set current channel number + Fixed to set "muxl_ibuf" in response to a transmit interrupt + Changed "mux_xbuf", "mux_rbuf" declarations from 8 to 16 bits + Fixed to set "mux_rchp" when a line break is received + Fixed incorrect "odd_par" table values + Reversed test in "RCV_PAR" to return "LIL_PAR" on odd parity + Fixed mux reset (ioCRS) to clear port parameters + Fixed to use PUT_DCH instead of PUT_CCH for data channel status + 10-Feb-07 JDB Added DIAG/TERM modifiers to implement diagnostic mode + 28-Dec-06 JDB Added ioCRS state to I/O decoders 02-Jun-06 JDB Fixed compiler warning for mux_ldsc init 22-Nov-05 RMS Revised for new terminal processing routines 29-Jun-05 RMS Added SET MUXLn DISCONNECT @@ -60,7 +72,9 @@ #define MUX_LINES 16 /* user lines */ #define MUX_ILINES 5 /* diag rcv only */ #define UNIT_V_MDM (TTUF_V_UF + 0) /* modem control */ +#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 @@ -85,7 +99,8 @@ #define OTL_V_BAUD 0 /* baud rate */ #define OTL_M_BAUD 0377 #define OTL_BAUD(x) (((x) >> OTL_V_BAUD) & OTL_M_BAUD) -#define OTL_CHAR 01777 /* char mask */ +#define OTL_CHAR 03777 /* char mask */ +#define OTL_PAR 0200 /* char parity */ /* LIA, lower = received data */ @@ -112,6 +127,7 @@ #define OTC_EC1 0000100 #define OTC_C2 0000040 /* Cn flops */ #define OTC_C1 0000020 +#define OTC_V_C 4 /* S1 to C1 */ #define OTC_ES2 0000010 /* enb comparison */ #define OTC_ES1 0000004 #define OTC_V_ES 2 @@ -139,14 +155,21 @@ ((muxc_ota[ch] & (OTC_ES2|OTC_ES1)) >> OTC_V_ES)) \ << LIC_V_I) +/* Debug flags */ + +#define DEB_CMDS (1 << 0) /* Command initiation and completion */ +#define DEB_CPU (1 << 1) /* CPU I/O */ +#define DEB_XFER (1 << 2) /* Socket receive and transmit */ + extern uint32 PC; extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2]; +extern FILE *sim_deb; -uint16 mux_sta[MUX_LINES]; /* line status */ +uint16 mux_sta[MUX_LINES + MUX_ILINES]; /* line status */ uint16 mux_rpar[MUX_LINES + MUX_ILINES]; /* rcv param */ uint16 mux_xpar[MUX_LINES]; /* xmt param */ -uint8 mux_rbuf[MUX_LINES + MUX_ILINES]; /* rcv buf */ -uint8 mux_xbuf[MUX_LINES]; /* xmt buf */ +uint16 mux_rbuf[MUX_LINES + MUX_ILINES]; /* rcv buf */ +uint16 mux_xbuf[MUX_LINES]; /* xmt buf */ 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 */ @@ -171,6 +194,7 @@ t_stat muxo_svc (UNIT *uptr); t_stat muxc_reset (DEVICE *dptr); t_stat mux_attach (UNIT *uptr, char *cptr); t_stat mux_detach (UNIT *uptr); +t_stat mux_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat mux_summ (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat mux_show (FILE *st, UNIT *uptr, int32 val, void *desc); void mux_data_int (void); @@ -179,24 +203,33 @@ void mux_diag (int32 c); static uint8 odd_par[256] = { 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 000-017 */ - 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 020-037 */ - 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 040-067 */ + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 020-037 */ + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 040-067 */ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 060-077 */ - 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 100-117 */ + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 100-117 */ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 120-137 */ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 140-157 */ - 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 160-177 */ - 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 200-217 */ + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 160-177 */ + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 200-217 */ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 220-237 */ - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 240-257 */ - 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 260-277 */ + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 240-267 */ + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 260-277 */ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 300-317 */ - 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 320-337 */ - 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, /* 340-367 */ + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 320-337 */ + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 340-357 */ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 /* 360-377 */ }; -#define RCV_PAR(x) (odd_par[(x) & 0377]? LIL_PAR: 0) +#define RCV_PAR(x) (odd_par[(x) & 0377] ? 0 : LIL_PAR) +#define XMT_PAR(x) (odd_par[(x) & 0377] ? 0 : OTL_PAR) + +/* Debug flags table */ + +DEBTAB mux_deb[] = { + { "CMDS", DEB_CMDS }, + { "CPU", DEB_CPU }, + { "XFER", DEB_XFER }, + { NULL, 0 } }; DIB mux_dib[] = { { MUXL, 0, 0, 0, 0, 0, &muxlio }, @@ -229,6 +262,8 @@ REG muxu_reg[] = { }; MTAB muxu_mod[] = { + { UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", &mux_setdiag }, + { UNIT_DIAG, 0, "terminal mode", "TERM", &mux_setdiag }, { UNIT_ATT, UNIT_ATT, "connections", NULL, NULL, &mux_summ }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, NULL, &mux_show, NULL }, @@ -246,7 +281,8 @@ DEVICE muxu_dev = { 1, 10, 31, 1, 8, 8, &tmxr_ex, &tmxr_dep, &muxc_reset, NULL, &mux_attach, &mux_detach, - &muxu_dib, DEV_NET | DEV_DISABLE + &muxu_dib, DEV_NET | DEV_DISABLE | DEV_DEBUG, + 0, mux_deb, NULL, NULL }; /* MUXL data structures @@ -301,11 +337,11 @@ REG muxl_reg[] = { { FLDATA (FLG, muxl_dib.flg, 0) }, { FLDATA (FBF, muxl_dib.fbf, 0) }, { FLDATA (SRQ, muxl_dib.srq, 0) }, - { BRDATA (STA, mux_sta, 8, 16, MUX_LINES) }, + { BRDATA (STA, mux_sta, 8, 16, MUX_LINES + MUX_ILINES) }, { BRDATA (RPAR, mux_rpar, 8, 16, MUX_LINES + MUX_ILINES) }, { BRDATA (XPAR, mux_xpar, 8, 16, MUX_LINES) }, - { BRDATA (RBUF, mux_rbuf, 8, 8, MUX_LINES + MUX_ILINES) }, - { BRDATA (XBUF, mux_xbuf, 8, 8, MUX_LINES) }, + { BRDATA (RBUF, mux_rbuf, 8, 16, MUX_LINES + MUX_ILINES) }, + { BRDATA (XBUF, mux_xbuf, 8, 16, MUX_LINES) }, { BRDATA (RCHP, mux_rchp, 8, 1, MUX_LINES + MUX_ILINES) }, { BRDATA (XDON, mux_xdon, 8, 1, MUX_LINES) }, { URDATA (TIME, muxl_unit[0].wait, 10, 24, 0, @@ -362,13 +398,25 @@ DEVICE muxc_dev = { &muxc_dib, DEV_DISABLE }; -/* IO instructions: data cards */ +/* IO instructions: data cards + + Implementation note: the operating manual says that "at least 100 + milliseconds of CLC 0s must be programmed" by systems employing the + multiplexer to ensure that the multiplexer resets. In practice, such systems + issue 128K CLC 0 instructions. As we provide debug logging of multiplexer + resets, a CRS counter is used to ensure that only one debug line is printed + in response to these 128K CRS invocations. +*/ int32 muxlio (int32 inst, int32 IR, int32 dat) { int32 dev, ln; +t_bool is_crs; +static uint32 crs_count = 0; /* cntr for crs repeat */ dev = IR & I_DEVMASK; /* get device no */ +is_crs = FALSE; + switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ @@ -385,37 +433,107 @@ switch (inst) { /* case on opcode */ case ioOTX: /* output */ muxl_obuf = dat; /* store data */ - break; - case ioMIX: /* merge */ - dat = dat | muxl_ibuf; + if (DEBUG_PRI (muxu_dev, DEB_CPU)) + if (dat & OTL_P) + fprintf (sim_deb, ">>MUXl OTx: Parameter = %06o\n", dat); + else + fprintf (sim_deb, ">>MUXl OTx: Data = %06o\n", dat); break; case ioLIX: /* load */ - dat = muxl_ibuf; + dat = 0; + + case ioMIX: /* merge */ + dat = dat | muxl_ibuf; + + if (DEBUG_PRI (muxu_dev, DEB_CPU)) + fprintf (sim_deb, ">>MUXl LIx: Data = %06o\n", dat); break; - case ioCRS: /* control reset (action unverif) */ + case ioCRS: /* control reset */ + is_crs = TRUE; + + if (crs_count) /* already reset? */ + break; /* skip redundant clear */ + + for (ln = 0; ln < MUX_LINES; ln++) { /* clear transmit info */ + mux_xbuf[ln] = mux_xpar[ln] = 0; + muxc_ota[ln] = muxc_lia[ln] = mux_xdon[ln] = 0; + } + + for (ln = 0; ln < (MUX_LINES + MUX_ILINES); ln++) { + mux_rbuf[ln] = mux_rpar[ln] = 0; /* clear receive info */ + mux_sta[ln] = mux_rchp[ln] = 0; + } /* fall into CLC SC */ + case ioCTL: /* control clear/set */ - if (IR & I_CTL) { clrCTL (dev); } /* CLC */ + if (IR & I_CTL) { /* CLC */ + clrCTL (dev); + + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MUXl CLC: Data interrupt inhibited\n"); + } else { /* STC */ setCTL (dev); /* set ctl */ ln = MUX_CHAN (muxu_obuf); /* get chan # */ - if (muxl_obuf & OTL_P) { /* parameter set? */ - if (muxl_obuf & OTL_TX) { /* transmit? */ - if (ln < MUX_LINES) /* to valid line? */ - mux_xpar[ln] = muxl_obuf; - } - else if (ln < (MUX_LINES + MUX_ILINES)) /* rcv, valid line? */ - mux_rpar[ln] = muxl_obuf; - } - else if ((muxl_obuf & OTL_TX) && /* xmit data? */ - (ln < MUX_LINES)) { /* to valid line? */ - if (sim_is_active (&muxl_unit[ln])) /* still working? */ - mux_sta[ln] = mux_sta[ln] | LIU_LOST; - else sim_activate (&muxl_unit[ln], muxl_unit[ln].wait); - mux_xbuf[ln] = muxl_obuf & OTL_CHAR; /* load buffer */ + + if (muxl_obuf & OTL_TX) { /* transmit? */ + if (ln < MUX_LINES) { /* line valid? */ + if (muxl_obuf & OTL_P) { /* parameter? */ + mux_xpar[ln] = muxl_obuf; /* store param value */ + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + 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? */ + muxl_obuf = /* add parity bit */ + muxl_obuf & ~OTL_PAR | + XMT_PAR(muxl_obuf); + mux_xbuf[ln] = muxl_obuf; /* load buffer */ + + if (sim_is_active (&muxl_unit[ln])) { /* still working? */ + mux_sta[ln] = mux_sta[ln] | LIU_LOST; /* char lost */ + 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 */ + sim_activate (&muxl_unit[ln], muxl_unit[ln].wait); + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + 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 */ + fprintf (sim_deb, ">>MUXl STC: Transmit channel %d invalid\n", ln); } + + else /* receive */ + if (ln < (MUX_LINES + MUX_ILINES)) { /* line valid? */ + if (muxl_obuf & OTL_P) { /* parameter? */ + mux_rpar[ln] = muxl_obuf; /* store param value */ + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, + ">>MUXl STC: Receive channel %d parameter %06o stored\n", + ln, muxl_obuf); + } + + else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* data (invalid action) */ + fprintf (sim_deb, + ">>MUXl STC: Receive channel %d parameter %06o invalid action\n", + ln, muxl_obuf); + } + + else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* line invalid */ + fprintf (sim_deb, ">>MUXl STC: Receive channel %d invalid\n", ln); } /* end STC */ break; @@ -423,6 +541,16 @@ switch (inst) { /* case on opcode */ break; } +if (is_crs) /* control reset? */ + crs_count = crs_count + 1; /* increment count */ + +else if (crs_count) { /* something else */ + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* report reset count */ + fprintf (sim_deb, + ">>MUXl CRS: Multiplexer reset %d times\n", crs_count); + crs_count = 0; /* clear counter */ + } + if (IR & I_HC) { /* H/C option */ clrFSR (dev); /* clear flag */ mux_data_int (); /* look for new int */ @@ -436,14 +564,19 @@ switch (inst) { /* case on opcode */ case ioOTX: /* output */ muxu_obuf = dat; /* store data */ - break; - case ioMIX: /* merge */ - dat = dat | muxu_ibuf; + if (DEBUG_PRI (muxu_dev, DEB_CPU)) + fprintf (sim_deb, ">>MUXu OTx: Data channel = %d\n", MUX_CHAN(dat)); break; case ioLIX: /* load */ - dat = muxu_ibuf; + dat = 0; + + case ioMIX: /* merge */ + dat = dat | muxu_ibuf; + + if (DEBUG_PRI (muxu_dev, DEB_CPU)) + fprintf (sim_deb, ">>MUXu LIx: Status = %06o, channel = %d\n", dat, MUX_CHAN(dat)); break; default: @@ -453,7 +586,12 @@ switch (inst) { /* case on opcode */ return dat; } -/* IO instructions: control card */ +/* IO 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) { @@ -475,38 +613,65 @@ switch (inst) { /* case on opcode */ break; case ioOTX: /* output */ + ln = muxc_chan = OTC_CHAN (dat); /* set channel */ + if (dat & OTC_SCAN) muxc_scan = 1; /* set scan flag */ else muxc_scan = 0; + if (dat & OTC_UPD) { /* update? */ - ln = OTC_CHAN (dat); /* get channel */ old = muxc_ota[ln]; /* save prior val */ - muxc_ota[ln] = (muxc_ota[ln] & ~OTC_RW) | /* save ESn,SSn */ - (dat & OTC_RW); - if (dat & OTC_EC2) muxc_ota[ln] = /* if EC2, upd C2 */ - (muxc_ota[ln] & ~OTC_C2) | (dat & OTC_C2); - if (dat & OTC_EC1) muxc_ota[ln] = /* if EC1, upd C1 */ - (muxc_ota[ln] & ~OTC_C1) | (dat & OTC_C1); - if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */ - (old & DTR) && !(muxc_ota[ln] & DTR)) { /* DTR drop? */ + muxc_ota[ln] = /* save ESn,SSn */ + (muxc_ota[ln] & ~OTC_RW) | (dat & OTC_RW); + + if (dat & OTC_EC2) /* if EC2, upd C2 */ + muxc_ota[ln] = + (muxc_ota[ln] & ~OTC_C2) | (dat & OTC_C2); + + if (dat & OTC_EC1) /* if EC1, upd C1 */ + muxc_ota[ln] = + (muxc_ota[ln] & ~OTC_C1) | (dat & OTC_C1); + + if (muxu_unit.flags & UNIT_DIAG) /* loopback? */ + muxc_lia[ln ^ 1] = /* set S1, S2 to C1, C2 */ + (muxc_lia[ln ^ 1] & ~(LIC_S2 | LIC_S1)) | + (muxc_ota[ln] & (OTC_C1 | OTC_C2)) >> OTC_V_C; + + else if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */ + (old & DTR) && /* DTR drop? */ + !(muxc_ota[ln] & DTR)) { tmxr_linemsg (&mux_ldsc[ln], "\r\nLine hangup\r\n"); tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */ muxc_lia[ln] = 0; /* dataset off */ } } /* end update */ + + if (DEBUG_PRI (muxu_dev, DEB_CPU)) + fprintf (sim_deb, ">>MUXc OTx: Parameter = %06o, channel = %d\n", + dat, ln); + + if ((muxu_unit.flags & UNIT_DIAG) && /* loopback? */ + (!FLG(muxc_dib.devno))) /* flag clear? */ + mux_ctrl_int (); /* status chg may interrupt */ break; case ioLIX: /* load */ dat = 0; + case ioMIX: /* merge */ t = LIC_MBO | PUT_CCH (muxc_chan) | /* mbo, chan num */ LIC_TSTI (muxc_chan) | /* I2, I1 */ (muxc_ota[muxc_chan] & (OTC_ES2 | OTC_ES1)) | /* ES2, ES1 */ (muxc_lia[muxc_chan] & (LIC_S2 | LIC_S1)); /* S2, S1 */ dat = dat | t; /* return status */ + + if (DEBUG_PRI (muxu_dev, DEB_CPU)) + fprintf (sim_deb, ">>MUXc LIx: Status = %06o, channel = %d\n", + dat, muxc_chan); + muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* incr channel */ break; - case ioCRS: /* control reset (action unverif) */ + case ioCRS: /* control reset */ case ioCTL: /* ctrl clear/set */ if (IR & I_CTL) { clrCTL (dev); } /* CLC */ else { setCTL (dev); } /* STC */ @@ -532,41 +697,70 @@ return dat; t_stat muxi_svc (UNIT *uptr) { int32 ln, c, t; +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 */ + ln = tmxr_poll_conn (&mux_desc); /* look for connect */ + if (ln >= 0) { /* got one? */ + if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */ + (muxc_ota[ln] & DTR)) /* DTR? */ + muxc_lia[ln] = muxc_lia[ln] | CDET; /* set cdet */ + muxc_lia[ln] = muxc_lia[ln] | DSR; /* set dsr */ + mux_ldsc[ln].rcve = 1; /* rcv enabled */ + } + tmxr_poll_rx (&mux_desc); /* poll for input */ +} -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 */ -ln = tmxr_poll_conn (&mux_desc); /* look for connect */ -if (ln >= 0) { /* got one? */ - if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */ - (muxc_ota[ln] & DTR)) /* DTR? */ - muxc_lia[ln] = muxc_lia[ln] | CDET; /* set cdet */ - muxc_lia[ln] = muxc_lia[ln] | DSR; /* set dsr */ - mux_ldsc[ln].rcve = 1; /* rcv enabled */ - } -tmxr_poll_rx (&mux_desc); /* poll for input */ for (ln = 0; ln < MUX_LINES; ln++) { /* loop thru lines */ if (mux_ldsc[ln].conn) { /* connected? */ - if (c = tmxr_getc_ln (&mux_ldsc[ln])) { /* get char */ + if (loopback) { /* diagnostic mode? */ + c = mux_xbuf[ln ^ 1] & OTL_CHAR; /* get char from xmit line */ + if (c == 0) /* all char bits = 0? */ + c = c | SCPE_BREAK; /* set break flag */ + mux_ldsc[ln].conn = 0; /* clear connection */ + } + + else + c = tmxr_getc_ln (&mux_ldsc[ln]); /* get char from Telnet */ + + if (c) { /* valid char? */ if (c & SCPE_BREAK) { /* break? */ mux_sta[ln] = mux_sta[ln] | LIU_BRK; mux_rbuf[ln] = 0; /* no char */ } else { /* normal */ - if (mux_rchp[ln]) mux_sta[ln] = mux_sta[ln] | LIU_LOST; - c = sim_tt_inpcvt (c, TT_GET_MODE (muxl_unit[ln].flags)); - if (mux_rpar[ln] & OTL_ECHO) { /* echo? */ - TMLN *lp = &mux_ldsc[ln]; /* get line */ - tmxr_putc_ln (lp, c); /* output char */ - tmxr_poll_tx (&mux_desc); /* poll xmt */ + if (mux_rchp[ln]) /* char already pending? */ + mux_sta[ln] = mux_sta[ln] | LIU_LOST; + + if (!loopback) { /* terminal mode? */ + c = sim_tt_inpcvt (c, TT_GET_MODE (muxl_unit[ln].flags)); + if (mux_rpar[ln] & OTL_ECHO) { /* echo? */ + TMLN *lp = &mux_ldsc[ln]; /* get line */ + tmxr_putc_ln (lp, c); /* output char */ + tmxr_poll_tx (&mux_desc); /* poll xmt */ + } } mux_rbuf[ln] = c; /* save char */ - mux_rchp[ln] = 1; /* char pending */ } + + mux_rchp[ln] = 1; /* char pending */ + + if (DEBUG_PRI (muxu_dev, DEB_XFER)) + fprintf (sim_deb, ">>MUXi svc: Line %d character %06o received\n", + ln, c); + if (mux_rpar[ln] & OTL_DIAG) mux_diag (c); /* rcv diag? */ } /* end if char */ } /* end if connected */ - else muxc_lia[ln] = 0; /* disconnected */ + + else /* not connected */ + if (!loopback) /* terminal mode? */ + muxc_lia[ln] = 0; /* line disconnected */ } /* end for */ if (!FLG (muxl_dib.devno)) mux_data_int (); /* scan for data int */ if (!FLG (muxc_dib.devno)) mux_ctrl_int (); /* scan modem */ @@ -577,33 +771,55 @@ return SCPE_OK; t_stat muxo_svc (UNIT *uptr) { -int32 c, ln = uptr - muxl_unit; /* line # */ +int32 c, fc, ln, altln; +t_bool loopback; + +ln = uptr - muxl_unit; /* line # */ +altln = ln ^ 1; /* alt. line for diag mode */ + +fc = mux_xbuf[ln] & OTL_CHAR; /* full character data */ +c = fc & 0377; /* Telnet character data */ + +loopback = ((muxu_unit.flags & UNIT_DIAG) != 0); /* diagnostic mode? */ if (mux_ldsc[ln].conn) { /* connected? */ if (mux_ldsc[ln].xmte) { /* xmt enabled? */ + if (loopback) /* diagnostic mode? */ + mux_ldsc[ln].conn = 0; /* clear connection */ + if ((mux_xbuf[ln] & OTL_SYNC) == 0) { /* start bit 0? */ TMLN *lp = &mux_ldsc[ln]; /* get line */ - c = mux_xbuf[ln]; /* get char */ c = sim_tt_outcvt (c, TT_GET_MODE (muxl_unit[ln].flags)); - if (mux_xpar[ln] & OTL_DIAG) /* xmt diag? */ - mux_diag (mux_xbuf[ln]); /* before munge */ - mux_xdon[ln] = 1; /* set done */ -/* In (default) UC or (new) 7P, all these chars are suppressed automatically */ -/* if ((TT_GET_MODE (muxl_unit[ln].flags) != TT_MODE_8B) && -/* (c != 0x7f) && (c != 0x13) && /* not del, ^S? */ -/* (c != 0x11) && (c != 0x5)) /* not ^Q, ^E? */ - if (c >= 0) /* valid? */ - tmxr_putc_ln (lp, c); /* output char */ - tmxr_poll_tx (&mux_desc); /* poll xmt */ + if (mux_xpar[ln] & OTL_DIAG) /* xmt diagnose? */ + mux_diag (fc); /* before munge */ + + if (loopback) { /* diagnostic mode? */ + mux_ldsc[altln].conn = 1; /* set recv connection */ + sim_activate (&muxu_unit, 1); /* schedule receive */ + } + + else { /* no loopback */ + if (c >= 0) /* valid? */ + tmxr_putc_ln (lp, c); /* output char */ + tmxr_poll_tx (&mux_desc); /* poll xmt */ + } } + + mux_xdon[ln] = 1; /* set for xmit irq */ + + if (DEBUG_PRI (muxu_dev, DEB_XFER) && (loopback | (c >= 0))) + fprintf (sim_deb, ">>MUXo svc: Line %d character %06o sent\n", + ln, (loopback ? fc : c)); } + else { /* buf full */ tmxr_poll_tx (&mux_desc); /* poll xmt */ sim_activate (uptr, muxl_unit[ln].wait); /* wait */ return SCPE_OK; } } + if (!FLG (muxl_dib.devno)) mux_data_int (); /* scan for int */ return SCPE_OK; } @@ -616,31 +832,48 @@ int32 i; for (i = 0; i < MUX_LINES; i++) { /* rcv lines */ if ((mux_rpar[i] & OTL_ENB) && mux_rchp[i]) { /* enabled, char? */ - muxl_ibuf = PUT_CCH (i) | mux_rbuf[i] | /* lo buf = char */ + muxl_ibuf = PUT_DCH (i) | /* lo buf = char */ + mux_rbuf[i] & LIL_CHAR | RCV_PAR (mux_rbuf[i]); - muxu_ibuf = PUT_CCH (i) | mux_sta[i]; /* hi buf = stat */ + muxu_ibuf = PUT_DCH (i) | mux_sta[i]; /* hi buf = stat */ mux_rchp[i] = 0; /* clr char, stat */ mux_sta[i] = 0; + + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MUXd irq: Receive channel %d interrupt requested\n", i); + setFSR (muxl_dib.devno); /* interrupt */ return; } } for (i = 0; i < MUX_LINES; i++) { /* xmt lines */ if ((mux_xpar[i] & OTL_ENB) && mux_xdon[i]) { /* enabled, done? */ - muxu_ibuf = PUT_CCH (i) | mux_sta[i] | LIU_TR; /* hi buf = stat */ + muxl_ibuf = PUT_DCH (i) | /* lo buf = last rcv char */ + mux_rbuf[i] & LIL_CHAR | + RCV_PAR (mux_rbuf[i]); + muxu_ibuf = PUT_DCH (i) | mux_sta[i] | LIU_TR; /* hi buf = stat */ mux_xdon[i] = 0; /* clr done, stat */ mux_sta[i] = 0; + + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MUXd irq: Transmit channel %d interrupt requested\n", i); + setFSR (muxl_dib.devno); /* interrupt */ return; } } for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) { /* diag lines */ if ((mux_rpar[i] & OTL_ENB) && mux_rchp[i]) { /* enabled, char? */ - muxl_ibuf = PUT_CCH (i) | mux_rbuf[i] | /* lo buf = char */ + muxl_ibuf = PUT_DCH (i) | /* lo buf = char */ + mux_rbuf[i] & LIL_CHAR | RCV_PAR (mux_rbuf[i]); - muxu_ibuf = PUT_CCH (i) | mux_sta[i] | LIU_DG; /* hi buf = stat */ + muxu_ibuf = PUT_DCH (i) | mux_sta[i] | LIU_DG; /* hi buf = stat */ mux_rchp[i] = 0; /* clr char, stat */ mux_sta[i] = 0; + + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MUXd irq: Receive channel %d interrupt requested\n", i); + setFSR (muxl_dib.devno); return; } @@ -648,16 +881,31 @@ for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) { /* diag lines */ return; } -/* Look for control interrupt */ +/* Look for control interrupt + + If either of the incoming status bits does not match the stored status, and + the corresponding mismatch is enabled, a control interrupt request is + 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) { -int32 i; +int32 i, line_count; -if (muxc_scan == 0) return; -for (i = 0; i < MUX_LINES; i++) { - muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* step channel */ +line_count = (muxc_scan ? MUX_LINES : 1); /* check one or all lines */ + +for (i = 0; i < line_count; i++) { + if (muxc_scan) /* scanning? */ + muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* step channel */ if (LIC_TSTI (muxc_chan)) { /* status change? */ + + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, + ">>MUXc irq: Control channel %d interrupt requested (poll = %d)\n", + muxc_chan, i + 1); + setFSR (muxc_dib.devno); /* set flag */ break; } @@ -694,7 +942,8 @@ mux_rpar[i] = mux_xpar[i] = 0; mux_rchp[i] = mux_xdon[i] = 0; mux_sta[i] = 0; muxc_ota[i] = muxc_lia[i] = 0; /* clear modem */ -if (mux_ldsc[i].conn) /* connected? */ +if (mux_ldsc[i].conn && /* connected? */ + ((muxu_unit.flags & UNIT_DIAG) == 0)) /* term mode? */ muxc_lia[i] = muxc_lia[i] | DSR | /* cdet, dsr */ (muxl_unit[i].flags & UNIT_MDM? CDET: 0); sim_cancel (&muxl_unit[i]); @@ -733,7 +982,9 @@ if (muxu_unit.flags & UNIT_ATT) { /* master att? */ } } else sim_cancel (&muxu_unit); /* else stop */ -for (i = 0; i < MUX_LINES; i++) mux_reset_ln (i); +for (i = 0; i < MUX_LINES; i++) mux_reset_ln (i); /* reset lines 0-15 */ +for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) /* reset lines 16-20 */ + mux_rbuf[i] = mux_rpar[i] = mux_sta[i] = mux_rchp[i] = 0; return SCPE_OK; } @@ -744,6 +995,9 @@ 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); @@ -764,12 +1018,50 @@ sim_cancel (uptr); /* stop poll */ return r; } +/* Diagnostic/normal mode routine + + Diagnostic testing wants to exercise as much of the regular simulation code + as possible to ensure good test coverage. Normally, input polling and output + transmission only occurs on connected lines. In diagnostic mode, line + connection flags are set selectively to enable processing on the lines under + test. The alternative to this would require duplicating the send/receive + code; the diagnostic would then test the copy but not the actual code used + for normal character transfers, which is undesirable. + + Therefore, to enable diagnostic mode, we must force a disconnect of the + master socket and any connected Telnet lines, which clears the connection + flags on all lines. Then we set the "transmission enabled" flags on all + lines to enable output character processing for the diagnostic. (Normally, + 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) +{ +int32 ln; + +if (val) { /* set diag? */ + mux_detach (uptr); /* detach lines */ + for (ln = 0; ln < MUX_LINES; ln++) /* enable transmission */ + mux_ldsc[ln].xmte = 1; /* on all lines */ + } +else { /* set term */ + for (ln = 0; ln < MUX_LINES; ln++) /* clear connections */ + mux_ldsc[ln].conn = 0; /* on all lines */ + } +return SCPE_OK; +} + /* Show summary processor */ t_stat mux_summ (FILE *st, UNIT *uptr, int32 val, void *desc) { int32 i, t; +if (muxu_unit.flags & UNIT_DIAG) /* diag mode? */ + return SCPE_NOFNC; /* command not allowed */ + for (i = t = 0; i < MUX_LINES; i++) t = t + (mux_ldsc[i].conn != 0); if (t == 1) fprintf (st, "1 connection"); else fprintf (st, "%d connections", t); @@ -782,6 +1074,9 @@ t_stat mux_show (FILE *st, UNIT *uptr, int32 val, void *desc) { int32 i, t; +if (muxu_unit.flags & UNIT_DIAG) /* diag mode? */ + return SCPE_NOFNC; /* command not allowed */ + for (i = t = 0; i < MUX_LINES; i++) t = t + (mux_ldsc[i].conn != 0); if (t) { for (i = 0; i < MUX_LINES; i++) { @@ -794,4 +1089,3 @@ if (t) { else fprintf (st, "all disconnected\n"); return SCPE_OK; } - diff --git a/I1401/i1401_cd.c b/I1401/i1401_cd.c index 8c3e9ef2..2a70fb69 100644 --- a/I1401/i1401_cd.c +++ b/I1401/i1401_cd.c @@ -1,6 +1,6 @@ /* i1401_cd.c: IBM 1402 card reader/punch - Copyright (c) 1993-2005, Robert M. Supnik + Copyright (c) 1993-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"), @@ -35,6 +35,7 @@ Cards are represented as ASCII text streams terminated by newlines. This allows cards to be created and edited as normal files. + 19-Jan-07 RMS Added UNIT_TEXT flag 20-Sep-05 RMS Revised for new code tables, compatible colbinary treatment 30-Aug-05 RMS Fixed read, punch to ignore modifier on 1,4 char inst (reported by Van Snyder) @@ -73,7 +74,7 @@ char colbin_to_bcd (uint32 cb); */ UNIT cdr_unit = { - UDATA (&cdr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), 100 + UDATA (&cdr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE+UNIT_TEXT, 0), 100 }; REG cdr_reg[] = { @@ -102,7 +103,7 @@ DEVICE cdr_dev = { */ UNIT cdp_unit = { - UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) + UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0) }; REG cdp_reg[] = { @@ -134,11 +135,11 @@ DEVICE cdp_dev = { */ UNIT stack_unit[] = { - { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) }, - { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) }, - { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) }, + { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0) }, + { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0) }, + { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0) }, { UDATA (NULL, UNIT_DIS, 0) }, /* unused */ - { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) } + { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0) } }; REG stack_reg[] = { @@ -179,10 +180,10 @@ fgets (rbuf, (cbn)? 2 * CBUFSIZE: CBUFSIZE, /* rd bin/char card */ cdr_unit.fileref); if (feof (cdr_unit.fileref)) return STOP_NOCD; /* eof? */ if (ferror (cdr_unit.fileref)) { /* error? */ + ind[IN_READ] = 1; perror ("Card reader I/O error"); clearerr (cdr_unit.fileref); if (iochk) return SCPE_IOERR; - ind[IN_READ] = 1; return SCPE_OK; } cdr_unit.pos = ftell (cdr_unit.fileref); /* update position */ @@ -236,12 +237,12 @@ for (i = CDR_WIDTH - 1; (i >= 0) && (rbuf[i] == ' '); i--) rbuf[i] = 0; rbuf[CDR_WIDTH] = 0; /* null at end */ fputs (rbuf, uptr->fileref); /* write card */ fputc ('\n', uptr->fileref); /* plus new line */ +uptr->pos = ftell (uptr->fileref); /* update position */ if (ferror (uptr->fileref)) { /* error? */ perror ("Card stacker I/O error"); clearerr (uptr->fileref); if (iochk) return SCPE_IOERR; } -uptr->pos = ftell (uptr->fileref); /* update position */ return SCPE_OK; } @@ -293,13 +294,13 @@ else { /* normal */ } fputs (pbuf, uptr->fileref); /* output card */ fputc ('\n', uptr->fileref); /* plus new line */ +uptr->pos = ftell (uptr->fileref); /* update position */ if (ferror (uptr->fileref)) { /* error? */ perror ("Card punch I/O error"); clearerr (uptr->fileref); if (iochk) return SCPE_IOERR; ind[IN_PNCH] = 1; } -uptr->pos = ftell (uptr->fileref); /* update position */ return SCPE_OK; } diff --git a/I1401/i1401_lp.c b/I1401/i1401_lp.c index 1c26d4b7..5bd4b5d8 100644 --- a/I1401/i1401_lp.c +++ b/I1401/i1401_lp.c @@ -1,6 +1,6 @@ /* i1401_lp.c: IBM 1403 line printer simulator - Copyright (c) 1993-2005, Robert M. Supnik + Copyright (c) 1993-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,6 +25,7 @@ lpt 1403 line printer + 19-Jan-07 RMS Added UNIT_TEXT flag 07-Mar-05 RMS Fixed bug in write_line (reported by Van Snyder) 25-Apr-03 RMS Revised for extended file support 30-May-02 RMS Widened POS to 32b @@ -69,7 +70,7 @@ char *pch_table[4] = { */ UNIT lpt_unit = { - UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) + UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0) }; REG lpt_reg[] = { @@ -136,10 +137,10 @@ else { } lines = lflag = 0; /* clear cc action */ if (ferror (lpt_unit.fileref)) { /* error? */ + ind[IN_LPT] = 1; perror ("Line printer I/O error"); clearerr (lpt_unit.fileref); if (iochk) return SCPE_IOERR; - ind[IN_LPT] = 1; } return SCPE_OK; } diff --git a/I1620/i1620_cd.c b/I1620/i1620_cd.c index 84169cdc..df19931e 100644 --- a/I1620/i1620_cd.c +++ b/I1620/i1620_cd.c @@ -1,6 +1,6 @@ /* i1620_cd.c: IBM 1622 card reader/punch - Copyright (c) 2002-2006, Robert M. Supnik + Copyright (c) 2002-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 @@ cdr 1622 card reader cdp 1622 card punch + 19-Jan-07 RMS Set UNIT_TEXT flag 13-Jul-06 RMS Fixed card reader fgets call (from Tom McBride) Fixed card reader boot sequence (from Tom McBride) 21-Sep-05 RMS Revised translation tables for 7094/1401 compatibility @@ -63,7 +64,7 @@ t_stat cdp_num (uint32 pa, uint32 ndig, t_bool dump); */ UNIT cdr_unit = { - UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0) + UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE+UNIT_TEXT, 0) }; REG cdr_reg[] = { @@ -87,7 +88,7 @@ DEVICE cdr_dev = { */ UNIT cdp_unit = { - UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) + UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0) }; REG cdp_reg[] = { @@ -421,13 +422,14 @@ while ((len > 0) && (cdp_buf[len - 1] == ' ')) --len; /* trim spaces */ cdp_buf[len] = '\n'; /* newline, null */ cdp_buf[len + 1] = 0; -if (fputs (cdp_buf, cdp_unit.fileref) == EOF) { /* write card */ - ind[IN_WRCHK] = 1; /* error? */ +fputs (cdp_buf, cdp_unit.fileref); /* write card */ +cdp_unit.pos = ftell (cdp_unit.fileref); /* count char */ +if (ferror (cdp_unit.fileref)) { /* error? */ + ind[IN_WRCHK] = 1; perror ("CDP I/O error"); clearerr (cdp_unit.fileref); return SCPE_IOERR; } -cdp_unit.pos = ftell (cdp_unit.fileref); /* count char */ return SCPE_OK; } diff --git a/I1620/i1620_lp.c b/I1620/i1620_lp.c index 097ba588..daa2152f 100644 --- a/I1620/i1620_lp.c +++ b/I1620/i1620_lp.c @@ -1,6 +1,6 @@ /* i1620_lp.c: IBM 1443 line printer simulator - Copyright (c) 2002-2005, Robert M. Supnik + Copyright (c) 2002-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,6 +25,7 @@ lpt 1443 line printer + 19-Jan-07 RMS Added UNIT_TEXT flag 21-Sep-05 RMS Revised translation tables for 7094/1401 compatibility 29-Dec-03 RMS Fixed bug in scheduling 25-Apr-03 RMS Revised for extended file support @@ -69,7 +70,7 @@ t_stat lpt_space (int32 lines, int32 lflag); */ UNIT lpt_unit = { - UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 50) + UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 50) }; REG lpt_reg[] = { diff --git a/I7094/i7094_cd.c b/I7094/i7094_cd.c index 969693be..4029c49f 100644 --- a/I7094/i7094_cd.c +++ b/I7094/i7094_cd.c @@ -1,6 +1,6 @@ /* i7094_cd.c: IBM 711/721 card reader/punch - Copyright (c) 2003-2006, Robert M. Supnik + Copyright (c) 2003-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 @@ cdr 711 card reader cdp 721 card punch + 19-Jan-07 RMS Added UNIT_TEXT 13-Jul-06 RMS Fixed problem with 80 column full cards Cards are represented as ASCII text streams terminated by newlines. @@ -106,7 +107,7 @@ extern uint32 col_masks[12]; DIB cdr_dib = { &cdr_chsel, NULL }; UNIT cdr_unit = { - UDATA (&cdr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0) + UDATA (&cdr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE+UNIT_TEXT, 0) }; REG cdr_reg[] = { @@ -144,7 +145,7 @@ DEVICE cdr_dev = { DIB cdp_dib = { &cdp_chsel, &cdp_chwr }; UNIT cdp_unit = { - UDATA (&cdp_svc, UNIT_SEQ+UNIT_ATTABLE, 0) + UDATA (&cdp_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0) }; REG cdp_reg[] = { @@ -443,12 +444,12 @@ for (i = ((2 * CD_CHRLNT) + 1); (i > 0) && cdp_cbuf[i++] = '\n'; /* append nl */ cdp_cbuf[i++] = 0; /* append nul */ fputs (cdp_cbuf, uptr->fileref); /* write card */ +uptr->pos = ftell (uptr->fileref); /* update position */ if (ferror (uptr->fileref)) { /* error? */ perror ("CDP I/O error"); clearerr (uptr->fileref); return SCPE_IOERR; } -uptr->pos = ftell (uptr->fileref); /* update position */ cdp_sta = CDS_END; /* end state */ sim_cancel (uptr); /* cancel current */ sim_activate (uptr, cdp_tstop); /* long timer */ diff --git a/I7094/i7094_cpu.c b/I7094/i7094_cpu.c index 790ace18..e5a49877 100644 --- a/I7094/i7094_cpu.c +++ b/I7094/i7094_cpu.c @@ -1,6 +1,6 @@ /* i7094_cpu.c: IBM 7094 CPU simulator - Copyright (c) 2003-2006, Robert M. Supnik + Copyright (c) 2003-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,6 +25,7 @@ cpu 7094 central processor + 28-Apr-07 RMS Removed clock initialization 29-Oct-06 RMS Added additional expanded core instructions 17-Oct-06 RMS Fixed the fix in halt IO wait loop 16-Jun-06 RMS Fixed bug in halt IO wait loop @@ -198,7 +199,6 @@ extern uint32 ch_sta[NUM_CHAN]; extern uint32 ch_flags[NUM_CHAN]; extern DEVICE mt_dev[NUM_CHAN]; extern DEVICE ch_dev[NUM_CHAN]; -extern UNIT clk_unit; extern FILE *sim_deb; extern int32 sim_int_char; extern int32 sim_interval; @@ -625,7 +625,6 @@ ind_reloc = ind_reloc & VA_BLK; /* canonical form */ ind_start = ind_start & VA_BLK; ind_limit = (ind_limit & VA_BLK) | VA_OFF; chtr_pend = chtr_eval (NULL); /* eval chan traps */ -sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init clock */ tracing = ((hst_lnt != 0) || DEBUG_PRS (cpu_dev)); if (ht_pend) { /* HTR pending? */ diff --git a/I7094/i7094_lp.c b/I7094/i7094_lp.c index 9ce001e6..f8b7c0c9 100644 --- a/I7094/i7094_lp.c +++ b/I7094/i7094_lp.c @@ -1,6 +1,6 @@ /* i7094_lp.c: IBM 716 line printer simulator - Copyright (c) 2003-2006, Robert M. Supnik + Copyright (c) 2003-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,6 +25,8 @@ lpt 716 line printer + 19-Jan-07 RMS Added UNIT_TEXT flag + Internally, the 7094 works only with column binary and is limited to 72 columns of data. Each row of the printed line is represented by 72b of data (two 36b words). A complete print line consists of 12 rows @@ -142,7 +144,7 @@ extern char colbin_to_bcd (uint32 colbin); DIB lpt_dib = { &lpt_chsel, &lpt_chwr }; UNIT lpt_unit = { - UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_CONS, 0) + UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_CONS+UNIT_TEXT, 0) }; REG lpt_reg[] = { @@ -306,7 +308,7 @@ return SCPE_OK; t_stat lpt_end_line (UNIT *uptr) { -uint32 i, j, col, row, bufw, colbin; +uint32 i, col, row, bufw, colbin; char *pch, bcd, lpt_cbuf[LPT_CHRLNT + 1]; t_uint64 dat; @@ -325,22 +327,23 @@ for (col = 0; col < 72; col++) { /* proc 72 columns */ } for (i = LPT_CHRLNT; (i > 0) && (lpt_cbuf[i - 1] == ' '); --i) ; /* trim spaces */ -lpt_cbuf[i++] = '\n'; /* append nl */ +lpt_cbuf[i] = 0; /* append nul */ if (uptr->flags & UNIT_ATT) { /* file? */ - fxwrite (lpt_cbuf, 1, i, uptr->fileref); /* write line */ + fputs (lpt_cbuf, uptr->fileref); /* write line */ + fputc ('\n', uptr->fileref); /* append nl */ + uptr->pos = ftell (uptr->fileref); /* update position */ if (ferror (uptr->fileref)) { /* error? */ perror ("LPT I/O error"); clearerr (uptr->fileref); return SCPE_IOERR; } - uptr->pos = ftell (uptr->fileref); /* update position */ } else if (uptr->flags & UNIT_CONS) { /* print to console? */ - for (j = 0; j < i; j++) sim_putchar (lpt_cbuf[j]); + for (i = 0; lpt_cbuf[i] != 0; i++) sim_putchar (lpt_cbuf[i]); sim_putchar ('\r'); + sim_putchar ('\n'); } else return SCPE_UNATT; /* otherwise error */ -uptr->pos = uptr->pos + strlen (lpt_cbuf); /* count char */ lpt_sta = LPS_END; /* end line state */ sim_cancel (uptr); /* cancel current */ sim_activate (uptr, lpt_tstop); /* long timer */ diff --git a/Interdata/id16_cpu.c b/Interdata/id16_cpu.c index 36e033d4..b24128fe 100644 --- a/Interdata/id16_cpu.c +++ b/Interdata/id16_cpu.c @@ -1,6 +1,6 @@ /* id16_cpu.c: Interdata 16b CPU simulator - Copyright (c) 2000-2006, Robert M. Supnik + Copyright (c) 2000-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,6 +25,7 @@ cpu Interdata 16b CPU + 28-Apr-07 RMS Removed clock initialization 27-Oct-06 RMS Added idle support Removed separate PASLA clock 06-Feb-06 RMS Fixed bug in DH (found by Mark Hittinger) @@ -222,7 +223,6 @@ extern int32 sim_interval; extern int32 sim_int_char; extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ extern t_bool sim_idle_enab; -extern UNIT pic_unit, lfc_unit; /* timers */ uint32 ReadB (uint32 loc); uint32 ReadH (uint32 loc); @@ -587,8 +587,6 @@ else { } int_eval (); /* eval interrupts */ cc = newPSW (PSW & psw_mask); /* split PSW, eval wait */ -sim_rtcn_init (lfc_unit.wait, TMR_LFC); /* init clock */ -sim_rtcn_init (pic_unit.wait, TMR_PIC); /* init timer */ reason = 0; /* Process events */ diff --git a/Interdata/id32_cpu.c b/Interdata/id32_cpu.c index 93d4970a..455f2efa 100644 --- a/Interdata/id32_cpu.c +++ b/Interdata/id32_cpu.c @@ -1,6 +1,6 @@ /* id32_cpu.c: Interdata 32b CPU simulator - Copyright (c) 2000-2006, Robert M. Supnik + Copyright (c) 2000-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,6 +25,7 @@ cpu Interdata 32b CPU + 28-Apr-07 RMS Removed clock initialization 27-Oct-06 RMS Added idle support Removed separate PASLA clock 09-Mar-06 RMS Added 8 register bank support for 8/32 @@ -252,7 +253,6 @@ extern int32 sim_interval; extern int32 sim_int_char; extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ extern t_bool sim_idle_enab; -extern UNIT pic_unit, lfc_unit; /* timers */ extern FILE *sim_deb; uint32 ReadB (uint32 loc, uint32 rel); @@ -627,8 +627,6 @@ if (cpu_unit.flags & UNIT_8RS) psw_reg_mask = 7; /* 8 register sets */ else psw_reg_mask = 1; /* 2 register sets */ int_eval (); /* eval interrupts */ cc = newPSW (PSW & PSW_MASK); /* split PSW, eval wait */ -sim_rtcn_init (lfc_unit.wait, TMR_LFC); /* init clock */ -sim_rtcn_init (pic_unit.wait, TMR_PIC); /* init timer */ reason = 0; /* Abort handling diff --git a/Interdata/id_lp.c b/Interdata/id_lp.c index 8cf32045..c3588398 100644 --- a/Interdata/id_lp.c +++ b/Interdata/id_lp.c @@ -1,6 +1,6 @@ /* id_lp.c: Interdata line printer - 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"), @@ -25,6 +25,7 @@ lpt M46-206 line printer + 19-Jan-07 RMS Added UNIT_TEXT flag 25-Apr-03 RMS Revised for extended file support */ @@ -83,7 +84,7 @@ t_stat lpt_spc (UNIT *uptr, int32 cnt); DIB lpt_dib = { d_LPT, -1, v_LPT, NULL, &lpt, NULL }; -UNIT lpt_unit = { UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_UC, 0) }; +UNIT lpt_unit = { UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_UC+UNIT_TEXT, 0) }; REG lpt_reg[] = { { HRDATA (STA, lpt_sta, 8) }, diff --git a/NOVA/nova_cpu.c b/NOVA/nova_cpu.c index 14c07f4c..921daf5c 100644 --- a/NOVA/nova_cpu.c +++ b/NOVA/nova_cpu.c @@ -1,6 +1,6 @@ /* nova_cpu.c: NOVA CPU simulator - Copyright (c) 1993-2006, Robert M. Supnik + Copyright (c) 1993-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,6 +25,7 @@ cpu Nova central processor + 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) 25-Aug-05 RMS Fixed DIVS case 2^31 / - 1 @@ -332,7 +333,6 @@ extern int32 sim_interval; int32 PC, IR, i; t_stat reason; void mask_out (int32 mask); -extern int32 clk_sel, clk_time[4]; /* Restore register state */ @@ -341,7 +341,6 @@ PC = saved_PC & AMASK; /* load local PC */ C = C & CBIT; mask_out (pimask); /* reset int system */ reason = 0; -sim_rtc_init (clk_time[clk_sel]); /* init calibration */ /* Main instruction fetch/decode loop */ diff --git a/NOVA/nova_lp.c b/NOVA/nova_lp.c index d155e07f..d3980d02 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-2005, Robert M. Supnik + Copyright (c) 1993-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,6 +25,7 @@ lpt line printer + 19-Jan-07 RMS Added UNIT_TEXT 25-Apr-03 RMS Revised for extended file support 30-May-02 RMS Widened POS to 32b */ @@ -49,7 +50,7 @@ t_stat lpt_reset (DEVICE *dptr); DIB lpt_dib = { DEV_LPT, INT_LPT, PI_LPT, &lpt }; UNIT lpt_unit = { - UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT + UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT }; REG lpt_reg[] = { @@ -110,12 +111,13 @@ dev_done = dev_done | INT_LPT; /* set done */ int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */ return IORETURN (lpt_stopioe, SCPE_UNATT); -if (putc (lpt_unit.buf, lpt_unit.fileref) == EOF) { +fputc (uptr->buf, uptr->fileref); +uptr->pos = ftell (uptr->fileref); +if (ferror (uptr->fileref)) { perror ("LPT I/O error"); - clearerr (lpt_unit.fileref); + clearerr (uptr->fileref); return SCPE_IOERR; } -lpt_unit.pos = lpt_unit.pos + 1; return SCPE_OK; } diff --git a/PDP1/pdp1_lp.c b/PDP1/pdp1_lp.c index f7b52c18..1b7b058d 100644 --- a/PDP1/pdp1_lp.c +++ b/PDP1/pdp1_lp.c @@ -1,6 +1,6 @@ /* pdp1_lp.c: PDP-1 line printer simulator - Copyright (c) 1993-2006, Robert M. Supnik + Copyright (c) 1993-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,6 +25,7 @@ lpt Type 62 line printer for the PDP-1 + 19-Jan-07 RMS Added UNIT_TEXT flag 21-Dec-06 RMS Added 16-channel SBS support 07-Sep-03 RMS Changed ioc to ios 23-Jul-03 RMS Fixed bugs in instruction decoding, overprinting @@ -67,7 +68,7 @@ t_stat lpt_reset (DEVICE *dptr); */ UNIT lpt_unit = { - UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT + UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT }; REG lpt_reg[] = { @@ -166,6 +167,7 @@ if (lpt_spc) { /* space? */ if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ return IORETURN (lpt_stopioe, SCPE_UNATT); fputs (lpt_cc[lpt_spc & 07], uptr->fileref); /* print cctl */ + uptr->pos = ftell (uptr->fileref); /* update position */ if (ferror (uptr->fileref)) { /* error? */ perror ("LPT I/O error"); clearerr (uptr->fileref); @@ -179,6 +181,7 @@ else { return IORETURN (lpt_stopioe, SCPE_UNATT); if (lpt_ovrpr) fputc ('\r', uptr->fileref); /* overprint? */ fputs (lpt_buf, uptr->fileref); /* print buffer */ + uptr->pos = ftell (uptr->fileref); /* update position */ if (ferror (uptr->fileref)) { /* test error */ perror ("LPT I/O error"); clearerr (uptr->fileref); @@ -188,7 +191,6 @@ else { for (i = 0; i <= LPT_BSIZE; i++) lpt_buf[i] = 0; /* clear buffer */ lpt_ovrpr = 1; /* set overprint */ } -lpt_unit.pos = ftell (uptr->fileref); /* update position */ return SCPE_OK; } diff --git a/PDP10/pdp10_cpu.c b/PDP10/pdp10_cpu.c index 9ae82377..af08c444 100644 --- a/PDP10/pdp10_cpu.c +++ b/PDP10/pdp10_cpu.c @@ -1,6 +1,6 @@ /* pdp10_cpu.c: PDP-10 CPU simulator - Copyright (c) 1993-2005, Robert M. Supnik + Copyright (c) 1993-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,6 +25,7 @@ cpu KS10 central processor + 28-Apr-07 RMS Removed clock initialization 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) Fixed warning in MOVNI 16-Aug-05 RMS Fixed C++ declaration and cast problems @@ -198,7 +199,6 @@ InstHistory *hst = NULL; /* instruction history * extern int32 sim_int_char; extern int32 sim_interval; extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ -extern UNIT tim_unit; /* Forward and external declarations */ @@ -633,7 +633,6 @@ pager_tc = FALSE; /* not in trap cycle */ pager_pi = FALSE; /* not in pi sequence */ rlog = 0; /* not in extend */ pi_eval (); /* eval pi system */ -sim_rtc_init (tim_unit.wait); /* init calibration */ if (!Q_ITS) its_1pr = 0; /* ~ITS, clr 1-proc */ t20_idlelock = 0; /* clr T20 idle lock */ diff --git a/PDP10/pdp10_lp20.c b/PDP10/pdp10_lp20.c index d29fe336..c7af5a95 100644 --- a/PDP10/pdp10_lp20.c +++ b/PDP10/pdp10_lp20.c @@ -1,6 +1,6 @@ /* pdp10_lp20.c: PDP-10 LP20 line printer simulator - Copyright (c) 1993-2005, Robert M Supnik + Copyright (c) 1993-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,6 +25,7 @@ lp20 line printer + 19-Jan-07 RMS Added UNIT_TEXT flag 04-Sep-05 RMS Fixed missing return (found by Peter Schorn) 07-Jul-05 RMS Removed extraneous externs 18-Mar-05 RMS Added attached test to detach routine @@ -185,7 +186,7 @@ DIB lp20_dib = { }; UNIT lp20_unit = { - UDATA (&lp20_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT + UDATA (&lp20_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT }; REG lp20_reg[] = { @@ -527,8 +528,9 @@ else { if (lpcolc >= LP_WIDTH) /* line full? */ r = lp20_adv (1, TRUE); /* adv carriage */ } -for (i = 0; i < rpt; i++) putc (lppdat, lp20_unit.fileref); -lp20_unit.pos = lp20_unit.pos + rpt; +for (i = 0; i < rpt; i++) + fputc (lppdat, lp20_unit.fileref); +lp20_unit.pos = ftell (lp20_unit.fileref); lpcolc = lpcolc + rpt; return r; } @@ -539,8 +541,9 @@ int32 i; if (cnt == 0) return TRUE; lpcolc = 0; /* reset col cntr */ -for (i = 0; i < cnt; i++) putc ('\n', lp20_unit.fileref); -lp20_unit.pos = lp20_unit.pos + cnt; /* print 'n' newlines */ +for (i = 0; i < cnt; i++) + fputc ('\n', lp20_unit.fileref); +lp20_unit.pos = ftell (lp20_unit.fileref); /* print 'n' newlines */ if (dvuadv) dvptr = (dvptr + cnt) % dvlnt; /* update DAVFU ptr */ if (davfu[dvptr] & (1 << DV_TOF)) { /* at top of form? */ if (lppagc = (lppagc - 1) & PAGC_MASK) { /* decr page cntr */ @@ -566,8 +569,8 @@ for (i = 0; i < dvlnt; i++) { /* search DAVFU */ if (davfu[dvptr] & (1 << cnt)) { /* channel stop set? */ if (cnt) return lp20_adv (i + 1, FALSE); /* ~TOF, adv */ if (lpcolc) lp20_adv (1, FALSE); /* TOF, need newline? */ - putc ('\f', lp20_unit.fileref); /* print form feed */ - lp20_unit.pos = lp20_unit.pos + 1; + fputc ('\f', lp20_unit.fileref); /* print form feed */ + lp20_unit.pos = ftell (lp20_unit.fileref); if (lppagc = (lppagc - 1) & PAGC_MASK) { /* decr page cntr */ lpcsa = lpcsa & ~CSA_PZRO; /* update status */ return TRUE; diff --git a/PDP10/pdp10_tu.c b/PDP10/pdp10_tu.c index e511383e..a430f716 100644 --- a/PDP10/pdp10_tu.c +++ b/PDP10/pdp10_tu.c @@ -1,6 +1,6 @@ /* pdp10_tu.c - PDP-10 RH11/TM03/TU45 magnetic tape simulator - Copyright (c) 1993-2006, Robert M Supnik + Copyright (c) 1993-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,6 +25,7 @@ tu RH11/TM03/TU45 magtape + 29-Apr-07 RMS Fixed bug in setting FCE on TMK (found by Naoki Hamada) 16-Feb-06 RMS Added tape capacity checking 16-Aug-05 RMS Fixed C++ declaration and cast problems 07-Jul-05 RMS Removed extraneous externs @@ -871,6 +872,7 @@ switch (fnc) { /* case on function */ tufs = tufs | FS_ID; /* PE BOT? ID burst */ TXFR (ba, wc, 0); /* validate transfer */ if (st = sim_tape_rdrecf (uptr, xbuf, &tbc, MT_MAXFR)) { /* read fwd */ + if (st == MTSE_TMK) set_tuer (ER_FCE); /* TMK also sets FCE */ r = tu_map_err (uptr, st, 1); /* map error */ break; /* done */ } @@ -924,6 +926,7 @@ switch (fnc) { /* case on function */ tufc = 0; /* clear frame count */ TXFR (ba, wc, 1); /* validate xfer rev */ if (st = sim_tape_rdrecr (uptr, xbuf + 4, &tbc, MT_MAXFR)) { /* read rev */ + if (st == MTSE_TMK) set_tuer (ER_FCE); /* TMK also sets FCE */ r = tu_map_err (uptr, st, 1); /* map error */ break; /* done */ } @@ -1032,7 +1035,6 @@ switch (st) { return SCPE_IERR; case MTSE_TMK: /* end of file */ - set_tuer (ER_FCE); /* also sets FCE */ tufs = tufs | FS_TMK; break; diff --git a/PDP11/pdp11_cpu.c b/PDP11/pdp11_cpu.c index f40dd71c..904d0f76 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-2006, Robert M Supnik + Copyright (c) 1993-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,6 +25,7 @@ cpu PDP-11 CPU + 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 24-May-06 RMS Added instruction history @@ -298,7 +299,6 @@ int32 dsmask[4] = { MMR3_KDS, MMR3_SDS, 0, MMR3_UDS }; /* dspace enables */ extern int32 CPUERR, MAINT; extern int32 sim_interval; -extern UNIT clk_unit, pclk_unit; extern int32 sim_int_char; extern uint32 sim_switches; extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ @@ -661,8 +661,6 @@ MMR0 = MMR0 | MMR0_IC; /* usually on */ trap_req = calc_ints (ipl, trap_req); /* upd int req */ trapea = 0; reason = 0; -sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init line clock */ -sim_rtcn_init (pclk_unit.wait, TMR_PCLK); /* init prog clock */ /* Abort handling diff --git a/PDP11/pdp11_cpumod.c b/PDP11/pdp11_cpumod.c index 4431c847..b77c8a22 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-2005, 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,6 +25,7 @@ system PDP-11 model-specific registers + 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 15-Feb-05 RMS Fixed bug in SHOW MODEL (from Sergey Okhapkin) @@ -83,6 +84,7 @@ extern FILE *sim_log; extern int32 STKLIM, PIRQ; extern uint32 cpu_model, cpu_type, cpu_opt; extern int32 clk_fie, clk_fnxm, clk_tps, clk_default; +extern int32 sim_switches; t_stat CPU24_rd (int32 *data, int32 addr, int32 access); t_stat CPU24_wr (int32 data, int32 addr, int32 access); @@ -1100,7 +1102,8 @@ for (i = 0; i < clim; i = i + 2) nM[i >> 1] = M[i >> 1]; free (M); M = nM; MEMSIZE = val; -cpu_set_bus (cpu_opt); +if (!(sim_switches & SIM_SW_REST)) /* unless restore, */ + cpu_set_bus (cpu_opt); /* alter periph config */ return SCPE_OK; } diff --git a/PDP11/pdp11_hk.c b/PDP11/pdp11_hk.c index ed2da536..e0fdc32d 100644 --- a/PDP11/pdp11_hk.c +++ b/PDP11/pdp11_hk.c @@ -1,6 +1,6 @@ /* pdp11_hk.c - RK611/RK06/RK07 disk controller - Copyright (c) 1993-2005, Robert M Supnik + Copyright (c) 1993-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,6 +25,8 @@ hk RK611/RK06/RK07 disk + 29-Apr-07 RMS NOP and DCLR (at least) do not check drive type + MR2 and MR3 only updated on NOP 17-Nov-05 RMS Removed unused variable 13-Nov-05 RMS Fixed overlapped seek interaction with NOP, DCLR, PACK 16-Aug-05 RMS Fixed C++ declaration and cast problems @@ -314,6 +316,12 @@ extern uint16 *M; #define RDH2_V_DHA 5 /* decoded head */ #define RDH2_GOOD 0140000 /* good sector flags */ +/* Debug detail levels */ + +#define HKDEB_OPS 001 /* transactions */ +#define HKDEB_RRD 002 /* reg reads */ +#define HKDEB_RWR 004 /* reg writes */ + extern int32 int_req[IPL_HLVL]; extern FILE *sim_deb; @@ -338,7 +346,7 @@ int32 hk_min2wait = 300; /* min time to 2nd int * int16 hkdb[3] = { 0 }; /* data buffer silo */ int16 hk_off[HK_NUMDR] = { 0 }; /* saved offset */ int16 hk_dif[HK_NUMDR] = { 0 }; /* cylinder diff */ -static int32 reg_in_drive[16] = { +static uint8 reg_in_drive[16] = { 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; DEVICE hk_dev; @@ -453,12 +461,20 @@ MTAB hk_mod[] = { { 0 } }; +DEBTAB hk_deb[] = { + { "OPS", HKDEB_OPS }, + { "RRD", HKDEB_RRD }, + { "RWR", HKDEB_RWR }, + { NULL, 0 } + }; + DEVICE hk_dev = { "HK", hk_unit, hk_reg, hk_mod, HK_NUMDR, DEV_RDX, 24, 1, DEV_RDX, 16, NULL, NULL, &hk_reset, &hk_boot, &hk_attach, &hk_detach, - &hk_dib, DEV_DISABLE | DEV_UBUS | DEV_Q18 | DEV_DEBUG + &hk_dib, DEV_DISABLE | DEV_UBUS | DEV_Q18 | DEV_DEBUG, 0, + hk_deb, NULL, 0 }; /* I/O dispatch routines, I/O addresses 17777440 - 17777476 */ @@ -538,14 +554,16 @@ switch (j) { /* decode PA<4:1> */ break; case 016: /* HKMR2 */ - *data = hkmr2 = hk_rdmr2 (GET_MS (hkmr)); + *data = hkmr2; break; case 017: /* HKMR3 */ - *data = hkmr3 = hk_rdmr3 (GET_MS (hkmr)); + *data = hkmr3; break; } +if (DEBUG_PRI (hk_dev, HKDEB_RRD)) + fprintf (sim_deb, ">>HK%d read: reg%d=%o\n", drv, j, *data); return SCPE_OK; } @@ -565,6 +583,8 @@ if ((hkcs1 & CS1_GO) && /* busy? */ return SCPE_OK; } +if (DEBUG_PRI (hk_dev, HKDEB_RWR)) + fprintf (sim_deb, ">>HK%d write: reg%d=%o\n", drv, j, data); switch (j) { /* decode PA<4:1> */ case 000: /* HKCS1 */ @@ -648,23 +668,27 @@ void hk_go (int32 drv) int32 fnc, t; UNIT *uptr; -static int32 fnc_nxf[16] = { +static uint8 fnc_cdt[16] = { + 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + +static uint8 fnc_nxf[16] = { 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0 }; -static int32 fnc_att[16] = { +static uint8 fnc_att[16] = { 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }; -static int32 fnc_rdy[16] = { +static uint8 fnc_rdy[16] = { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }; -static int32 fnc_cyl[16] = { +static uint8 fnc_cyl[16] = { 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0 }; fnc = GET_FNC (hkcs1); -if (DEBUG_PRS (hk_dev)) fprintf (sim_deb, - ">>HK%d go: fnc=%o, ds=%o, cyl=%o, da=%o, ba=%o, wc=%o\n", - drv, fnc, hkds[drv], hkdc, hkda, hkba, hkwc); +if (DEBUG_PRI (hk_dev, HKDEB_OPS)) fprintf (sim_deb, + ">>HK%d strt: fnc=%o, cs1=%o, cs2=%o, ds=%o, er=%o, cyl=%o, da=%o, ba=%o, wc=%o\n", + drv, fnc, hkcs1, hkcs2, hkds[drv], hker[drv], hkdc, hkda, hkba, hkwc); uptr = hk_dev.units + drv; /* get unit */ if (fnc != FNC_NOP) hkmr = hkmr & ~MR_MS; /* !nop, clr msg sel */ if (uptr->flags & UNIT_DIS) { /* nx unit? */ @@ -672,11 +696,12 @@ if (uptr->flags & UNIT_DIS) { /* nx unit? */ update_hkcs (CS1_DONE, drv); /* done */ return; } -if (((hkcs1 & CS1_DT) != 0) != /* dtype mismatch? */ - ((uptr->flags & UNIT_DTYPE) != 0)) { - hk_cmderr (ER_DTY, drv); /* type error */ - return; - } +if (fnc_cdt[fnc] && + (((hkcs1 & CS1_DT) != 0) != /* need dtype match? */ + ((uptr->flags & UNIT_DTYPE) != 0))) { + hk_cmderr (ER_DTY, drv); /* type error */ + return; + } if (fnc_nxf[fnc] && ((hkds[drv] & DS_VV) == 0)) { /* need vol valid? */ hk_cmderr (ER_NXF, drv); /* non exec func */ return; @@ -699,10 +724,15 @@ switch (fnc) { /* case on function */ /* Instantaneous functions (unit may be busy, can't schedule thread) */ + case FNC_NOP: /* no operation */ + hkmr2 = hk_rdmr2 (GET_MS (hkmr)); /* get serial msgs */ + hkmr3 = hk_rdmr3 (GET_MS (hkmr)); + update_hkcs (CS1_DONE, drv); /* done */ + break; + case FNC_DCLR: /* drive clear */ hkds[drv] &= ~DS_ATA; /* clr ATA */ hker[drv] = 0; /* clear errors */ - case FNC_NOP: /* no operation */ update_hkcs (CS1_DONE, drv); /* done */ break; @@ -929,9 +959,6 @@ switch (fnc) { /* case on function */ break; } /* end case func */ -if (DEBUG_PRS (hk_dev)) fprintf (sim_deb, - ">>HK%d done: fnc=%o, cs1 = %o, cs2 = %o, ds=%o, cyl=%o, da=%o, ba=%o, wc=%o\n", - drv, fnc, hkcs1, hkcs2, hkds[drv], hkdc, hkda, hkba, hkwc); return SCPE_OK; } @@ -961,6 +988,11 @@ for (i = 0; i < HK_NUMDR; i++) { /* if ATA, set DI */ } if (hker[drv] | (hkcs1 & (CS1_PAR | CS1_CTO)) | /* if err, set ERR */ (hkcs2 & CS2_ERR)) hkcs1 = hkcs1 | CS1_ERR; +if ((flag & CS1_DONE) && /* set done && debug? */ + (DEBUG_PRI (hk_dev, HKDEB_OPS))) + fprintf (sim_deb, + ">>HK%d done: fnc=%o, cs1=%o, cs2=%o, ds=%o, er=%o, cyl=%o, da=%o, ba=%o, wc=%o\n", + drv, GET_FNC (hkcs1), hkcs1, hkcs2, hkds[drv], hker[drv], hkdc, hkda, hkba, hkwc); return; } diff --git a/PDP11/pdp11_lp.c b/PDP11/pdp11_lp.c index 084bf8e6..691ca6ce 100644 --- a/PDP11/pdp11_lp.c +++ b/PDP11/pdp11_lp.c @@ -1,6 +1,6 @@ /* pdp11_lp.c: PDP-11 line printer simulator - Copyright (c) 1993-2005, Robert M Supnik + Copyright (c) 1993-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,6 +25,7 @@ lpt LP11 line printer + 19-Jan-07 RMS Added UNIT_TEXT flag 07-Jul-05 RMS Removed extraneous externs 19-May-03 RMS Revised for new conditional compilation scheme 25-Apr-03 RMS Revised for extended file support @@ -76,7 +77,7 @@ DIB lpt_dib = { }; UNIT lpt_unit = { - UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT + UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT }; REG lpt_reg[] = { @@ -151,15 +152,16 @@ t_stat lpt_svc (UNIT *uptr) { lpt_csr = lpt_csr | CSR_ERR | CSR_DONE; if (lpt_csr & CSR_IE) SET_INT (LPT); -if ((lpt_unit.flags & UNIT_ATT) == 0) +if ((uptr->flags & UNIT_ATT) == 0) return IORETURN (lpt_stopioe, SCPE_UNATT); -if (putc (lpt_unit.buf & 0177, lpt_unit.fileref) == EOF) { +fputc (uptr->buf & 0177, uptr->fileref); +uptr->pos = ftell (uptr->fileref); +if (ferror (uptr->fileref)) { perror ("LPT I/O error"); - clearerr (lpt_unit.fileref); + clearerr (uptr->fileref); return SCPE_IOERR; } lpt_csr = lpt_csr & ~CSR_ERR; -lpt_unit.pos = lpt_unit.pos + 1; return SCPE_OK; } diff --git a/PDP11/pdp11_tu.c b/PDP11/pdp11_tu.c index 21815c4b..3063d90e 100644 --- a/PDP11/pdp11_tu.c +++ b/PDP11/pdp11_tu.c @@ -25,6 +25,7 @@ tu TM02/TM03 magtape + 29-Apr-07 RMS Fixed bug in setting FCE on TMK (found by Naoki Hamada) 16-Feb-06 RMS Added tape capacity checking 12-Nov-05 RMS Changed default formatter to TM03 (for VMS) 31-Oct-05 RMS Fixed address width for large files @@ -671,6 +672,7 @@ switch (fnc) { /* case on function */ if ((uptr->UDENS == TC_1600) && sim_tape_bot (uptr)) tufs = tufs | FS_ID; /* PE BOT? ID burst */ if (st = sim_tape_rdrecf (uptr, xbuf, &tbc, MT_MAXFR)) { /* read fwd */ + if (st == MTSE_TMK) tu_set_er (ER_FCE); /* tmk also sets FCE */ r = tu_map_err (drv, st, 1); /* map error */ break; /* done */ } @@ -729,6 +731,7 @@ switch (fnc) { /* case on function */ case FNC_WCHKR: /* wcheck = read */ tufc = 0; /* clear frame count */ if (st = sim_tape_rdrecr (uptr, xbuf + 4, &tbc, MT_MAXFR)) { /* read rev */ + if (st == MTSE_TMK) tu_set_er (ER_FCE); /* tmk also sets FCE */ r = tu_map_err (drv, st, 1); /* map error */ break; /* done */ } @@ -826,7 +829,6 @@ switch (st) { case MTSE_TMK: /* end of file */ tufs = tufs | FS_TMK; - tu_set_er (ER_FCE); /* also sets FCE */ break; case MTSE_IOERR: /* IO error */ diff --git a/PDP11/pdp11_xu.c b/PDP11/pdp11_xu.c index 87ba7992..cf3bbe85 100644 --- a/PDP11/pdp11_xu.c +++ b/PDP11/pdp11_xu.c @@ -32,31 +32,37 @@ These manuals can be found online at: http://www.spies.com/~aek/pdf/dec/unibus - - What this BETA version contains: - 1) Basic Transmit/Receive packet functionality. - 2) Promiscuous/All_Multicast/Multicast/MAC support - Testing performed: 1) Receives/Transmits single packet under custom RSX driver 2) Passes RSTS 10.1 controller diagnostics during boot 3) VMS 7.2 on VAX780 summary: - LAT - Runs properly both in and out - DECNET - Starts without error, but will not do anything - TCP/IP - Starts with errors, will ping in/out but nothing else - Clustering - Not tested + (May/2007: WinXP x64 host; MS VC++ 2005; SIMH v3.7-0 base; WinPcap 4.0) + LAT - SET HOST/LAT in/out + DECNET - SET HOST in/out, COPY in/out + TCP/IP - PING in/out; SET HOST/TELNET out, COPY/FTP out + - can't seem to connect in + - possible TCPIP v5.0 misconfiguration? + - issues with host WinXP firewall or Domain policy? + Clustering - Successfully clustered with AlphaVMS 8.2 + - no hangs or offlines, some odd delays and jerkiness + - out-of-order ring messages causing retransmits? + - caused by ping times (min/avg/max) of 2/7/16 ms? + 4) Runs VAX EVDWA diagnostic tests 1-10; tests 11-19 (M68000/ROM/RAM) fail Known issues: 1) Transmit/Receive rings have not been thoroughly tested, particularly when and where the ring pointers get reset. 2) Most auxiliary commands are not implemented yet. - 3) System_ID broadcast is not implemented - 4) Error/Interrupt signalling is still iffy from merge of FvK and sim_ether + 3) System_ID broadcast is not implemented. + 4) Error/Interrupt signalling is still iffy from merge of FvK and sim_ether. + 5) There are residual Map_ReadB and Map_WriteB from the FvK version that + probably need to be converted to Map_ReadW and Map_WriteW calls. ------------------------------------------------------------------------------ Modification history: + 03-May-07 DTH Added missing FC_RMAL command; cleared multicast on write 29-Oct-06 RMS Synced poll and clock 08-Dec-05 DTH Implemented ancilliary functions 022/023/024/025 18-Nov-05 DTH Corrected time between system ID packets @@ -598,7 +604,7 @@ t_stat xu_reset(DEVICE* dptr) int32 xu_command(CTLR* xu) { uint32 udbb; - int fnc, mtlen; + int fnc, mtlen, i, j; uint16 value, pltlen; t_stat status, rstatus, wstatus, wstatus2, wstatus3; struct xu_stats* stats = &xu->var->stats; @@ -666,12 +672,24 @@ int32 xu_command(CTLR* xu) return PCSR0_PCEI; break; + case FC_RMAL: /* read multicast address list */ + mtlen = (xu->var->pcb[2] & 0xFF00) >> 8; + udbb = xu->var->pcb[1] | ((xu->var->pcb[2] & 03) << 16); + wstatus = Map_WriteB(udbb, mtlen * 3, (uint8*) &xu->var->setup.macs[1]); + break; + case FC_WMAL: /* write multicast address list */ mtlen = (xu->var->pcb[2] & 0xFF00) >> 8; sim_debug(DBG_TRC, xu->dev, "FC_WAL: mtlen=%d\n", mtlen); if (mtlen > 10) return PCSR0_PCEI; udbb = xu->var->pcb[1] | ((xu->var->pcb[2] & 03) << 16); + /* clear existing multicast list */ + for (i=1; ivar->setup.macs[i][j] = 0; + } + /* get multicast list from host */ rstatus = Map_ReadB(udbb, mtlen * 6, (uint8*) &xu->var->setup.macs[1]); if (rstatus == 0) { xu->var->setup.mac_count = mtlen + 1; diff --git a/PDP18B/pdp18b_cpu.c b/PDP18B/pdp18b_cpu.c index b2563876..ea535995 100644 --- a/PDP18B/pdp18b_cpu.c +++ b/PDP18B/pdp18b_cpu.c @@ -1,6 +1,6 @@ /* pdp18b_cpu.c: 18b PDP CPU simulator - Copyright (c) 1993-2006, Robert M Supnik + Copyright (c) 1993-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,6 +25,7 @@ cpu PDP-4/7/9/15 central processor + 28-Apr-07 RMS Removed clock initialization 26-Dec-06 RMS Fixed boundary test in KT15/XVM (reported by Andrew Warkentin) 30-Oct-06 RMS Added idle and infinite loop detection 08-Oct-06 RMS Added RDCLK instruction @@ -581,7 +582,6 @@ int32 api_int, api_usmd, skp; int32 iot_data, device, pulse; int32 last_IR; t_stat reason; -extern UNIT clk_unit; if (build_dev_tab ()) return SCPE_STOP; /* build, chk tables */ PC = PC & AMASK; /* clean variables */ @@ -589,8 +589,8 @@ LAC = LAC & LACMASK; MQ = MQ & DMASK; reason = 0; last_IR = -1; -sim_rtc_init (clk_unit.wait); /* init calibration */ -if (cpu_unit.flags & UNIT_NOAPI) api_enb = api_req = api_act = 0; +if (cpu_unit.flags & UNIT_NOAPI) /* no API? */ + api_enb = api_req = api_act = 0; api_int = api_eval (&int_pend); /* eval API */ api_usmd = 0; /* not API user cycle */ diff --git a/PDP18B/pdp18b_lp.c b/PDP18B/pdp18b_lp.c index c930a160..411b3c12 100644 --- a/PDP18B/pdp18b_lp.c +++ b/PDP18B/pdp18b_lp.c @@ -1,6 +1,6 @@ /* pdp18b_lp.c: 18b PDP's line printer simulator - Copyright (c) 1993-2006, Robert M Supnik + Copyright (c) 1993-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"), @@ -28,6 +28,7 @@ lp09 (PDP-9,15) LP09 line printer lp15 (PDP-15) LP15 line printer + 19-Jan-07 RMS Added UNIT_TEXT flag 11-Jun-06 RMS Made character translation table global scope 14-Jan-04 RMS Revised IO device call interface 23-Jul-03 RMS Fixed overprint bug in Type 62 @@ -95,7 +96,7 @@ t_stat lp62_reset (DEVICE *dptr); DIB lp62_dib = { DEV_LPT, 2, &lp62_iors, { &lp62_65, &lp62_66 } }; UNIT lp62_unit = { - UDATA (&lp62_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT + UDATA (&lp62_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT }; REG lp62_reg[] = { @@ -179,6 +180,7 @@ if (lp62_spc) { /* space? */ if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ return IORETURN (lp62_stopioe, SCPE_UNATT); fputs (lp62_cc[lp62_spc & 07], uptr->fileref); /* print cctl */ + uptr->pos = ftell (uptr->fileref); /* update position */ if (ferror (uptr->fileref)) { /* error? */ perror ("LPT I/O error"); clearerr (uptr->fileref); @@ -192,6 +194,7 @@ else { return IORETURN (lp62_stopioe, SCPE_UNATT); if (lp62_ovrpr) fputc ('\r', uptr->fileref); /* overprint? */ fputs (lp62_buf, uptr->fileref); /* print buffer */ + uptr->pos = ftell (uptr->fileref); /* update position */ if (ferror (uptr->fileref)) { /* test error */ perror ("LPT I/O error"); clearerr (uptr->fileref); @@ -201,7 +204,6 @@ else { for (i = 0; i <= LP62_BSIZE; i++) lp62_buf[i] = 0; /* clear buffer */ lp62_ovrpr = 1; /* set overprint */ } -uptr->pos = ftell (uptr->fileref); /* update position */ return SCPE_OK; } @@ -274,7 +276,7 @@ t_stat lp647_detach (UNIT *uptr); DIB lp647_dib = { DEV_LPT, 2, &lp647_iors, { &lp647_65, &lp647_66 } }; UNIT lp647_unit = { - UDATA (&lp647_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT + UDATA (&lp647_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT }; REG lp647_reg[] = { @@ -393,7 +395,7 @@ return dat; t_stat lp647_svc (UNIT *uptr) { int32 i; -char pbuf[LP647_BSIZE + 1]; +char pbuf[LP647_BSIZE + 2]; lp647_don = 1; if (lp647_ie) SET_INT (LPT); /* set flag */ @@ -405,8 +407,10 @@ if ((lp647_iot & 020) == 0) { /* print? */ for (i = 0; i < lp647_bp; i++) /* translate buffer */ pbuf[i] = lp647_buf[i] | ((lp647_buf[i] >= 040)? 0: 0100); if ((lp647_iot & 060) == 0) pbuf[lp647_bp++] = '\r'; + pbuf[lp647_bp++] = 0; /* append nul */ for (i = 0; i < LP647_BSIZE; i++) lp647_buf[i] = 0; /* clear buffer */ - fwrite (pbuf, 1, lp647_bp, uptr->fileref); /* print buffer */ + fputs (pbuf, uptr->fileref); /* print buffer */ + uptr->pos = ftell (uptr->fileref); /* update position */ if (ferror (uptr->fileref)) { /* error? */ perror ("LPT I/O error"); clearerr (uptr->fileref); @@ -417,13 +421,13 @@ if ((lp647_iot & 020) == 0) { /* print? */ } if (lp647_iot & 060) { /* space? */ fputs (lp647_cc[lp647_iot & 07], uptr->fileref); /* write cctl */ + uptr->pos = ftell (uptr->fileref); /* update position */ if (ferror (uptr->fileref)) { /* error? */ perror ("LPT I/O error"); clearerr (uptr->fileref); return SCPE_IOERR; } } -uptr->pos = ftell (uptr->fileref); /* update position */ return SCPE_OK; } @@ -501,7 +505,7 @@ t_stat lp09_detach (UNIT *uptr); DIB lp09_dib = { DEV_LPT, 2, &lp09_iors, { NULL, &lp09_66 } }; UNIT lp09_unit = { - UDATA (&lp09_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT + UDATA (&lp09_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT }; REG lp09_reg[] = { @@ -582,12 +586,13 @@ if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ } c = uptr->buf & 0177; /* get char */ if ((c == 0) || (c == 0177)) return SCPE_OK; /* skip NULL, DEL */ -if (fputc (c, uptr->fileref) == EOF) { /* print char */ +fputc (c, uptr->fileref); /* print char */ +uptr->pos = ftell (uptr->fileref); /* update position */ +if (ferror (uptr->fileref)) { /* error? */ perror ("LPT I/O error"); clearerr (uptr->fileref); return SCPE_IOERR; } -uptr->pos = uptr->pos + 1; /* update position */ return SCPE_OK; } @@ -657,7 +662,7 @@ int32 lp15_stopioe = 0; int32 lp15_mode = 0; int32 lp15_lc = 0; int32 lp15_bp = 0; -char lp15_buf[LP15_BSIZE] = { 0 }; +char lp15_buf[LP15_BSIZE + 1] = { 0 }; DEVICE lp15_dev; int32 lp15_65 (int32 dev, int32 pulse, int32 dat); @@ -678,7 +683,7 @@ int32 lp15_updsta (int32 new); DIB lp15_dib = { DEV_LPT, 2, &lp15_iors, { &lp15_65, &lp15_66 } }; UNIT lp15_unit = { - UDATA (&lp15_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT + UDATA (&lp15_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT }; REG lp15_reg[] = { @@ -786,8 +791,10 @@ for (more = 1; more != 0; ) { /* loop until ctrl */ } for (i = 0; i < ccnt; i++) { /* loop through */ if ((c[i] <= 037) && ctrl[c[i]]) { /* control char? */ - fwrite (lp15_buf, 1, lp15_bp, uptr->fileref); - fputs (ctrl[c[i]], uptr->fileref); + lp15_buf[lp15_bp] = 0; /* append nul */ + fputs (lp15_buf, uptr->fileref); /* print line */ + fputs (ctrl[c[i]], uptr->fileref); /* space */ + uptr->pos = ftell (uptr->fileref); if (ferror (uptr->fileref)) { /* error? */ perror ("LPT I/O error"); clearerr (uptr->fileref); @@ -795,7 +802,6 @@ for (more = 1; more != 0; ) { /* loop until ctrl */ lp15_updsta (STA_DON | STA_ALM); return SCPE_IOERR; } - uptr->pos = ftell (uptr->fileref); lp15_bp = more = 0; } else { diff --git a/PDP8/pdp8_cpu.c b/PDP8/pdp8_cpu.c index 43cf5952..63d3bfbb 100644 --- a/PDP8/pdp8_cpu.c +++ b/PDP8/pdp8_cpu.c @@ -1,6 +1,6 @@ /* pdp8_cpu.c: PDP-8 CPU simulator - Copyright (c) 1993-2006, Robert M Supnik + Copyright (c) 1993-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,6 +25,7 @@ cpu central processor + 28-Apr-07 RMS Removed clock initialization 30-Oct-06 RMS Added idle and infinite loop detection 30-Sep-06 RMS Fixed SC value after DVI overflow (found by Don North) 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) @@ -244,7 +245,6 @@ extern int32 sim_int_char; extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ extern DEVICE *sim_devices[]; extern FILE *sim_log; -extern UNIT clk_unit, ttix_unit; extern t_bool sim_idle_enab; t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); @@ -338,8 +338,6 @@ LAC = saved_LAC & 017777; MQ = saved_MQ & 07777; int_req = INT_UPDATE; reason = 0; -sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init clk calib */ -sim_rtcn_init (ttix_unit.wait, TMR_TTX); /* init ttx calib */ /* Main instruction fetch/decode loop */ diff --git a/PDP8/pdp8_lp.c b/PDP8/pdp8_lp.c index d41e30ac..28f792f4 100644 --- a/PDP8/pdp8_lp.c +++ b/PDP8/pdp8_lp.c @@ -1,6 +1,6 @@ /* pdp8_lp.c: PDP-8 line printer simulator - Copyright (c) 1993-2005, Robert M Supnik + Copyright (c) 1993-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,6 +25,7 @@ lpt LP8E line printer + 19-Jan-07 RMS Added UNIT_TEXT 25-Apr-03 RMS Revised for extended file support 04-Oct-02 RMS Added DIB, enable/disable, device number support 30-May-02 RMS Widened POS to 32b @@ -54,7 +55,7 @@ t_stat lpt_detach (UNIT *uptr); DIB lpt_dib = { DEV_LPT, 1, { &lpt } }; UNIT lpt_unit = { - UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT + UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT }; REG lpt_reg[] = { @@ -135,16 +136,17 @@ t_stat lpt_svc (UNIT *uptr) { dev_done = dev_done | INT_LPT; /* set done */ int_req = INT_UPDATE; /* update interrupts */ -if ((lpt_unit.flags & UNIT_ATT) == 0) { +if ((uptr->flags & UNIT_ATT) == 0) { lpt_err = 1; return IORETURN (lpt_stopioe, SCPE_UNATT); } -if (putc (lpt_unit.buf, lpt_unit.fileref) == EOF) { +fputc (uptr->buf, uptr->fileref); /* print char */ +uptr->pos = ftell (uptr->fileref); +if (ferror (uptr->fileref)) { /* error? */ perror ("LPT I/O error"); - clearerr (lpt_unit.fileref); + clearerr (uptr->fileref); return SCPE_IOERR; } -lpt_unit.pos = lpt_unit.pos + 1; return SCPE_OK; } diff --git a/SDS/sds_cpu.c b/SDS/sds_cpu.c index d3a8e654..38c2e804 100644 --- a/SDS/sds_cpu.c +++ b/SDS/sds_cpu.c @@ -1,6 +1,6 @@ /* sds_cpu.c: SDS 940 CPU simulator - Copyright (c) 2001-2006, 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 @@ cpu central processor rtc real time clock + 28-Apr-07 RMS Removed clock initialization 29-Dec-06 RMS Fixed breakpoint variable declarations 16-Aug-05 RMS Fixed C++ declaration and cast problems 07-Nov-04 RMS Added instruction history @@ -195,7 +196,6 @@ int32 rtc_tps = 60; /* rtc ticks/sec */ extern int32 sim_int_char; extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ -extern UNIT mux_unit; 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); @@ -373,8 +373,6 @@ api_lvl = api_lvl & ~1; /* <0> reserved */ set_dyn_map (); /* set up mapping */ int_reqhi = api_findreq (); /* recalc int req */ chan_req = chan_testact (); /* recalc chan act */ -sim_rtcn_init (rtc_unit.wait, TMR_RTC); /* init calibration */ -sim_rtcn_init (mux_unit.wait, TMR_MUX); /* init calibration */ /* Main instruction fetch/decode loop */ diff --git a/SDS/sds_lp.c b/SDS/sds_lp.c index b419e00d..b8dd52ee 100644 --- a/SDS/sds_lp.c +++ b/SDS/sds_lp.c @@ -1,6 +1,6 @@ /* sds_lp.c: SDS 940 line printer simulator - 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"), @@ -25,6 +25,7 @@ lpt line printer + 19-Jan-07 RMS Added UNIT_TEXT flag 25-Apr-03 RMS Revised for extended file support */ @@ -77,7 +78,7 @@ t_stat lpt (uint32 fnc, uint32 inst, uint32 *dat); DIB lpt_dib = { CHAN_W, DEV_LPT, XFR_LPT, lpt_tplt, &lpt }; UNIT lpt_unit = { - UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0) + UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0) }; REG lpt_reg[] = { diff --git a/VAX/vax780_bugs.txt b/VAX/vax780_bugs.txt index 432e6759..9c75193b 100644 --- a/VAX/vax780_bugs.txt +++ b/VAX/vax780_bugs.txt @@ -51,6 +51,10 @@ 50. LDPCTX: 11/780 implements mbz tests on PCB fields. 51. LDPCTX/MTPR: 11/780 validity checks PCBB, SCBB, SBR, SLR, P0BR, P0LR, P1BR, P1LR. 52. TMR: tmr_inc not updated in standard (100Hz) mode. +53. MTPR SBR/PCBB/SCBB: 11/780 only checks that bits<1:0> == 0. +54. MTPR xLR: 11/780 excludes bits<31:24> from mbz test. +55. MTPR PxBR: 11/780 only checks bits<31,1:0> == 1,00. + diff --git a/VAX/vax780_defs.h b/VAX/vax780_defs.h index 6f178b2a..b5abed71 100644 --- a/VAX/vax780_defs.h +++ b/VAX/vax780_defs.h @@ -1,6 +1,6 @@ /* vax780_defs.h: VAX 780 model-specific definitions file - 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"), @@ -23,9 +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. - 29-Oct-2006 RMS Added clock coscheduler function - 17-May-2006 RMS Added CR11/CD11 support (from John Dundas) - 10-May-2006 RMS Added model-specific reserved operand check macros + 29-Apr-07 RMS Modified model-specific reserved operand check macros + to reflect 780 microcode patches (found by Naoki Hamada) + 29-Oct-06 RMS Added clock coscheduler function + 17-May-06 RMS Added CR11/CD11 support (from John Dundas) + 10-May-06 RMS Added model-specific reserved operand check macros This file covers the VAX 11/780, the first VAX. @@ -119,10 +121,20 @@ /* Machine specific reserved operand tests */ -#define ML_PA_TEST(r) if ((r) & 0xC0000003) RSVD_OPND_FAULT -#define ML_LR_TEST(r) if ((uint32)(r) > 0x200000) RSVD_OPND_FAULT -#define ML_BR_TEST(r) if ((((r) & 0xC0000000) != 0x80000000) || \ +/* 780 microcode patch 37 - only test LR<23:0> for appropriate length */ + +#define ML_LR_TEST(r) if ((uint32)((r) & 0xFFFFFF) > 0x200000) RSVD_OPND_FAULT + +/* 780 microcode patch 38 - only test PxBR<31>=1 and xBR<1:0> = 0 */ + +#define ML_PXBR_TEST(r) if ((((r) & 0x80000000) == 0) || \ ((r) & 0x00000003)) RSVD_OPND_FAULT +#define ML_SBR_TEST(r) if ((r) & 0x00000003) RSVD_OPND_FAULT + +/* 780 microcode patch 78 - only test xCBB<1:0> = 0 */ + +#define ML_PA_TEST(r) if ((r) & 0x00000003) RSVD_OPND_FAULT + #define LP_AST_TEST(r) if ((r) > AST_MAX) RSVD_OPND_FAULT #define LP_MBZ84_TEST(r) if ((r) & 0xF8C00000) RSVD_OPND_FAULT #define LP_MBZ92_TEST(r) if ((r) & 0x7FC00000) RSVD_OPND_FAULT diff --git a/VAX/vax_cpu.c b/VAX/vax_cpu.c index 5fc6af33..627a7fa4 100644 --- a/VAX/vax_cpu.c +++ b/VAX/vax_cpu.c @@ -1,6 +1,6 @@ /* vax_cpu.c: VAX CPU - Copyright (c) 1998-2006, Robert M Supnik + Copyright (c) 1998-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,6 +25,7 @@ cpu VAX central processor + 28-Apr-07 RMS Removed clock initialization 29-Oct-06 RMS Added idle support 22-May-06 RMS Fixed format error in CPU history (found by Peter Schorn) 10-May-06 RMS Added -kesu switches for virtual addressing modes @@ -284,7 +285,6 @@ extern int32 sim_int_char; extern int32 sim_switches; extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ extern t_bool sim_idle_enab; -extern UNIT clk_unit; extern t_stat build_dib_tab (void); extern UNIT rom_unit, nvr_unit; @@ -501,7 +501,6 @@ set_map_reg (); /* set map reg */ GET_CUR; /* set access mask */ SET_IRQL; /* eval interrupts */ FLUSH_ISTR; /* clear prefetch */ -sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init clock */ abortval = setjmp (save_env); /* set abort hdlr */ if (abortval > 0) { /* sim stop? */ diff --git a/VAX/vax_cpu1.c b/VAX/vax_cpu1.c index 79353dd6..d703cc0d 100644 --- a/VAX/vax_cpu1.c +++ b/VAX/vax_cpu1.c @@ -1,6 +1,6 @@ /* vax_cpu1.c: VAX complex instructions - Copyright (c) 1998-2006, Robert M Supnik + Copyright (c) 1998-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"), @@ -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. + 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 22-Sep-06 RMS Fixed declarations (from Sterling Garwood) @@ -1230,7 +1231,7 @@ newpc = ReadLP (pcbpa + 72); /* get PC, PSL */ newpsl = ReadLP (pcbpa + 76); t = ReadLP (pcbpa + 80); -ML_BR_TEST (t); /* validate P0BR */ +ML_PXBR_TEST (t); /* validate P0BR */ P0BR = t & BR_MASK; /* restore P0BR */ t = ReadLP (pcbpa + 84); LP_MBZ84_TEST (t); /* test mbz */ @@ -1240,7 +1241,7 @@ t = (t >> 24) & AST_MASK; LP_AST_TEST (t); /* validate AST */ ASTLVL = t; /* restore AST */ t = ReadLP (pcbpa + 88); -ML_BR_TEST (t + 0x800000); /* validate P1BR */ +ML_PXBR_TEST (t + 0x800000); /* validate P1BR */ P1BR = t & BR_MASK; /* restore P1BR */ t = ReadLP (pcbpa + 92); LP_MBZ92_TEST (t); /* test MBZ */ @@ -1387,7 +1388,7 @@ switch (prn) { /* case on reg # */ break; case MT_P0BR: /* P0BR */ - ML_BR_TEST (val); /* validate */ + ML_PXBR_TEST (val); /* validate */ P0BR = val & BR_MASK; /* lw aligned */ zap_tb (0); /* clr proc TLB */ set_map_reg (); @@ -1401,7 +1402,7 @@ switch (prn) { /* case on reg # */ break; case MT_P1BR: /* P1BR */ - ML_BR_TEST (val + 0x800000); /* validate */ + ML_PXBR_TEST (val + 0x800000); /* validate */ P1BR = val & BR_MASK; /* lw aligned */ zap_tb (0); /* clr proc TLB */ set_map_reg (); @@ -1415,7 +1416,7 @@ switch (prn) { /* case on reg # */ break; case MT_SBR: /* SBR */ - ML_PA_TEST (val); /* validate */ + ML_SBR_TEST (val); /* validate */ SBR = val & BR_MASK; /* lw aligned */ zap_tb (1); /* clr entire TLB */ set_map_reg (); diff --git a/VAX/vax_mmu.c b/VAX/vax_mmu.c index f0418a82..1a4be293 100644 --- a/VAX/vax_mmu.c +++ b/VAX/vax_mmu.c @@ -1,6 +1,6 @@ /* vax_mmu.c - VAX memory management - Copyright (c) 1998-2005, Robert M Supnik + Copyright (c) 1998-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"), @@ -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. + 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 19-Sep-03 RMS Fixed upper/lower case linkage problems on VMS @@ -444,7 +445,7 @@ static TLBENT zero_pte = { 0, 0 }; if (va & VA_S0) { /* system space? */ if (ptidx >= d_slr) /* system */ MM_ERR (PR_LNV); - ptead = d_sbr + ptidx; + ptead = (d_sbr + ptidx) & PAMASK; } else { if (va & VA_P1) { /* P1? */ @@ -463,7 +464,7 @@ else { ptidx = ((uint32) ptead) >> 7; /* xlate like sys */ if (ptidx >= d_slr) MM_ERR (PR_PLNV); - pte = ReadLP (d_sbr + ptidx); /* get system pte */ + pte = ReadLP ((d_sbr + ptidx) & PAMASK); /* get system pte */ #if defined (VAX_780) if ((pte & PTE_ACC) == 0) MM_ERR (PR_PACV); /* spte ACV? */ #endif diff --git a/VAX/vaxmod_defs.h b/VAX/vaxmod_defs.h index cec46c3d..f808c396 100644 --- a/VAX/vaxmod_defs.h +++ b/VAX/vaxmod_defs.h @@ -1,6 +1,6 @@ /* vaxmod_defs.h: VAX model-specific definitions file - Copyright (c) 1998-2006, Robert M Supnik + Copyright (c) 1998-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"), @@ -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. + 29-Apr-07 RMS Separated checks for PxBR and SBR 17-May-06 RMS Added CR11/CD11 support 10-May-06 RMS Added NOP'd reserved operand checking macros 05-Oct-05 RMS Added XU definitions for autoconfigure @@ -204,7 +205,8 @@ #define ML_PA_TEST(r) #define ML_LR_TEST(r) -#define ML_BR_TEST(r) +#define ML_SBR_TEST(r) +#define ML_PXBR_TEST(r) #define LP_AST_TEST(r) #define LP_MBZ84_TEST(r) #define LP_MBZ92_TEST(r) diff --git a/makefile b/makefile index b509dc59..4973273d 100644 --- a/makefile +++ b/makefile @@ -10,7 +10,11 @@ OS_CCDEFS = -lsocket -lnsl -lpthread -D_GNU_SOURCE 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 diff --git a/scp.c b/scp.c index 11c7bee2..ac983c30 100644 --- a/scp.c +++ b/scp.c @@ -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. + 28-Apr-07 RMS Modified sim_instr invocation to call sim_rtcn_init_all + Fixed bug in get_sim_opt + Fixed bug in restoration with changed memory size + 08-Mar-07 JDB Fixed breakpoint actions in DO command file processing 30-Jan-07 RMS Fixed bugs in get_ipaddr 17-Oct-06 RMS Added idle support 04-Oct-06 JDB DO cmd failure now echoes cmd unless -q @@ -832,8 +836,10 @@ if ((fpin = fopen (do_arg[0], "r")) == NULL) { /* file failed to open? if (flag < 1) flag = 1; /* start at level 1 */ do { - ocptr = cptr = read_line (cbuf, CBUFSIZE, fpin); /* get cmd line */ - sub_args (cbuf, gbuf, CBUFSIZE, nargs, do_arg); + ocptr = cptr = sim_brk_getact (cbuf, CBUFSIZE); /* get bkpt action */ + if (!ocptr) /* no pending action? */ + ocptr = cptr = read_line (cbuf, CBUFSIZE, fpin); /* get cmd line */ + sub_args (cbuf, gbuf, CBUFSIZE, nargs, do_arg); /* substitute args */ if (cptr == NULL) { /* EOF? */ stat = SCPE_OK; /* set good return */ break; @@ -2169,6 +2175,7 @@ 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? */ @@ -2214,7 +2221,6 @@ for ( ;; ) { /* device loop */ (!(dptr->flags & DEV_NET) || /* not net dev or */ !(uptr->flags & UNIT_ATT) || /* not currently att */ (buf[0] == 0))) { /* or will not be att */ - sim_switches = SIM_SW_REST; /* att-det/rest */ r = scp_detach_unit (dptr, uptr); /* detach old */ if (r != SCPE_OK) return r; if (buf[0] != 0) { /* any file? */ @@ -2232,16 +2238,16 @@ for ( ;; ) { /* device loop */ printf ("Can't restore memory: %s%d\n", sim_dname (dptr), unitno); return SCPE_INCOMP; } - if (high != old_capac) { + if (high != old_capac) { /* size change? */ + uptr->capac = old_capac; /* temp restore old */ if ((dptr->flags & DEV_DYNM) && ((dptr->msize == NULL) || (dptr->msize (uptr, (int32) high, NULL, NULL) != SCPE_OK))) { printf ("Can't change memory size: %s%d\n", sim_dname (dptr), unitno); - uptr->capac = old_capac; return SCPE_INCOMP; } - uptr->capac = high; + uptr->capac = high; /* new memory size */ printf ("Memory size changed: %s%d = ", sim_dname (dptr), unitno); fprint_capac (stdout, dptr, uptr); printf ("\n"); @@ -2382,6 +2388,7 @@ if (sim_step) sim_activate (&sim_step_unit, sim_step); /* set step timer */ sim_throt_sched (); /* set throttle */ sim_is_running = 1; /* flag running */ sim_brk_clract (); /* defang actions */ +sim_rtcn_init_all (); /* re-init clocks */ r = sim_instr(); sim_is_running = 0; /* flag idle */ @@ -3495,6 +3502,7 @@ 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; @@ -3508,6 +3516,7 @@ sim_stab.mask = 0; sim_stab.comp = 0; sim_dfdev = sim_dflt_dev; sim_dfunit = sim_dfdev->units; +dfdu = FALSE; /* no default yet */ *st = SCPE_OK; while (*cptr) { /* loop through modifiers */ svptr = cptr; /* save current position */ @@ -3532,13 +3541,14 @@ 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) && /* if allowed, */ + else if ((opt & CMD_OPT_DFT) && !dfdu && /* if allowed, 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 */ } else return svptr; /* not rec, break out */ } diff --git a/sim_defs.h b/sim_defs.h index a80fba13..4f6e6f9c 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -1,6 +1,6 @@ /* sim_defs.h: simulator definitions - Copyright (c) 1993-2006, Robert M Supnik + Copyright (c) 1993-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"), @@ -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. + 18-Mar-07 RMS Added UNIT_TEXT flag + 07-Mar-07 JDB Added DEBUG_PRJ macro 18-Oct-06 RMS Added limit check for clock synchronized keyboard waits 13-Jul-06 RMS Guarantee CBUFSIZE is at least 256 07-Jan-06 RMS Added support for breakpoint spaces @@ -363,6 +365,7 @@ struct sim_unit { #define UNIT_DISABLE 002000 /* disable-able */ #define UNIT_DIS 004000 /* disabled */ #define UNIT_RAW 010000 /* raw mode */ +#define UNIT_TEXT 020000 /* text mode */ #define UNIT_UFMASK_31 (((1u << UNIT_V_RSV) - 1) & ~((1u << UNIT_V_UF_31) - 1)) #define UNIT_UFMASK (((1u << UNIT_V_RSV) - 1) & ~((1u << UNIT_V_UF) - 1)) @@ -470,6 +473,7 @@ struct sim_debtab { #define DEBUG_PRS(d) (sim_deb && d.dctrl) #define DEBUG_PRD(d) (sim_deb && d->dctrl) #define DEBUG_PRI(d,m) (sim_deb && (d.dctrl & (m))) +#define DEBUG_PRJ(d,m) (sim_deb && (d->dctrl & (m))) /* The following macros define structure contents */ diff --git a/sim_rev.h b/sim_rev.h index 0c22c146..481068a6 100644 --- a/sim_rev.h +++ b/sim_rev.h @@ -1,6 +1,6 @@ /* sim_rev.h: simulator revisions and current rev level - Copyright (c) 1993-2006, Robert M Supnik + Copyright (c) 1993-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"), @@ -29,12 +29,67 @@ #define SIM_MAJOR 3 #define SIM_MINOR 7 -#define SIM_PATCH 0 +#define SIM_PATCH 1 /* V3.7 revision history patch date module(s) and fix(es) + 1 tbd scp.c: + - modified sim_instr invocation to call sim_rtcn_init_all + - fixed bug in get_sim_opt (reported by Don North) + - fixed bug in RESTORE with changed memory size + - added global 'RESTORE in progress' flag + - fixed breakpoint actions in DO command file processing + (from Dave Bryan) + + all CPU's with clocks: + - removed clock initialization (now done in SCP) + + hp2100_cpu.c (from Dave Bryan): + - EDT passes input flag and DMA channel in dat parameter + + hp2100_ipl.c (from Dave Bryan): + - IPLI EDT delays DMA completion interrupt for TSB + + hp2100_mux.c (from Dave Bryan): + - corrected "mux_sta" size from 16 to 21 elements + - fixed "muxc_reset" to clear lines 16-20 + - fixed control card OTx to set current channel number + - fixed to set "muxl_ibuf" in response to a transmit interrupt + - changed "mux_xbuf", "mux_rbuf" declarations from 8 to 16 bits + - fixed to set "mux_rchp" when a line break is received + - fixed incorrect "odd_par" table values + - reversed test in "RCV_PAR" to return "LIL_PAR" on odd parity + - rixed mux reset (ioCRS) to clear port parameters + - fixed to use PUT_DCH instead of PUT_CCH for data channel status + - added DIAG/TERM modifiers to implement diagnostic mode + + pdp11_cpumod.c: + - changed memory size routine to work with RESTORE + + pdp11_hk.c: + - NOP and DCLR (at least) do not check drive type + - MR2 and MR3 only updated on NOP + + pdp10_tu.c, pdp11_tu.c: + - TMK sets FCE only on read (found by Naoki Hamada) + + pdp11_xu.c: + - added missing FC_RMAL command + - cleared multicast on write + + vax_moddefs.h, vax_cpu1.c: + - separated PxBR and SBR mbz checks + + vax780_defs.h + - separated PxBR and SBR mbz checks + - modified mbz checks to reflect 780 microcode patches + (found by Naoki Hamada) + + vax_mmu.c: + - added address masking to all SBR-based memory reads + 0 30-Jan-07 scp.c: - implemented throttle commands - added -e to control error processing in DO command files diff --git a/sim_timer.c b/sim_timer.c index b7ba926c..360319ae 100644 --- a/sim_timer.c +++ b/sim_timer.c @@ -1,6 +1,6 @@ /* sim_timer.c: simulator timer library - Copyright (c) 1993-2006, Robert M Supnik + Copyright (c) 1993-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"), @@ -23,9 +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. + 22-Aug-07 RMS Added sim_rtcn_init_all 17-Oct-06 RMS Added idle support (based on work by Mark Pizzolato) Added throttle support - 21-Aug-05 RMS Added sim_rtcn_init_all 16-Aug-05 RMS Fixed C++ declaration and cast problems 02-Jan-04 RMS Split out from SCP @@ -344,6 +344,16 @@ static int32 rtc_based[SIM_NTIMERS] = { 0 }; /* base delay */ static int32 rtc_currd[SIM_NTIMERS] = { 0 }; /* current delay */ static int32 rtc_initd[SIM_NTIMERS] = { 0 }; /* initial delay */ +void sim_rtcn_init_all (void) +{ +uint32 i; + +for (i = 0; i < SIM_NTIMERS; i++) { + if (rtc_initd[i] != 0) sim_rtcn_init (rtc_initd[i], i); + } +return; +} + int32 sim_rtcn_init (int32 time, int32 tmr) { if (time == 0) time = 1; diff --git a/sim_timer.h b/sim_timer.h index ed0b9279..c7660fd7 100644 --- a/sim_timer.h +++ b/sim_timer.h @@ -1,6 +1,6 @@ /* sim_timer.h: simulator timer library headers - Copyright (c) 1993-2006, Robert M Supnik + Copyright (c) 1993-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"), @@ -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-Apr-07 RMS Added sim_rtc_init_all 17-Oct-06 RMS Added idle support 02-Jan-04 RMS Split out from SCP */ @@ -48,6 +49,7 @@ t_bool sim_timer_init (void); int32 sim_rtcn_init (int32 time, int32 tmr); +void sim_rtcn_init_all (void); int32 sim_rtcn_calb (int32 ticksper, int32 tmr); int32 sim_rtc_init (int32 time); int32 sim_rtc_calb (int32 ticksper);