cpu/z80/r800.cpp: (#12530)

- Removed undocumented Z80 instructions that are not supported by the R800
- Updated basic instruction timing
- Implement MULUB and MULUW
  Other R800 features are not implemented
This commit is contained in:
wilbertpol 2024-07-11 00:34:51 +01:00 committed by GitHub
parent 4183b96612
commit 2c479b20dd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 2194 additions and 44 deletions

View file

@ -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

View file

@ -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
@ -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"
}

View file

@ -1,5 +1,5 @@
// license:BSD-3-Clause
// copyright-holders:AJR
// copyright-holders:AJR,Wilbert Pol
/***************************************************************************
ASCII R800 CPU
@ -24,10 +24,25 @@ public:
// 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

View file

@ -27,15 +27,14 @@ TODO:
#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[] = {};
/***************************************************************
@ -538,14 +537,8 @@ void z80_device::device_start()
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;

View file

@ -181,14 +181,15 @@ protected:
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 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 std::unique_ptr<u8[]> SZHVC_add;
static std::unique_ptr<u8[]> SZHVC_sub;
static u8 SZHVC_add[2 * 0x100 * 0x100];
static u8 SZHVC_sub[2 * 0x100 * 0x100];
};
DECLARE_DEVICE_TYPE(Z80, z80_device)

File diff suppressed because it is too large Load diff