📄 zz80.c
字号:
/* z80stb.c * Zilog Z80 processor emulator in C. Modified to be API compliant with Neil * Bradley's MZ80 (for ported projects) * Ported to 'C' by Jeff Mitchell; original copyright follows: * * Abstract: * Internal declarations for Zilog Z80 emulator. * * Revisions: * 18-Apr-97 EAM Created * ??-???-97 EAM Released in MageX 0.5 * 26-Jul-97 EAM Fixed Time Pilot slowdown bug and * Gyruss hiscore bugs (opcode 0xC3) * * Original copyright (C) 1997 Edward Massey */// Dave#define FALSE 0#define TRUE 1#define HOST_TO_LE16 /**/#include <stdio.h>#include <stdlib.h>#include <assert.h>#include "mz80.h"#include "z80stb.h"/* *************************************************************************** * Edward's Internals (so to speak) * *************************************************************************** */#define _ASSERT assertULONG m_cRef; // reference countunion { /* WARN: Endianness! */ WORD m_regAF; struct {#ifdef BIG_ENDIAN BYTE m_regA; BYTE m_regF;#else BYTE m_regF; BYTE m_regA;#endif } regAFs;} regAF;#define m_regAF regAF.m_regAF#define m_regF regAF.regAFs.m_regF#define m_regA regAF.regAFs.m_regAunion { /* WARN: Endianness! */ WORD m_regBC; struct {#ifdef BIG_ENDIAN BYTE m_regB; BYTE m_regC;#else BYTE m_regC; BYTE m_regB;#endif } regBCs;} regBC;#define m_regBC regBC.m_regBC#define m_regB regBC.regBCs.m_regB#define m_regC regBC.regBCs.m_regCunion { /* WARN: Endianness! */ WORD m_regDE; struct {#ifdef BIG_ENDIAN BYTE m_regD; BYTE m_regE;#else BYTE m_regE; BYTE m_regD;#endif } regDEs;} regDE;#define m_regDE regDE.m_regDE#define m_regD regDE.regDEs.m_regD#define m_regE regDE.regDEs.m_regEunion { /* WARN: Endianness! */ WORD m_regHL; struct {#ifdef BIG_ENDIAN BYTE m_regH; BYTE m_regL;#else BYTE m_regL; BYTE m_regH;#endif } regHLs;} regHL;#define m_regHL regHL.m_regHL#define m_regH regHL.regHLs.m_regH#define m_regL regHL.regHLs.m_regLunion { /* WARN: Endianness! */ WORD m_regIX; struct {#ifdef BIG_ENDIAN BYTE m_regIXh; BYTE m_regIXl;#else BYTE m_regIXl; BYTE m_regIXh;#endif } regIXs;} regIX;#define m_regIX regIX.m_regIX#define m_regIXl regIX.regIXs.m_regIXl#define m_regIXh regIX.regIXs.m_regIXhunion { WORD m_regIY; struct {#ifdef BIG_ENDIAN BYTE m_regIYh; BYTE m_regIYl;#else BYTE m_regIYl; BYTE m_regIYh;#endif } regIYs;} regIY;#define m_regIY regIY.m_regIY#define m_regIYl regIY.regIYs.m_regIYl#define m_regIYh regIY.regIYs.m_regIYhconst BYTE *m_rgbOpcode; // takes place of the PC registerLPBYTE m_rgbStack; // takes place of the SP registerLPBYTE m_rgbMemory; // direct access to memory buffer (RAM)const BYTE *m_rgbOpcodeBase; // "base" pointer for m_rgbOpcodeLPBYTE m_rgbStackBase;static int cCycles = 0;BYTE m_regR; // consider: should be int for performance?BYTE m_regI; // consider: combine into// TODO: combine into a single int...int m_iff1, m_iff2;BOOL m_fHalt;int m_nIM;BOOL m_fPendingInterrupt = FALSE;WORD m_regAF2;static WORD m_regBC2;static WORD m_regDE2;static WORD m_regHL2;WORD z80intAddr = 0x38;WORD z80nmiAddr = 0x66;/* *************************************************************************** * Pre-calculated math tables and junk (sucked from Marat and Edward) * *************************************************************************** */void InitTables (void);BYTE ZSTable[256];BYTE ZSPTable[256];BYTE rgfAdd[256][256];BYTE rgfSub[256][256];BYTE rgfAddc[256][256][2];BYTE rgfSubc[256][256][2];BYTE rgfInc[256];BYTE rgfDec[256];BYTE rgfBit[256][8];static UINT32 dwElapsedTicks = 0;/* #include "z80daa.h" */#include "z80stbd.h"/* *************************************************************************** * Retrocade guts stuff * *************************************************************************** */static struct MemoryReadByte *z80MemoryRead = NULL;static struct MemoryWriteByte *z80MemoryWrite = NULL;static struct z80PortRead *z80IoRead = NULL;static struct z80PortWrite *z80IoWrite = NULL;WORD z80pc = 0;/* *************************************************************************** * Retrocade interface follows * *************************************************************************** *//* reset registers, interrupts, memory read/write memory handlers, * port read and writing handlers, etc. */void mz80reset(void) { InitTables(); m_fPendingInterrupt = FALSE; m_rgbOpcodeBase = m_rgbMemory; /* m_rgbMemory = */ m_rgbStackBase = m_rgbMemory; m_regAF = 0; m_regBC = 0; m_regDE = 0; m_regHL = 0; m_regAF2 = 0; m_regBC2 = 0; m_regDE2 = 0; m_regHL2 = 0; m_regR = rand(); m_regI = 0; m_fHalt = FALSE; m_nIM = 0; m_regIX = 0xffff; // Yes, this intentional, and the way a Z80 comes m_regIY = 0xffff; // up in power-on state! m_iff1 = 0; m_iff2 = 0; z80intAddr = 0x38; z80nmiAddr = 0x66; SetPC(0x0000); SetSP(0x0000);#if 0 fprintf ( stderr, "Reset\n" );#endif}/* UINT32 mz80int(UINT32 a) { * return ( Irq ( (BYTE) ( a & 0xFF ) ) ); * } *//* UINT32 mz80nmi(void) { * return ( Nmi() ); * } *//* *************************************************************************** * Edward Memory Handlers (guesses) * *************************************************************************** */#define ImmedByte() *m_rgbOpcode++/* static */ UINT16 ImmedWord ( void ) { WORD w = HOST_TO_LE16(*(WORD*)m_rgbOpcode); m_rgbOpcode += 2; return w; // attn: little endian specific}#define GetPC() ( (WORD)(m_rgbOpcode - m_rgbOpcodeBase) )void SetPC ( WORD wAddr ) { m_rgbOpcode = &m_rgbOpcodeBase[wAddr];}void AdjustPC ( signed char cb ) { m_rgbOpcode += cb;}void Push(WORD wArg) { MemWriteByte(--m_rgbStack - m_rgbStackBase, HIBYTE(wArg)); MemWriteByte(--m_rgbStack - m_rgbStackBase, LOBYTE(wArg));}WORD Pop() { unsigned short wAddr = 0; wAddr = MemReadByte(m_rgbStack++ - m_rgbStackBase); wAddr |= (MemReadByte(m_rgbStack++ - m_rgbStackBase) << 8); return(wAddr);}WORD GetSP() { return (WORD)(m_rgbStack - m_rgbStackBase);}void SetSP(WORD wAddr) { m_rgbStack = &m_rgbStackBase[wAddr];}/* static */ UINT8 mz80GetMemory ( UINT16 addr ) { struct MemoryReadByte *mr = z80MemoryRead; z80pc = GetPC(); /* for some of the platforms */ while ( mr -> lowAddr != 0xffffffff ) { if (addr >= mr->lowAddr && addr <= mr->highAddr) { z80pc = GetPC(); return ( mr -> memoryCall ( addr, mr ) ); } ++mr; } return ( m_rgbMemory [ addr ] );}/* static */ void mz80PutMemory ( unsigned short int addr, unsigned char byte ) { struct MemoryWriteByte *mr = z80MemoryWrite; while ( mr->lowAddr != 0xffffffff ) { if (addr >= mr->lowAddr && addr <= mr->highAddr) { z80pc = GetPC(); mr->memoryCall(addr, byte, mr); return; } mr++; } m_rgbMemory [ addr ] = byte;}BYTE In(BYTE bPort) { BYTE bVal; // BYTE bVal = m_rgpfnPortRead[bPort](bPort); struct z80PortRead *mr = z80IoRead; z80pc = GetPC(); /* for some of the platforms */ while ( mr->lowIoAddr != 0xffff ) { if ( bPort >= mr->lowIoAddr && bPort <= mr->highIoAddr) { bVal = mr->IOCall ( bPort, mr ); break; } mr++; } m_regF = (m_regF & C_FLAG) | ZSPTable[bVal]; return bVal;}BYTE InRaw (BYTE bPort) { BYTE bVal; struct z80PortRead *mr = z80IoRead; z80pc = GetPC(); /* for some of the platforms */ while ( mr->lowIoAddr != 0xffff ) { if ( bPort >= mr->lowIoAddr && bPort <= mr->highIoAddr) { bVal = mr->IOCall ( bPort, mr ); break; } mr++; } // m_regF = (m_regF & C_FLAG) | ZSPTable[bVal]; return bVal;}void Out(BYTE bPort, BYTE bVal) { // m_rgpfnPortWrite[bPort](bPort, bVal); struct z80PortWrite *mr = z80IoWrite; z80pc = GetPC(); /* for some of the platforms */ while ( mr->lowIoAddr != 0xffff ) { if (bPort >= mr->lowIoAddr && bPort <= mr->highIoAddr) { mr->IOCall ( bPort, bVal, mr ); return; } mr++; }}/* static */ void MemWriteWord ( UINT16 wAddr, UINT16 wVal ) { MemWriteByte ( wAddr++, LOBYTE ( wVal ) ); MemWriteByte ( wAddr, HIBYTE ( wVal ) );}/* static */ /* inline */ void MemWriteByte ( UINT16 wAddr, UINT8 bVal ) { mz80PutMemory ( wAddr, bVal );}/* static */ /* inline */ UINT8 MemReadByte ( UINT16 wAddr ) { return ( mz80GetMemory ( wAddr ) );}/* static */ /* inline */ UINT16 MemReadWord ( UINT16 wAddr ) { UINT8 op1; UINT8 op2; op1 = MemReadByte(wAddr ++); op2 = MemReadByte(wAddr); return ( MAKEWORD ( op1, op2 ) );}/* *************************************************************************** * Retrocade guts stuff (again) (these guys are defined after macros) * *************************************************************************** */unsigned long int mz80GetContextSize(void) { return ( sizeof ( CONTEXTMZ80 ) );}/* set memory base, etc. */void mz80GetContext ( void *receiver ) { CONTEXTMZ80 *c = receiver; c -> z80MemRead = z80MemoryRead; c -> z80MemWrite = z80MemoryWrite; c -> z80Base = (UINT8 *) m_rgbOpcodeBase; c -> z80IoRead = z80IoRead; c -> z80IoWrite = z80IoWrite; c -> z80af = m_regAF; c -> z80bc = m_regBC; c -> z80de = m_regDE; c -> z80hl = m_regHL; c -> z80afprime = m_regAF2; c -> z80bcprime = m_regBC2; c -> z80deprime = m_regDE2; c -> z80hlprime = m_regHL2; c -> z80ix = m_regIX; c -> z80iy = m_regIY; c -> z80sp = GetSP(); c -> z80pc = GetPC(); c -> z80i = m_regI; c -> z80r = m_regR; c -> z80intAddr = z80intAddr; c -> z80nmiAddr = z80nmiAddr; c -> z80inInterrupt = m_iff1; c -> z80interruptMode = m_nIM; c -> z80interruptState = m_iff2; c -> z80halted = m_fHalt; #if 0 fprintf ( stderr, "GetContext\n" );#endif}void mz80SetContext( void *sender ) { CONTEXTMZ80 *c = sender; z80MemoryRead = c -> z80MemRead; z80MemoryWrite = c -> z80MemWrite; m_rgbMemory = c -> z80Base; z80IoRead = c -> z80IoRead; z80IoWrite = c -> z80IoWrite; m_regAF = c -> z80af; m_regBC = c -> z80bc; m_regDE = c -> z80de; m_regHL = c -> z80hl; m_regAF2 = c -> z80afprime; m_regBC2 = c -> z80bcprime; m_regDE2 = c -> z80deprime; m_regHL2 = c -> z80hlprime; m_regIX = c -> z80ix; m_regIY = c -> z80iy; m_regI = c -> z80i; m_regR = c -> z80r; z80intAddr = c -> z80intAddr; z80nmiAddr = c -> z80nmiAddr; m_rgbOpcodeBase = m_rgbMemory; m_iff1 = c->z80inInterrupt; m_iff2 = c->z80interruptState; m_nIM = c->z80interruptMode; m_fHalt = c->z80halted; SetPC ( c -> z80pc ); SetSP ( c -> z80sp );#if 0 fprintf ( stderr, "SetContext\n" );#endif}/* *************************************************************************** * Z80 Please-inline-my-ass opcodes * *************************************************************************** *//* inline */ int Ret0(int f){ if (f) { SetPC(Pop()); return 6; } else { return 0; }}/* inline */ int Ret1(int f){ if (f) { return 0; } else { SetPC(Pop()); return 6; }}/* inline */ WORD Adc_2 (WORD wArg1, WORD wArg2){#ifdef ARITH_TABLES int q = wArg1 + wArg2 + (m_regF & C_FLAG); m_regF = (((wArg1^q^wArg2)&0x1000)>>8)|((q>>16)&1)|((q&0x8000)>>8)|((q&65535)?0:Z_FLAG)|(((wArg2^wArg1^0x8000)&(wArg2^q)&0x8000)>>13); return q;#else int q = wArg1 + wArg2 + (m_regF & C_FLAG); m_regF = (((wArg1^q^wArg2)&0x1000)>>8)|((q>>16)&1)|((q&0x8000)>>8)|((q&65535)?0:Z_FLAG)|(((wArg2^wArg1^0x8000)&(wArg2^q)&0x8000)>>13); return q;#endif}/* inline */ WORD Sbc_2 (WORD wArg1, WORD wArg2){#ifdef ARITH_TABLES int q = wArg1 - wArg2 - (m_regF & C_FLAG); m_regF = (((wArg1^q^wArg2)&0x1000)>>8)|((q>>16)&1)|((q&0x8000)>>8)| ((q&65535)?0:Z_FLAG)|(((wArg1^wArg2)&(wArg1^q)&0x8000)>>13)|N_FLAG; return q;#else int q = wArg1 - wArg2 - (m_regF & C_FLAG); m_regF = (((wArg1^q^wArg2)&0x1000)>>8)|((q>>16)&1)|((q&0x8000)>>8)| ((q&65535)?0:Z_FLAG)|(((wArg1^wArg2)&(wArg1^q)&0x8000)>>13)|N_FLAG; return q;#endif}/* inline */ WORD Add_2 (WORD wArg1, WORD wArg2){#ifdef ARITH_TABLES int q = wArg1 + wArg2; m_regF = (m_regF&(S_FLAG|Z_FLAG|V_FLAG))|(((wArg1^q^wArg2)&0x1000)>>8)|((q>>16)&1); return q;#else int q = wArg1 + wArg2; m_regF = (m_regF&(S_FLAG|Z_FLAG|V_FLAG))|(((wArg1^q^wArg2)&0x1000)>>8)|((q>>16)&1); return q;#endif}/* inline */ void Add_1 (BYTE bArg){#ifdef ARITH_TABLES int q = m_regA + bArg; m_regF = rgfAdd[m_regA][bArg]; m_regA = q;#else int q = m_regA + bArg; m_regF=ZSTable[q&255]|((q&256)>>8)| ((m_regA^q^bArg)&H_FLAG)| (((bArg^m_regA^0x80)&(bArg^q)&0x80)>>5); m_regA=q;#endif}/* inline */ void Adc_1 (BYTE bArg){#ifdef ARITH_TABLES int q = m_regA + bArg + (m_regF & C_FLAG); m_regF = rgfAddc[m_regA][bArg][m_regF & C_FLAG]; m_regA = q;#else int q = m_regA + bArg + (m_regF & C_FLAG); m_regF = ZSTable[q & 255]|((q & 256)>>8)|((m_regA^q^bArg)&H_FLAG)|(((bArg^m_regA^0x80)&(bArg^q)&0x80)>>5); m_regA = q;#endif}/* inline */ void Sub_1 (BYTE bArg){#ifdef ARITH_TABLES int q = m_regA - bArg; m_regF = rgfSub[m_regA][bArg]; m_regA = q;#else int q = m_regA - bArg; m_regF = ZSTable[q&255]|((q&256)>>8)|N_FLAG|((m_regA^q^bArg)&H_FLAG)|(((bArg^m_regA)&(m_regA^q)&0x80)>>5); m_regA = q;#endif}/* inline */ void Sbc_1 (BYTE bArg){#ifdef ARITH_TABLES int q = m_regA - bArg - (m_regF & C_FLAG); m_regF = rgfSubc[m_regA][bArg][m_regF & C_FLAG]; m_regA = q;#else int q = m_regA - bArg - (m_regF & C_FLAG); m_regF=ZSTable[q&255]|((q&256)>>8)|N_FLAG|((m_regA^q^bArg)&H_FLAG)|(((bArg^m_regA)&(bArg^q)&0x80)>>5); m_regA=q;#endif}/* inline */ void And (BYTE bArg){ m_regF = ZSPTable[m_regA &= bArg] | H_FLAG;}/* inline */ void Or(BYTE bArg){ m_regF = ZSPTable[m_regA |= bArg];}/* inline */ void Xor(BYTE bArg){ m_regF = ZSPTable[m_regA ^= bArg];}/* inline */ void Cp(BYTE bArg){#ifdef ARITH_TABLES int q = m_regA - bArg; m_regF = rgfSub[m_regA][bArg];#else int q = m_regA - bArg; m_regF = ZSTable[q&255]|((q&256)>>8)|N_FLAG|((m_regA^q^bArg)&H_FLAG)|(((bArg^m_regA)&(bArg^q)&0x80)>>5);#endif}/* inline */ static BYTE Inc(BYTE bArg){#ifdef ARITH_TABLES bArg++; m_regF = (m_regF & C_FLAG) | rgfInc[bArg]; return bArg;#else bArg++; m_regF = (m_regF&C_FLAG)|ZSTable[bArg]|((bArg==0x80)?V_FLAG:0)|((bArg&0x0F)?0:H_FLAG); return bArg;#endif}/* inline */ static BYTE Dec(BYTE bArg){#ifdef ARITH_TABLES m_regF = (m_regF & C_FLAG) | rgfDec[bArg--]; return bArg;#else m_regF=(m_regF&C_FLAG)|N_FLAG| ((bArg==0x80)?V_FLAG:0)|((bArg&0x0F)?0:H_FLAG); m_regF|=ZSTable[--bArg]; return bArg;#endif}// shouldn't even be members.../* inline */ BYTE Set(BYTE bArg, int nBit){ return (bArg | (1 << nBit));}/* inline */ BYTE Res(BYTE bArg, int nBit){ return (bArg & ~(1 << nBit));}/* inline */ void Bit(BYTE bArg, int nBit){#ifdef ARITH_TABLES m_regF = (m_regF & C_FLAG) | rgfBit[bArg][nBit];#else m_regF = (m_regF & C_FLAG) | H_FLAG | ((bArg&(1<< nBit))? ((nBit==7)?S_FLAG:0):Z_FLAG);#endif}/* inline */ BYTE Rlc(BYTE bArg){ int q = bArg >> 7; bArg = (bArg << 1) | q; m_regF = ZSPTable[bArg] | q; return bArg;}/* inline */ BYTE Rrc(BYTE bArg){ int q = bArg & 1; bArg = (bArg >> 1) | (q << 7); m_regF = ZSPTable[bArg]|q; return bArg;}/* inline */ BYTE Rl(BYTE bArg){ int q=bArg>>7; bArg=(bArg<<1)|(m_regF&1); m_regF=ZSPTable[bArg]|q; return bArg;}/* inline */ BYTE Rr(BYTE bArg){ int q = bArg&1; bArg=(bArg>>1)|(m_regF<<7); m_regF=ZSPTable[bArg]|q; return bArg;}/* inline */ BYTE Sll(BYTE bArg){ int q = bArg>>7; bArg=(bArg<<1)|1; m_regF=ZSPTable[bArg]|q; return bArg;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -