diff options
Diffstat (limited to 'src/devices/cpu')
-rw-r--r-- | src/devices/cpu/mcs48/mcs48.cpp | 2 | ||||
-rw-r--r-- | src/devices/cpu/pdp1/pdp1.cpp | 93 | ||||
-rw-r--r-- | src/devices/cpu/pdp1/pdp1.h | 31 | ||||
-rw-r--r-- | src/devices/cpu/pdp1/pdp1dasm.cpp | 4 | ||||
-rw-r--r-- | src/devices/cpu/pdp1/tx0.cpp | 4 | ||||
-rw-r--r-- | src/devices/cpu/pdp8/pdp8.cpp | 2 | ||||
-rw-r--r-- | src/devices/cpu/pdp8/pdp8dasm.cpp | 4 | ||||
-rw-r--r-- | src/devices/cpu/tms57002/tms57002.cpp | 37 | ||||
-rw-r--r-- | src/devices/cpu/tms57002/tms57002.h | 2 | ||||
-rw-r--r-- | src/devices/cpu/z80/kc82.cpp | 6 | ||||
-rw-r--r-- | src/devices/cpu/z80/kl5c80a12.cpp | 9 | ||||
-rw-r--r-- | src/devices/cpu/z80/kl5c80a16.cpp | 10 | ||||
-rw-r--r-- | src/devices/cpu/z80/kp63.cpp | 477 | ||||
-rw-r--r-- | src/devices/cpu/z80/kp63.h | 98 | ||||
-rw-r--r-- | src/devices/cpu/z80/kp69.cpp | 10 |
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 ¶ms) @@ -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 ¶ms) @@ -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); }); } |