/* z80 - Z80 emulation Copyright (C) 2021 Ian Cowburn (ianc@noddybox.co.uk) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see ------------------------------------------------------------------------- $Id$ Private macros for Z80 */ #ifndef Z80_PRIVATE_H #define Z80_PRIVATE_H "$Id$" #include "z80_config.h" #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #define MAX_PER_CALLBACK 10 /* ---------------------------------------- TYPES */ struct Z80Private { Z80Val cycle; Z80Val timer[Z80_NO_TIMERS]; int halt; Z80Byte shift; int raise; Z80Byte devbyte; int nmi; #ifndef ENABLE_ARRAY_MEMORY Z80ReadMemory disread; Z80ReadMemory mread; Z80WriteMemory mwrite; #endif Z80ReadPort pread; Z80WritePort pwrite; Z80Callback callback[eZ80_NO_CALLBACK][MAX_PER_CALLBACK]; int last_cb; Z80Reg memptr; }; #define PRIV cpu->priv /* ---------------------------------------- ARRAY MEMORY */ #ifdef ENABLE_ARRAY_MEMORY extern Z80Byte Z80_MEMORY[]; #endif /* ---------------------------------------- MACROS */ /* NOTE: A lot of these macros assume you have a variable called 'cpu' which is a pointer to Z80 */ /* Invoke a callback class */ #define CALLBACK(r,d) do \ { \ int f; \ \ for(f=0;fcallback[r][f]) \ PRIV->last_cb &= \ PRIV->callback[r][f](cpu,d);\ } while(0) /* Flag register */ #define C_Z80 0x01 #define N_Z80 0x02 #define P_Z80 0x04 #define V_Z80 P_Z80 #define H_Z80 0x10 #define Z_Z80 0x40 #define S_Z80 0x80 #define B3_Z80 0x08 #define B5_Z80 0x20 #define HIDDEN_Z80 (B3_Z80|B5_Z80) #define SET(v,b) (v)|=b #define CLR(v,b) (v)&=~(b) #define SETFLAG(f) SET(cpu->AF.b.lo,f) #define CLRFLAG(f) CLR(cpu->AF.b.lo,f) #ifdef ENABLE_ARRAY_MEMORY #define PEEK(addr) Z80_MEMORY[addr] /* This can't be a macro as the macro is used as PEEKW(FETCH_WORD) */ static inline Z80Word PEEKW(Z80Word addr) { return (PEEK(addr) | (Z80Word)PEEK(addr+1)<<8); } #define POKE(addr,val) do \ { \ Z80Word ba=addr; \ if (ba>=RAMBOT && ba<=RAMTOP) \ Z80_MEMORY[ba]=val; \ } while(0) #define POKEW(addr,val) do \ { \ Z80Word wa=addr; \ Z80Word wv=val; \ POKE(wa,wv); \ POKE(wa+1,wv>>8); \ } while(0) #define FETCH_BYTE (Z80_MEMORY[cpu->PC++]) #define FETCH_WORD (cpu->PC+=2, \ Z80_MEMORY[cpu->PC-2]| \ ((Z80Word)Z80_MEMORY[cpu->PC-1]<<8)) #else Z80Word FPEEKW(Z80 *cpu, Z80Word addr); void FPOKEW(Z80 *cpu, Z80Word addr, Z80Word val); #define PEEK(addr) (PRIV->mread(cpu,addr)) #define PEEKW(addr) FPEEKW(cpu,addr) #define POKE(addr,val) PRIV->mwrite(cpu,addr,val) #define POKEW(addr,val) FPOKEW(cpu,addr,val) #define FETCH_BYTE (PRIV->mread(cpu,cpu->PC++)) #define FETCH_WORD (cpu->PC+=2,FPEEKW(cpu,cpu->PC-2)) #endif #define IS_C (cpu->AF.b.lo&C_Z80) #define IS_N (cpu->AF.b.lo&N_Z80) #define IS_P (cpu->AF.b.lo&P_Z80) #define IS_H (cpu->AF.b.lo&H_Z80) #define IS_Z (cpu->AF.b.lo&Z_Z80) #define IS_S (cpu->AF.b.lo&S_Z80) #define CARRY IS_C #define IS_IX_IY (PRIV->shift==0xdd || PRIV->shift==0xfd) #define OFFSET(base,off) do \ { \ if (IS_IX_IY) \ { \ off=(Z80Relative)FETCH_BYTE; \ PRIV->memptr.w=base+off; \ } \ else \ { \ off=0; \ } \ } while(0) #define TSTATE(n) do \ { \ PRIV->cycle+=n; \ PRIV->timer[Z80_TIMER_1]+=n; \ PRIV->timer[Z80_TIMER_2]+=n; \ PRIV->timer[Z80_TIMER_3]+=n; \ } while(0) #define ADD_R(v) cpu->R=((cpu->R&0x80)|((cpu->R+(v))&0x7f)) #define INC_R ADD_R(1) #ifdef ENABLE_ARRAY_MEMORY #define PUSH(REG) do \ { \ Z80Word pv=REG; \ cpu->SP-=2; \ POKE(cpu->SP,pv); \ POKE(cpu->SP+1,pv>>8); \ } while(0) #else #define PUSH(REG) do \ { \ Z80Word pushv=REG; \ cpu->SP-=2; \ PRIV->mwrite(cpu,cpu->SP,pushv); \ PRIV->mwrite(cpu,cpu->SP+1,pushv>>8);\ } while(0) #endif #define POP(REG) do \ { \ REG=PEEK(cpu->SP) | \ (Z80Word)PEEK(cpu->SP+1)<<8; \ cpu->SP+=2; \ } while(0) #define SETHIDDEN(res) cpu->AF.b.lo=(cpu->AF.b.lo&~(B3_Z80|B5_Z80))|\ ((res)&(B3_Z80|B5_Z80)) #define CALL do \ { \ PUSH(cpu->PC+2); \ cpu->PC=PEEKW(cpu->PC); \ PRIV->memptr.w=cpu->PC; \ } while(0) #define NOCALL cpu->PC+=2 #define JP do \ { \ cpu->PC=PEEKW(cpu->PC); \ PRIV->memptr.w=cpu->PC; \ } while(0) #define NOJP NOCALL #define JR do \ { \ cpu->PC+=(Z80Relative)PEEK(cpu->PC)+1; \ PRIV->memptr.w=cpu->PC; \ } while(0) #define NOJR cpu->PC++ #define OUT(P,V) do \ { \ if (PRIV->pwrite) \ PRIV->pwrite(cpu,P,V); \ } while(0) #define IN(P) (PRIV->pread?PRIV->pread(cpu,P):0) /* ---------------------------------------- LABELS */ extern Z80Label *z80_labels; /* ---------------------------------------- GLOBAL GENERAL OPCODES/ROUTINES */ void Z80_Decode(Z80 *cpu, Z80Byte opcode); void Z80_InitialiseInternals(void); /* ---------------------------------------- DISASSEMBLY */ #ifdef ENABLE_DISASSEM typedef void (*DIS_OP_CALLBACK)(Z80 *z80, Z80Byte op, Z80Word *pc); extern DIS_OP_CALLBACK dis_CB_opcode[]; extern DIS_OP_CALLBACK dis_DD_opcode[]; extern DIS_OP_CALLBACK dis_DD_CB_opcode[]; extern DIS_OP_CALLBACK dis_ED_opcode[]; extern DIS_OP_CALLBACK dis_FD_opcode[]; extern DIS_OP_CALLBACK dis_FD_CB_opcode[]; extern DIS_OP_CALLBACK dis_opcode_z80[]; const char *Z80_Dis_Printf(const char *format, ...); Z80Byte Z80_Dis_FetchByte(Z80 *cpu, Z80Word *pc); Z80Word Z80_Dis_FetchWord(Z80 *cpu, Z80Word *pc); void Z80_Dis_Set(const char *op, const char *arg); const char *Z80_Dis_GetOp(void); const char *Z80_Dis_GetArg(void); #endif /* ENABLE_DISASSEM */ #endif /* Z80_PRIVATE_H */ /* END OF FILE */