📄 z80.c
字号:
/*****************************************************************************
*
* z80.c
* Portable Z80 emulator V2.7
*
* Copyright (C) 1998,1999,2000 Juergen Buchmueller, all rights reserved.
*
* - This source code is released as freeware for non-commercial purposes.
* - You are free to use and redistribute this code in modified or
* unmodified form, provided you list me in the credits.
* - If you modify this source code, you must add a notice to each modified
* source file that it has been changed. If you're a nice person, you
* will clearly mark each change too. :)
* - If you wish to use this for commercial purposes, please contact me at
* pullmoll@t-online.de
* - The author of this copywritten work reserves the right to change the
* terms of its usage and license at any time, including retroactively
* - This entire notice must remain in the source code.
*
* Changes in 2.7:
* - removed z80_vm specific code, it's not needed (and never was).
* Changes in 2.6:
* - BUSY_LOOP_HACKS needed to call change_pc16() earlier, before
* checking the opcodes at the new address, because otherwise they
* might access the old (wrong or even NULL) banked memory region.
* Thanks to Sean Young for finding this nasty bug.
* Changes in 2.5:
* - Burning cycles always adjusts the ICount by a multiple of 4.
* - In REPEAT_AT_ONCE cases the R register wasn't incremented twice
* per repetition as it should have been. Those repeated opcodes
* could also underflow the ICount.
* - Simplified TIME_LOOP_HACKS for BC and added two more for DE + HL
* timing loops. I think those hacks weren't endian safe before too.
* Changes in 2.4:
* - z80_reset zaps the entire context, sets IX and IY to 0xffff(!) and
* sets the Z flag. With these changes the Tehkan World Cup driver
* _seems_ to work again.
* Changes in 2.3:
* - External termination of the execution loop calls z80_burn() and
* z80_vm_burn() to burn an amount of cycles (R adjustment)
* - Shortcuts which burn CPU cycles (BUSY_LOOP_HACKS and TIME_LOOP_HACKS)
* now also adjust the R register depending on the skipped opcodes.
* Changes in 2.2:
* - Fixed bugs in CPL, SCF and CCF instructions flag handling.
* - Changed variable EA and ARG16() function to UINT32; this
* produces slightly more efficient code.
* - The DD/FD XY CB opcodes where XY is 40-7F and Y is not 6/E
* are changed to calls to the X6/XE opcodes to reduce object size.
* They're hardly ever used so this should not yield a speed penalty.
* New in 2.0:
* - Optional more exact Z80 emulation (#define Z80_EXACT 1) according
* to a detailed description by Sean Young which can be found at:
* http://www.msxnet.org/tech/Z80/z80undoc.txt
*****************************************************************************/
#include "cpuintrf.h"
#include "z80.h"
#include "..\shared.h"
extern void cpu_writemem16(int address, int data);
extern void cpu_writeport(int port, int data);
extern int cpu_readport(int port);
unsigned char *cpu_readmap[8];
unsigned char *cpu_writemap[8];
#define cpu_readmem16(a) cpu_readmap[(a) >> 13][(a) & 0x1FFF]
#define cpu_readop(a) cpu_readmap[(a) >> 13][(a) & 0x1FFF]
#define cpu_readop_arg(a) cpu_readmap[(a) >> 13][(a) & 0x1FFF]
/* execute main opcodes inside a big switch statement */
#ifndef BIG_SWITCH
#define BIG_SWITCH 1
#endif
/* big flags array for ADD/ADC/SUB/SBC/CP results */
#define BIG_FLAGS_ARRAY 1
/* Set to 1 for a more exact (but somewhat slower) Z80 emulation */
#define Z80_EXACT 1
/* repetitive commands (ldir,cpdr etc.) repeat at
once until cycles used up or B(C) counted down. */
#define REPEAT_AT_ONCE 1
/* on JP and JR opcodes check for tight loops */
#define BUSY_LOOP_HACKS 1
/* check for delay loops counting down BC */
#define TIME_LOOP_HACKS 1
#ifdef X86_ASM
#undef BIG_FLAGS_ARRAY
#define BIG_FLAGS_ARRAY 0
#endif
#ifdef PSX
#undef BIG_FLAGS_ARRAY
#define BIG_FLAGS_ARRAY 0
#endif
#define CF 0x01
#define NF 0x02
#define PF 0x04
#define VF PF
#define XF 0x08
#define HF 0x10
#define YF 0x20
#define ZF 0x40
#define SF 0x80
#define INT_IRQ 0x01
#define NMI_IRQ 0x02
#define _PPC Z80.PREPC.d /* previous program counter */
#define _PCD Z80.PC.d
#define _PC Z80.PC.w.l
#define _SPD Z80.SP.d
#define _SP Z80.SP.w.l
#define _AFD Z80.AF.d
#define _AF Z80.AF.w.l
#define _A Z80.AF.b.h
#define _F Z80.AF.b.l
#define _BCD Z80.BC.d
#define _BC Z80.BC.w.l
#define _B Z80.BC.b.h
#define _C Z80.BC.b.l
#define _DED Z80.DE.d
#define _DE Z80.DE.w.l
#define _D Z80.DE.b.h
#define _E Z80.DE.b.l
#define _HLD Z80.HL.d
#define _HL Z80.HL.w.l
#define _H Z80.HL.b.h
#define _L Z80.HL.b.l
#define _IXD Z80.IX.d
#define _IX Z80.IX.w.l
#define _HX Z80.IX.b.h
#define _LX Z80.IX.b.l
#define _IYD Z80.IY.d
#define _IY Z80.IY.w.l
#define _HY Z80.IY.b.h
#define _LY Z80.IY.b.l
#define _I Z80.I
#define _R Z80.R
#define _R2 Z80.R2
#define _IM Z80.IM
#define _IFF1 Z80.IFF1
#define _IFF2 Z80.IFF2
#define _HALT Z80.HALT
int z80_ICount;
static Z80_Regs Z80;
Z80_Regs *Z80_Context = &Z80;
static UINT32 EA;
int after_EI = 0;
static UINT8 SZ[256]; /* zero and sign flags */
static UINT8 SZ_BIT[256]; /* zero, sign and parity/overflow (=zero) flags for BIT opcode */
static UINT8 SZP[256]; /* zero, sign and parity flags */
static UINT8 SZHV_inc[256]; /* zero, sign, half carry and overflow flags INC r8 */
static UINT8 SZHV_dec[256]; /* zero, sign, half carry and overflow flags DEC r8 */
#include "z80daa.h"
#if BIG_FLAGS_ARRAY
#include <signal.h>
static UINT8 *SZHVC_add = 0;
static UINT8 *SZHVC_sub = 0;
#endif
#if Z80_EXACT
/* tmp1 value for ini/inir/outi/otir for [C.1-0][io.1-0] */
static UINT8 irep_tmp1[4][4] = {
{0,0,1,0},{0,1,0,1},{1,0,1,1},{0,1,1,0}
};
/* tmp1 value for ind/indr/outd/otdr for [C.1-0][io.1-0] */
static UINT8 drep_tmp1[4][4] = {
{0,1,0,0},{1,0,0,1},{0,0,1,0},{0,1,0,1}
};
/* tmp2 value for all in/out repeated opcodes for B.7-0 */
static UINT8 breg_tmp2[256] = {
0,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,
0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,
1,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,
1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,
0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,
1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,
0,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,
0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,
1,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,
1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,
0,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,
0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,
1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,
0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,
1,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,
1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1
};
#endif
static UINT8 cc_op[0x100] = {
4,10, 7, 6, 4, 4, 7, 4, 4,11, 7, 6, 4, 4, 7, 4,
8,10, 7, 6, 4, 4, 7, 4,12,11, 7, 6, 4, 4, 7, 4,
7,10,16, 6, 4, 4, 7, 4, 7,11,16, 6, 4, 4, 7, 4,
7,10,13, 6,11,11,10, 4, 7,11,13, 6, 4, 4, 7, 4,
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
7, 7, 7, 7, 7, 7, 4, 7, 4, 4, 4, 4, 4, 4, 7, 4,
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
4, 4, 4, 4, 4, 4, 7, 4, 4, 4, 4, 4, 4, 4, 7, 4,
5,10,10,10,10,11, 7,11, 5, 4,10, 0,10,10, 7,11,
5,10,10,11,10,11, 7,11, 5, 4,10,11,10, 0, 7,11,
5,10,10,19,10,11, 7,11, 5, 4,10, 4,10, 0, 7,11,
5,10,10, 4,10,11, 7,11, 5, 6,10, 4,10, 0, 7,11};
static UINT8 cc_cb[0x100] = {
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
8, 8, 8, 8, 8, 8,12, 8, 8, 8, 8, 8, 8, 8,12, 8,
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8,
8, 8, 8, 8, 8, 8,15, 8, 8, 8, 8, 8, 8, 8,15, 8};
static UINT8 cc_dd[0x100] = {
4, 4, 4, 4, 4, 4, 4, 4, 4,15, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4,15, 4, 4, 4, 4, 4, 4,
4,14,20,10, 9, 9, 9, 4, 4,15,20,10, 9, 9, 9, 4,
4, 4, 4, 4,23,23,19, 4, 4,15, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 9, 9,19, 4, 4, 4, 4, 4, 9, 9,19, 4,
4, 4, 4, 4, 9, 9,19, 4, 4, 4, 4, 4, 9, 9,19, 4,
9, 9, 9, 9, 9, 9,19, 9, 9, 9, 9, 9, 9, 9,19, 9,
19,19,19,19,19,19, 4,19, 4, 4, 4, 4, 9, 9,19, 4,
4, 4, 4, 4, 9, 9,19, 4, 4, 4, 4, 4, 9, 9,19, 4,
4, 4, 4, 4, 9, 9,19, 4, 4, 4, 4, 4, 9, 9,19, 4,
4, 4, 4, 4, 9, 9,19, 4, 4, 4, 4, 4, 9, 9,19, 4,
4, 4, 4, 4, 9, 9,19, 4, 4, 4, 4, 4, 9, 9,19, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4,14, 4,23, 4,15, 4, 4, 4, 8, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4,10, 4, 4, 4, 4, 4, 4};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -