mame/src/devices/cpu/z80/z80.cpp
Andrei Holub a9bc46cb17
Some checks are pending
CI (Linux) / build-linux (-U_FORTIFY_SOURCE, gcc, gcc, g++, mametiny, tiny) (push) Waiting to run
CI (Linux) / build-linux (clang, clang, clang++, mame, mame) (push) Waiting to run
CI (macOS) / build-macos (push) Waiting to run
CI (Windows) / build-windows (clang, clang, clang++, mametiny, tiny) (push) Waiting to run
CI (Windows) / build-windows (gcc, gcc, g++, mame, mame) (push) Waiting to run
cpu/z80: Improved z80 code generation
before: ~/workspace/mame (z80-perf*) » ./mame pacman -bench 300
Average speed: 11871.24% (299 seconds)

after: ~/workspace/mame (z80-perf*) » ./mame pacman -bench 300
Average speed: 12235.35% (299 seconds)
2025-04-05 09:02:08 -04:00

852 lines
23 KiB
C++

// license:BSD-3-Clause
// copyright-holders:Juergen Buchmueller
/*****************************************************************************
ZiLOG Z80 emulator
TODO:
- Interrupt mode 0 should be able to execute arbitrary opcodes
- If LD A,I or LD A,R is interrupted, P/V flag gets reset, even if IFF2
was set before this instruction (implemented, but not enabled: we need
document Z80 types first, see below)
- Ideally, the tiny differences between Z80 types should be supported,
currently known differences:
- LD A,I/R P/V flag reset glitch is fixed on CMOS Z80
- OUT (C),0 outputs 0 on NMOS Z80, $FF on CMOS Z80
- SCF/CCF X/Y flags is ((flags | A) & 0x28) on SGS/SHARP/ZiLOG NMOS Z80,
(flags & A & 0x28).
However, recent findings say that SCF/CCF X/Y results depend on whether
or not the previous instruction touched the flag register.
This Z80 emulator assumes a ZiLOG NMOS model.
*****************************************************************************/
#include "emu.h"
#include "z80.h"
#include "z80dasm.h"
#include "z80.inc"
#define LOG_INT (1U << 1) // z80.lst
#define LOG_UNDOC (1U << 2)
#define VERBOSE (LOG_UNDOC)
#include "logmacro.h"
bool z80_device::tables_initialised = false;
u8 z80_device::SZ[] = {}; // zero and sign flags
u8 z80_device::SZ_BIT[] = {}; // zero, sign and parity/overflow (=zero) flags for BIT opcode
u8 z80_device::SZP[] = {}; // zero, sign and parity flags
u8 z80_device::SZHV_inc[] = {}; // zero, sign, half carry and overflow flags INC r8
u8 z80_device::SZHV_dec[] = {}; // zero, sign, half carry and overflow flags DEC r8
u8 z80_device::SZHVC_add[] = {};
u8 z80_device::SZHVC_sub[] = {};
/***************************************************************
* Enter halt state; write 1 to callback on first execution
***************************************************************/
void z80_device::halt()
{
if (!m_halt)
{
m_halt = 1;
m_halt_cb(1);
}
}
/***************************************************************
* Leave halt state; write 0 to callback
***************************************************************/
void z80_device::leave_halt()
{
if (m_halt)
{
m_halt = 0;
m_halt_cb(0);
}
}
/***************************************************************
* Read a byte from given memory location
***************************************************************/
u8 z80_device::data_read(u16 addr)
{
return m_data.read_interruptible(translate_memory_address(addr));
}
/***************************************************************
* Write a byte to given memory location
***************************************************************/
void z80_device::data_write(u16 addr, u8 value)
{
m_data.write_interruptible(translate_memory_address((u32)addr), value);
}
/***************************************************************
* 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
***************************************************************/
u8 z80_device::opcode_read()
{
return m_opcodes.read_byte(translate_memory_address(PC));
}
/****************************************************************
* 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
* out: TDAT8
***************************************************************/
u8 z80_device::arg_read()
{
return m_args.read_byte(translate_memory_address(PC));
}
/***************************************************************
* INC r8
***************************************************************/
void z80_device::inc(u8 &r)
{
++r;
set_f((F & CF) | SZHV_inc[r]);
}
/***************************************************************
* DEC r8
***************************************************************/
void z80_device::dec(u8 &r)
{
--r;
set_f((F & CF) | SZHV_dec[r]);
}
/***************************************************************
* RLCA
***************************************************************/
void z80_device::rlca()
{
A = (A << 1) | (A >> 7);
set_f((F & (SF | ZF | PF)) | (A & (YF | XF | CF)));
}
/***************************************************************
* RRCA
***************************************************************/
void z80_device::rrca()
{
set_f((F & (SF | ZF | PF)) | (A & CF));
A = (A >> 1) | (A << 7);
F |= (A & (YF | XF));
}
/***************************************************************
* RLA
***************************************************************/
void z80_device::rla()
{
u8 res = (A << 1) | (F & CF);
u8 c = (A & 0x80) ? CF : 0;
set_f((F & (SF | ZF | PF)) | c | (res & (YF | XF)));
A = res;
}
/***************************************************************
* RRA
***************************************************************/
void z80_device::rra()
{
u8 res = (A >> 1) | (F << 7);
u8 c = (A & 0x01) ? CF : 0;
set_f((F & (SF | ZF | PF)) | c | (res & (YF | XF)));
A = res;
}
/***************************************************************
* ADD A,n
***************************************************************/
void z80_device::add_a(u8 value)
{
u32 ah = AF & 0xff00;
u32 res = (u8)((ah >> 8) + value);
set_f(SZHVC_add[ah | res]);
A = res;
}
/***************************************************************
* ADC A,n
***************************************************************/
void z80_device::adc_a(u8 value)
{
u32 ah = AF & 0xff00, c = AF & 1;
u32 res = (u8)((ah >> 8) + value + c);
set_f(SZHVC_add[(c << 16) | ah | res]);
A = res;
}
/***************************************************************
* SUB n
***************************************************************/
void z80_device::sub(u8 value)
{
u32 ah = AF & 0xff00;
u32 res = (u8)((ah >> 8) - value);
set_f(SZHVC_sub[ah | res]);
A = res;
}
/***************************************************************
* SBC A,n
***************************************************************/
void z80_device::sbc_a(u8 value)
{
u32 ah = AF & 0xff00, c = AF & 1;
u32 res = (u8)((ah >> 8) - value - c);
set_f(SZHVC_sub[(c << 16) | ah | res]);
A = res;
}
/***************************************************************
* NEG
***************************************************************/
void z80_device::neg()
{
u8 value = A;
A = 0;
sub(value);
}
/***************************************************************
* DAA
***************************************************************/
void z80_device::daa()
{
u8 a = A;
if (F & NF)
{
if ((F&HF) | ((A&0xf)>9)) a-=6;
if ((F&CF) | (A>0x99)) a-=0x60;
}
else
{
if ((F&HF) | ((A&0xf)>9)) a+=6;
if ((F&CF) | (A>0x99)) a+=0x60;
}
set_f((F&(CF|NF)) | (A>0x99) | ((A^a)&HF) | SZP[a]);
A = a;
}
/***************************************************************
* AND n
***************************************************************/
void z80_device::and_a(u8 value)
{
A &= value;
set_f(SZP[A] | HF);
}
/***************************************************************
* OR n
***************************************************************/
void z80_device::or_a(u8 value)
{
A |= value;
set_f(SZP[A]);
}
/***************************************************************
* XOR n
***************************************************************/
void z80_device::xor_a(u8 value)
{
A ^= value;
set_f(SZP[A]);
}
/***************************************************************
* CP n
***************************************************************/
void z80_device::cp(u8 value)
{
unsigned val = value;
u32 ah = AF & 0xff00;
u32 res = (u8)((ah >> 8) - val);
set_f((SZHVC_sub[ah | res] & ~(YF | XF)) | (val & (YF | XF)));
}
/***************************************************************
* EXX
***************************************************************/
void z80_device::exx()
{
using std::swap;
swap(m_bc, m_bc2);
swap(m_de, m_de2);
swap(m_hl, m_hl2);
}
/***************************************************************
* RLC r8
***************************************************************/
u8 z80_device::rlc(u8 value)
{
unsigned res = value;
unsigned c = (res & 0x80) ? CF : 0;
res = ((res << 1) | (res >> 7)) & 0xff;
set_f(SZP[res] | c);
return res;
}
/***************************************************************
* RRC r8
***************************************************************/
u8 z80_device::rrc(u8 value)
{
unsigned res = value;
unsigned c = (res & 0x01) ? CF : 0;
res = ((res >> 1) | (res << 7)) & 0xff;
set_f(SZP[res] | c);
return res;
}
/***************************************************************
* RL r8
***************************************************************/
u8 z80_device::rl(u8 value)
{
unsigned res = value;
unsigned c = (res & 0x80) ? CF : 0;
res = ((res << 1) | (F & CF)) & 0xff;
set_f(SZP[res] | c);
return res;
}
/***************************************************************
* RR r8
***************************************************************/
u8 z80_device::rr(u8 value)
{
unsigned res = value;
unsigned c = (res & 0x01) ? CF : 0;
res = ((res >> 1) | (F << 7)) & 0xff;
set_f(SZP[res] | c);
return res;
}
/***************************************************************
* SLA r8
***************************************************************/
u8 z80_device::sla(u8 value)
{
unsigned res = value;
unsigned c = (res & 0x80) ? CF : 0;
res = (res << 1) & 0xff;
set_f(SZP[res] | c);
return res;
}
/***************************************************************
* SRA r8
***************************************************************/
u8 z80_device::sra(u8 value)
{
unsigned res = value;
unsigned c = (res & 0x01) ? CF : 0;
res = ((res >> 1) | (res & 0x80)) & 0xff;
set_f(SZP[res] | c);
return res;
}
/***************************************************************
* SLL r8
***************************************************************/
u8 z80_device::sll(u8 value)
{
unsigned res = value;
unsigned c = (res & 0x80) ? CF : 0;
res = ((res << 1) | 0x01) & 0xff;
set_f(SZP[res] | c);
return res;
}
/***************************************************************
* SRL r8
***************************************************************/
u8 z80_device::srl(u8 value)
{
unsigned res = value;
unsigned c = (res & 0x01) ? CF : 0;
res = (res >> 1) & 0xff;
set_f(SZP[res] | c);
return res;
}
/***************************************************************
* BIT bit,r8
***************************************************************/
void z80_device::bit(int bit, u8 value)
{
set_f((F & CF) | HF | (SZ_BIT[value & (1 << bit)] & ~(YF | XF)) | (value & (YF | XF)));
}
/***************************************************************
* BIT bit,(HL)
***************************************************************/
void z80_device::bit_hl(int bit, u8 value)
{
set_f((F & CF) | HF | (SZ_BIT[value & (1 << bit)] & ~(YF | XF)) | (WZ_H & (YF | XF)));
}
/***************************************************************
* BIT bit,(IX/Y+o)
***************************************************************/
void z80_device::bit_xy(int bit, u8 value)
{
set_f((F & CF) | HF | (SZ_BIT[value & (1 << bit)] & ~(YF | XF)) | ((m_ea >> 8) & (YF | XF)));
}
/***************************************************************
* RES bit,r8
***************************************************************/
u8 z80_device::res(int bit, u8 value)
{
return value & ~(1 << bit);
}
/***************************************************************
* SET bit,r8
***************************************************************/
u8 z80_device::set(int bit, u8 value)
{
return value | (1 << bit);
}
void z80_device::block_io_interrupted_flags()
{
F &= ~(YF | XF);
F |= (PC >> 8) & (YF | XF);
if (F & CF)
{
F &= ~HF;
if (TDAT8 & 0x80)
{
F ^= (SZP[(B - 1) & 0x07] ^ PF) & PF;
if ((B & 0x0f) == 0x00) F |= HF;
}
else
{
F ^= (SZP[(B + 1) & 0x07] ^ PF) & PF;
if ((B & 0x0f) == 0x0f) F |= HF;
}
}
else
{
F ^=(SZP[B & 0x07] ^ PF) & PF;
}
}
/***************************************************************
* EI
***************************************************************/
void z80_device::ei()
{
m_iff1 = m_iff2 = 1;
m_after_ei = true;
}
void z80_device::set_f(u8 f)
{
QT = 0;
F = f;
}
void z80_device::illegal_1()
{
LOGMASKED(LOG_UNDOC, "ill. opcode $%02x $%02x ($%04x)\n",
m_opcodes.read_byte(translate_memory_address((PC - 1) & 0xffff)),
m_opcodes.read_byte(translate_memory_address(PC)), PC - 1);
}
void z80_device::illegal_2()
{
LOGMASKED(LOG_UNDOC, "ill. opcode $ed $%02x\n",
m_opcodes.read_byte(translate_memory_address((PC - 1) & 0xffff)));
}
/****************************************************************************
* Processor initialization
****************************************************************************/
void z80_device::device_validity_check(validity_checker &valid) const
{
cpu_device::device_validity_check(valid);
if (4 > m_m1_cycles)
osd_printf_error("M1 cycles %u is less than minimum 4\n", m_m1_cycles);
if (3 > m_memrq_cycles)
osd_printf_error("MEMRQ cycles %u is less than minimum 3\n", m_memrq_cycles);
if (4 > m_iorq_cycles)
osd_printf_error("IORQ cycles %u is less than minimum 4\n", m_iorq_cycles);
}
void z80_device::device_start()
{
if (!tables_initialised)
{
u8 *padd = &SZHVC_add[ 0*256];
u8 *padc = &SZHVC_add[256*256];
u8 *psub = &SZHVC_sub[ 0*256];
u8 *psbc = &SZHVC_sub[256*256];
for (int oldval = 0; oldval < 256; oldval++)
{
for (int newval = 0; newval < 256; newval++)
{
// add or adc w/o carry set
int val = newval - oldval;
*padd = (newval) ? ((newval & 0x80) ? SF : 0) : ZF;
*padd |= (newval & (YF | XF)); // undocumented flag bits 5+3
if ((newval & 0x0f) < (oldval & 0x0f)) *padd |= HF;
if (newval < oldval) *padd |= CF;
if ((val^oldval^0x80) & (val^newval) & 0x80) *padd |= VF;
padd++;
// adc with carry set
val = newval - oldval - 1;
*padc = (newval) ? ((newval & 0x80) ? SF : 0) : ZF;
*padc |= (newval & (YF | XF)); // undocumented flag bits 5+3
if ((newval & 0x0f) <= (oldval & 0x0f)) *padc |= HF;
if (newval <= oldval) *padc |= CF;
if ((val^oldval^0x80) & (val^newval) & 0x80) *padc |= VF;
padc++;
// cp, sub or sbc w/o carry set
val = oldval - newval;
*psub = NF | ((newval) ? ((newval & 0x80) ? SF : 0) : ZF);
*psub |= (newval & (YF | XF)); // undocumented flag bits 5+3
if ((newval & 0x0f) > (oldval & 0x0f)) *psub |= HF;
if (newval > oldval) *psub |= CF;
if ((val^oldval) & (oldval^newval) & 0x80) *psub |= VF;
psub++;
// sbc with carry set
val = oldval - newval - 1;
*psbc = NF | ((newval) ? ((newval & 0x80) ? SF : 0) : ZF);
*psbc |= (newval & (YF | XF)); // undocumented flag bits 5+3
if ((newval & 0x0f) >= (oldval & 0x0f)) *psbc |= HF;
if (newval >= oldval) *psbc |= CF;
if ((val^oldval) & (oldval^newval) & 0x80) *psbc |= VF;
psbc++;
}
}
for (int i = 0; i < 256; i++)
{
int p = 0;
for (int b = 0; b < 8; b++)
p += BIT(i, b);
SZ[i] = i ? i & SF : ZF;
SZ[i] |= (i & (YF | XF)); // undocumented flag bits 5+3
SZ_BIT[i] = i ? i & SF : ZF | PF;
SZ_BIT[i] |= (i & (YF | XF)); // undocumented flag bits 5+3
SZP[i] = SZ[i] | ((p & 1) ? 0 : PF);
SZHV_inc[i] = SZ[i];
if (i == 0x80) SZHV_inc[i] |= VF;
if ((i & 0x0f) == 0x00) SZHV_inc[i] |= HF;
SZHV_dec[i] = SZ[i] | NF;
if (i == 0x7f) SZHV_dec[i] |= VF;
if ((i & 0x0f) == 0x0f) SZHV_dec[i] |= HF;
}
tables_initialised = true;
}
save_item(NAME(PRVPC));
save_item(NAME(PC));
save_item(NAME(SP));
save_item(NAME(AF));
save_item(NAME(BC));
save_item(NAME(DE));
save_item(NAME(HL));
save_item(NAME(IX));
save_item(NAME(IY));
save_item(NAME(WZ));
save_item(NAME(m_af2.w));
save_item(NAME(m_bc2.w));
save_item(NAME(m_de2.w));
save_item(NAME(m_hl2.w));
save_item(NAME(QT));
save_item(NAME(Q));
save_item(NAME(R));
save_item(NAME(R2));
save_item(NAME(m_iff1));
save_item(NAME(m_iff2));
save_item(NAME(m_halt));
save_item(NAME(m_im));
save_item(NAME(m_i));
save_item(NAME(m_nmi_state));
save_item(NAME(m_nmi_pending));
save_item(NAME(m_irq_state));
save_item(NAME(m_wait_state));
save_item(NAME(m_busrq_state));
save_item(NAME(m_busack_state));
save_item(NAME(m_after_ei));
save_item(NAME(m_after_ldair));
save_item(NAME(m_ea));
save_item(NAME(m_tmp_irq_vector));
save_item(NAME(m_shared_addr.w));
save_item(NAME(m_shared_data.w));
save_item(NAME(m_shared_data2.w));
save_item(NAME(m_rtemp));
save_item(NAME(m_ref));
// Reset registers to their initial values
PRVPC = 0;
PC = 0;
SP = 0;
AF = 0;
BC = 0;
DE = 0;
HL = 0;
IX = 0;
IY = 0;
WZ = 0;
m_af2.w = 0;
m_bc2.w = 0;
m_de2.w = 0;
m_hl2.w = 0;
QT = 0;
Q = 0;
R = 0;
R2 = 0;
m_iff1 = 0;
m_iff2 = 0;
m_halt = 0;
m_im = 0;
m_i = 0;
m_nmi_state = 0;
m_nmi_pending = false;
m_irq_state = 0;
m_wait_state = 0;
m_busrq_state = 0;
m_busack_state = 0;
m_after_ei = false;
m_after_ldair = false;
m_ea = 0;
m_rtemp = 0;
space(AS_PROGRAM).cache(m_args);
space(has_space(AS_OPCODES) ? AS_OPCODES : AS_PROGRAM).cache(m_opcodes);
space(AS_PROGRAM).specific(m_data);
space(AS_IO).specific(m_io);
IX = IY = 0xffff; // IX and IY are FFFF after a reset!
set_f(ZF); // Zero flag is set
// set up the state table
state_add(STATE_GENPC, "PC", m_pc.w).callimport();
state_add(STATE_GENPCBASE, "CURPC", m_prvpc.w).callimport().noshow();
state_add(Z80_SP, "SP", SP);
state_add(STATE_GENFLAGS, "GENFLAGS", F).noshow().formatstr("%8s");
state_add(Z80_A, "A", A).noshow();
state_add(Z80_B, "B", B).noshow();
state_add(Z80_C, "C", C).noshow();
state_add(Z80_D, "D", D).noshow();
state_add(Z80_E, "E", E).noshow();
state_add(Z80_H, "H", H).noshow();
state_add(Z80_L, "L", L).noshow();
state_add(Z80_AF, "AF", AF);
state_add(Z80_BC, "BC", BC);
state_add(Z80_DE, "DE", DE);
state_add(Z80_HL, "HL", HL);
state_add(Z80_IX, "IX", IX);
state_add(Z80_IY, "IY", IY);
state_add(Z80_AF2, "AF2", m_af2.w);
state_add(Z80_BC2, "BC2", m_bc2.w);
state_add(Z80_DE2, "DE2", m_de2.w);
state_add(Z80_HL2, "HL2", m_hl2.w);
state_add(Z80_WZ, "WZ", WZ);
state_add(Z80_R, "R", m_rtemp).callimport().callexport();
state_add(Z80_I, "I", m_i);
state_add(Z80_IM, "IM", m_im).mask(0x3);
state_add(Z80_IFF1, "IFF1", m_iff1).mask(0x1);
state_add(Z80_IFF2, "IFF2", m_iff2).mask(0x1);
state_add(Z80_HALT, "HALT", m_halt).mask(0x1);
// set our instruction counter
set_icountptr(m_icount);
}
/****************************************************************************
* Do a reset
****************************************************************************/
void z80_device::device_reset()
{
leave_halt();
m_ref = 0xffff00;
PC = 0x0000;
WZ = PC;
m_i = 0;
m_r = 0;
m_r2 = 0;
m_nmi_pending = false;
m_after_ei = false;
m_after_ldair = false;
m_iff1 = 0;
m_iff2 = 0;
}
/****************************************************************************
* Execute 'cycles' T-states.
****************************************************************************/
void z80_device::execute_run()
{
#include "cpu/z80/z80.hxx"
}
void z80_device::execute_set_input(int inputnum, int state)
{
switch (inputnum)
{
case Z80_INPUT_LINE_BUSRQ:
m_busrq_state = state;
break;
case INPUT_LINE_NMI:
// mark an NMI pending on the rising edge
if (m_nmi_state == CLEAR_LINE && state != CLEAR_LINE)
m_nmi_pending = true;
m_nmi_state = state;
break;
case INPUT_LINE_IRQ0:
// update the IRQ state via the daisy chain
m_irq_state = state;
if (daisy_chain_present())
m_irq_state = (daisy_update_irq_state() == ASSERT_LINE) ? ASSERT_LINE : m_irq_state;
// the main execute loop will take the interrupt
break;
case Z80_INPUT_LINE_WAIT:
m_wait_state = state;
break;
default:
break;
}
}
/**************************************************************************
* STATE IMPORT/EXPORT
**************************************************************************/
void z80_device::state_import(const device_state_entry &entry)
{
switch (entry.index())
{
case STATE_GENPCBASE:
m_pc = m_prvpc;
[[fallthrough]];
case STATE_GENPC:
m_prvpc = m_pc;
m_ref = 0xffff00;
m_after_ei = false;
m_after_ldair = false;
break;
case Z80_R:
m_r = m_rtemp & 0x7f;
m_r2 = m_rtemp & 0x80;
break;
default:
fatalerror("CPU_IMPORT_STATE() called for unexpected value\n");
}
}
void z80_device::state_export(const device_state_entry &entry)
{
switch (entry.index())
{
case Z80_R:
m_rtemp = (m_r & 0x7f) | (m_r2 & 0x80);
break;
default:
fatalerror("CPU_EXPORT_STATE() called for unexpected value\n");
}
}
void z80_device::state_string_export(const device_state_entry &entry, std::string &str) const
{
switch (entry.index())
{
case STATE_GENFLAGS:
str = string_format("%c%c%c%c%c%c%c%c",
F & 0x80 ? 'S':'.',
F & 0x40 ? 'Z':'.',
F & 0x20 ? 'Y':'.',
F & 0x10 ? 'H':'.',
F & 0x08 ? 'X':'.',
F & 0x04 ? 'P':'.',
F & 0x02 ? 'N':'.',
F & 0x01 ? 'C':'.');
break;
}
}
/**************************************************************************
* disassemble - call the disassembly helper function
**************************************************************************/
std::unique_ptr<util::disasm_interface> z80_device::create_disassembler()
{
return std::make_unique<z80_disassembler>();
}
z80_device::z80_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: z80_device(mconfig, Z80, tag, owner, clock)
{
}
z80_device::z80_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) :
cpu_device(mconfig, type, tag, owner, clock),
z80_daisy_chain_interface(mconfig, *this),
m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0),
m_opcodes_config("opcodes", ENDIANNESS_LITTLE, 8, 16, 0),
m_io_config("io", ENDIANNESS_LITTLE, 8, 16, 0),
m_irqack_cb(*this),
m_refresh_cb(*this),
m_nomreq_cb(*this),
m_halt_cb(*this),
m_busack_cb(*this),
m_branch_cb(*this),
m_irqfetch_cb(*this),
m_reti_cb(*this),
m_m1_cycles(4),
m_memrq_cycles(3),
m_iorq_cycles(4)
{
}
device_memory_interface::space_config_vector z80_device::memory_space_config() const
{
if (has_configured_map(AS_OPCODES))
{
return space_config_vector {
std::make_pair(AS_PROGRAM, &m_program_config),
std::make_pair(AS_OPCODES, &m_opcodes_config),
std::make_pair(AS_IO, &m_io_config) };
}
else
{
return space_config_vector {
std::make_pair(AS_PROGRAM, &m_program_config),
std::make_pair(AS_IO, &m_io_config) };
}
}
DEFINE_DEVICE_TYPE(Z80, z80_device, "z80", "Zilog Z80")