summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu')
-rw-r--r--src/devices/cpu/mcs48/mcs48.cpp2
-rw-r--r--src/devices/cpu/pdp1/pdp1.cpp93
-rw-r--r--src/devices/cpu/pdp1/pdp1.h31
-rw-r--r--src/devices/cpu/pdp1/pdp1dasm.cpp4
-rw-r--r--src/devices/cpu/pdp1/tx0.cpp4
-rw-r--r--src/devices/cpu/pdp8/pdp8.cpp2
-rw-r--r--src/devices/cpu/pdp8/pdp8dasm.cpp4
-rw-r--r--src/devices/cpu/tms57002/tms57002.cpp37
-rw-r--r--src/devices/cpu/tms57002/tms57002.h2
-rw-r--r--src/devices/cpu/z80/kc82.cpp6
-rw-r--r--src/devices/cpu/z80/kl5c80a12.cpp9
-rw-r--r--src/devices/cpu/z80/kl5c80a16.cpp10
-rw-r--r--src/devices/cpu/z80/kp63.cpp477
-rw-r--r--src/devices/cpu/z80/kp63.h98
-rw-r--r--src/devices/cpu/z80/kp69.cpp10
15 files changed, 665 insertions, 124 deletions
diff --git a/src/devices/cpu/mcs48/mcs48.cpp b/src/devices/cpu/mcs48/mcs48.cpp
index f43e25e7986..58f3d31b150 100644
--- a/src/devices/cpu/mcs48/mcs48.cpp
+++ b/src/devices/cpu/mcs48/mcs48.cpp
@@ -889,10 +889,10 @@ OPHANDLER( stop_tcnt ) { burn_cycles(1); m_timecount_enabled = 0; }
OPHANDLER( strt_t ) { burn_cycles(1); m_timecount_enabled = TIMER_ENABLED; m_prescaler = 0; }
OPHANDLER( strt_cnt )
{
+ burn_cycles(1);
if (!(m_timecount_enabled & COUNTER_ENABLED))
m_t1_history = test_r(1);
- burn_cycles(1);
m_timecount_enabled = COUNTER_ENABLED;
}
diff --git a/src/devices/cpu/pdp1/pdp1.cpp b/src/devices/cpu/pdp1/pdp1.cpp
index a8704ad29d3..2d04709a4a9 100644
--- a/src/devices/cpu/pdp1/pdp1.cpp
+++ b/src/devices/cpu/pdp1/pdp1.cpp
@@ -348,8 +348,8 @@
#define LOG_EXTRA 0
#define LOG_IOT_EXTRA 0
-#define READ_PDP_18BIT(A) ((signed)m_program->read_dword((A)<<2))
-#define WRITE_PDP_18BIT(A,V) (m_program->write_dword((A)<<2,(V)))
+#define READ_PDP_18BIT(A) ((signed)m_program->read_dword(A))
+#define WRITE_PDP_18BIT(A,V) (m_program->write_dword((A),(V)))
#define PC m_pc
@@ -378,12 +378,14 @@
#define PREVIOUS_PC ((PC & ADDRESS_EXTENSION_MASK) | ((PC-1) & BASE_ADDRESS_MASK))
-DEFINE_DEVICE_TYPE(PDP1, pdp1_device, "pdp1_cpu", "DEC PDP1")
+DEFINE_DEVICE_TYPE(PDP1, pdp1_device, "pdp1_cpu", "DEC PDP-1 Central Processor")
pdp1_device::pdp1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: cpu_device(mconfig, PDP1, tag, owner, clock)
- , m_program_config("program", ENDIANNESS_BIG, 32, 18, 0)
+ , m_program_config("program", ENDIANNESS_BIG, 32, 18, -2) // data is actually 18 bits wide
+ , m_extern_iot(*this)
+ , m_io_sc_callback(*this)
{
m_program_config.m_is_octal = true;
}
@@ -405,16 +407,9 @@ void pdp1_device::device_config_complete()
// or initialize to defaults if none provided
else
{
- memset(&read_binary_word, 0, sizeof(read_binary_word));
- memset(&io_sc_callback, 0, sizeof(io_sc_callback));
extend_support = 0;
hw_mul_div = 0;
type_20_sbs = 0;
-
- for (auto & elem : extern_iot)
- {
- memset(&elem, 0, sizeof(elem));
- }
}
}
@@ -495,34 +490,6 @@ void pdp1_device::execute_set_input(int irqline, int state)
}
-static void null_iot(device_t *device, int op2, int nac, int mb, int *io, int ac)
-{
- pdp1_device *pdp1 = dynamic_cast<pdp1_device*>(device);
-
- pdp1->pdp1_null_iot(op2, nac, mb, io, ac);
-}
-
-static void lem_eem_iot(device_t *device, int op2, int nac, int mb, int *io, int ac)
-{
- pdp1_device *pdp1 = dynamic_cast<pdp1_device*>(device);
-
- pdp1->pdp1_lem_eem_iot(op2, nac, mb, io, ac);
-}
-
-static void sbs_iot(device_t *device, int op2, int nac, int mb, int *io, int ac)
-{
- pdp1_device *pdp1 = dynamic_cast<pdp1_device*>(device);
-
- pdp1->pdp1_sbs_iot(op2, nac, mb, io, ac);
-}
-
-static void type_20_sbs_iot(device_t *device, int op2, int nac, int mb, int *io, int ac)
-{
- pdp1_device *pdp1 = dynamic_cast<pdp1_device*>(device);
-
- pdp1->pdp1_type_20_sbs_iot(op2, nac, mb, io, ac);
-}
-
void pdp1_device::device_start()
{
int i;
@@ -569,12 +536,11 @@ void pdp1_device::device_start()
/* set up params and callbacks */
for (i=0; i<64; i++)
{
- m_extern_iot[i] = (extern_iot[i])
- ? extern_iot[i]
- : null_iot;
+ m_extern_iot[i].resolve();
+ if (m_extern_iot[i].isnull())
+ m_extern_iot[i] = iot_delegate(*this, FUNC(pdp1_device::null_iot));
}
- m_read_binary_word = read_binary_word;
- m_io_sc_callback = io_sc_callback;
+ m_io_sc_callback.resolve();
m_extend_support = extend_support;
m_hw_mul_div = hw_mul_div;
m_type_20_sbs = type_20_sbs;
@@ -599,13 +565,13 @@ void pdp1_device::device_start()
if (m_extend_support)
{
- m_extern_iot[074] = lem_eem_iot;
+ m_extern_iot[074] = iot_delegate(*this, FUNC(pdp1_device::lem_eem_iot));
}
- m_extern_iot[054] = m_extern_iot[055] = m_extern_iot[056] = sbs_iot;
+ m_extern_iot[054] = m_extern_iot[055] = m_extern_iot[056] = iot_delegate(*this, FUNC(pdp1_device::sbs_iot));
if (m_type_20_sbs)
{
m_extern_iot[050] = m_extern_iot[051] = m_extern_iot[052] = m_extern_iot[053]
- = type_20_sbs_iot;
+ = iot_delegate(*this, FUNC(pdp1_device::type_20_sbs_iot));
}
state_add( PDP1_PC, "PC", m_pc).formatstr("%06O");
@@ -796,9 +762,6 @@ void pdp1_device::execute_run()
{
do
{
- debugger_instruction_hook(PC);
-
-
/* ioh should be cleared at the end of the instruction cycle, and ios at the
start of next instruction cycle, but who cares? */
if (m_ioh && m_ios)
@@ -808,15 +771,19 @@ void pdp1_device::execute_run()
if ((! m_run) && (! m_rim))
+ {
+ debugger_instruction_hook(PC);
m_icount = 0; /* if processor is stopped, just burn cycles */
+ }
else if (m_rim)
{
switch (m_rim_step)
{
case 0:
/* read first word as instruction */
- if (m_read_binary_word)
- (*m_read_binary_word)(this); /* data will be transferred to IO register */
+ MB = 0;
+ /* data will be transferred to IO register in response to RPB */
+ m_extern_iot[2](2, 0, 1, IO, AC);
m_rim_step = 1;
m_ios = 0;
break;
@@ -860,8 +827,9 @@ void pdp1_device::execute_run()
case 2:
/* read second word as data */
- if (m_read_binary_word)
- (*m_read_binary_word)(this); /* data will be transferred to IO register */
+ MB = 0;
+ /* data will be transferred to IO register in response to RPB */
+ m_extern_iot[2](2, 0, 1, IO, AC);
m_rim_step = 3;
m_ios = 0;
break;
@@ -940,6 +908,7 @@ void pdp1_device::execute_run()
if (! m_cycle)
{ /* no instruction in progress: time to fetch a new instruction, I guess */
+ debugger_instruction_hook(PC);
MB = READ_PDP_18BIT(MA = PC);
INCREMENT_PC;
IR = MB >> 13; /* basic opcode */
@@ -1564,7 +1533,7 @@ void pdp1_device::execute_instruction()
{ /* IOT with IO wait */
if (m_ioc)
{ /* the iot command line is pulsed only if ioc is asserted */
- (*m_extern_iot[MB & 0000077])(this, MB & 0000077, (MB & 0004000) == 0, MB, &IO, AC);
+ m_extern_iot[MB & 0000077](MB & 0000077, (MB & 0004000) == 0, MB, IO, AC);
m_ioh = 1; /* enable io wait */
@@ -1587,7 +1556,7 @@ void pdp1_device::execute_instruction()
}
else
{ /* IOT with no IO wait */
- (*m_extern_iot[MB & 0000077])(this, MB & 0000077, (MB & 0004000) != 0, MB, &IO, AC);
+ m_extern_iot[MB & 0000077](MB & 0000077, (MB & 0004000) != 0, MB, IO, AC);
}
break;
case OPR: /* Operate Instruction Group */
@@ -1639,7 +1608,7 @@ no_fetch:
/*
Handle unimplemented IOT
*/
-void pdp1_device::pdp1_null_iot(int op2, int nac, int mb, int *io, int ac)
+void pdp1_device::null_iot(int op2, int nac, int mb, int &io, int ac)
{
/* Note that the dummy IOT 0 is used to wait for the completion pulse
generated by the a pending IOT (IOT with completion pulse but no IO wait) */
@@ -1661,7 +1630,7 @@ void pdp1_device::pdp1_null_iot(int op2, int nac, int mb, int *io, int ac)
IOT 74: LEM/EEM
*/
-void pdp1_device::pdp1_lem_eem_iot(int op2, int nac, int mb, int *io, int ac)
+void pdp1_device::lem_eem_iot(int op2, int nac, int mb, int &io, int ac)
{
if (! m_extend_support) /* extend mode supported? */
{
@@ -1684,7 +1653,7 @@ void pdp1_device::pdp1_lem_eem_iot(int op2, int nac, int mb, int *io, int ac)
IOT 55: esm
IOT 56: cbs
*/
-void pdp1_device::pdp1_sbs_iot(int op2, int nac, int mb, int *io, int ac)
+void pdp1_device::sbs_iot(int op2, int nac, int mb, int &io, int ac)
{
switch (op2)
{
@@ -1727,7 +1696,7 @@ void pdp1_device::pdp1_sbs_iot(int op2, int nac, int mb, int *io, int ac)
IOT 52: isb
IOT 53: cac
*/
-void pdp1_device::pdp1_type_20_sbs_iot(int op2, int nac, int mb, int *io, int ac)
+void pdp1_device::type_20_sbs_iot(int op2, int nac, int mb, int &io, int ac)
{
int channel, mask;
if (! m_type_20_sbs) /* type 20 sequence break system supported? */
@@ -1820,6 +1789,6 @@ void pdp1_device::pulse_start_clear()
field_interrupt();
/* now, we kindly ask IO devices to reset, too */
- if (m_io_sc_callback)
- (*m_io_sc_callback)(this);
+ if (!m_io_sc_callback.isnull())
+ m_io_sc_callback();
}
diff --git a/src/devices/cpu/pdp1/pdp1.h b/src/devices/cpu/pdp1/pdp1.h
index 1c2d5c7eea3..0a81c8177d4 100644
--- a/src/devices/cpu/pdp1/pdp1.h
+++ b/src/devices/cpu/pdp1/pdp1.h
@@ -20,20 +20,8 @@ enum
};
-typedef void (*pdp1_extern_iot_func)(device_t *device, int op2, int nac, int mb, int *io, int ac);
-typedef void (*pdp1_read_binary_word_func)(device_t *device);
-typedef void (*pdp1_io_sc_func)(device_t *device);
-
-
struct pdp1_reset_param_t
{
- /* callbacks for iot instructions (required for any I/O) */
- pdp1_extern_iot_func extern_iot[64];
- /* read a word from the perforated tape reader (required for read-in mode) */
- pdp1_read_binary_word_func read_binary_word;
- /* callback called when sc is pulsed: IO devices should reset */
- pdp1_io_sc_func io_sc_callback;
-
/* 0: no extend support, 1: extend with 15-bit address, 2: extend with 16-bit address */
int extend_support;
/* 1 to use hardware multiply/divide (MUL, DIV) instead of MUS, DIS */
@@ -49,6 +37,9 @@ class pdp1_device : public cpu_device
, public pdp1_reset_param_t
{
public:
+ typedef device_delegate<void (int op2, int nac, int mb, int &io, int ac)> iot_delegate;
+ typedef device_delegate<void ()> io_sc_delegate;
+
enum opcode
{
AND = 001,
@@ -83,14 +74,16 @@ public:
// construction/destruction
pdp1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ template <int I, typename... T> void set_iot_callback(T &&... args) { m_extern_iot[I].set(std::forward<T>(args)...); }
+ template <typename... T> void set_io_sc_callback(T &&... args) { m_io_sc_callback.set(std::forward<T>(args)...); }
void set_reset_param(const pdp1_reset_param_t *param) { m_reset_param = param; }
void pulse_start_clear();
void io_complete() { m_ios = 1; }
- void pdp1_null_iot(int op2, int nac, int mb, int *io, int ac);
- void pdp1_lem_eem_iot(int op2, int nac, int mb, int *io, int ac);
- void pdp1_sbs_iot(int op2, int nac, int mb, int *io, int ac);
- void pdp1_type_20_sbs_iot(int op2, int nac, int mb, int *io, int ac);
+ void null_iot(int op2, int nac, int mb, int &io, int ac);
+ void lem_eem_iot(int op2, int nac, int mb, int &io, int ac);
+ void sbs_iot(int op2, int nac, int mb, int &io, int ac);
+ void type_20_sbs_iot(int op2, int nac, int mb, int &io, int ac);
protected:
// device-level overrides
@@ -167,11 +160,9 @@ private:
int m_no_sequence_break; /* disable sequence break recognition for one cycle */
/* callbacks for iot instructions (required for any I/O) */
- pdp1_extern_iot_func m_extern_iot[64];
- /* read a word from the perforated tape reader (required for read-in mode) */
- pdp1_read_binary_word_func m_read_binary_word;
+ iot_delegate::array<64> m_extern_iot;
/* callback called when sc is pulsed: IO devices should reset */
- pdp1_io_sc_func m_io_sc_callback;
+ io_sc_delegate m_io_sc_callback;
/* 0: no extend support, 1: extend with 15-bit address, 2: extend with 16-bit address */
int m_extend_support;
diff --git a/src/devices/cpu/pdp1/pdp1dasm.cpp b/src/devices/cpu/pdp1/pdp1dasm.cpp
index 9b04c91ec87..0c3286a9257 100644
--- a/src/devices/cpu/pdp1/pdp1dasm.cpp
+++ b/src/devices/cpu/pdp1/pdp1dasm.cpp
@@ -19,7 +19,7 @@ inline void pdp1_disassembler::ea()
u32 pdp1_disassembler::opcode_alignment() const
{
- return 4;
+ return 1;
}
offs_t pdp1_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params)
@@ -290,5 +290,5 @@ offs_t pdp1_disassembler::disassemble(std::ostream &stream, offs_t pc, const dat
//etime = 5;
break;
}
- return 4;
+ return 1;
}
diff --git a/src/devices/cpu/pdp1/tx0.cpp b/src/devices/cpu/pdp1/tx0.cpp
index 99636fcb9c2..19ec75f223b 100644
--- a/src/devices/cpu/pdp1/tx0.cpp
+++ b/src/devices/cpu/pdp1/tx0.cpp
@@ -19,8 +19,8 @@
#define LOG_EXTRA 0
-#define READ_TX0_18BIT(A) ((signed)m_program->read_dword((A)<<2))
-#define WRITE_TX0_18BIT(A,V) (m_program->write_dword((A)<<2,(V)))
+#define READ_TX0_18BIT(A) ((signed)m_program->read_dword(A))
+#define WRITE_TX0_18BIT(A,V) (m_program->write_dword((A),(V)))
#define io_handler_rim 3
diff --git a/src/devices/cpu/pdp8/pdp8.cpp b/src/devices/cpu/pdp8/pdp8.cpp
index 3084c1bb29d..e8090c8dfde 100644
--- a/src/devices/cpu/pdp8/pdp8.cpp
+++ b/src/devices/cpu/pdp8/pdp8.cpp
@@ -51,7 +51,7 @@ DEFINE_DEVICE_TYPE(PDP8, pdp8_device, "pdp8_cpu", "DEC PDP8")
pdp8_device::pdp8_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: cpu_device(mconfig, PDP8, tag, owner, clock),
- m_program_config("program", ENDIANNESS_BIG, 12, 12),
+ m_program_config("program", ENDIANNESS_BIG, 12, 12, -1),
m_pc(0),
m_ac(0),
m_mb(0),
diff --git a/src/devices/cpu/pdp8/pdp8dasm.cpp b/src/devices/cpu/pdp8/pdp8dasm.cpp
index 389cf11fda7..8c2e57573b5 100644
--- a/src/devices/cpu/pdp8/pdp8dasm.cpp
+++ b/src/devices/cpu/pdp8/pdp8dasm.cpp
@@ -11,7 +11,7 @@
u32 pdp8_disassembler::opcode_alignment() const
{
- return 2;
+ return 1;
}
offs_t pdp8_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params)
@@ -164,5 +164,5 @@ offs_t pdp8_disassembler::disassemble(std::ostream &stream, offs_t pc, const dat
}
}
- return 2 | SUPPORTED;
+ return 1 | SUPPORTED | (opcode == 4 ? STEP_OVER : 0);
}
diff --git a/src/devices/cpu/tms57002/tms57002.cpp b/src/devices/cpu/tms57002/tms57002.cpp
index 8464a10e2f0..c2cf28f3f92 100644
--- a/src/devices/cpu/tms57002/tms57002.cpp
+++ b/src/devices/cpu/tms57002/tms57002.cpp
@@ -918,28 +918,22 @@ void tms57002_device::execute_run()
icount = 0;
}
-void tms57002_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
+void tms57002_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
- assert(samples == 1);
+ assert(inputs[0].samples() == 1);
+ assert(outputs[0].samples() == 1);
- if (st0 & ST0_SIM)
- {
- si[0] = (inputs[0][0] << 8) & 0xffffff;
- si[1] = (inputs[1][0] << 8) & 0xffffff;
- si[2] = (inputs[2][0] << 8) & 0xffffff;
- si[3] = (inputs[3][0] << 8) & 0xffffff;
- }
- else
- {
- si[0] = inputs[0][0] & 0xffffff;
- si[1] = inputs[1][0] & 0xffffff;
- si[2] = inputs[2][0] & 0xffffff;
- si[3] = inputs[3][0] & 0xffffff;
- }
- outputs[0][0] = int16_t(so[0] >> 8);
- outputs[1][0] = int16_t(so[1] >> 8);
- outputs[2][0] = int16_t(so[2] >> 8);
- outputs[3][0] = int16_t(so[3] >> 8);
+ stream_buffer::sample_t in_scale = 32768.0 * ((st0 & ST0_SIM) ? 256.0 : 1.0);
+ si[0] = s32(inputs[0].get(0) * in_scale) & 0xffffff;
+ si[1] = s32(inputs[1].get(0) * in_scale) & 0xffffff;
+ si[2] = s32(inputs[2].get(0) * in_scale) & 0xffffff;
+ si[3] = s32(inputs[3].get(0) * in_scale) & 0xffffff;
+
+ stream_buffer::sample_t out_scale = 1.0 / (32768.0 * 65536.0);
+ outputs[0].put(0, stream_buffer::sample_t(s32(so[0] << 8)) * out_scale);
+ outputs[1].put(0, stream_buffer::sample_t(s32(so[1] << 8)) * out_scale);
+ outputs[2].put(0, stream_buffer::sample_t(s32(so[2] << 8)) * out_scale);
+ outputs[3].put(0, stream_buffer::sample_t(s32(so[3] << 8)) * out_scale);
sync_w(1);
}
@@ -981,8 +975,7 @@ void tms57002_device::device_start()
state_add(TMS57002_HOST3, "HOST3", host[3]);
set_icountptr(icount);
-
- stream_alloc(4, 4, STREAM_SYNC);
+ stream_alloc(4, 4, SAMPLE_RATE_INPUT_ADAPTIVE, STREAM_SYNCHRONOUS);
save_item(NAME(macc));
save_item(NAME(macc_read));
diff --git a/src/devices/cpu/tms57002/tms57002.h b/src/devices/cpu/tms57002/tms57002.h
index b1a96823b06..12bcd732120 100644
--- a/src/devices/cpu/tms57002/tms57002.h
+++ b/src/devices/cpu/tms57002/tms57002.h
@@ -36,7 +36,7 @@ protected:
virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_reset() override;
- virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
virtual space_config_vector memory_space_config() const override;
virtual u32 execute_min_cycles() const noexcept override;
virtual u32 execute_max_cycles() const noexcept override;
diff --git a/src/devices/cpu/z80/kc82.cpp b/src/devices/cpu/z80/kc82.cpp
index dbea8fc70f5..bf0a26290c4 100644
--- a/src/devices/cpu/z80/kc82.cpp
+++ b/src/devices/cpu/z80/kc82.cpp
@@ -64,13 +64,11 @@ void kc82_device::device_start()
for (int n = 1; n <= 4; n++)
{
- state_add<u8>(KC82_B1 + n - 1, string_format("B%d", n).c_str(),
- [this, n]() { return m_mmu_b[n]; },
+ state_add(KC82_B1 + n - 1, string_format("B%d", n).c_str(), m_mmu_b[n],
[this, n](u8 data) { m_mmu_b[n] = data; mmu_remap_pages(); }
).mask(0x3f);
if (n != 4)
- state_add<u16>(KC82_A1 + n - 1, string_format("A%d", n).c_str(),
- [this, n]() { return m_mmu_a[n]; },
+ state_add(KC82_A1 + n - 1, string_format("A%d", n).c_str(), m_mmu_a[n],
[this, n](u16 data) { m_mmu_a[n] = data; mmu_remap_pages(); }
).mask(0x3ff);
}
diff --git a/src/devices/cpu/z80/kl5c80a12.cpp b/src/devices/cpu/z80/kl5c80a12.cpp
index dd7bd6060a6..7f79c37dec9 100644
--- a/src/devices/cpu/z80/kl5c80a12.cpp
+++ b/src/devices/cpu/z80/kl5c80a12.cpp
@@ -12,7 +12,7 @@
Important functional blocks:
— MMU
— USART (KP51) (unemulated)
- — 16-bit timer/counters (KP64, KP63) (unemulated)
+ — 16-bit timer/counters (KP64, KP63) (KP64 unemulated)
— 16-level interrupt controller (KP69)
— Parallel ports (KP65, KP66) (unemulated)
— 512-byte high-speed RAM
@@ -22,6 +22,7 @@
#include "emu.h"
#include "kl5c80a12.h"
+#include "kp63.h"
// device type definition
DEFINE_DEVICE_TYPE(KL5C80A12, kl5c80a12_device, "kl5c80a12", "Kawasaki Steel KL5C80A12")
@@ -59,6 +60,7 @@ void kl5c80a12_device::internal_ram(address_map &map)
void kl5c80a12_device::internal_io(address_map &map)
{
map(0x00, 0x07).mirror(0xff00).rw(FUNC(kl5c80a12_device::mmu_r), FUNC(kl5c80a12_device::mmu_w));
+ map(0x20, 0x25).mirror(0xff00).rw("timerb", FUNC(kp63_3channel_device::read), FUNC(kp63_3channel_device::write));
map(0x34, 0x34).mirror(0xff00).rw(m_kp69, FUNC(kp69_device::isrl_r), FUNC(kp69_device::lerl_pgrl_w));
map(0x35, 0x35).mirror(0xff00).rw(m_kp69, FUNC(kp69_device::isrh_r), FUNC(kp69_device::lerh_pgrh_w));
map(0x36, 0x36).mirror(0xff00).rw(m_kp69, FUNC(kp69_device::imrl_r), FUNC(kp69_device::imrl_w));
@@ -97,6 +99,11 @@ void kl5c80a12_device::device_add_mconfig(machine_config &config)
{
KP69(config, m_kp69);
m_kp69->int_callback().set_inputline(*this, INPUT_LINE_IRQ0);
+
+ kp63_3channel_device &timerb(KP63_3CHANNEL(config, "timerb", DERIVED_CLOCK(1, 2)));
+ timerb.outs_callback<0>().set(m_kp69, FUNC(kp69_device::ir_w<13>));
+ timerb.outs_callback<1>().set(m_kp69, FUNC(kp69_device::ir_w<14>));
+ timerb.outs_callback<2>().set(m_kp69, FUNC(kp69_device::ir_w<15>));
}
diff --git a/src/devices/cpu/z80/kl5c80a16.cpp b/src/devices/cpu/z80/kl5c80a16.cpp
index 6328a7322f4..8fa31925366 100644
--- a/src/devices/cpu/z80/kl5c80a16.cpp
+++ b/src/devices/cpu/z80/kl5c80a16.cpp
@@ -9,7 +9,7 @@
— DMA controller (KP27) (unemulated)
— UART (KP61) (unemulated)
— Synchronous serial port (KP62) (unemulated)
- — 16-bit timer/counters (KP63A) (unemulated)
+ — 16-bit timer/counters (KP63A)
— 16-level interrupt controller (KP69)
— Parallel ports (KP67) (unemulated)
— External bus/DRAM interface unit (unemulated)
@@ -18,6 +18,7 @@
#include "emu.h"
#include "kl5c80a16.h"
+#include "kp63.h"
// device type definition
DEFINE_DEVICE_TYPE(KL5C80A16, kl5c80a16_device, "kl5c80a16", "Kawasaki Steel KL5C80A16")
@@ -45,6 +46,7 @@ kl5c80a16_device::kl5c80a16_device(const machine_config &mconfig, const char *ta
void kl5c80a16_device::internal_io(address_map &map)
{
map(0x00, 0x07).mirror(0xff00).rw(FUNC(kl5c80a16_device::mmu_r), FUNC(kl5c80a16_device::mmu_w));
+ map(0x20, 0x27).mirror(0xff00).rw("timer", FUNC(kp63a_device::read), FUNC(kp63a_device::write));
map(0x34, 0x34).mirror(0xff00).rw(m_kp69, FUNC(kp69_device::isrl_r), FUNC(kp69_device::lerl_pgrl_w));
map(0x35, 0x35).mirror(0xff00).rw(m_kp69, FUNC(kp69_device::isrh_r), FUNC(kp69_device::lerh_pgrh_w));
map(0x36, 0x36).mirror(0xff00).rw(m_kp69, FUNC(kp69_device::imrl_r), FUNC(kp69_device::imrl_w));
@@ -83,6 +85,12 @@ void kl5c80a16_device::device_add_mconfig(machine_config &config)
{
KP69(config, m_kp69);
m_kp69->int_callback().set_inputline(*this, INPUT_LINE_IRQ0);
+
+ kp63a_device &timer(KP63A(config, "timer", DERIVED_CLOCK(1, 2)));
+ timer.outs_callback<0>().set(m_kp69, FUNC(kp69_device::ir_w<12>));
+ timer.outs_callback<1>().set(m_kp69, FUNC(kp69_device::ir_w<13>));
+ //timer.outs_callback<2>().set(m_kp69, FUNC(kp69_device::ir_w<0>)); // TODO: multiplexed with P20 input by SCR1 bit 4
+ //timer.outs_callback<3>().set(m_kp69, FUNC(kp69_device::ir_w<1>)); // TODO: multiplexed with P21 input by SCR1 bit 5 (may also be NMI)
}
diff --git a/src/devices/cpu/z80/kp63.cpp b/src/devices/cpu/z80/kp63.cpp
new file mode 100644
index 00000000000..a1a9e5913c8
--- /dev/null
+++ b/src/devices/cpu/z80/kp63.cpp
@@ -0,0 +1,477 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/***************************************************************************
+
+ Kawasaki Steel (Kawatetsu) KP63(A) Timer/Counter
+
+ These macro cells provide 4 independent 16-bit down counters (reduced
+ to 3 in some versions) driven by an 8-bit prescaler attached to the
+ system clock. This prescaler is not fully emulated here, since its
+ operations are mostly transparent, though a divide-by-4 clock output
+ (SYNC) may be selected to appear on a port pin.
+
+ Each counter has a single and optional external input (GATEn), which
+ on the KP63 can only be used to gate a divide-by-4 count but can also
+ be configured as an input clock on the KP63A.
+
+ Two outputs are generated for each counter. The pulse or toggle output
+ (OUTPn) has configurable polarity and can be used for 8-bit PWM. The
+ strobe output (OUTSn) goes active high for 4 clock cycles when the
+ counter underflows and is connected to the interrupt controller.
+
+ Writing the initial count register (CR) and reading the current count
+ are two-step processes, effective at the second write or first read.
+ These must not be overlapped with each other since they share a
+ temporary register.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "kp63.h"
+
+#define VERBOSE 1
+#include "logmacro.h"
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// device type definitions
+DEFINE_DEVICE_TYPE(KP63_3CHANNEL, kp63_3channel_device, "kp63_3channel", "Kawasaki Steel KP63 Timer/Counter (3 channels)")
+DEFINE_DEVICE_TYPE(KP63A, kp63a_device, "kp63a", "Kawasaki Steel KP63A Timer/Counter")
+
+const char *const kp63_device::s_count_modes[4] =
+{
+ "one-shot",
+ "continuous count",
+ "WDT",
+ "PWM"
+};
+
+
+//**************************************************************************
+// KP63 DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// kp63_device - constructor
+//-------------------------------------------------
+
+kp63_device::kp63_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u8 num_counters, u8 mode_mask)
+ : device_t(mconfig, type, tag, owner, clock)
+ , m_out_pulse_callback(*this)
+ , m_out_strobe_callback(*this)
+ , c_num_counters(num_counters)
+ , c_mode_mask(mode_mask)
+ , m_timer{0}
+ , m_strobe_timer{0}
+ , m_pwm_timer{0}
+ , m_cr{0}
+ , m_last_count{0}
+ , m_count_tmp{0}
+ , m_status{0}
+ , m_rw_seq(0)
+ , m_timer_started(0)
+ , m_gate_input(0xf)
+{
+}
+
+
+//-------------------------------------------------
+// kp63_3channel_device - constructor
+//-------------------------------------------------
+
+kp63_3channel_device::kp63_3channel_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : kp63_device(mconfig, KP63_3CHANNEL, tag, owner, clock, 3, 0x1f)
+{
+}
+
+
+//-------------------------------------------------
+// kp63a_device - constructor
+//-------------------------------------------------
+
+kp63a_device::kp63a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : kp63_device(mconfig, KP63A, tag, owner, clock, 4, 0x3f)
+{
+}
+
+
+//-------------------------------------------------
+// device_resolve_objects - resolve objects that
+// may be needed for other devices to set
+// initial conditions at start time
+//-------------------------------------------------
+
+void kp63_device::device_resolve_objects()
+{
+ // Resolve output callbacks
+ m_out_pulse_callback.resolve_all_safe();
+ m_out_strobe_callback.resolve_all_safe();
+}
+
+
+//-------------------------------------------------
+// timer_expired - handle timed count underflow
+//-------------------------------------------------
+
+template <int N>
+TIMER_CALLBACK_MEMBER(kp63_device::timer_expired)
+{
+ timer_pulse(N);
+}
+
+
+//-------------------------------------------------
+// strobe_off - handle end of strobe output
+//-------------------------------------------------
+
+template <int N>
+TIMER_CALLBACK_MEMBER(kp63_device::strobe_off)
+{
+ m_out_strobe_callback[N](0);
+}
+
+
+//-------------------------------------------------
+// pwm_off - handle PWM phase change
+//-------------------------------------------------
+
+template <int N>
+TIMER_CALLBACK_MEMBER(kp63_device::pwm_off)
+{
+ m_status[N] &= 0x7f;
+ m_out_pulse_callback[N](BIT(m_status[N], 4) ? 1 : 0);
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void kp63_device::device_start()
+{
+ // Setup timers
+ m_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kp63_device::timer_expired<0>), this));
+ m_strobe_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kp63_device::strobe_off<0>), this));
+ m_pwm_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kp63_device::pwm_off<0>), this));
+ m_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kp63_device::timer_expired<1>), this));
+ m_strobe_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kp63_device::strobe_off<1>), this));
+ m_pwm_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kp63_device::pwm_off<1>), this));
+ m_timer[2] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kp63_device::timer_expired<2>), this));
+ m_strobe_timer[2] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kp63_device::strobe_off<2>), this));
+ m_pwm_timer[2] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kp63_device::pwm_off<2>), this));
+ if (c_num_counters > 3)
+ {
+ m_timer[3] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kp63_device::timer_expired<3>), this));
+ m_strobe_timer[3] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kp63_device::strobe_off<3>), this));
+ m_pwm_timer[3] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(kp63_device::pwm_off<3>), this));
+ }
+
+ // Save state
+ save_item(NAME(m_cr));
+ save_item(NAME(m_last_count));
+ save_item(NAME(m_count_tmp));
+ save_item(NAME(m_status));
+ save_item(NAME(m_rw_seq));
+ save_item(NAME(m_timer_started));
+ save_item(NAME(m_gate_input));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void kp63_device::device_reset()
+{
+ for (unsigned n = 0; n < c_num_counters; n++)
+ {
+ // Turn off timers
+ m_timer[n]->adjust(attotime::never);
+ m_strobe_timer[n]->adjust(attotime::never);
+ m_pwm_timer[n]->adjust(attotime::never);
+
+ // Reset status and count
+ m_status[n] = 0;
+ m_cr[n] = 0xffff;
+ m_last_count[n] = 0xffff;
+
+ // Clear outputs
+ m_out_pulse_callback[n](0);
+ m_out_strobe_callback[n](0);
+ }
+
+ // Clear read/write sequence for all counters
+ m_rw_seq = 0;
+ m_timer_started = 0;
+}
+
+
+//-------------------------------------------------
+// timer_pulse - change outputs and stop or
+// reload timer as count underflows
+//-------------------------------------------------
+
+void kp63_device::timer_pulse(unsigned n)
+{
+ // Toggle pulse output
+ m_status[n] ^= 0x80;
+ m_out_pulse_callback[n](BIT(m_status[n], 7) != BIT(m_status[n], 4) ? 1 : 0);
+
+ // Begin strobe output
+ m_out_strobe_callback[n](1);
+ m_strobe_timer[n]->adjust(clocks_to_attotime(4));
+
+ // Reload timer in continuous count and PWM modes
+ if (BIT(m_status[n], 2))
+ timer_reload(n);
+ else
+ {
+ // Stop count at FFFF in one-shot and WDT modes
+ m_last_count[n] = 0xffff;
+ m_timer_started &= ~(1 << n);
+ }
+}
+
+
+//-------------------------------------------------
+// timer_reload - reload timer from CR
+//-------------------------------------------------
+
+void kp63_device::timer_reload(unsigned n)
+{
+ m_timer_started |= 1 << n;
+
+ if (BIT(m_status[n], 5) || ((m_status[n] & 0x03) == 0x03 && !BIT(m_gate_input, n)))
+ m_last_count[n] = m_cr[n];
+ else
+ {
+ unsigned prescale = BIT(m_status[n], 1) ? 4 : BIT(m_status[n], 0) ? 16 : 256;
+ if ((m_status[n] & 0x0c) == 0x0c)
+ {
+ // PWM
+ m_timer[n]->adjust(clocks_to_attotime(prescale * ((m_cr[n] & 0x00ff) + 1)));
+ m_pwm_timer[n]->adjust(clocks_to_attotime(prescale * ((m_cr[n] >> 8) + 1)));
+ }
+ else
+ m_timer[n]->adjust(clocks_to_attotime(prescale * (u32(m_cr[n]) + 1)));
+ }
+}
+
+
+//-------------------------------------------------
+// timer_resume_count - start counting again
+//-------------------------------------------------
+
+void kp63_device::timer_resume_count(unsigned n)
+{
+ if (!BIT(m_status[n], 5) || ((m_status[n] & 0x03) != 0x03 || BIT(m_gate_input, n)))
+ {
+ unsigned prescale = BIT(m_status[n], 1) ? 4 : BIT(m_status[n], 0) ? 16 : 256;
+ if ((m_status[n] & 0x0c) == 0x0c)
+ {
+ // PWM
+ m_timer[n]->adjust(clocks_to_attotime(prescale * ((m_last_count[n] & 0x00ff) + 1)));
+ m_pwm_timer[n]->adjust(clocks_to_attotime(prescale * ((m_last_count[n] >> 8) + 1)));
+ }
+ else
+ m_timer[n]->adjust(clocks_to_attotime(prescale * (u32(m_last_count[n]) + 1)));
+ }
+}
+
+
+//-------------------------------------------------
+// timer_get_count - obtain the instant count in
+// case of a readout or pause
+//-------------------------------------------------
+
+u16 kp63_device::timer_get_count(unsigned n) const
+{
+ if (!BIT(m_timer_started, n) || BIT(m_status[n], 5) || ((m_status[n] & 0x03) == 0x03 && !BIT(m_gate_input, n)))
+ return m_last_count[n];
+ else
+ {
+ unsigned prescale = BIT(m_status[n], 1) ? 4 : BIT(m_status[n], 0) ? 16 : 256;
+ if ((m_status[n] & 0x0c) == 0x0c)
+ {
+ // PWM
+ u8 ticks = attotime_to_clocks(m_timer[n]->remaining()) / prescale;
+ return ticks | ((m_cr[n] - (u16(ticks) << 8)) & 0xff00);
+ }
+ else
+ return attotime_to_clocks(m_timer[n]->remaining()) / prescale;
+ }
+}
+
+
+//-------------------------------------------------
+// read - read count or status register
+//-------------------------------------------------
+
+u8 kp63_device::read(offs_t offset)
+{
+ const unsigned n = offset >> 1;
+ assert(n < c_num_counters);
+
+ if (BIT(offset, 0))
+ {
+ // Status read clears read/write sequence
+ if (!machine().side_effects_disabled())
+ m_rw_seq &= ~(1 << n);
+ return m_status[n];
+ }
+ else if (BIT(m_rw_seq, n))
+ {
+ // Second step of counter readout
+ if (!machine().side_effects_disabled())
+ m_rw_seq &= ~(1 << n);
+ return m_count_tmp[n];
+ }
+ else
+ {
+ // First step of counter readout
+ u16 count = timer_get_count(n);
+ if (!machine().side_effects_disabled())
+ {
+ // Latch high byte into TMP register
+ m_rw_seq |= 1 << n;
+ m_count_tmp[n] = count >> 8;
+ }
+ return count & 0x00ff;
+ }
+}
+
+//-------------------------------------------------
+// write - set CR or mode register
+//-------------------------------------------------
+
+void kp63_device::write(offs_t offset, u8 data)
+{
+ const unsigned n = offset >> 1;
+ assert(n < c_num_counters);
+
+ if (BIT(offset, 0))
+ {
+ bool old_outp = BIT(m_status[n], 7) != BIT(m_status[n], 4);
+
+ // Stop count before setting mode
+ if (BIT(m_timer_started, n))
+ {
+ if (!BIT(m_status[n], 5) || ((m_status[n] & 0x03) != 0x03 || BIT(m_gate_input, n)))
+ {
+ m_last_count[n] = timer_get_count(n);
+ m_timer[n]->adjust(attotime::never);
+ m_pwm_timer[n]->adjust(attotime::never);
+ }
+ m_timer_started &= ~(1 << n);
+ }
+
+ if (BIT(data & c_mode_mask, 5))
+ LOG("%s: Timer #%d configured for %s mode, %s edges of GATE, initial output %c\n",
+ machine().describe_context(),
+ n,
+ s_count_modes[BIT(data, 2, 2)],
+ BIT(data, 1) ? "???" : BIT(data, 0) ? "falling" : "rising",
+ BIT(data, 4) ? 'H' : 'L');
+ else
+ LOG("%s: Timer #%d configured for %s mode, 1/%d system clock (GATE %s), initial output %c\n",
+ machine().describe_context(),
+ n,
+ s_count_modes[BIT(data, 2, 2)],
+ BIT(data, 1) ? 4 : BIT(data, 0) ? 16 : 256,
+ (data & 0x03) == 0x03 ? "effective" : "ignored",
+ BIT(data, 4) ? 'H' : 'L');
+ m_status[n] = data & c_mode_mask;
+
+ // Update OUTP
+ if (old_outp != BIT(data, 4))
+ m_out_pulse_callback[n](BIT(data, 4) ? 1 : 0);
+ }
+ else if ((m_status[n] & 0x0c) == 0x08)
+ {
+ // WDT retrigger (data ignored; initial count must be written using a different mode)
+ timer_reload(n);
+ }
+ else if (BIT(m_rw_seq, n))
+ {
+ // Second step of initial count write
+ m_rw_seq &= ~(1 << n);
+ m_cr[n] = u16(data) << 8 | m_count_tmp[n];
+
+ LOG("%s: Timer #%d initial count = %d\n", machine().describe_context(), n, (m_status[n] == 0x0c) ? m_cr[n] & 0x00ff : m_cr[n]);
+
+ // Automatic retrigger in one-shot and continuous modes
+ if (!BIT(m_status[n], 3) || !BIT(m_timer_started, n))
+ {
+ if (!BIT(m_status[n], 7))
+ {
+ // Toggle OUTP
+ m_status[n] |= 0x80;
+ m_out_pulse_callback[n](BIT(m_status[n], 4) ? 0 : 1);
+ }
+ timer_reload(n);
+ }
+ }
+ else
+ {
+ // First step of initial count write (held in TMP register)
+ m_rw_seq |= 1 << n;
+ m_count_tmp[n] = data;
+ }
+}
+
+//-------------------------------------------------
+// write_gate - handle gate inputs
+//-------------------------------------------------
+
+void kp63_device::write_gate(unsigned n, bool state)
+{
+ assert(n < c_num_counters);
+
+ if (BIT(m_gate_input, n) != state)
+ return;
+
+ if (state)
+ m_gate_input |= 1 << n;
+ else
+ m_gate_input &= ~(1 << n);
+
+ if (BIT(m_timer_started, n))
+ {
+ if ((m_status[n] & 0x23) == 0x03)
+ {
+ // Timer gated on or off
+ if (state)
+ timer_resume_count(n);
+ else
+ {
+ m_last_count[n] = timer_get_count(n);
+ m_timer[n]->adjust(attotime::never);
+ }
+ }
+ else if ((m_status[n] & 0x23) == (state ? 0x21 : 0x20))
+ {
+ // Count edges of gate input
+ if ((m_status[n] & 0x0c) == 0x0c)
+ {
+ // PWM: count is in lower 8 bits
+ if ((m_last_count[n] & 0x00ff) == 0)
+ timer_pulse(n);
+ else
+ {
+ // Decrement both halves and check for underflow in upper half
+ m_last_count[n] -= 0x0101;
+ if (m_last_count[n] >= 0xff00)
+ {
+ m_status[n] &= 0x7f;
+ m_out_pulse_callback[n](BIT(m_status[n], 4) ? 1 : 0);
+ }
+ }
+ }
+ else if (m_last_count[n]-- == 0)
+ timer_pulse(n);
+ }
+ }
+}
diff --git a/src/devices/cpu/z80/kp63.h b/src/devices/cpu/z80/kp63.h
new file mode 100644
index 00000000000..73e269fb72b
--- /dev/null
+++ b/src/devices/cpu/z80/kp63.h
@@ -0,0 +1,98 @@
+// license:BSD-3-Clause
+// copyright-holders:AJR
+/***************************************************************************
+
+ Kawasaki Steel (Kawatetsu) KP63(A) Timer/Counter
+
+***************************************************************************/
+
+#ifndef MAME_CPU_Z80_KP63_H
+#define MAME_CPU_Z80_KP63_H
+
+#pragma once
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class kp63_device : public device_t
+{
+public:
+ // callback configuration
+ template <int N> auto outp_callback() { return m_out_pulse_callback[N].bind(); }
+ template <int N> auto outs_callback() { return m_out_strobe_callback[N].bind(); }
+
+ // register interface
+ u8 read(offs_t offset);
+ void write(offs_t offset, u8 data);
+
+ // input line interface
+ template <int N> DECLARE_WRITE_LINE_MEMBER(gate_w) { write_gate(N, state); }
+
+protected:
+ // construction/destruction
+ kp63_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u8 num_counters, u8 mode_mask);
+
+ // device-level overrides
+ virtual void device_resolve_objects() override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ static const char *const s_count_modes[4];
+
+ // timer callbacks
+ template <int N> TIMER_CALLBACK_MEMBER(timer_expired);
+ template <int N> TIMER_CALLBACK_MEMBER(strobe_off);
+ template <int N> TIMER_CALLBACK_MEMBER(pwm_off);
+
+ // internal helpers
+ void timer_pulse(unsigned n);
+ void timer_reload(unsigned n);
+ void timer_resume_count(unsigned n);
+ u16 timer_get_count(unsigned n) const;
+ void write_gate(unsigned n, bool state);
+
+ // callback objects
+ devcb_write_line::array<4> m_out_pulse_callback;
+ devcb_write_line::array<4> m_out_strobe_callback;
+
+ // constant parameters
+ const u8 c_num_counters;
+ const u8 c_mode_mask;
+
+ // internal timers
+ emu_timer *m_timer[4];
+ emu_timer *m_strobe_timer[4];
+ emu_timer *m_pwm_timer[4];
+
+ // internal state
+ u16 m_cr[4];
+ u16 m_last_count[4];
+ u8 m_count_tmp[4];
+ u8 m_status[4];
+ u8 m_rw_seq;
+ u8 m_timer_started;
+ u8 m_gate_input;
+};
+
+class kp63_3channel_device : public kp63_device
+{
+public:
+ // device type constructor
+ kp63_3channel_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+};
+
+class kp63a_device : public kp63_device
+{
+public:
+ // device type constructor
+ kp63a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+};
+
+// device type declarations
+DECLARE_DEVICE_TYPE(KP63_3CHANNEL, kp63_3channel_device)
+DECLARE_DEVICE_TYPE(KP63A, kp63a_device)
+
+#endif // MAME_CPU_Z80_KP63_H
diff --git a/src/devices/cpu/z80/kp69.cpp b/src/devices/cpu/z80/kp69.cpp
index dca74ff3b25..84be060c4c7 100644
--- a/src/devices/cpu/z80/kp69.cpp
+++ b/src/devices/cpu/z80/kp69.cpp
@@ -107,12 +107,12 @@ void kp69_device::device_start()
void kp69_base_device::add_to_state(device_state_interface &state, int index)
{
- state.state_add<u16>(index, "IRR", [this]() { return m_irr; }, [this](u16 data) { set_irr(data); });
- state.state_add<u16>(index + 1, "ISR", [this]() { return m_isr; }, [this](u16 data) { set_isr(data); });
+ state.state_add(index, "IRR", m_irr, [this](u16 data) { set_irr(data); });
+ state.state_add(index + 1, "ISR", m_isr, [this](u16 data) { set_isr(data); });
state.state_add(index + 2, "IVR", m_ivr).mask(0xe0);
- state.state_add<u16>(index + 3, "LER", [this]() { return m_ler; }, [this](u16 data) { set_ler(data); });
- state.state_add<u16>(index + 4, "PGR", [this]() { return m_pgr; }, [this](u16 data) { set_pgr(data); });
- state.state_add<u16>(index + 5, "IMR", [this]() { return m_imr; }, [this](u16 data) { set_imr(data); });
+ state.state_add(index + 3, "LER", m_ler, [this](u16 data) { set_ler(data); });
+ state.state_add(index + 4, "PGR", m_pgr, [this](u16 data) { set_pgr(data); });
+ state.state_add(index + 5, "IMR", m_imr, [this](u16 data) { set_imr(data); });
}