// license:BSD-3-Clause // copyright-holders:Juergen Buchmueller /*************************************************************** * Enter HALT state; write 1 to fake port on first execution ***************************************************************/ #define ENTER_HALT() { \ _PC--; \ m_HALT = 1; \ } /*************************************************************** * Leave HALT state; write 0 to fake port ***************************************************************/ #define LEAVE_HALT() { \ if( m_HALT ) \ { \ m_HALT = 0; \ _PC++; \ } \ } /*************************************************************** * Input a byte from given I/O port ***************************************************************/ inline u8 z180_device::IN(u16 port) { if (is_internal_io_address(port)) return z180_readcontrol(port); m_extra_cycles += io_wait_states(); return m_io.read_byte(port); } /*************************************************************** * Output a byte to given I/O port ***************************************************************/ inline void z180_device::OUT(u16 port, u8 value) { if (is_internal_io_address(port)) z180_writecontrol(port,value); else { m_extra_cycles += io_wait_states(); m_io.write_byte(port, value); } } /*************************************************************** * MMU calculate the memory management lookup table * bb and cb specify a 4K page * If the 4 most significant bits of an 16 bit address are * greater or equal to the bank base, the bank base register * specifies the 4K offset into the 20 bit address space. * If the 4 bits are also greater or equal to the common base, * the common base register is used to specify the offset. ***************************************************************/ void z180_device::z180_mmu() { offs_t addr, page, bb, cb; bb = m_mmu_cbar & 15; cb = m_mmu_cbar >> 4; for( page = 0; page < 16; page++ ) { addr = page << 12; if (page >= bb) { if (page >= cb) addr += (m_mmu_cbr << 12); else addr += (m_mmu_bbr << 12); } m_mmu[page] = (addr & 0xfffff); } } #define MMU_REMAP_ADDR(addr) (m_mmu[((addr)>>12)&15]|((addr)&4095)) /*************************************************************** * Read a byte from given memory location ***************************************************************/ inline u8 z180_device::RM(offs_t addr) { m_extra_cycles += memory_wait_states(); return z180_read_memory(MMU_REMAP_ADDR(addr)); } /*************************************************************** * Write a byte to given memory location ***************************************************************/ #define WM(addr,value) m_extra_cycles += memory_wait_states(); z180_write_memory(MMU_REMAP_ADDR(addr),value) /*************************************************************** * Read a word from given memory location ***************************************************************/ void z180_device::RM16( offs_t addr, PAIR *r ) { r->b.l = RM(addr); r->b.h = RM(addr+1); } /*************************************************************** * Write a word to given memory location ***************************************************************/ void z180_device::WM16( offs_t addr, PAIR *r ) { WM(addr, r->b.l); WM(addr+1, r->b.h); } /*************************************************************** * ROP() is identical to RM() except it is used for * reading opcodes. In case of system with memory mapped I/O, * this function can be used to greatly speed up emulation ***************************************************************/ uint8_t z180_device::ROP() { offs_t addr = _PCD; _PC++; m_extra_cycles += memory_wait_states(); return m_copcodes.read_byte(MMU_REMAP_ADDR(addr)); } /**************************************************************** * ARG() is identical to ROP() except it is used * for reading opcode arguments. This difference can be used to * support systems that use different encoding mechanisms for * opcodes and opcode arguments ***************************************************************/ uint8_t z180_device::ARG() { offs_t addr = _PCD; _PC++; m_extra_cycles += memory_wait_states(); return m_cprogram.read_byte(MMU_REMAP_ADDR(addr)); } uint32_t z180_device::ARG16() { offs_t addr = _PCD; _PC += 2; m_extra_cycles += memory_wait_states() * 2; return m_cprogram.read_byte(MMU_REMAP_ADDR(addr)) | (m_cprogram.read_byte(MMU_REMAP_ADDR(addr+1)) << 8); } /*************************************************************** * Calculate the effective address m_ea of an opcode using * IX+offset resp. IY+offset addressing. ***************************************************************/ #define EAX() m_ea = (uint32_t)(uint16_t)(_IX + (int8_t)ARG()) #define EAY() m_ea = (uint32_t)(uint16_t)(_IY + (int8_t)ARG()) /*************************************************************** * POP ***************************************************************/ #define POP(DR) { RM16(_SPD, &m_##DR ); _SP += 2; } /*************************************************************** * PUSH ***************************************************************/ #define PUSH(SR) { _SP -= 2; WM16(_SPD, &m_##SR); } /*************************************************************** * JP ***************************************************************/ #define JP { \ _PCD = ARG16(); \ } /*************************************************************** * JP_COND ***************************************************************/ #define JP_COND(cond) \ if( cond ) \ { \ _PCD = ARG16(); \ } \ else \ { \ _PC += 2; \ } /*************************************************************** * JR ***************************************************************/ #define JR() \ { \ int8_t arg = (int8_t)ARG(); /* ARG() also increments _PC */ \ _PC += arg; /* so don't do _PC += ARG() */ \ } /*************************************************************** * JR_COND ***************************************************************/ #define JR_COND(cond,opcode) \ if( cond ) \ { \ int8_t arg = (int8_t)ARG(); /* ARG() also increments _PC */ \ _PC += arg; /* so don't do _PC += ARG() */ \ CC(ex,opcode); \ } \ else _PC++; /*************************************************************** * CALL ***************************************************************/ #define CALL() \ m_ea = ARG16(); \ PUSH( PC ); \ _PCD = m_ea; /*************************************************************** * CALL_COND ***************************************************************/ #define CALL_COND(cond,opcode) \ if( cond ) \ { \ m_ea = ARG16(); \ PUSH( PC ); \ _PCD = m_ea; \ CC(ex,opcode); \ } \ else \ { \ _PC+=2; \ } /*************************************************************** * RET_COND ***************************************************************/ #define RET_COND(cond,opcode) \ if( cond ) \ { \ POP(PC); \ CC(ex,opcode); \ } /*************************************************************** * RETN ***************************************************************/ #define RETN { \ LOG("Z180 RETN IFF1:%d IFF2:%d\n", m_IFF1, m_IFF2); \ POP(PC); \ m_IFF1 = m_IFF2; \ } /*************************************************************** * RETI ***************************************************************/ #define RETI { \ POP(PC); \ /* according to http://www.msxnet.org/tech/Z80/z80undoc.txt */ \ /* m_IFF1 = m_IFF2; */ \ daisy_call_reti_device(); \ } /*************************************************************** * LD R,A ***************************************************************/ #define LD_R_A { \ m_R = _A; \ m_R2 = _A & 0x80; /* keep bit 7 of R */ \ } /*************************************************************** * LD A,R ***************************************************************/ #define LD_A_R { \ _A = (m_R & 0x7f) | m_R2; \ _F = (_F & CF) | SZ[_A] | ( m_IFF2 << 2 ); \ } /*************************************************************** * LD I,A ***************************************************************/ #define LD_I_A { \ m_I = _A; \ } /*************************************************************** * LD A,I ***************************************************************/ #define LD_A_I { \ _A = m_I; \ _F = (_F & CF) | SZ[_A] | ( m_IFF2 << 2 ); \ } /*************************************************************** * RST ***************************************************************/ #define RST(addr) \ PUSH( PC ); \ _PCD = addr; /*************************************************************** * INC r8 ***************************************************************/ uint8_t z180_device::INC(uint8_t value) { uint8_t res = value + 1; _F = (_F & CF) | SZHV_inc[res]; return (uint8_t)res; } /*************************************************************** * DEC r8 ***************************************************************/ uint8_t z180_device::DEC(uint8_t value) { uint8_t res = value - 1; _F = (_F & CF) | SZHV_dec[res]; return res; } /*************************************************************** * RLCA ***************************************************************/ #define RLCA \ _A = (_A << 1) | (_A >> 7); \ _F = (_F & (SF | ZF | PF)) | (_A & (YF | XF | CF)) /*************************************************************** * RRCA ***************************************************************/ #define RRCA \ _F = (_F & (SF | ZF | PF)) | (_A & (YF | XF | CF)); \ _A = (_A >> 1) | (_A << 7) /*************************************************************** * RLA ***************************************************************/ #define RLA { \ uint8_t res = (_A << 1) | (_F & CF); \ uint8_t c = (_A & 0x80) ? CF : 0; \ _F = (_F & (SF | ZF | PF)) | c | (res & (YF | XF)); \ _A = res; \ } /*************************************************************** * RRA ***************************************************************/ #define RRA { \ uint8_t res = (_A >> 1) | (_F << 7); \ uint8_t c = (_A & 0x01) ? CF : 0; \ _F = (_F & (SF | ZF | PF)) | c | (res & (YF | XF)); \ _A = res; \ } /*************************************************************** * RRD ***************************************************************/ #define RRD { \ uint8_t n = RM(_HL); \ WM( _HL, (n >> 4) | (_A << 4) ); \ _A = (_A & 0xf0) | (n & 0x0f); \ _F = (_F & CF) | SZP[_A]; \ } /*************************************************************** * RLD ***************************************************************/ #define RLD { \ uint8_t n = RM(_HL); \ WM( _HL, (n << 4) | (_A & 0x0f) ); \ _A = (_A & 0xf0) | (n >> 4); \ _F = (_F & CF) | SZP[_A]; \ } /*************************************************************** * ADD A,n ***************************************************************/ #define ADD(value) \ { \ uint32_t ah = _AFD & 0xff00; \ uint32_t res = (uint8_t)((ah >> 8) + value); \ _F = SZHVC_add[ah | res]; \ _A = res; \ } /*************************************************************** * ADC A,n ***************************************************************/ #define ADC(value) \ { \ uint32_t ah = _AFD & 0xff00, c = _AFD & 1; \ uint32_t res = (uint8_t)((ah >> 8) + value + c); \ _F = SZHVC_add[(c << 16) | ah | res]; \ _A = res; \ } /*************************************************************** * SUB n ***************************************************************/ #define SUB(value) \ { \ uint32_t ah = _AFD & 0xff00; \ uint32_t res = (uint8_t)((ah >> 8) - value); \ _F = SZHVC_sub[ah | res]; \ _A = res; \ } /*************************************************************** * SBC A,n ***************************************************************/ #define SBC(value) \ { \ uint32_t ah = _AFD & 0xff00, c = _AFD & 1; \ uint32_t res = (uint8_t)((ah >> 8) - value - c); \ _F = SZHVC_sub[(c<<16) | ah | res]; \ _A = res; \ } /*************************************************************** * NEG ***************************************************************/ #define NEG { \ uint8_t value = _A; \ _A = 0; \ SUB(value); \ } /*************************************************************** * DAA ***************************************************************/ #define DAA { \ uint8_t r = _A; \ if (_F&NF) { \ if ((_F&HF)|((_A&0xf)>9)) r-=6; \ if ((_F&CF)|(_A>0x99)) r-=0x60; \ } \ else { \ if ((_F&HF)|((_A&0xf)>9)) r+=6; \ if ((_F&CF)|(_A>0x99)) r+=0x60; \ } \ _F=(_F&3)|(_A>0x99)|((_A^r)&HF)|SZP[r]; \ _A=r; \ } /*************************************************************** * AND n ***************************************************************/ #define AND(value) \ _A &= value; \ _F = SZP[_A] | HF /*************************************************************** * OR n ***************************************************************/ #define OR(value) \ _A |= value; \ _F = SZP[_A] /*************************************************************** * XOR n ***************************************************************/ #define XOR(value) \ _A ^= value; \ _F = SZP[_A] /*************************************************************** * CP n ***************************************************************/ #define CP(value) \ { \ uint32_t ah = _AFD & 0xff00; \ uint32_t res = (uint8_t)((ah >> 8) - value); \ _F = SZHVC_sub[ah | res]; \ } /*************************************************************** * EX AF,AF' ***************************************************************/ #define EX_AF { \ PAIR tmp; \ tmp = m_AF; m_AF = m_AF2; m_AF2 = tmp; \ } /*************************************************************** * EX DE,HL ***************************************************************/ #define EX_DE_HL { \ PAIR tmp; \ tmp = m_DE; m_DE = m_HL; m_HL = tmp; \ } /*************************************************************** * EXX ***************************************************************/ #define EXX { \ PAIR tmp; \ tmp = m_BC; m_BC = m_BC2; m_BC2 = tmp; \ tmp = m_DE; m_DE = m_DE2; m_DE2 = tmp; \ tmp = m_HL; m_HL = m_HL2; m_HL2 = tmp; \ } /*************************************************************** * EX (SP),r16 ***************************************************************/ #define EXSP(DR) \ { \ PAIR tmp = { { 0, 0, 0, 0 } }; \ RM16( _SPD, &tmp ); \ WM16( _SPD, &m_##DR ); \ m_##DR = tmp; \ } /*************************************************************** * ADD16 ***************************************************************/ #define ADD16(DR,SR) \ { \ uint32_t res = m_##DR.d + m_##SR.d; \ _F = (_F & (SF | ZF | VF)) | \ (((m_##DR.d ^ res ^ m_##SR.d) >> 8) & HF) | \ ((res >> 16) & CF); \ m_##DR.w.l = (uint16_t)res; \ } /*************************************************************** * ADC r16,r16 ***************************************************************/ #define ADC16(DR) \ { \ uint32_t res = _HLD + m_##DR.d + (_F & CF); \ _F = (((_HLD ^ res ^ m_##DR.d) >> 8) & HF) | \ ((res >> 16) & CF) | \ ((res >> 8) & SF) | \ ((res & 0xffff) ? 0 : ZF) | \ (((m_##DR.d ^ _HLD ^ 0x8000) & (m_##DR.d ^ res) & 0x8000) >> 13); \ _HL = (uint16_t)res; \ } /*************************************************************** * SBC r16,r16 ***************************************************************/ #define SBC16(DR) \ { \ uint32_t res = _HLD - m_##DR.d - (_F & CF); \ _F = (((_HLD ^ res ^ m_##DR.d) >> 8) & HF) | NF | \ ((res >> 16) & CF) | \ ((res >> 8) & SF) | \ ((res & 0xffff) ? 0 : ZF) | \ (((m_##DR.d ^ _HLD) & (_HLD ^ res) &0x8000) >> 13); \ _HL = (uint16_t)res; \ } /*************************************************************** * RLC r8 ***************************************************************/ uint8_t z180_device::RLC(uint8_t value) { unsigned res = value; unsigned c = (res & 0x80) ? CF : 0; res = ((res << 1) | (res >> 7)) & 0xff; _F = SZP[res] | c; return res; } /*************************************************************** * RRC r8 ***************************************************************/ uint8_t z180_device::RRC(uint8_t value) { unsigned res = value; unsigned c = (res & 0x01) ? CF : 0; res = ((res >> 1) | (res << 7)) & 0xff; _F = SZP[res] | c; return res; } /*************************************************************** * RL r8 ***************************************************************/ uint8_t z180_device::RL(uint8_t value) { unsigned res = value; unsigned c = (res & 0x80) ? CF : 0; res = ((res << 1) | (_F & CF)) & 0xff; _F = SZP[res] | c; return res; } /*************************************************************** * RR r8 ***************************************************************/ uint8_t z180_device::RR(uint8_t value) { unsigned res = value; unsigned c = (res & 0x01) ? CF : 0; res = ((res >> 1) | (_F << 7)) & 0xff; _F = SZP[res] | c; return res; } /*************************************************************** * SLA r8 ***************************************************************/ uint8_t z180_device::SLA(uint8_t value) { unsigned res = value; unsigned c = (res & 0x80) ? CF : 0; res = (res << 1) & 0xff; _F = SZP[res] | c; return res; } /*************************************************************** * SRA r8 ***************************************************************/ uint8_t z180_device::SRA(uint8_t value) { unsigned res = value; unsigned c = (res & 0x01) ? CF : 0; res = ((res >> 1) | (res & 0x80)) & 0xff; _F = SZP[res] | c; return res; } /*************************************************************** * SLL r8 ***************************************************************/ uint8_t z180_device::SLL(uint8_t value) { unsigned res = value; unsigned c = (res & 0x80) ? CF : 0; res = ((res << 1) | 0x01) & 0xff; _F = SZP[res] | c; return res; } /*************************************************************** * SRL r8 ***************************************************************/ uint8_t z180_device::SRL(uint8_t value) { unsigned res = value; unsigned c = (res & 0x01) ? CF : 0; res = (res >> 1) & 0xff; _F = SZP[res] | c; return res; } /*************************************************************** * BIT bit,r8 ***************************************************************/ #undef BIT #define BIT(bit,reg) \ _F = (_F & CF) | HF | SZ_BIT[reg & (1<>8) & (YF|XF)) /*************************************************************** * RES bit,r8 ***************************************************************/ uint8_t z180_device::RES(uint8_t bit, uint8_t value) { return value & ~(1< flag 5 */ \ if( (_A + io) & 0x08 ) _F |= XF; /* bit 3 -> flag 3 */ \ _HL++; _DE++; _BC--; \ if( _BC ) _F |= VF; \ } /*************************************************************** * CPI ***************************************************************/ #define CPI { \ uint8_t val = RM(_HL); \ uint8_t res = _A - val; \ _HL++; _BC--; \ _F = (_F & CF) | (SZ[res] & ~(YF|XF)) | ((_A ^ val ^ res) & HF) | NF; \ if( _F & HF ) res -= 1; \ if( res & 0x02 ) _F |= YF; /* bit 1 -> flag 5 */ \ if( res & 0x08 ) _F |= XF; /* bit 3 -> flag 3 */ \ if( _BC ) _F |= VF; \ } /*************************************************************** * INI ***************************************************************/ #define INI { \ uint8_t io = IN(_BC); \ _B--; \ WM( _HL, io ); \ _HL++; \ _F = SZ[_B]; \ if( io & SF ) _F |= NF; \ if( (_C + io + 1) & 0x100 ) _F |= HF | CF; \ if( (irep_tmp1[_C & 3][io & 3] ^ \ breg_tmp2[_B] ^ \ (_C >> 2) ^ \ (io >> 2)) & 1 ) \ _F |= PF; \ } /*************************************************************** * OUTI ***************************************************************/ #define OUTI { \ uint8_t io = RM(_HL); \ _B--; \ OUT( _BC, io ); \ _HL++; \ _F = SZ[_B]; \ if( io & SF ) _F |= NF; \ if( (_C + io + 1) & 0x100 ) _F |= HF | CF; \ if( (irep_tmp1[_C & 3][io & 3] ^ \ breg_tmp2[_B] ^ \ (_C >> 2) ^ \ (io >> 2)) & 1 ) \ _F |= PF; \ } /*************************************************************** * LDD ***************************************************************/ #define LDD { \ uint8_t io = RM(_HL); \ WM( _DE, io ); \ _F &= SF | ZF | CF; \ if( (_A + io) & 0x02 ) _F |= YF; /* bit 1 -> flag 5 */ \ if( (_A + io) & 0x08 ) _F |= XF; /* bit 3 -> flag 3 */ \ _HL--; _DE--; _BC--; \ if( _BC ) _F |= VF; \ } /*************************************************************** * CPD ***************************************************************/ #define CPD { \ uint8_t val = RM(_HL); \ uint8_t res = _A - val; \ _HL--; _BC--; \ _F = (_F & CF) | (SZ[res] & ~(YF|XF)) | ((_A ^ val ^ res) & HF) | NF; \ if( _F & HF ) res -= 1; \ if( res & 0x02 ) _F |= YF; /* bit 1 -> flag 5 */ \ if( res & 0x08 ) _F |= XF; /* bit 3 -> flag 3 */ \ if( _BC ) _F |= VF; \ } /*************************************************************** * IND ***************************************************************/ #define IND { \ uint8_t io = IN(_BC); \ _B--; \ WM( _HL, io ); \ _HL--; \ _F = SZ[_B]; \ if( io & SF ) _F |= NF; \ if( (_C + io - 1) & 0x100 ) _F |= HF | CF; \ if( (drep_tmp1[_C & 3][io & 3] ^ \ breg_tmp2[_B] ^ \ (_C >> 2) ^ \ (io >> 2)) & 1 ) \ _F |= PF; \ } /*************************************************************** * OUTD ***************************************************************/ #define OUTD { \ uint8_t io = RM(_HL); \ _B--; \ OUT( _BC, io ); \ _HL--; \ _F = SZ[_B]; \ if( io & SF ) _F |= NF; \ if( (_C + io - 1) & 0x100 ) _F |= HF | CF; \ if( (drep_tmp1[_C & 3][io & 3] ^ \ breg_tmp2[_B] ^ \ (_C >> 2) ^ \ (io >> 2)) & 1 ) \ _F |= PF; \ } /*************************************************************** * LDIR ***************************************************************/ #define LDIR \ LDI; \ if( _BC ) \ { \ _PC -= 2; \ CC(ex,0xb0); \ } /*************************************************************** * CPIR ***************************************************************/ #define CPIR \ CPI; \ if( _BC && !(_F & ZF) ) \ { \ _PC -= 2; \ CC(ex,0xb1); \ } /*************************************************************** * INIR ***************************************************************/ #define INIR \ INI; \ if( _B ) \ { \ _PC -= 2; \ CC(ex,0xb2); \ } /*************************************************************** * OTIR ***************************************************************/ #define OTIR \ OUTI; \ if( _B ) \ { \ _PC -= 2; \ CC(ex,0xb3); \ } /*************************************************************** * LDDR ***************************************************************/ #define LDDR \ LDD; \ if( _BC ) \ { \ _PC -= 2; \ CC(ex,0xb8); \ } /*************************************************************** * CPDR ***************************************************************/ #define CPDR \ CPD; \ if( _BC && !(_F & ZF) ) \ { \ _PC -= 2; \ CC(ex,0xb9); \ } /*************************************************************** * INDR ***************************************************************/ #define INDR \ IND; \ if( _B ) \ { \ _PC -= 2; \ CC(ex,0xba); \ } /*************************************************************** * OTDR ***************************************************************/ #define OTDR \ OUTD; \ if( _B ) \ { \ _PC -= 2; \ CC(ex,0xbb); \ } /*************************************************************** * EI ***************************************************************/ #define EI { \ m_IFF1 = m_IFF2 = 1; \ m_after_EI = 1; \ } /*************************************************************** * TST n ***************************************************************/ #define TST(value) \ _F = SZP[_A & value] | HF /*************************************************************** * MLT rr ***************************************************************/ #define MLT(DR) { \ m_##DR.w.l = m_##DR.b.l * m_##DR.b.h; \ } /*************************************************************** * OTIM ***************************************************************/ #define OTIM { \ _B--; \ OUT( _C, RM(_HL) ); \ _HL++; \ _C++; \ _F = (_B) ? NF : NF | ZF; \ } /*************************************************************** * OTDM ***************************************************************/ #define OTDM { \ _B--; \ OUT( _C, RM(_HL) ); \ _HL--; \ _C--; \ _F = (_B) ? NF : NF | ZF; \ } /*************************************************************** * OTIMR ***************************************************************/ #define OTIMR \ OTIM; \ if( _B ) \ { \ _PC -= 2; \ CC(ex,0xb3); \ } /*************************************************************** * OTDMR ***************************************************************/ #define OTDMR \ OTDM; \ if( _B ) \ { \ _PC -= 2; \ CC(ex,0xb3); \ } /*************************************************************** * OTDMR ***************************************************************/ #define SLP { \ m_icount = 0; \ m_HALT = 2; \ }