Skip to content

cpu/z80/r800.cpp: Updated instruction execution. #12530

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions scripts/src/cpu.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3001,11 +3001,13 @@ if CPUS["Z80"] or CPUS["KC80"] or CPUS["Z80N"] then
dependency {
{ MAME_DIR .. "src/devices/cpu/z80/z80.cpp", GEN_DIR .. "emu/cpu/z80/z80.hxx" },
{ MAME_DIR .. "src/devices/cpu/z80/z80.cpp", GEN_DIR .. "emu/cpu/z80/ncs800.hxx" },
{ MAME_DIR .. "src/devices/cpu/z80/r800.cpp", GEN_DIR .. "emu/cpu/z80/r800.hxx" },
}

custombuildtask {
{ MAME_DIR .. "src/devices/cpu/z80/z80.lst", GEN_DIR .. "emu/cpu/z80/z80.hxx", { MAME_DIR .. "src/devices/cpu/z80/z80make.py" }, { "@echo Generating Z80 source file...", PYTHON .. " $(1) $(<) $(@)" } },
{ MAME_DIR .. "src/devices/cpu/z80/z80.lst", GEN_DIR .. "emu/cpu/z80/ncs800.hxx", { MAME_DIR .. "src/devices/cpu/z80/z80make.py" }, { "@echo Generating NSC800 source file...", PYTHON .. " $(1) ncs800 $(<) $(@)" } },
{ MAME_DIR .. "src/devices/cpu/z80/z80.lst", GEN_DIR .. "emu/cpu/z80/r800.hxx", { MAME_DIR .. "src/devices/cpu/z80/z80make.py" }, { "@echo Generating R800 source file...", PYTHON .. " $(1) r800 $(<) $(@)" } },
}
end

Expand Down
153 changes: 150 additions & 3 deletions src/devices/cpu/z80/r800.cpp
Original file line number Diff line number Diff line change
@@ -1,17 +1,33 @@
// license:BSD-3-Clause
// copyright-holders:AJR
// copyright-holders:AJR,Wilbert Pol
/***************************************************************************

ASCII R800 CPU

TODO: this uses a sped-up Z80 core with added multiply instructions
('mulub', 'muluw').
TODO:
- Internal configuration registers.
- External 24 bits address bus accessible through 9 memory mappers.
- DMA channels.
- Interrupt levels.
- Bits 3 and 5 of the flag register behave differently from the z80.
- Page break penalties.
- Refresh delays.

***************************************************************************/

#include "emu.h"
#include "r800.h"
#include "r800dasm.h"

#define LOG_UNDOC (1U << 1)
#define LOG_INT (1U << 2)
#define LOG_TIME (1U << 3)

//#define VERBOSE ( LOG_UNDOC /*| LOG_INT*/ )
#include "logmacro.h"

#define LOGUNDOC(...) LOGMASKED(LOG_UNDOC, __VA_ARGS__)
#define LOGINT(...) LOGMASKED(LOG_INT, __VA_ARGS__)

//**************************************************************************
// GLOBAL VARIABLES
Expand All @@ -32,4 +48,135 @@ DEFINE_DEVICE_TYPE(R800, r800_device, "r800", "ASCII R800")
r800_device::r800_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: z80_device(mconfig, R800, tag, owner, clock)
{
z80_set_m1_cycles(1);
z80_set_memrq_cycles(1);
z80_set_iorq_cycles(1);
}

std::unique_ptr<util::disasm_interface> r800_device::create_disassembler()
{
return std::make_unique<r800_disassembler>();
}

void r800_device::device_validity_check(validity_checker &valid) const
{
cpu_device::device_validity_check(valid);
}



#define HAS_LDAIR_QUIRK 0

/****************************************************************************
* The Z80 registers. halt is set to 1 when the CPU is halted, the refresh
* register is calculated as follows: refresh = (r & 127) | (r2 & 128)
****************************************************************************/
#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 PRVPC m_prvpc.d // previous program counter

#define PCD m_pc.d
#define PC m_pc.w.l

#define SPD m_sp.d
#define SP m_sp.w.l

#define AFD m_af.d
#define AF m_af.w.l
#define A m_af.b.h
#define F m_af.b.l
#define Q m_q
#define QT m_qtemp
#define I m_i
#define R m_r
#define R2 m_r2

#define BCD m_bc.d
#define BC m_bc.w.l
#define B m_bc.b.h
#define C m_bc.b.l

#define DED m_de.d
#define DE m_de.w.l
#define D m_de.b.h
#define E m_de.b.l

#define HLD m_hl.d
#define HL m_hl.w.l
#define H m_hl.b.h
#define L m_hl.b.l

#define IXD m_ix.d
#define IX m_ix.w.l
#define HX m_ix.b.h
#define LX m_ix.b.l

#define IYD m_iy.d
#define IY m_iy.w.l
#define HY m_iy.b.h
#define LY m_iy.b.l

#define WZ m_wz.w.l
#define WZ_H m_wz.b.h
#define WZ_L m_wz.b.l

#define TADR m_shared_addr.w // Typically represents values from A0..15 pins. 16bit input in steps.
#define TADR_H m_shared_addr.b.h
#define TADR_L m_shared_addr.b.l
#define TDAT m_shared_data.w // 16bit input(if use as second parameter) or output in steps.
#define TDAT2 m_shared_data2.w
#define TDAT_H m_shared_data.b.h
#define TDAT_L m_shared_data.b.l
#define TDAT8 m_shared_data.b.l // Typically represents values from D0..8 pins. 8bit input or output in steps.


/***************************************************************
* adjust cycle count by n T-states
***************************************************************/
#define T(icount) { m_icount -= icount; }

/***************************************************************
* SLL r8
***************************************************************/
u8 r800_device::r800_sll(u8 value)
{
const u8 c = (value & 0x80) ? CF : 0;
const u8 res = u8(value << 1);
set_f(SZP[res] | c);
return res;
}

void r800_device::mulub(u8 value)
{
const u16 res = A * value;
HL = res;
const u8 c = (H) ? CF : 0;
const u8 z = (res) ? 0 : ZF;
set_f((F & (HF|NF)) | z | c);
}

void r800_device::muluw(u16 value)
{
const u32 res = HL * value;
DE = res >> 16;
HL = res & 0xffff;
const u8 c = (DE) ? CF : 0;
const u8 z = (res) ? 0 : ZF;
set_f((F & (HF|NF)) | z | c);
}

void r800_device::do_op()
{
#include "cpu/z80/r800.hxx"
}
17 changes: 16 additions & 1 deletion src/devices/cpu/z80/r800.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
// copyright-holders:AJR
// copyright-holders:AJR,Wilbert Pol
/***************************************************************************

ASCII R800 CPU
Expand All @@ -24,10 +24,25 @@ class r800_device : public z80_device
// device type constructor
r800_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);

static constexpr feature_type imperfect_features() { return feature::TIMING; }

protected:
// device_t implementation
virtual void device_validity_check(validity_checker &valid) const override;

// device_execute_interface overrides
virtual u32 execute_min_cycles() const noexcept override { return 1; }
virtual u64 execute_clocks_to_cycles(u64 clocks) const noexcept override { return (clocks + 4 - 1) / 4; }
virtual u64 execute_cycles_to_clocks(u64 cycles) const noexcept override { return (cycles * 4); }

// device_disasm_interface implementation
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;

u8 r800_sll(u8 value);
void mulub(u8 value);
void muluw(u16 value);

virtual void do_op() override;
};

// device type declaration
Expand Down
59 changes: 26 additions & 33 deletions src/devices/cpu/z80/z80.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,14 @@

#include "z80.inc"

static bool tables_initialised = false;
std::unique_ptr<u8[]> z80_device::SZ = std::make_unique<u8[]>(0x100); // zero and sign flags
std::unique_ptr<u8[]> z80_device::SZ_BIT = std::make_unique<u8[]>(0x100); // zero, sign and parity/overflow (=zero) flags for BIT opcode
std::unique_ptr<u8[]> z80_device::SZP = std::make_unique<u8[]>(0x100); // zero, sign and parity flags
std::unique_ptr<u8[]> z80_device::SZHV_inc = std::make_unique<u8[]>(0x100); // zero, sign, half carry and overflow flags INC r8
std::unique_ptr<u8[]> z80_device::SZHV_dec = std::make_unique<u8[]>(0x100); // zero, sign, half carry and overflow flags DEC r8

std::unique_ptr<u8[]> z80_device::SZHVC_add = std::make_unique<u8[]>(2 * 0x100 * 0x100);
std::unique_ptr<u8[]> z80_device::SZHVC_sub = std::make_unique<u8[]>(2 * 0x100 * 0x100);
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[] = {};


/***************************************************************
Expand Down Expand Up @@ -501,62 +500,56 @@ void z80_device::device_start()
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;
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;
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;
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;
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;
if( i&0x01 ) ++p;
if( i&0x02 ) ++p;
if( i&0x04 ) ++p;
if( i&0x08 ) ++p;
if( i&0x10 ) ++p;
if( i&0x20 ) ++p;
if( i&0x40 ) ++p;
if( i&0x80 ) ++p;
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;
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;
if (i == 0x7f) SZHV_dec[i] |= VF;
if ((i & 0x0f) == 0x0f) SZHV_dec[i] |= HF;
}

tables_initialised = true;
Expand Down
17 changes: 9 additions & 8 deletions src/devices/cpu/z80/z80.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,14 +181,15 @@ class z80_device : public cpu_device, public z80_daisy_chain_interface
u8 m_memrq_cycles;
u8 m_iorq_cycles;

static std::unique_ptr<u8[]> SZ; // zero and sign flags
static std::unique_ptr<u8[]> SZ_BIT; // zero, sign and parity/overflow (=zero) flags for BIT opcode
static std::unique_ptr<u8[]> SZP; // zero, sign and parity flags
static std::unique_ptr<u8[]> SZHV_inc; // zero, sign, half carry and overflow flags INC r8
static std::unique_ptr<u8[]> SZHV_dec; // zero, sign, half carry and overflow flags DEC r8

static std::unique_ptr<u8[]> SZHVC_add;
static std::unique_ptr<u8[]> SZHVC_sub;
static bool tables_initialised;
static u8 SZ[0x100]; // zero and sign flags
static u8 SZ_BIT[0x100]; // zero, sign and parity/overflow (=zero) flags for BIT opcode
static u8 SZP[0x100]; // zero, sign and parity flags
static u8 SZHV_inc[0x100]; // zero, sign, half carry and overflow flags INC r8
static u8 SZHV_dec[0x100]; // zero, sign, half carry and overflow flags DEC r8

static u8 SZHVC_add[2 * 0x100 * 0x100];
static u8 SZHVC_sub[2 * 0x100 * 0x100];
};

DECLARE_DEVICE_TYPE(Z80, z80_device)
Expand Down
Loading
Loading