Skip to content

Commit 2c479b2

Browse files
authored
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
1 parent 4183b96 commit 2c479b2

File tree

6 files changed

+2195
-45
lines changed

6 files changed

+2195
-45
lines changed

scripts/src/cpu.lua

+2
Original file line numberDiff line numberDiff line change
@@ -3001,11 +3001,13 @@ if CPUS["Z80"] or CPUS["KC80"] or CPUS["Z80N"] then
30013001
dependency {
30023002
{ MAME_DIR .. "src/devices/cpu/z80/z80.cpp", GEN_DIR .. "emu/cpu/z80/z80.hxx" },
30033003
{ MAME_DIR .. "src/devices/cpu/z80/z80.cpp", GEN_DIR .. "emu/cpu/z80/ncs800.hxx" },
3004+
{ MAME_DIR .. "src/devices/cpu/z80/r800.cpp", GEN_DIR .. "emu/cpu/z80/r800.hxx" },
30043005
}
30053006

30063007
custombuildtask {
30073008
{ 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) $(<) $(@)" } },
30083009
{ 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 $(<) $(@)" } },
3010+
{ 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 $(<) $(@)" } },
30093011
}
30103012
end
30113013

src/devices/cpu/z80/r800.cpp

+150-3
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,33 @@
11
// license:BSD-3-Clause
2-
// copyright-holders:AJR
2+
// copyright-holders:AJR,Wilbert Pol
33
/***************************************************************************
44
55
ASCII R800 CPU
66
7-
TODO: this uses a sped-up Z80 core with added multiply instructions
8-
('mulub', 'muluw').
7+
TODO:
8+
- Internal configuration registers.
9+
- External 24 bits address bus accessible through 9 memory mappers.
10+
- DMA channels.
11+
- Interrupt levels.
12+
- Bits 3 and 5 of the flag register behave differently from the z80.
13+
- Page break penalties.
14+
- Refresh delays.
915
1016
***************************************************************************/
1117

1218
#include "emu.h"
1319
#include "r800.h"
20+
#include "r800dasm.h"
1421

22+
#define LOG_UNDOC (1U << 1)
23+
#define LOG_INT (1U << 2)
24+
#define LOG_TIME (1U << 3)
25+
26+
//#define VERBOSE ( LOG_UNDOC /*| LOG_INT*/ )
27+
#include "logmacro.h"
28+
29+
#define LOGUNDOC(...) LOGMASKED(LOG_UNDOC, __VA_ARGS__)
30+
#define LOGINT(...) LOGMASKED(LOG_INT, __VA_ARGS__)
1531

1632
//**************************************************************************
1733
// GLOBAL VARIABLES
@@ -32,4 +48,135 @@ DEFINE_DEVICE_TYPE(R800, r800_device, "r800", "ASCII R800")
3248
r800_device::r800_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
3349
: z80_device(mconfig, R800, tag, owner, clock)
3450
{
51+
z80_set_m1_cycles(1);
52+
z80_set_memrq_cycles(1);
53+
z80_set_iorq_cycles(1);
54+
}
55+
56+
std::unique_ptr<util::disasm_interface> r800_device::create_disassembler()
57+
{
58+
return std::make_unique<r800_disassembler>();
59+
}
60+
61+
void r800_device::device_validity_check(validity_checker &valid) const
62+
{
63+
cpu_device::device_validity_check(valid);
64+
}
65+
66+
67+
68+
#define HAS_LDAIR_QUIRK 0
69+
70+
/****************************************************************************
71+
* The Z80 registers. halt is set to 1 when the CPU is halted, the refresh
72+
* register is calculated as follows: refresh = (r & 127) | (r2 & 128)
73+
****************************************************************************/
74+
#define CF 0x01
75+
#define NF 0x02
76+
#define PF 0x04
77+
#define VF PF
78+
#define XF 0x08
79+
#define HF 0x10
80+
#define YF 0x20
81+
#define ZF 0x40
82+
#define SF 0x80
83+
84+
#define INT_IRQ 0x01
85+
#define NMI_IRQ 0x02
86+
87+
#define PRVPC m_prvpc.d // previous program counter
88+
89+
#define PCD m_pc.d
90+
#define PC m_pc.w.l
91+
92+
#define SPD m_sp.d
93+
#define SP m_sp.w.l
94+
95+
#define AFD m_af.d
96+
#define AF m_af.w.l
97+
#define A m_af.b.h
98+
#define F m_af.b.l
99+
#define Q m_q
100+
#define QT m_qtemp
101+
#define I m_i
102+
#define R m_r
103+
#define R2 m_r2
104+
105+
#define BCD m_bc.d
106+
#define BC m_bc.w.l
107+
#define B m_bc.b.h
108+
#define C m_bc.b.l
109+
110+
#define DED m_de.d
111+
#define DE m_de.w.l
112+
#define D m_de.b.h
113+
#define E m_de.b.l
114+
115+
#define HLD m_hl.d
116+
#define HL m_hl.w.l
117+
#define H m_hl.b.h
118+
#define L m_hl.b.l
119+
120+
#define IXD m_ix.d
121+
#define IX m_ix.w.l
122+
#define HX m_ix.b.h
123+
#define LX m_ix.b.l
124+
125+
#define IYD m_iy.d
126+
#define IY m_iy.w.l
127+
#define HY m_iy.b.h
128+
#define LY m_iy.b.l
129+
130+
#define WZ m_wz.w.l
131+
#define WZ_H m_wz.b.h
132+
#define WZ_L m_wz.b.l
133+
134+
#define TADR m_shared_addr.w // Typically represents values from A0..15 pins. 16bit input in steps.
135+
#define TADR_H m_shared_addr.b.h
136+
#define TADR_L m_shared_addr.b.l
137+
#define TDAT m_shared_data.w // 16bit input(if use as second parameter) or output in steps.
138+
#define TDAT2 m_shared_data2.w
139+
#define TDAT_H m_shared_data.b.h
140+
#define TDAT_L m_shared_data.b.l
141+
#define TDAT8 m_shared_data.b.l // Typically represents values from D0..8 pins. 8bit input or output in steps.
142+
143+
144+
/***************************************************************
145+
* adjust cycle count by n T-states
146+
***************************************************************/
147+
#define T(icount) { m_icount -= icount; }
148+
149+
/***************************************************************
150+
* SLL r8
151+
***************************************************************/
152+
u8 r800_device::r800_sll(u8 value)
153+
{
154+
const u8 c = (value & 0x80) ? CF : 0;
155+
const u8 res = u8(value << 1);
156+
set_f(SZP[res] | c);
157+
return res;
158+
}
159+
160+
void r800_device::mulub(u8 value)
161+
{
162+
const u16 res = A * value;
163+
HL = res;
164+
const u8 c = (H) ? CF : 0;
165+
const u8 z = (res) ? 0 : ZF;
166+
set_f((F & (HF|NF)) | z | c);
167+
}
168+
169+
void r800_device::muluw(u16 value)
170+
{
171+
const u32 res = HL * value;
172+
DE = res >> 16;
173+
HL = res & 0xffff;
174+
const u8 c = (DE) ? CF : 0;
175+
const u8 z = (res) ? 0 : ZF;
176+
set_f((F & (HF|NF)) | z | c);
177+
}
178+
179+
void r800_device::do_op()
180+
{
181+
#include "cpu/z80/r800.hxx"
35182
}

src/devices/cpu/z80/r800.h

+16-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// license:BSD-3-Clause
2-
// copyright-holders:AJR
2+
// copyright-holders:AJR,Wilbert Pol
33
/***************************************************************************
44
55
ASCII R800 CPU
@@ -24,10 +24,25 @@ class r800_device : public z80_device
2424
// device type constructor
2525
r800_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
2626

27+
static constexpr feature_type imperfect_features() { return feature::TIMING; }
28+
2729
protected:
30+
// device_t implementation
31+
virtual void device_validity_check(validity_checker &valid) const override;
32+
2833
// device_execute_interface overrides
34+
virtual u32 execute_min_cycles() const noexcept override { return 1; }
2935
virtual u64 execute_clocks_to_cycles(u64 clocks) const noexcept override { return (clocks + 4 - 1) / 4; }
3036
virtual u64 execute_cycles_to_clocks(u64 cycles) const noexcept override { return (cycles * 4); }
37+
38+
// device_disasm_interface implementation
39+
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
40+
41+
u8 r800_sll(u8 value);
42+
void mulub(u8 value);
43+
void muluw(u16 value);
44+
45+
virtual void do_op() override;
3146
};
3247

3348
// device type declaration

src/devices/cpu/z80/z80.cpp

+26-33
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,14 @@
2727

2828
#include "z80.inc"
2929

30-
static bool tables_initialised = false;
31-
std::unique_ptr<u8[]> z80_device::SZ = std::make_unique<u8[]>(0x100); // zero and sign flags
32-
std::unique_ptr<u8[]> z80_device::SZ_BIT = std::make_unique<u8[]>(0x100); // zero, sign and parity/overflow (=zero) flags for BIT opcode
33-
std::unique_ptr<u8[]> z80_device::SZP = std::make_unique<u8[]>(0x100); // zero, sign and parity flags
34-
std::unique_ptr<u8[]> z80_device::SZHV_inc = std::make_unique<u8[]>(0x100); // zero, sign, half carry and overflow flags INC r8
35-
std::unique_ptr<u8[]> z80_device::SZHV_dec = std::make_unique<u8[]>(0x100); // zero, sign, half carry and overflow flags DEC r8
36-
37-
std::unique_ptr<u8[]> z80_device::SZHVC_add = std::make_unique<u8[]>(2 * 0x100 * 0x100);
38-
std::unique_ptr<u8[]> z80_device::SZHVC_sub = std::make_unique<u8[]>(2 * 0x100 * 0x100);
30+
bool z80_device::tables_initialised = false;
31+
u8 z80_device::SZ[] = {}; // zero and sign flags
32+
u8 z80_device::SZ_BIT[] = {}; // zero, sign and parity/overflow (=zero) flags for BIT opcode
33+
u8 z80_device::SZP[] = {}; // zero, sign and parity flags
34+
u8 z80_device::SZHV_inc[] = {}; // zero, sign, half carry and overflow flags INC r8
35+
u8 z80_device::SZHV_dec[] = {}; // zero, sign, half carry and overflow flags DEC r8
36+
u8 z80_device::SZHVC_add[] = {};
37+
u8 z80_device::SZHVC_sub[] = {};
3938

4039

4140
/***************************************************************
@@ -501,62 +500,56 @@ void z80_device::device_start()
501500
int val = newval - oldval;
502501
*padd = (newval) ? ((newval & 0x80) ? SF : 0) : ZF;
503502
*padd |= (newval & (YF | XF)); // undocumented flag bits 5+3
504-
if( (newval & 0x0f) < (oldval & 0x0f) ) *padd |= HF;
505-
if( newval < oldval ) *padd |= CF;
506-
if( (val^oldval^0x80) & (val^newval) & 0x80 ) *padd |= VF;
503+
if ((newval & 0x0f) < (oldval & 0x0f)) *padd |= HF;
504+
if (newval < oldval) *padd |= CF;
505+
if ((val^oldval^0x80) & (val^newval) & 0x80) *padd |= VF;
507506
padd++;
508507

509508
// adc with carry set
510509
val = newval - oldval - 1;
511510
*padc = (newval) ? ((newval & 0x80) ? SF : 0) : ZF;
512511
*padc |= (newval & (YF | XF)); // undocumented flag bits 5+3
513-
if( (newval & 0x0f) <= (oldval & 0x0f) ) *padc |= HF;
514-
if( newval <= oldval ) *padc |= CF;
515-
if( (val^oldval^0x80) & (val^newval) & 0x80 ) *padc |= VF;
512+
if ((newval & 0x0f) <= (oldval & 0x0f)) *padc |= HF;
513+
if (newval <= oldval) *padc |= CF;
514+
if ((val^oldval^0x80) & (val^newval) & 0x80) *padc |= VF;
516515
padc++;
517516

518517
// cp, sub or sbc w/o carry set
519518
val = oldval - newval;
520519
*psub = NF | ((newval) ? ((newval & 0x80) ? SF : 0) : ZF);
521520
*psub |= (newval & (YF | XF)); // undocumented flag bits 5+3
522-
if( (newval & 0x0f) > (oldval & 0x0f) ) *psub |= HF;
523-
if( newval > oldval ) *psub |= CF;
524-
if( (val^oldval) & (oldval^newval) & 0x80 ) *psub |= VF;
521+
if ((newval & 0x0f) > (oldval & 0x0f)) *psub |= HF;
522+
if (newval > oldval) *psub |= CF;
523+
if ((val^oldval) & (oldval^newval) & 0x80) *psub |= VF;
525524
psub++;
526525

527526
// sbc with carry set
528527
val = oldval - newval - 1;
529528
*psbc = NF | ((newval) ? ((newval & 0x80) ? SF : 0) : ZF);
530529
*psbc |= (newval & (YF | XF)); // undocumented flag bits 5+3
531-
if( (newval & 0x0f) >= (oldval & 0x0f) ) *psbc |= HF;
532-
if( newval >= oldval ) *psbc |= CF;
533-
if( (val^oldval) & (oldval^newval) & 0x80 ) *psbc |= VF;
530+
if ((newval & 0x0f) >= (oldval & 0x0f)) *psbc |= HF;
531+
if (newval >= oldval) *psbc |= CF;
532+
if ((val^oldval) & (oldval^newval) & 0x80) *psbc |= VF;
534533
psbc++;
535534
}
536535
}
537536

538537
for (int i = 0; i < 256; i++)
539538
{
540539
int p = 0;
541-
if( i&0x01 ) ++p;
542-
if( i&0x02 ) ++p;
543-
if( i&0x04 ) ++p;
544-
if( i&0x08 ) ++p;
545-
if( i&0x10 ) ++p;
546-
if( i&0x20 ) ++p;
547-
if( i&0x40 ) ++p;
548-
if( i&0x80 ) ++p;
540+
for (int b = 0; b < 8; b++)
541+
p += BIT(i, b);
549542
SZ[i] = i ? i & SF : ZF;
550543
SZ[i] |= (i & (YF | XF)); // undocumented flag bits 5+3
551544
SZ_BIT[i] = i ? i & SF : ZF | PF;
552545
SZ_BIT[i] |= (i & (YF | XF)); // undocumented flag bits 5+3
553546
SZP[i] = SZ[i] | ((p & 1) ? 0 : PF);
554547
SZHV_inc[i] = SZ[i];
555-
if( i == 0x80 ) SZHV_inc[i] |= VF;
556-
if( (i & 0x0f) == 0x00 ) SZHV_inc[i] |= HF;
548+
if (i == 0x80) SZHV_inc[i] |= VF;
549+
if ((i & 0x0f) == 0x00) SZHV_inc[i] |= HF;
557550
SZHV_dec[i] = SZ[i] | NF;
558-
if( i == 0x7f ) SZHV_dec[i] |= VF;
559-
if( (i & 0x0f) == 0x0f ) SZHV_dec[i] |= HF;
551+
if (i == 0x7f) SZHV_dec[i] |= VF;
552+
if ((i & 0x0f) == 0x0f) SZHV_dec[i] |= HF;
560553
}
561554

562555
tables_initialised = true;

src/devices/cpu/z80/z80.h

+9-8
Original file line numberDiff line numberDiff line change
@@ -181,14 +181,15 @@ class z80_device : public cpu_device, public z80_daisy_chain_interface
181181
u8 m_memrq_cycles;
182182
u8 m_iorq_cycles;
183183

184-
static std::unique_ptr<u8[]> SZ; // zero and sign flags
185-
static std::unique_ptr<u8[]> SZ_BIT; // zero, sign and parity/overflow (=zero) flags for BIT opcode
186-
static std::unique_ptr<u8[]> SZP; // zero, sign and parity flags
187-
static std::unique_ptr<u8[]> SZHV_inc; // zero, sign, half carry and overflow flags INC r8
188-
static std::unique_ptr<u8[]> SZHV_dec; // zero, sign, half carry and overflow flags DEC r8
189-
190-
static std::unique_ptr<u8[]> SZHVC_add;
191-
static std::unique_ptr<u8[]> SZHVC_sub;
184+
static bool tables_initialised;
185+
static u8 SZ[0x100]; // zero and sign flags
186+
static u8 SZ_BIT[0x100]; // zero, sign and parity/overflow (=zero) flags for BIT opcode
187+
static u8 SZP[0x100]; // zero, sign and parity flags
188+
static u8 SZHV_inc[0x100]; // zero, sign, half carry and overflow flags INC r8
189+
static u8 SZHV_dec[0x100]; // zero, sign, half carry and overflow flags DEC r8
190+
191+
static u8 SZHVC_add[2 * 0x100 * 0x100];
192+
static u8 SZHVC_sub[2 * 0x100 * 0x100];
192193
};
193194

194195
DECLARE_DEVICE_TYPE(Z80, z80_device)

0 commit comments

Comments
 (0)