From af1e3c01bae0a0fa5cd0883c965e90a5f4435909 Mon Sep 17 00:00:00 2001 From: Joakim Larsson Edstrom Date: Fri, 18 Aug 2017 13:35:03 +0200 Subject: m68340: Added implementations for VCO clock synthesizer and Timer module Counters, IRQ:s and one operational mode --- src/devices/machine/68340.cpp | 50 +++- src/devices/machine/68340.h | 73 ++++- src/devices/machine/68340sim.cpp | 507 +++++++++++++++++++------------- src/devices/machine/68340sim.h | 97 ++++++- src/devices/machine/68340tmu.cpp | 612 ++++++++++++++++++++++++++++++++++++++- src/devices/machine/68340tmu.h | 81 +++++- src/mame/drivers/dbox.cpp | 67 ++++- 7 files changed, 1249 insertions(+), 238 deletions(-) diff --git a/src/devices/machine/68340.cpp b/src/devices/machine/68340.cpp index 0de1bf4dcf8..1aaa6ee78dd 100644 --- a/src/devices/machine/68340.cpp +++ b/src/devices/machine/68340.cpp @@ -77,12 +77,24 @@ WRITE32_MEMBER( m68340_cpu_device::m68340_internal_base_w ) { int base = m68340_base & 0xfffff000; - internal->install_readwrite_handler(base + 0x000, base + 0x03f, read16_delegate(FUNC(m68340_cpu_device::m68340_internal_sim_r),this), write16_delegate(FUNC(m68340_cpu_device::m68340_internal_sim_w),this),0xffffffff); - internal->install_readwrite_handler(base + 0x010, base + 0x01f, read8_delegate(FUNC(m68340_cpu_device::m68340_internal_sim_ports_r),this),write8_delegate(FUNC(m68340_cpu_device::m68340_internal_sim_ports_w),this),0xffffffff); - internal->install_readwrite_handler(base + 0x040, base + 0x05f, read32_delegate(FUNC(m68340_cpu_device::m68340_internal_sim_cs_r),this), write32_delegate(FUNC(m68340_cpu_device::m68340_internal_sim_cs_w),this)); - internal->install_readwrite_handler(base + 0x600, base + 0x67f, read32_delegate(FUNC(m68340_cpu_device::m68340_internal_timer_r),this), write32_delegate(FUNC(m68340_cpu_device::m68340_internal_timer_w),this)); - internal->install_readwrite_handler(base + 0x700, base + 0x723, read32_delegate(FUNC(m68340_cpu_device::m68340_internal_serial_r),this), write32_delegate(FUNC(m68340_cpu_device::m68340_internal_serial_w),this)); - internal->install_readwrite_handler(base + 0x780, base + 0x7bf, read32_delegate(FUNC(m68340_cpu_device::m68340_internal_dma_r),this), write32_delegate(FUNC(m68340_cpu_device::m68340_internal_dma_w),this)); + internal->install_readwrite_handler(base + 0x000, base + 0x03f, + read16_delegate(FUNC(m68340_cpu_device::m68340_internal_sim_r),this), + write16_delegate(FUNC(m68340_cpu_device::m68340_internal_sim_w),this),0xffffffff); + internal->install_readwrite_handler(base + 0x010, base + 0x01f, // Intentionally punches a hole in previous address mapping + read8_delegate(FUNC(m68340_cpu_device::m68340_internal_sim_ports_r),this), + write8_delegate(FUNC(m68340_cpu_device::m68340_internal_sim_ports_w),this),0xffffffff); + internal->install_readwrite_handler(base + 0x040, base + 0x05f, + read32_delegate(FUNC(m68340_cpu_device::m68340_internal_sim_cs_r),this), + write32_delegate(FUNC(m68340_cpu_device::m68340_internal_sim_cs_w),this)); + internal->install_readwrite_handler(base + 0x600, base + 0x67f, + read16_delegate(FUNC(m68340_cpu_device::m68340_internal_timer_r),this), + write16_delegate(FUNC(m68340_cpu_device::m68340_internal_timer_w),this),0xffffffff); + internal->install_readwrite_handler(base + 0x700, base + 0x723, + read32_delegate(FUNC(m68340_cpu_device::m68340_internal_serial_r),this), + write32_delegate(FUNC(m68340_cpu_device::m68340_internal_serial_w),this)); + internal->install_readwrite_handler(base + 0x780, base + 0x7bf, + read32_delegate(FUNC(m68340_cpu_device::m68340_internal_dma_r),this), + write32_delegate(FUNC(m68340_cpu_device::m68340_internal_dma_w),this)); } @@ -107,10 +119,19 @@ ADDRESS_MAP_END m68340_cpu_device::m68340_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : fscpu32_device(mconfig, tag, owner, clock, M68340, 32,32, ADDRESS_MAP_NAME(m68340_internal_map)) - ,m_pa_out_cb(*this) - ,m_pa_in_cb(*this) - ,m_pb_out_cb(*this) - ,m_pb_in_cb(*this) + , m_clock_mode(0) + , m_crystal(0) + , m_extal(0) + , m_pa_out_cb(*this) + , m_pa_in_cb(*this) + , m_pb_out_cb(*this) + , m_pb_in_cb(*this) + , m_tout1_out_cb(*this) + , m_tin1_in_cb(*this) + , m_tgate1_in_cb(*this) + , m_tout2_out_cb(*this) + , m_tin2_in_cb(*this) + , m_tgate2_in_cb(*this) { m68340SIM = nullptr; m68340DMA = nullptr; @@ -129,6 +150,14 @@ void m68340_cpu_device::device_reset() fscpu32_device::device_reset(); } +// Some hardwares pulls this low when resetting peripherals, most just ties this line to GND or VCC +// TODO: Support Limp mode and external clock with no PLL +WRITE_LINE_MEMBER( m68340_cpu_device::set_modck ) +{ + m_modck = state; + m_clock_mode &= ~(m68340_sim::CLOCK_MODCK | m68340_sim::CLOCK_PLL); + m_clock_mode |= ((m_modck == ASSERT_LINE) ? (m68340_sim::CLOCK_MODCK | m68340_sim::CLOCK_PLL) : 0); +} void m68340_cpu_device::device_start() { @@ -145,6 +174,7 @@ void m68340_cpu_device::device_start() m68340TIMER->reset(); start_68340_sim(); + start_68340_timer(); m68340_base = 0x00000000; diff --git a/src/devices/machine/68340.h b/src/devices/machine/68340.h index deb31c5e9f0..81a8e83ad98 100644 --- a/src/devices/machine/68340.h +++ b/src/devices/machine/68340.h @@ -28,6 +28,27 @@ #define MCFG_MC68340_PB_OUTPUT_CB(_devcb) \ devcb = &m68340_cpu_device::set_pb_out_callback (*device, DEVCB_##_devcb); +#define MCFG_MC68340_ADD_CRYSTAL(_crystal) \ + m68340_cpu_device::set_crystal(*device, _crystal); + +#define MCFG_MC68340_TOUT1_OUTPUT_CB(_devcb) \ + devcb = &m68340_cpu_device::set_tout1_out_callback (*device, DEVCB_##_devcb); + +#define MCFG_MC68340_TIN1_INPUT_CB(_devcb) \ + devcb = &m68340_cpu_device::set_tin1_out_callback (*device, DEVCB_##_devcb); + +#define MCFG_MC68340_TGATE1_INPUT_CB(_devcb) \ + devcb = &m68340_cpu_device::set_tgate1_out_callback (*device, DEVCB_##_devcb); + +#define MCFG_MC68340_TOUT2_OUTPUT_CB(_devcb) \ + devcb = &m68340_cpu_device::set_tout2_out_callback (*device, DEVCB_##_devcb); + +#define MCFG_MC68340_TIN2_INPUT_CB(_devcb) \ + devcb = &m68340_cpu_device::set_tin2_out_callback (*device, DEVCB_##_devcb); + +#define MCFG_MC68340_TGATE2_INPUT_CB(_devcb) \ + devcb = &m68340_cpu_device::set_tgate2_out_callback (*device, DEVCB_##_devcb); + class m68340_cpu_device : public fscpu32_device { public: @@ -37,9 +58,24 @@ public: template static devcb_base &set_pa_out_callback (device_t &device, Object &&cb){ return downcast(device).m_pa_out_cb.set_callback (std::forward(cb)); } template static devcb_base &set_pb_in_callback (device_t &device, Object &&cb){ return downcast(device).m_pb_in_cb.set_callback (std::forward(cb)); } template static devcb_base &set_pb_out_callback (device_t &device, Object &&cb){ return downcast(device).m_pb_out_cb.set_callback (std::forward(cb)); } + + template static devcb_base &set_tout1_out_callback (device_t &device, Object &&cb){ return downcast(device).m_tout1_out_cb.set_callback (std::forward(cb)); } + template static devcb_base &set_tin1_in_callback (device_t &device, Object &&cb) { return downcast(device).m_tin1_in_cb.set_callback (std::forward(cb)); } + template static devcb_base &set_tgate1_in_callback (device_t &device, Object &&cb){ return downcast(device).m_tgate1_in_cb.set_callback (std::forward(cb)); } + template static devcb_base &set_tout2_out_callback (device_t &device, Object &&cb){ return downcast(device).m_tout2_out_cb.set_callback (std::forward(cb)); } + template static devcb_base &set_tin2_in_callback (device_t &device, Object &&cb) { return downcast(device).m_tin2_in_cb.set_callback (std::forward(cb)); } + template static devcb_base &set_tgate2_in_callback (device_t &device, Object &&cb){ return downcast(device).m_tgate2_in_cb.set_callback (std::forward(cb)); } uint16_t get_cs(offs_t address); + // TODO: Support Limp mode and external clock with no PLL + static void set_crystal(device_t &device, int crystal) + { + m68340_cpu_device &dev = downcast(device); + dev.m_crystal = crystal; + dev.m_clock_mode |= (m68340_sim::CLOCK_MODCK | m68340_sim::CLOCK_PLL); + } + READ32_MEMBER( m68340_internal_base_r ); WRITE32_MEMBER( m68340_internal_base_w ); READ32_MEMBER( m68340_internal_dma_r ); @@ -52,20 +88,41 @@ public: WRITE16_MEMBER( m68340_internal_sim_w ); WRITE8_MEMBER( m68340_internal_sim_ports_w ); WRITE32_MEMBER( m68340_internal_sim_cs_w ); - READ32_MEMBER( m68340_internal_timer_r ); - WRITE32_MEMBER( m68340_internal_timer_w ); + READ16_MEMBER( m68340_internal_timer_r ); + WRITE16_MEMBER( m68340_internal_timer_w ); + + // Clock/VCO setting TODO: support external clock with PLL and Limp mode + DECLARE_WRITE_LINE_MEMBER( set_modck ); + DECLARE_WRITE_LINE_MEMBER( extal_w ); + + // Timer input methods, can be used instead of the corresponding polling MCFG callbacks + DECLARE_WRITE_LINE_MEMBER( tin1_w ); + DECLARE_WRITE_LINE_MEMBER( tgate1_w ); + DECLARE_WRITE_LINE_MEMBER( tin2_w ); + DECLARE_WRITE_LINE_MEMBER( tgate2_w ); protected: virtual void device_start() override; virtual void device_reset() override; TIMER_CALLBACK_MEMBER(periodic_interrupt_timer_callback); + TIMER_CALLBACK_MEMBER(timer1_callback); + TIMER_CALLBACK_MEMBER(timer2_callback); + void start_68340_sim(); - void do_timer_irq(); + void start_68340_timer(); + void do_pit_irq(); + void do_tick_pit(); + void do_timer_irq(int id); + void do_timer_tick(int id); int calc_cs(offs_t address) const; int m_currentcs; + uint32_t m_clock_mode; + uint32_t m_modck; + uint32_t m_crystal; + uint32_t m_extal; /* 68340 peripheral modules */ m68340_sim* m68340SIM; @@ -75,16 +132,18 @@ protected: uint32_t m68340_base; - uint16_t m_avr; - uint16_t m_picr; - uint16_t m_pitr; - emu_timer *m_irq_timer; devcb_write8 m_pa_out_cb; devcb_read8 m_pa_in_cb; devcb_write8 m_pb_out_cb; devcb_read8 m_pb_in_cb; + devcb_write_line m_tout1_out_cb; + devcb_write_line m_tin1_in_cb; + devcb_write_line m_tgate1_in_cb; + devcb_write_line m_tout2_out_cb; + devcb_write_line m_tin2_in_cb; + devcb_write_line m_tgate2_in_cb; }; DECLARE_DEVICE_TYPE(M68340, m68340_cpu_device) diff --git a/src/devices/machine/68340sim.cpp b/src/devices/machine/68340sim.cpp index 34ce985cc22..701369269f8 100644 --- a/src/devices/machine/68340sim.cpp +++ b/src/devices/machine/68340sim.cpp @@ -13,8 +13,13 @@ #define LOG_SETUP (1U << 1) #define LOG_READ (1U << 2) #define LOG_PORTS (1U << 3) +#define LOG_SIM (1U << 4) +#define LOG_CLOCK (1U << 5) +#define LOG_DATA (1U << 6) +#define LOG_INT (1U << 7) +#define LOG_PIT (1U << 8) -//#define VERBOSE (LOG_PORTS|LOG_SETUP|LOG_READ) +//#define VERBOSE (LOG_SETUP) #define LOG_OUTPUT_FUNC printf // Needs always to be enabled as the default value 'logerror' is not available here #include "logmacro.h" @@ -23,6 +28,11 @@ #define LOGSETUP(...) LOGMASKED(LOG_SETUP, __VA_ARGS__) #define LOGR(...) LOGMASKED(LOG_READ, __VA_ARGS__) #define LOGPORTS(...) LOGMASKED(LOG_PORTS, __VA_ARGS__) +#define LOGSIM(...) LOGMASKED(LOG_SIM, __VA_ARGS__) +#define LOGCLOCK(...) LOGMASKED(LOG_CLOCK, __VA_ARGS__) +#define LOGDATA(...) LOGMASKED(LOG_DATA, __VA_ARGS__) +#define LOGINT(...) LOGMASKED(LOG_INT, __VA_ARGS__) +#define LOGPIT(...) LOGMASKED(LOG_PIT, __VA_ARGS__) #ifdef _MSC_VER #define FUNCNAME __func__ @@ -30,92 +40,157 @@ #define FUNCNAME __PRETTY_FUNCTION__ #endif -#define m68340SIM_MCR (0x00) -// (0x02) -#define m68340SIM_SYNCR (0x04) -#define m68340SIM_AVR_RSR (0x06) -// (0x08) -// (0x0a) -// (0x0c) -// (0x0e) -#define m68340SIM_PORTA (0x11) -#define m68340SIM_DDRA (0x13) -#define m68340SIM_PPARA1 (0x15) -#define m68340SIM_PPARA2 (0x17) -#define m68340SIM_PORTB (0x19) -#define m68340SIM_PORTB1 (0x1b) -#define m68340SIM_DDRB (0x1d) -#define m68340SIM_PPARB (0x1f) -#define m68340SIM_SWIV_SYPCR (0x20) -#define m68340SIM_PICR (0x22) -#define m68340SIM_PITR (0x24) -#define m68340SIM_SWSR (0x26) -// (0x28) -// (0x2a) -// (0x2c) -// (0x2e) -// (0x30) -// (0x32) -// (0x34) -// (0x36) -// (0x38) -// (0x3a) -// (0x3c) -// (0x3e) -#define m68340SIM_AM_CS0 (0x40) -#define m68340SIM_BA_CS0 (0x44) -#define m68340SIM_AM_CS1 (0x48) -#define m68340SIM_BA_CS1 (0x4c) -#define m68340SIM_AM_CS2 (0x50) -#define m68340SIM_BA_CS2 (0x54) -#define m68340SIM_AM_CS3 (0x58) -#define m68340SIM_BA_CS3 (0x5c) +READ16_MEMBER( m68340_cpu_device::m68340_internal_sim_r ) +{ + LOGR("%s\n", FUNCNAME); + assert(m68340SIM); + m68340_sim &sim = *m68340SIM; + int val = space.machine().rand(); + int pc = space.device().safe_pc(); + switch (offset * 2) + { + case m68340_sim::REG_MCR: + LOGSIM("- %08x %s %04x, (%04x) (MCR - Module Configuration Register) - not implemented\n", pc, FUNCNAME, offset * 2, mem_mask); + val = sim.m_mcr; + break; + case m68340_sim::REG_SYNCR: + LOGSIM("- %08x %s %04x, (%04x) (SYNCR - Clock Synthesizer Register) - not implemented\n", pc, FUNCNAME, offset*2,mem_mask); + val = sim.m_syncr; + break; -READ16_MEMBER( m68340_cpu_device::m68340_internal_sim_r ) + case m68340_sim::REG_AVR_RSR: + LOGSIM("- %08x %s %04x, (%04x) (AVR, RSR - Auto Vector Register, Reset Status Register) - not implemented\n", pc, FUNCNAME, offset*2,mem_mask); + val = sim.m_avr_rsr; + break; + + case m68340_sim::REG_SWIV_SYPCR: + LOGSIM("- %08x %s %04x, (%04x) (SWIV_SYPCR - Software Interrupt Vector, System Protection Control Register) - not implemented\n", pc, FUNCNAME, offset*2,mem_mask); + val = sim.m_swiv_sypcr; + break; + + case m68340_sim::REG_PICR: + LOGPIT("- %08x %s %04x, (%04x) (PICR - Periodic Interrupt Control Register) - not implemented\n", pc, FUNCNAME, offset*2,mem_mask); + val = sim.m_picr; + break; + + case m68340_sim::REG_PITR: + LOGPIT("- %08x %s %04x, (%04x) (PITR - Periodic Interrupt Timer Register) - not implemented\n", pc, FUNCNAME, offset*2,mem_mask); + val = sim.m_pitr; + break; + + case m68340_sim::REG_SWSR: + LOGSIM("- %08x %s %04x, (%04x) (SWSR - Software Service) - not implemented\n", pc, FUNCNAME, offset*2,mem_mask); + val = sim.m_swsr; + break; + + default: + LOGSIM("- %08x %s %04x, (%04x)\n", pc, FUNCNAME, offset * 2, mem_mask); + } + + LOGR(" * Reg %02x -> %02x - %s\n", offset * 2, val, + ((offset * 2) >= 0x10 && (offset * 2) < 0x20) || (offset * 2) >= 0x60 ? "Error - should not happen" : + std::array {{"MCR", "reserved", "SYNCR", "AVR/RSR", "SWIV/SYPCR", "PICR", "PITR", "SWSR"}}[(offset * 2) <= m68340_sim::REG_AVR_RSR ? offset : offset - 0x10 + 0x04]); + + return 0x0000; +} + +WRITE16_MEMBER( m68340_cpu_device::m68340_internal_sim_w ) { - LOGR("%s\n", FUNCNAME); + LOG("\n%s\n", FUNCNAME); + LOGSETUP(" * Reg %02x <- %02x - %s\n", offset * 2, data, + ((offset * 2) >= 0x10 && (offset * 2) < 0x20) || (offset * 2) >= 0x60 ? "Error - should not happen" : + std::array {{"MCR", "reserved", "SYNCR", "AVR/RSR", "SWIV/SYPCR", "PICR", "PITR", "SWSR"}}[(offset * 2) <= m68340_sim::REG_AVR_RSR ? offset : offset - 0x10 + 0x04]); + assert(m68340SIM); - //m68340_sim &sim = *m68340SIM; + m68340_sim &sim = *m68340SIM; int pc = space.device().safe_pc(); switch (offset<<1) { - case m68340SIM_MCR: - LOGR("- %08x m68340_internal_sim_r %04x, (%04x) (MCR - Module Configuration Register) - not implemented\n", pc, offset*2,mem_mask); - return space.machine().rand(); + case m68340_sim::REG_MCR: + COMBINE_DATA(&sim.m_mcr); + LOGSIM("PC: %08x %s %04x, %04x (%04x) (MCR - Module Configuration Register)\n", pc, FUNCNAME, offset * 2, data, mem_mask); + LOGPIT("- FRZ1: Watchdog and PIT timer are %s\n", (data & m68340_sim::REG_MCR_FRZ1) == 0 ? "enabled" : "disabled"); + LOGSIM("- FRZ0: The BUS monitor is %s\n", (data & m68340_sim::REG_MCR_FRZ0) == 0 ? "enabled" : "disabled"); + LOGSIM("- FIRQ: Full Interrupt Request Mode %s\n", data & m68340_sim::REG_MCR_FIRQ ? "used on port B" : "supressed, adding 4 chip select lines on Port B"); + LOGSIM("- SHEN0-SHEN1: Show Cycle Enable %02x - not implemented\n", ((data & m68340_sim::REG_MCR_SHEN) >> 8)); + LOGSIM("- Supervisor registers %s - not implemented\n", data & m68340_sim::REG_MCR_SVREG ? "requries supervisor privileges" : "can be accessed by user privileged software"); + LOGSIM("- Interrupt Arbitration level: %02x\n", data & m68340_sim::REG_MCR_ARBLV); + break; + + case m68340_sim::REG_SYNCR: + LOGSIM("PC: %08x %s %04x, %04x (%04x) (SYNCR - Clock Synthesizer Register) - not implemented\n", pc, FUNCNAME, offset * 2, data, mem_mask); + COMBINE_DATA(&sim.m_syncr); + LOGSIM("- W : VCO x %d\n", data & m68340_sim::REG_SYNCR_W ? 4 : 1); + LOGSIM("- X : System clock / %d\n", data & m68340_sim::REG_SYNCR_X ? 1 : 2); + LOGSIM("- Y5-Y0: Divider: %d\n", (data & m68340_sim::REG_SYNCR_Y_MSK) >> 8); + LOGSIM("- SLIMP: Loss of VCO input reference: %s\n", data & m68340_sim::REG_SYNCR_SLIMP ? "yes" : "no"); + LOGSIM("- SLOCK: Synthesizer lock: %s\n", data & m68340_sim::REG_SYNCR_SLOCK ? "yes" : "no"); + LOGSIM("- RSTEN: Loss of signal causes %s\n", data & m68340_sim::REG_SYNCR_RSTEN ? "system reset" : "limp mode (no external reference)"); + LOGSIM("- STSIM: LPSTOP makes SIM40 to use %s\n", data & m68340_sim::REG_SYNCR_STSIM ? "VCO" : "external clock/oscillator"); + LOGSIM("- STEXT: LPSTOP makes CLKOUT %s\n", data & m68340_sim::REG_SYNCR_STEXT ? "driven by SIM40 clock" : "low"); + + // Adjust VCO + if (m_clock_mode == m68340_sim::CLOCK_MODE_CRYSTAL) + { + set_unscaled_clock(m_crystal * + (4 << (((sim.m_syncr & m68340_sim::REG_SYNCR_W) != 0 ? 2 : 0) + ((sim.m_syncr & m68340_sim::REG_SYNCR_X) != 0 ? 1 : 0))) * + (((sim.m_syncr & m68340_sim::REG_SYNCR_Y_MSK) >> 8) & 0x3f)); + LOGCLOCK( " - Clock: %d [0x%08x]\n", clock(), clock()); + } + break; - case m68340SIM_SYNCR: - LOGR("- %08x m68340_internal_sim_r %04x, (%04x) (SYNCR - Clock Synthesizer Register) - not implemented\n", pc, offset*2,mem_mask); - return space.machine().rand(); + case m68340_sim::REG_AVR_RSR: + LOGSIM("PC: %08x %s %04x, %04x (%04x) (AVR, RSR - Auto Vector Register, Reset Status Register)\n", pc, FUNCNAME, offset * 2, data, mem_mask); + COMBINE_DATA(&sim.m_avr_rsr); + LOGSIM("- AVR: AV7-AV1 autovector bits: %02x\n", ((data & m68340_sim::REG_AVR_VEC) >> 8) & 0xff); + LOGSIM("- RSR: Last reset type: %02x - not implemented\n", (data & m68340_sim::REG_RSR_RESBITS) & 0xff); + break; - case m68340SIM_AVR_RSR: - LOGR("- %08x m68340_internal_sim_r %04x, (%04x) (AVR, RSR - Auto Vector Register, Reset Status Register) - not implemented\n", pc, offset*2,mem_mask); - return space.machine().rand(); + case m68340_sim::REG_SWIV_SYPCR: + LOGSIM("PC: %08x %s %04x, %04x (%04x) (SWIV_SYPCR - Software Interrupt Vector, System Protection Control Register) - not implemented\n", pc, FUNCNAME, offset * 2, data, mem_mask); + COMBINE_DATA(&sim.m_swiv_sypcr); + LOGSIM("- SWIV: Software watchdog Interrupt Vector: %02x\n", ((data & m68340_sim::REG_SWIV_VEC) >> 8) & 0xff); + LOGSIM("- SWE : Software watchdog %s\n", (data & m68340_sim::REG_SYPCR_SWE) ? "enabled" : "disabled"); + LOGSIM("- SWRI: Software watchdog causes %s\n", (data & m68340_sim::REG_SYPCR_SWRI) ? "system reset" : "level 7 IRQ (NMI)"); + LOGSIM("- SWT : Software watchdog timing 2^%s/EXTAL Input Frequency\n", + std::array {{"9", "11", "13", "15", "18", "20", "22", "24"}}[((data & m68340_sim::REG_SYPCR_SWT) >> 4) | ((sim.m_pitr & m68340_sim::REG_PITR_SWP) >> 7)]); + break; - case m68340SIM_SWIV_SYPCR: - LOGR("- %08x m68340_internal_sim_r %04x, (%04x) (SWIV_SYPCR - Software Interrupt Vector, System Protection Control Register) - not implemented\n", pc, offset*2,mem_mask); - return space.machine().rand(); + case m68340_sim::REG_PICR: + LOGPIT("PC: %08x %s %04x, %04x (%04x) (PICR - Periodic Interrupt Control Register)\n", pc, FUNCNAME, offset*2,data,mem_mask); + COMBINE_DATA(&sim.m_picr); + LOGPIT("- PIRQL: Periodic Interrupt Level %d%s\n", (data & m68340_sim::REG_PICR_PIRQL) >> 8, (data & m68340_sim::REG_PICR_PIRQL) == 0 ? " (disabled)" : ""); + LOGPIT("- PIV : Periodic Interrupt Vector %02x\n", (data & m68340_sim::REG_PICR_PIVEC)); + break; - case m68340SIM_PICR: - LOGR("- %08x m68340_internal_sim_r %04x, (%04x) (PICR - Periodic Interrupt Control Register) - not implemented\n", pc, offset*2,mem_mask); - return space.machine().rand(); + case m68340_sim::REG_PITR: + LOGPIT("PC: %08x %s %04x, %04x (%04x) (PITR - Periodic Interrupt Timer Register)\n", pc, FUNCNAME, offset*2,data,mem_mask); + COMBINE_DATA(&sim.m_pitr); + LOGSIM("- SWP : Software watchdog prescale factor is %d\n", (data & m68340_sim::REG_PITR_SWP) ? 512 : 1); + LOGPIT("- PTP : Periodic timer prescale factor is %d\n", (data & m68340_sim::REG_PITR_PTP) ? 512 : 1); + LOGPIT("- COUNT: is %d%s\n", (data & m68340_sim::REG_PITR_COUNT), (data & m68340_sim::REG_PITR_COUNT) == 0 ? " (off)" : "d"); + if ( (sim.m_mcr & m68340_sim::REG_MCR_FRZ1) == 0 && (sim.m_pitr & m68340_sim::REG_PITR_COUNT) != 0) + { + LOGPIT("Starting PIT timer\n"); + sim.m_pit_counter = sim.m_pitr & m68340_sim::REG_PITR_COUNT; + m_irq_timer->adjust(cycles_to_attotime((m_crystal / 4) / ((sim.m_pitr & m68340_sim::REG_PITR_PTP) != 0 ? 512 : 1))); + } - case m68340SIM_PITR: - LOGR("- %08x m68340_internal_sim_r %04x, (%04x) (PITR - Periodic Interrupt Timer Register) - not implemented\n", pc, offset*2,mem_mask); - return space.machine().rand(); + break; - case m68340SIM_SWSR: - LOGR("- %08x m68340_internal_sim_r %04x, (%04x) (SWSR - Software Service) - not implemented\n", pc, offset*2,mem_mask); - return space.machine().rand(); + case m68340_sim::REG_SWSR: + // basically watchdog, you must write an alternating pattern of 0x55 / 0xaa to keep the watchdog from resetting the system + //LOGSIM("- %08x %s %04x, %04x (%04x) (SWSR - Software Service)\n", pc, FUNCNAME, offset*2,data,mem_mask); + break; default: - LOGR("- %08x m68340_internal_sim_r %04x, (%04x)\n", pc, offset*2,mem_mask); - } + LOGSIM("- %08x %s %04x, %04x (%04x) - not implemented\n", pc, FUNCNAME, offset*2,data,mem_mask); - return 0x0000; + } } READ8_MEMBER( m68340_cpu_device::m68340_internal_sim_ports_r ) @@ -130,8 +205,8 @@ READ8_MEMBER( m68340_cpu_device::m68340_internal_sim_ports_r ) switch (offset) { - case m68340SIM_PORTA: - LOGR("- %08x m68340_internal_sim_r %04x (PORTA - Port A Data)\n", pc, offset); + case m68340_sim::REG_PORTA: + LOGR("- %08x %s %04x (PORTA - Port A Data)\n", pc, FUNCNAME, offset); sim.m_porta &= sim.m_ddra; // TODO: call callback @@ -148,26 +223,26 @@ READ8_MEMBER( m68340_cpu_device::m68340_internal_sim_ports_r ) val = sim.m_porta; break; - case m68340SIM_DDRA: - LOGR("- %08x m68340_internal_sim_r %04x (DDRA - Port A Data Direction)\n", pc, offset); + case m68340_sim::REG_DDRA: + LOGR("- %08x %s %04x (DDRA - Port A Data Direction)\n", pc, FUNCNAME, offset); val = sim.m_ddra; break; - case m68340SIM_PPARA1: - LOGR("- %08x m68340_internal_sim_r %04x (PPRA1 - Port A Pin Assignment 1)\n", pc, offset); + case m68340_sim::REG_PPARA1: + LOGR("- %08x %s %04x (PPRA1 - Port A Pin Assignment 1)\n", pc, FUNCNAME, offset); val = sim.m_ppara1; break; - case m68340SIM_PPARA2: - LOGR("- %08x m68340_internal_sim_r %04x (PPRA2 - Port A Pin Assignment 2) - not implemented\n", pc, offset); + case m68340_sim::REG_PPARA2: + LOGR("- %08x %s %04x (PPRA2 - Port A Pin Assignment 2) - not implemented\n", pc, FUNCNAME, offset); val = sim.m_ppara2; break; - case m68340SIM_PORTB1: - LOGR("- %08x m68340_internal_sim_r %04x (PORTB1 - Port B Data 1)\n", pc, offset); + case m68340_sim::REG_PORTB1: + LOGR("- %08x %s %04x (PORTB1 - Port B Data 1)\n", pc, FUNCNAME, offset); // Fallthrough to mirror register - case m68340SIM_PORTB: - LOGR("- %08x m68340_internal_sim_r %04x (PORTB - Port B Data 0)\n", pc, offset); + case m68340_sim::REG_PORTB: + LOGR("- %08x %s %04x (PORTB - Port B Data 0)\n", pc, FUNCNAME, offset); sim.m_portb &= sim.m_ddrb; // TODO: call callback @@ -184,19 +259,19 @@ READ8_MEMBER( m68340_cpu_device::m68340_internal_sim_ports_r ) val = sim.m_portb; break; - case m68340SIM_DDRB: - LOGR("- %08x m68340_internal_sim_r %04x (DDR - Port B Data Direction)\n", pc, offset); + case m68340_sim::REG_DDRB: + LOGR("- %08x %s %04x (DDR - Port B Data Direction)\n", pc, FUNCNAME, offset); val = sim.m_ddrb; break; - case m68340SIM_PPARB: - LOGR("- %08x m68340_internal_sim_r %04x (PPARB - Port B Pin Assignment)\n", pc, offset); + case m68340_sim::REG_PPARB: + LOGR("- %08x %s %04x (PPARB - Port B Pin Assignment)\n", pc, FUNCNAME, offset); val = sim.m_pparb; break; default: - LOGR("- %08x m68340_internal_sim_r %04x (ILLEGAL?)\n", pc, offset); - logerror("%08x m68340_internal_sim_r %04x (ILLEGAL?)\n", pc, offset); + LOGR("- %08x %s %04x (ILLEGAL?)\n", pc, FUNCNAME, offset); + logerror("%08x m68340_internal_sim_r %04x (ILLEGAL?)\n", pc, FUNCNAME, offset); break; } LOGR(" * Reg %02x -> %02x - %s\n", offset, val, std::array @@ -205,89 +280,6 @@ READ8_MEMBER( m68340_cpu_device::m68340_internal_sim_ports_r ) return val; } -READ32_MEMBER( m68340_cpu_device::m68340_internal_sim_cs_r ) -{ - LOGR("%s\n", FUNCNAME); - offset += m68340SIM_AM_CS0>>2; - - assert(m68340SIM); - m68340_sim &sim = *m68340SIM; - - int pc = space.device().safe_pc(); - - switch (offset<<2) - { - case m68340SIM_AM_CS0: return sim.m_am[0]; - case m68340SIM_BA_CS0: return sim.m_ba[0]; - case m68340SIM_AM_CS1: return sim.m_am[1]; - case m68340SIM_BA_CS1: return sim.m_ba[1]; - case m68340SIM_AM_CS2: return sim.m_am[2]; - case m68340SIM_BA_CS2: return sim.m_ba[2]; - case m68340SIM_AM_CS3: return sim.m_am[3]; - case m68340SIM_BA_CS3: return sim.m_ba[3]; - - default: - logerror("%08x m68340_internal_sim_r %08x, (%08x)\n", pc, offset*4,mem_mask); - } - - return 0x00000000; -} - -WRITE16_MEMBER( m68340_cpu_device::m68340_internal_sim_w ) -{ - LOGSETUP("%s\n", FUNCNAME); - assert(m68340SIM); - //m68340_sim &sim = *m68340SIM; - - int pc = space.device().safe_pc(); - - switch (offset<<1) - { - case m68340SIM_MCR: - LOGSETUP("- %08x m68340_internal_sim_w %04x, %04x (%04x) (MCR - Module Configuration Register) - not implemented\n", pc, offset*2,data,mem_mask); - break; - - case m68340SIM_SYNCR: - LOGSETUP("- %08x m68340_internal_sim_w %04x, %04x (%04x) (SYNCR - Clock Synthesizer Register) - not implemented\n", pc, offset*2,data,mem_mask); - break; - - - case m68340SIM_AVR_RSR: - LOGSETUP("- %08x m68340_internal_sim_w %04x, %04x (%04x) (AVR, RSR - Auto Vector Register, Reset Status Register)\n", pc, offset*2,data,mem_mask); - COMBINE_DATA(&m_avr); - break; - - case m68340SIM_SWIV_SYPCR: - LOGSETUP("- %08x m68340_internal_sim_w %04x, %04x (%04x) (SWIV_SYPCR - Software Interrupt Vector, System Protection Control Register) - not implemented\n", pc, offset*2,data,mem_mask); - break; - - case m68340SIM_PICR: - LOGSETUP("- %08x m68340_internal_sim_w %04x, %04x (%04x) (PICR - Periodic Interrupt Control Register)\n", pc, offset*2,data,mem_mask); - COMBINE_DATA(&m_picr); - break; - - case m68340SIM_PITR: - LOGSETUP("- %08x m68340_internal_sim_w %04x, %04x (%04x) (PITR - Periodic Interrupt Timer Register)\n", pc, offset*2,data,mem_mask); - COMBINE_DATA(&m_pitr); - if (m_pitr !=0 ) // hack - { - //LOGSETUP("- timer set\n"); - m_irq_timer->adjust(cycles_to_attotime(20000)); // hack - } - - break; - - case m68340SIM_SWSR: - // basically watchdog, you must write an alternating pattern of 0x55 / 0xaa to keep the watchdog from resetting the system - //LOGSETUP("- %08x m68340_internal_sim_w %04x, %04x (%04x) (SWSR - Software Service)\n", pc, offset*2,data,mem_mask); - break; - - default: - LOGSETUP("- %08x m68340_internal_sim_w %04x, %04x (%04x) - not implemented\n", pc, offset*2,data,mem_mask); - - } -} - WRITE8_MEMBER( m68340_cpu_device::m68340_internal_sim_ports_w ) { LOG("%s", FUNCNAME); @@ -297,66 +289,95 @@ WRITE8_MEMBER( m68340_cpu_device::m68340_internal_sim_ports_w ) int pc = space.device().safe_pc(); - LOGSETUP(" * Reg %02x <- %02x - %s\n", offset, data, std::array - {{"", "PORTA", "", "DDRA", "", "PPRA1", "", "PPRA2", "", "PORTB","", "PORTB1", "", "DDRB", "", "PPARB"}}[offset - 0x10]); - + LOGSETUP(" * Reg %02x <- %02x - %s\n", offset, data, std::array + {{"PORTA", "DDRA", "PPRA1", "PPRA2", "PORTB", "PORTB1", "DDRB", "PPARB"}}[(offset - 0x10) / 2]); switch (offset) { - case m68340SIM_PORTA: - LOGPORTS("- %08x %04x, %02x (PORTA - Port A Data)\n", pc, offset,data); + case m68340_sim::REG_PORTA: + LOGDATA("- %08x %04x, %02x (PORTA - Port A Data)\n", pc, offset,data); sim.m_porta = (data & sim.m_ddra & sim.m_ppara1); // callback m_pa_out_cb ((offs_t)0, sim.m_porta); break; - case m68340SIM_DDRA: + case m68340_sim::REG_DDRA: LOGPORTS("- %08x %04x, %02x (DDRA - Port A Data Direction)\n", pc, offset,data); sim.m_ddra = data; break; - case m68340SIM_PPARA1: + case m68340_sim::REG_PPARA1: LOGPORTS("- %08x %04x, %02x (PPARA1 - Port A Pin Assignment 1)\n", pc, offset,data); sim.m_ppara1 = data; break; - case m68340SIM_PPARA2: + case m68340_sim::REG_PPARA2: LOGPORTS("- %08x %04x, %02x (PPARA2 - Port A Pin Assignment 2)\n", pc, offset,data); sim.m_ppara2 = data; break; - case m68340SIM_PORTB1: - LOGPORTS("- %08x %04x, %02x (PORTB1 - Port B Data - mirror)\n", pc, offset,data); + case m68340_sim::REG_PORTB1: + LOGDATA("- %08x %04x, %02x (PORTB1 - Port B Data - mirror)\n", pc, offset,data); // Falling through to mirrored register portb - case m68340SIM_PORTB: - LOGPORTS("- %08x %04x, %02x (PORTB - Port B Data)\n", pc, offset,data); + case m68340_sim::REG_PORTB: + LOGDATA("- %08x %04x, %02x (PORTB - Port B Data)\n", pc, offset,data); sim.m_portb = (data & sim.m_ddrb & sim.m_pparb); // callback m_pb_out_cb ((offs_t)0, sim.m_portb); break; - case m68340SIM_DDRB: + case m68340_sim::REG_DDRB: LOGPORTS("- %08x %04x, %02x (DDR - Port B Data Direction)\n", pc, offset,data); sim.m_ddrb = data; break; - case m68340SIM_PPARB: + case m68340_sim::REG_PPARB: LOGPORTS("- %08x %04x, %02x (PPARB - Port B Pin Assignment)\n", pc, offset,data); sim.m_pparb = data; break; default: - LOGPORTS("- %08x %04x, %02x (ILLEGAL?) - not implemented\n", pc, offset,data); - logerror("%08x m68340_internal_sim_w %04x, %02x (ILLEGAL?)\n", pc, offset,data); + LOGPORTS("- %08x %s %04x, %02x (ILLEGAL?) - not implemented\n", pc, FUNCNAME, offset,data); + logerror("%08x m68340_internal_sim_ports_w %04x, %02x (ILLEGAL?)\n", pc, offset,data); break; } } +READ32_MEMBER( m68340_cpu_device::m68340_internal_sim_cs_r ) +{ + LOGR("%s\n", FUNCNAME); + offset += m68340_sim::REG_AM_CS0>>2; + + assert(m68340SIM); + m68340_sim &sim = *m68340SIM; + + int pc = space.device().safe_pc(); + + switch (offset<<2) + { + case m68340_sim::REG_AM_CS0: return sim.m_am[0]; + case m68340_sim::REG_BA_CS0: return sim.m_ba[0]; + case m68340_sim::REG_AM_CS1: return sim.m_am[1]; + case m68340_sim::REG_BA_CS1: return sim.m_ba[1]; + case m68340_sim::REG_AM_CS2: return sim.m_am[2]; + case m68340_sim::REG_BA_CS2: return sim.m_ba[2]; + case m68340_sim::REG_AM_CS3: return sim.m_am[3]; + case m68340_sim::REG_BA_CS3: return sim.m_ba[3]; + + default: + logerror("%08x m68340_internal_sim_r %08x, (%08x)\n", pc, offset*4,mem_mask); + } + + return 0x00000000; +} + WRITE32_MEMBER( m68340_cpu_device::m68340_internal_sim_cs_w ) { - LOGSETUP("%s\n", FUNCNAME); - offset += m68340SIM_AM_CS0>>2; + LOG("%s\n", FUNCNAME); + offset += m68340_sim::REG_AM_CS0>>2; + LOGSETUP("- %08x %s %08x, %08x (%08x) - not implemented\n", pc, FUNCNAME, offset*4,data,mem_mask); + assert(m68340SIM); m68340_sim &sim = *m68340SIM; @@ -364,54 +385,58 @@ WRITE32_MEMBER( m68340_cpu_device::m68340_internal_sim_cs_w ) switch (offset<<2) { - case m68340SIM_AM_CS0: + case m68340_sim::REG_AM_CS0: COMBINE_DATA(&sim.m_am[0]); break; - case m68340SIM_BA_CS0: + case m68340_sim::REG_BA_CS0: COMBINE_DATA(&sim.m_ba[0]); break; - case m68340SIM_AM_CS1: + case m68340_sim::REG_AM_CS1: COMBINE_DATA(&sim.m_am[1]); break; - case m68340SIM_BA_CS1: + case m68340_sim::REG_BA_CS1: COMBINE_DATA(&sim.m_ba[1]); break; - case m68340SIM_AM_CS2: + case m68340_sim::REG_AM_CS2: COMBINE_DATA(&sim.m_am[2]); break; - case m68340SIM_BA_CS2: + case m68340_sim::REG_BA_CS2: COMBINE_DATA(&sim.m_ba[2]); break; - case m68340SIM_AM_CS3: + case m68340_sim::REG_AM_CS3: COMBINE_DATA(&sim.m_am[3]); break; - case m68340SIM_BA_CS3: + case m68340_sim::REG_BA_CS3: COMBINE_DATA(&sim.m_ba[3]); break; default: - LOGSETUP("- %08x m68340_internal_sim_w %08x, %08x (%08x) - not implemented\n", pc, offset*4,data,mem_mask); - logerror("%08x m68340_internal_sim_w %08x, %08x (%08x)\n", pc, offset*4,data,mem_mask); + logerror("%08x m68340_internal_sim_cs_w %08x, %08x (%08x)\n", pc, offset*4,data,mem_mask); break; } } -void m68340_cpu_device::do_timer_irq() +void m68340_cpu_device::do_pit_irq() { - //logerror("do_timer_irq\n"); - int timer_irq_level = (m_picr & 0x0700)>>8; - int timer_irq_vector = (m_picr & 0x00ff)>>0; + assert(m68340SIM); + m68340_sim &sim = *m68340SIM; + + //logerror("do_pit_irq\n"); + int timer_irq_level = (sim.m_picr & 0x0700) >> 8; + int timer_irq_vector = (sim.m_picr & 0x00ff) >> 0; if (timer_irq_level) // 0 is irq disabled { - int use_autovector = (m_avr >> timer_irq_level)&1; + int use_autovector = (sim.m_avr_rsr >> (8 + timer_irq_level)) & 1; + + LOGPIT("PIT IRQ triggered, Lvl: %d using Vector: %d (0 = auto vector)\n", timer_irq_level, use_autovector ? 0 : timer_irq_vector); if (use_autovector) { @@ -429,12 +454,13 @@ void m68340_cpu_device::do_timer_irq() TIMER_CALLBACK_MEMBER(m68340_cpu_device::periodic_interrupt_timer_callback) { - do_timer_irq(); - m_irq_timer->adjust(cycles_to_attotime(20000)); // hack + do_tick_pit(); } void m68340_cpu_device::start_68340_sim() { + LOG("%s\n", FUNCNAME); + LOGCLOCK( " - Clock: %d [0x%08x]\n", clock(), clock()); m_irq_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(m68340_cpu_device::periodic_interrupt_timer_callback),this)); // resolve callbacks Port A @@ -444,11 +470,35 @@ void m68340_cpu_device::start_68340_sim() // resolve callbacks Port B m_pb_out_cb.resolve_safe(); m_pb_in_cb.resolve(); + + // Setup correct VCO/clock speed based on reset values and crystal + assert(m68340SIM); + m68340_sim &sim = *m68340SIM; + switch (m_clock_mode) + { + case m68340_sim::CLOCK_MODE_EXT: + LOGCLOCK("External Clock Mode\n"); + break; + case m68340_sim::CLOCK_MODE_EXT_PLL: + LOGCLOCK("External Clock Mode with PLL - not implemented\n"); + logerror("External Clock Mode with PLL - not implemented\n"); + break; + case m68340_sim::CLOCK_MODE_CRYSTAL: + LOGCLOCK("Crystal Mode with VCO and PLL\n"); + set_unscaled_clock(m_crystal * + (4 << (((sim.m_syncr & m68340_sim::REG_SYNCR_W) != 0 ? 2 : 0) + ((sim.m_syncr & m68340_sim::REG_SYNCR_X) != 0 ? 1 : 0))) * + (((sim.m_syncr & m68340_sim::REG_SYNCR_Y_MSK) >> 8) & 0x3f)); + LOGCLOCK("SYNCR: %04x\n", sim.m_syncr); + break; + default: + logerror("Unknown Clock mode, check schematics and/or the source code\n"); + } + LOGCLOCK( " - Clock: %d [0x%08x]\n", clock(), clock()); } void m68340_sim::reset() { - LOGSETUP("%s\n", FUNCNAME); + LOG("%s\n", FUNCNAME); // Ports - only setup those that are affected by reset m_ddra = 0x00; @@ -456,4 +506,51 @@ void m68340_sim::reset() m_ppara2 = 0x00; m_ddrb = 0x00; m_pparb = 0xff; + + // SIM + m_mcr = 0x608f; + m_syncr = 0x3f00; + m_avr_rsr = 0x0000; + m_swiv_sypcr = 0x0f00; + m_picr= 0x000f; + m_pitr= 0x0000; // TODO: read MODCK pin to set the clock modes for watch dog and periodic timer + m_swsr= 0x0000; + +} + +/* do_tick_pit works on whole clock cycles, no flank support */ +void m68340_cpu_device::do_tick_pit() +{ + assert(m68340SIM); + m68340_sim &sim = *m68340SIM; + + sim.m_pit_counter--; + if ( ( (sim.m_mcr & m68340_sim::REG_MCR_FRZ1) == 0) && + ( (sim.m_pit_counter != 0 || (sim.m_pitr & m68340_sim::REG_PITR_COUNT) != 0))) + { + LOGPIT("Re-arming PIT timer\n"); + sim.m_pit_counter = sim.m_pitr & m68340_sim::REG_PITR_COUNT; + m_irq_timer->adjust(cycles_to_attotime((m_crystal / 4) / ((sim.m_pitr & m68340_sim::REG_PITR_PTP) != 0 ? 512 : 1))); + } + else + { + LOGPIT("Stopping PIT timer dues to %s\n", (sim.m_mcr & m68340_sim::REG_MCR_FRZ1) != 0 ? "Freeze" : "Counter disabled"); + m_irq_timer->adjust(attotime::never); + } + + if (sim.m_pit_counter == 0) // Zero detect + { + LOGPIT("PIT timer reached zero!\n"); + do_pit_irq(); + } +} + +WRITE_LINE_MEMBER( m68340_cpu_device::extal_w ) +{ + LOGPIT("%s H1 set to %d\n", FUNCNAME, state); + m_extal = state; + if (m_extal == ASSERT_LINE) + { + do_tick_pit(); + } } diff --git a/src/devices/machine/68340sim.h b/src/devices/machine/68340sim.h index c56f782d4a9..be4710934b5 100644 --- a/src/devices/machine/68340sim.h +++ b/src/devices/machine/68340sim.h @@ -12,7 +12,7 @@ public: uint32_t m_am[4]; // chip select address mask + control, unaffected by reset uint32_t m_ba[4]; // chip select base address + control, unaffected by reset - // Ports Reset values + // Port registers Reset values uint8_t m_porta; // unaffected by reset uint8_t m_ddra; // 0x00 uint8_t m_ppara1; // 0xff @@ -21,7 +21,102 @@ public: uint8_t m_ddrb; // 0x00 uint8_t m_pparb; // 0xff + // SIM + uint16_t m_mcr; // 0x608f + uint16_t m_syncr; // 0x3f00 + uint16_t m_avr_rsr; // 0x0000 + uint16_t m_swiv_sypcr;//0x0f00 + uint16_t m_picr; // 0x000f + uint16_t m_pitr; // 0x0000 | ~MODCK pin + uint16_t m_swsr; // 0x0000 + + // Timers and counters + uint8_t m_pit_counter; + void reset(); + + enum { + REG_MCR = 0x00, + REG_SYNCR = 0x04, + REG_AVR_RSR = 0x06, + REG_PORTA = 0x11, + REG_DDRA = 0x13, + REG_PPARA1 = 0x15, + REG_PPARA2 = 0x17, + REG_PORTB = 0x19, + REG_PORTB1 = 0x1b, + REG_DDRB = 0x1d, + REG_PPARB = 0x1f, + REG_SWIV_SYPCR = 0x20, + REG_PICR = 0x22, + REG_PITR = 0x24, + REG_SWSR = 0x26, + REG_AM_CS0 = 0x40, + REG_BA_CS0 = 0x44, + REG_AM_CS1 = 0x48, + REG_BA_CS1 = 0x4c, + REG_AM_CS2 = 0x50, + REG_BA_CS2 = 0x54, + REG_AM_CS3 = 0x58, + REG_BA_CS3 = 0x5c, + }; + + enum { + REG_MCR_FRZ1 = 0x4000, + REG_MCR_FRZ0 = 0x2000, + REG_MCR_FIRQ = 0x1000, + REG_MCR_SHEN = 0x0300, + REG_MCR_SVREG = 0x0800, + REG_MCR_ARBLV = 0x000f, + }; + + enum { + REG_AVR_VEC = 0xff00, + REG_RSR_RESBITS = 0x00ff, + }; + + enum { + REG_SWIV_VEC = 0xff00, + REG_SYPCR_SWE = 0x0080, + REG_SYPCR_SWRI = 0x0040, + REG_SYPCR_SWT = 0x0030, + REG_SYPCR_DBFE = 0x0008, + REG_SYPCR_BME = 0x0004, + REG_SYPCR_BMT = 0x0003, + }; + + enum { + REG_PICR_PIRQL = 0x0700, + REG_PICR_PIVEC = 0x00ff, + }; + + enum { + REG_PITR_SWP = 0x0200, + REG_PITR_PTP = 0x0100, + REG_PITR_COUNT = 0x00ff, + }; + + enum { + REG_SYNCR_W = 0x8000, + REG_SYNCR_X = 0x4000, + REG_SYNCR_Y_MSK = 0x3f00, + REG_SYNCR_SLIMP = 0x0010, + REG_SYNCR_SLOCK = 0x0008, + REG_SYNCR_RSTEN = 0x0004, + REG_SYNCR_STSIM = 0x0002, + REG_SYNCR_STEXT = 0x0001, + }; + + enum { + CLOCK_PLL = 0x01, + CLOCK_MODCK = 0x02, + }; + + enum { + CLOCK_MODE_EXT = 0x00, + CLOCK_MODE_EXT_PLL = 0x01, + CLOCK_MODE_CRYSTAL = 0x03, + }; }; #endif // MAME_MACHINE_68340SIM_H diff --git a/src/devices/machine/68340tmu.cpp b/src/devices/machine/68340tmu.cpp index 92014401a34..713800aa40f 100644 --- a/src/devices/machine/68340tmu.cpp +++ b/src/devices/machine/68340tmu.cpp @@ -1,31 +1,627 @@ // license:BSD-3-Clause -// copyright-holders:David Haywood +// copyright-holders:David Haywood, Joakim Larsson Edstrom /* 68340 TIMER module */ +/* + * TODO: + * - Make the timer a device and instantiate two from 68340.cpp + * - implement all timer modes, only "Input Capture/Output Compare" mode is verified to work + */ + #include "emu.h" #include "68340.h" +//************************************************************************** +// MACROS / CONSTANTS +//************************************************************************** + +//#define LOG_GENERAL (1U << 0) // Already defined in logmacro.h +#define LOG_SETUP (1U << 1) +#define LOG_READ (1U << 2) +#define LOG_TIMER (1U << 3) +#define LOG_INT (1U << 4) + +//#define VERBOSE (LOG_SETUP|LOG_INT|LOG_TIMER) +#define LOG_OUTPUT_FUNC printf // Needs always to be enabled as the default value 'logerror' is not available here + +#include "logmacro.h" + +//#define LOG(...) LOGMASKED(LOG_GENERAL, __VA_ARGS__) // Already defined in logmacro.h +#define LOGSETUP(...) LOGMASKED(LOG_SETUP, __VA_ARGS__) +#define LOGR(...) LOGMASKED(LOG_READ, __VA_ARGS__) +#define LOGTIMER(...) LOGMASKED(LOG_TIMER, __VA_ARGS__) +#define LOGINT(...) LOGMASKED(LOG_INT, __VA_ARGS__) -READ32_MEMBER( m68340_cpu_device::m68340_internal_timer_r ) +#ifdef _MSC_VER +#define FUNCNAME __func__ +#else +#define FUNCNAME __PRETTY_FUNCTION__ +#endif + +READ16_MEMBER( m68340_cpu_device::m68340_internal_timer_r ) { + LOGSETUP("%s\n", FUNCNAME); + assert(m68340TIMER); - //m68340_timer &timer = *m68340TIMER; + m68340_timer &timer = *m68340TIMER; + int val = 0; int pc = space.device().safe_pc(); - logerror("%08x m68340_internal_timer_r %08x, (%08x)\n", pc, offset*4,mem_mask); + logerror("%08x m68340_internal_timer_r %08x, (%08x)\n", pc, offset * 2, mem_mask); + + int id = (offset * 2) < 0x40 ? 0 : 1; // Timer1 or Timer2 - return 0x00000000; + /*Setting the STP bit stops all clocks within the timer module except for the clock + from the IMB. The clock from the IMB remains active to allow the CPU32 access to the MCR. + Accesses to timer module registers while in stop mode produce a bus error. */ + if ( (timer.m_mcr[id] & m68340_timer::REG_MCR_STP) && ((offset * 2) % 0x40) != m68340_timer::REG_MCR) + { + logerror("Attempt to access timer registers while timer clocks are stopped, STP bit in MCR is set!"); + return val; // TODO: Should cause BUSERROR + } + + switch ((offset * 2) % 0x40) + { + case m68340_timer::REG_MCR: + val = timer.m_mcr[id]; + LOGTIMER("- %08x %s %04x, %04x (%04x) (MCR - Module Configuration Register)\n", pc, FUNCNAME, offset * 2, val, mem_mask); + break; + case m68340_timer::REG_IR: + val = timer.m_ir[id]; + LOGTIMER("- %08x %s %04x, %04x (%04x) (IR - Interrupt Register)\n", pc, FUNCNAME, offset * 2, val, mem_mask); + break; + case m68340_timer::REG_CR: + val = timer.m_cr[id]; + LOGTIMER("- %08x %s %04x, %04x (%04x) (CR - Control Register)\n", pc, FUNCNAME, offset * 2, val, mem_mask); + break; + case m68340_timer::REG_SR: + val = timer.m_sr[id]; + LOGTIMER("- %08x %s %04x, %04x (%04x) (SR - Status/Prescaler Register)\n", pc, FUNCNAME, offset * 2, val, mem_mask); + break; + case m68340_timer::REG_CNTR: + val = timer.m_cntr_reg[id]; + LOGTIMER("- %08x %s %04x, %04x (%04x) (CNTR - Counter Register)\n", pc, FUNCNAME, offset * 2, val, mem_mask); + break; + case m68340_timer::REG_PREL1: + val = timer.m_prel1[id]; + LOGTIMER("- %08x %s %04x, %04x (%04x) (PREL1 - Preload 1 Register)\n", pc, FUNCNAME, offset * 2, val, mem_mask); + break; + case m68340_timer::REG_PREL2: + val = timer.m_prel2[id]; + LOGTIMER("- %08x %s %04x, %04x (%04x) (PREL2 - Preload 2 Register)\n", pc, FUNCNAME, offset * 2, val, mem_mask); + break; + case m68340_timer::REG_COM: + val = timer.m_com[id]; + LOGTIMER("- %08x %s %04x, %04x (%04x) (COM - Compare Register)\n", pc, FUNCNAME, offset * 2, val, mem_mask); + break; + default: + LOGTIMER("- %08x FUNCNAME %08x, %08x (%08x) - not implemented\n", pc, offset * 2, val, mem_mask); + logerror("%08x m68340_internal_timer_r %08x, %08x (%08x)\n", pc, offset * 2, val, mem_mask); + break; + } + LOGR(" * Timer%d Reg %02x [%02x] -> %02x - %s\n", id + 1, offset * 2 % 0x40, offset, val, ((offset * 2) % 0x40) > 0x12 ? "reserved" : std::array {{"MCR", "reserved", "IR", "CR", "SR", "CNTR", "PREL1", "PREL2", "COM"}}[offset % 0x20]); + return val; } -WRITE32_MEMBER( m68340_cpu_device::m68340_internal_timer_w ) +WRITE16_MEMBER( m68340_cpu_device::m68340_internal_timer_w ) { + int id = (offset * 2) < 0x40 ? 0 : 1; // Timer1 or Timer2 + + LOGSETUP("\n%s\n", FUNCNAME); + LOGSETUP(" * Timer%d Reg %02x [%02x] <- %02x - %s\n", id + 1, (offset * 2) % 0x40, offset, data, + ((offset * 2) % 0x40) > 0x12 ? "reserved" : std::array + {{"MCR", "reserved", "IR", "CR", "SR", "CNTR", "PREL1", "PREL2", "COM"}}[offset % 0x20]); + assert(m68340TIMER); - //m68340_timer &timer = *m68340TIMER; + m68340_timer &timer = *m68340TIMER; + + /*Setting the STP bit stops all clocks within the timer module except for the clock + from the IMB. The clock from the IMB remains active to allow the CPU32 access to the MCR. + Accesses to timer module registers while in stop mode produce a bus error. */ + if ( (timer.m_mcr[id] & m68340_timer::REG_MCR_STP) && ((offset * 2) % 0x40) != m68340_timer::REG_MCR) + { + logerror("Attempt to access timer registers while timer clocks are stopped, STP bit in MCR is set!"); + return; // TODO: Should cause BUSERROR + } + + switch ((offset * 2) % 0x40) + { + case m68340_timer::REG_MCR: + COMBINE_DATA(&timer.m_mcr[id]); + LOGTIMER("PC: %08x %s %04x, %04x (%04x) (MCR - Module Configuration Register)\n", pc, FUNCNAME, offset * 2, data, mem_mask); + LOGTIMER("- Clocks are %s\n", data & m68340_timer::REG_MCR_STP ? "stopped" : "running"); + LOGTIMER("- Freeze signal %s - not implemented\n", data & m68340_timer::REG_MCR_FRZ1 ? "stops execution" : "is ignored"); + LOGTIMER("- Supervisor registers %s - not implemented\n", data & m68340_timer::REG_MCR_SUPV ? "requries supervisor privileges" : "can be accessed by user privileged software"); + LOGTIMER("- Interrupt Arbitration level: %02x - not implemented\n", data & m68340_timer::REG_MCR_ARBLV); + break; + case m68340_timer::REG_IR: + COMBINE_DATA(&timer.m_ir[id]); + LOGTIMER("PC: %08x %s %04x, %04x (%04x) (IR - Interrupt Register)\n", pc, FUNCNAME, offset * 2, data, mem_mask); + LOGTIMER("- Interrupt level : %02x\n", (data & m68340_timer::REG_IR_INTLEV) >> 8); + LOGTIMER("- Interrupt vector: %02x\n", (data & m68340_timer::REG_IR_INTVEC)); + break; + case m68340_timer::REG_CR: + COMBINE_DATA(&timer.m_cr[id]); + LOGTIMER("PC %08x %s %04x, %04x (%04x) (CR - Module Control Register)\n", pc, FUNCNAME, offset * 2, data, mem_mask); + LOGTIMER("- Software reset: %s\n", (data & m68340_timer::REG_CR_SWR) ? "inactive" : "active" ); + LOGTIMER("- Enabled interrupts: %02x TO:%d TG:%d TC:%d\n", + data & m68340_timer::REG_CR_INTMSK, + (data & m68340_timer::REG_CR_IE0) ? 1 : 0, + (data & m68340_timer::REG_CR_IE1) ? 1 : 0, + (data & m68340_timer::REG_CR_IE2) ? 1 : 0); + LOGTIMER("- TGE signal, TGATE%d is %s\n", id + 1, (data & m68340_timer::REG_CR_TGE) ? "enabled" : "disabled"); + LOGTIMER("- PCLK: Counter uses %s\n", (data & m68340_timer::REG_CR_PCLK) ? "prescaler" : "clock"); + LOGTIMER("- CPE: Counter is %s\n", (data & m68340_timer::REG_CR_CPE) ? "enabled" : "disabled"); + LOGTIMER("- CLK: Clock is %s\n", (data & m68340_timer::REG_CR_CLK) ? "TIN (external)" : "system clock / 2"); + LOGTIMER("- Prescaler: Divide by %d\n", (data & m68340_timer::REG_CR_POT_MASK) ? ( 1 << ((data & m68340_timer::REG_CR_POT_MASK) >> 5)) : 256); + LOGTIMER("- Prescaler: Divide by %d\n", (0x101 << ((data & m68340_timer::REG_CR_POT_MASK) >> 5) & 0x1fe)); + LOGTIMER("- MODE: %s\n", std::array + {{ "Input Capture/Output Compare", + "Square-Wave Generator - not implemented", + "Variable Duty-Cycle Square-Wave Generator - not implemented", + "Variable-Width Single-Shot Pulse Generator - not implemented", + "Pulse Width Measurement - not implemented", + "Period Measurement - not implemented", + "Event Count - not implemented", + "Timer Bypass (Simple Test Method) - not implemented" + }}[data & m68340_timer::REG_CR_MODE_MASK]); + + LOGTIMER("- OC: %s mode\n", std::array{{"Disabled", "Toggle", "Zero", "One"}}[data & m68340_timer::REG_CR_OC_MASK]); + + /* The timer is enabled when the counter prescaler enable (CPE) and SWRx bits in the CR + are set. Once enabled, the counter enable (ON) bit in the SR is set, and the next falling + edge of the counter clock causes the counter to be loaded with the value in the preload 1 + register (PREL1). TODO: make sure of the intial load of PREL1 on first falling flank */ + if (timer.m_cr[id] & m68340_timer::REG_CR_SWR) + { + if (timer.m_cr[id] & m68340_timer::REG_CR_CPE) + { + timer.m_sr[id] |= m68340_timer::REG_SR_ON; // Starts the counter + LOGTIMER("Starts counter %d\n", id); + if ((timer.m_cr[id] & m68340_timer::REG_CR_CLK) == 0) + { + LOGTIMER("- Using system clock/2\n"); + timer.m_timer[id]->adjust(cycles_to_attotime( (clock() / 2) / (0x101 << ((timer.m_cr[id] & m68340_timer::REG_CR_POT_MASK) >> 5) & 0x1fe) * 2)); + } + else + { + LOGTIMER("- Using TIN%d\n", id); + } + } + else + { + timer.m_sr[id] &= ~m68340_timer::REG_SR_ON; // Stops the counter + LOGTIMER("Stops counter %d\n", id); + timer.m_timer[id]->adjust(attotime::never); + } + } + else + { // TODO: Detect Disable mode setting line to three state + if ((timer.m_cr[id] & m68340_timer::REG_CR_OC_MASK) == m68340_timer::REG_CR_OC_ONE) + { + id == 0 ? m_tout1_out_cb(ASSERT_LINE) : m_tout2_out_cb(ASSERT_LINE); + } + else + { + id == 0 ? m_tout1_out_cb(CLEAR_LINE) : m_tout2_out_cb(CLEAR_LINE); + } + } + break; + case m68340_timer::REG_SR: + LOGTIMER("PC %08x %s %04x, %04x (%04x) (SR - Status/Prescaler Register)\n", pc, FUNCNAME, offset * 2, data, mem_mask); + + /* IRQ - Interrupt Request bit + 1 = An interrupt condition has occurred. This bit is the logical OR of the enabled TO, TG, and TC interrupt bits. + 0 = The bit(s) that caused the interrupt condition has been cleared. If an IRQ signal has been asserted, it is negated when this bit is cleared. */ + data = (timer.m_sr[id] & ~(data & (m68340_timer::REG_SR_TO | m68340_timer::REG_SR_TG | m68340_timer::REG_SR_TC))); // Clear only the set interrupt bits + if ((data & (m68340_timer::REG_SR_TO | m68340_timer::REG_SR_TG | m68340_timer::REG_SR_TC)) == 0) + { + data &= ~m68340_timer::REG_SR_IRQ; + // TODO: clear IRQ line + } + COMBINE_DATA(&timer.m_sr[id]); + LOGTIMER("PC %08x %s %04x, %04x (%04x) (SR - Status/Prescaler Register)\n", pc, FUNCNAME, offset * 2, data, mem_mask); + LOGTIMER("- IRQ: %s\n", (data & m68340_timer::REG_SR_IRQ) ? "Yes" : "None"); + LOGTIMER("- TO TimeOut int : %s\n", (data & m68340_timer::REG_SR_TO) ? "Asserted" : "Cleared"); + LOGTIMER("- TG Timer Gate int : %s\n", (data & m68340_timer::REG_SR_TG) ? "Asserted" : "Cleared"); + LOGTIMER("- TC Timer Counter int: %s\n", (data & m68340_timer::REG_SR_TC) ? "Asserted" : "Cleared"); + LOGTIMER("- TGL: %s\n", (data & m68340_timer::REG_SR_TGL) ? "Negated" : "Asserted"); + LOGTIMER("- ON Counter is: %s\n", (data & m68340_timer::REG_SR_ON) ? "Enabled" : "Disabled"); + LOGTIMER("- OUT: Tout is %s\n", (data & m68340_timer::REG_SR_OUT) ? "1" : "0 or three-stated"); + LOGTIMER("- COM: Compare is %s\n", (data & m68340_timer::REG_SR_COM) ? "Match" : "Cleared"); + LOGTIMER("- PO7-PO0: %02x\n", (data & m68340_timer::REG_SR_PSC_OUT)); + break; + case m68340_timer::REG_CNTR: + COMBINE_DATA(&timer.m_cntr_reg[id]); + LOGTIMER("- %08x %s %04x, %04x (%04x) (CNTR - Counter Register)\n", pc, FUNCNAME, offset * 2, data, mem_mask); + break; + case m68340_timer::REG_PREL1: + COMBINE_DATA(&timer.m_prel1[id]); + LOGTIMER("PC %08x %s %04x, %04x (%04x) (PREL1 - Preload 1 Register)\n", pc, FUNCNAME, offset * 2, data, mem_mask); + LOGTIMER("- PR1-15 to PR1-0: %04x\n", (data & 0xffff)); + break; + case m68340_timer::REG_PREL2: + COMBINE_DATA(&timer.m_prel2[id]); + LOGTIMER("PC %08x %s %04x, %04x (%04x) (PREL2 - Preload 2 Register)\n", pc, FUNCNAME, offset * 2, data, mem_mask); + LOGTIMER("- PR2-15 to PR2-0: %04x\n", (data & 0xffff)); + break; + case m68340_timer::REG_COM: + COMBINE_DATA(&timer.m_com[id]); + LOGTIMER("PC %08x %s %04x, %04x (%04x) (COM - Compare Register)\n", pc, FUNCNAME, offset * 2, data, mem_mask); + LOGTIMER("- COM15-COM0: %04x\n", (data & 0xfff)); + break; + default: + LOGTIMER("- %08x FUNCNAME %08x, %08x (%08x) - not implemented\n", pc, offset * 2, data, mem_mask); + logerror("%08x m68340_internal_sim_w %08x, %08x (%08x)\n", pc, offset * 2, data, mem_mask); + break; + } int pc = space.device().safe_pc(); - logerror("%08x m68340_internal_timer_w %08x, %08x (%08x)\n", pc, offset*4,data,mem_mask); + logerror("%08x m68340_internal_timer_w %08x, %08x (%08x)\n", pc, offset * 2, data, mem_mask); } void m68340_timer::reset() { + LOGSETUP("%s\n", FUNCNAME); +} + +WRITE_LINE_MEMBER( m68340_cpu_device::tin1_w) +{ + LOGTIMER("%s\n", FUNCNAME); + + assert(m68340TIMER); + m68340_timer &timer = *m68340TIMER; + + timer.m_tin[0] = state; +} + +WRITE_LINE_MEMBER( m68340_cpu_device::tgate1_w) +{ + LOGTIMER("%s\n", FUNCNAME); + + assert(m68340TIMER); + m68340_timer &timer = *m68340TIMER; + + timer.m_tgate[0] = state; + if (state == ASSERT_LINE) + { + if (timer.m_cr[0] & m68340_timer::REG_CR_TGE) + { + timer.m_sr[0] |= m68340_timer::REG_SR_TG; + if (timer.m_cr[0] & m68340_timer::REG_CR_IE1) + { + LOGTIMER(" - TG interrupt"); + do_timer_irq(0); + timer.m_sr[0] |= m68340_timer::REG_SR_IRQ; + + } + } + timer.m_sr[0] |= m68340_timer::REG_SR_TGL; + } + else + { + timer.m_sr[0] &= ~m68340_timer::REG_SR_TGL; + } +} + +WRITE_LINE_MEMBER( m68340_cpu_device::tin2_w) +{ + LOGTIMER("%s\n", FUNCNAME); + + assert(m68340TIMER); + m68340_timer &timer = *m68340TIMER; + + timer.m_tin[1] = state; +} + +WRITE_LINE_MEMBER( m68340_cpu_device::tgate2_w) +{ + LOGTIMER("%s\n", FUNCNAME); + + assert(m68340TIMER); + m68340_timer &timer = *m68340TIMER; + + timer.m_tgate[1] = state; + if (state == ASSERT_LINE) + { + if (timer.m_cr[1] & m68340_timer::REG_CR_TGE) + { + timer.m_sr[1] |= m68340_timer::REG_SR_TG; + if (timer.m_cr[1] & m68340_timer::REG_CR_IE1) + { + LOGTIMER(" - TG interrupt"); + do_timer_irq(1); + timer.m_sr[1] |= m68340_timer::REG_SR_IRQ; + + } + } + timer.m_sr[1] |= m68340_timer::REG_SR_TGL; + } + else + { + timer.m_sr[1] &= ~m68340_timer::REG_SR_TGL; + } +} + +TIMER_CALLBACK_MEMBER(m68340_cpu_device::timer1_callback) +{ + assert(m68340TIMER); + m68340_timer &timer = *m68340TIMER; + do_timer_tick(0); + if ((timer.m_sr[0] & m68340_timer::REG_SR_ON) != 0) + { + LOGTIMER("Re-arming timer 1 using system clock/2 as base %d Hz\n", (clock() / 2) / (0x101 << ((timer.m_cr[0] & m68340_timer::REG_CR_POT_MASK) >> 5) & 0x1fe)); + timer.m_timer[0]->adjust(cycles_to_attotime( (clock() / 2) / (0x101 << ((timer.m_cr[0] & m68340_timer::REG_CR_POT_MASK) >> 5) & 0x1fe) * 2)); + } +} + +TIMER_CALLBACK_MEMBER(m68340_cpu_device::timer2_callback) +{ + assert(m68340TIMER); + m68340_timer &timer = *m68340TIMER; + do_timer_tick(1); + if ((timer.m_sr[1] & m68340_timer::REG_SR_ON) != 0) + { + LOGTIMER("Re-arming timer 2 using system clock/2 as base: %d Hz\n", (clock() / 2) / (0x101 << ((timer.m_cr[1] & m68340_timer::REG_CR_POT_MASK) >> 5) & 0x1fe)); + timer.m_timer[1]->adjust(cycles_to_attotime( (clock() / 2) / (0x101 << ((timer.m_cr[1] & m68340_timer::REG_CR_POT_MASK) >> 5) & 0x1fe) * 2)); + } +} + +void m68340_cpu_device::start_68340_timer() +{ + LOGSETUP("%s\n", FUNCNAME); + + assert(m68340TIMER); + m68340_timer &timer = *m68340TIMER; + + timer.m_timer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(m68340_cpu_device::timer1_callback),this)); + timer.m_timer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(m68340_cpu_device::timer2_callback),this)); + + // resolve callbacks Port A + m_pa_out_cb.resolve_safe(); + m_pa_in_cb.resolve(); + + // Resolve Timer callbacks + m_tout1_out_cb.resolve_safe(); + m_tgate1_in_cb.resolve_safe(); + m_tin1_in_cb.resolve_safe(); + m_tout2_out_cb.resolve_safe(); + m_tgate2_in_cb.resolve_safe(); + m_tin2_in_cb.resolve_safe(); +} + +void m68340_cpu_device::do_timer_irq(int id) +{ + assert(m68340TIMER); + m68340_timer &timer = *m68340TIMER; + + assert(m68340SIM); + m68340_sim &sim = *m68340SIM; + + int timer_irq_level = (timer.m_ir[id] & 0x0700) >> 8; + int timer_irq_vector = (timer.m_ir[id] & 0x00ff) >> 0; + + if (timer_irq_level) // 0 is irq disabled + { + int use_autovector = (sim.m_avr_rsr >> (8 + timer_irq_level)) & 1; + + LOGINT("TIMER IRQ triggered, Lvl: %d using Vector: %d (0 = auto vector)\n", timer_irq_level, use_autovector ? 0 : timer_irq_vector); + + if (use_autovector) + { + //logerror("irq with autovector\n"); + set_input_line(timer_irq_level, HOLD_LINE); + } + else + { + //logerror("irq without autovector\n"); + set_input_line_and_vector(timer_irq_level, HOLD_LINE, timer_irq_vector); + } + } +} + +/* do_timer_tick works on flanks, thus half clock cycles, to capture both rising and falling clock flanks */ +void m68340_cpu_device::do_timer_tick( int id ) +{ + assert(m68340TIMER); + m68340_timer &timer = *m68340TIMER; + + timer.m_timer_counter[id]--; // Count flanks, least significant bit is state of the clock line + if ( (timer.m_mcr[id] & m68340_timer::REG_MCR_STP) == 0) + { + if (timer.m_timer_counter[id] & 1) // Raising flank, copy shadow to register + { + // Shadow the counter only if we are NOT in the ICOC mode WHILE the TG bit is set + if (!((timer.m_cr[id] & m68340_timer::REG_CR_MODE_MASK) == m68340_timer::REG_CR_MODE_ICOC && + (timer.m_sr[id] & m68340_timer::REG_SR_TG) != 0)) + timer.m_cntr_reg[id] = timer.m_cntr[id]; + } + else // Falling flank + { + timer.m_cntr[id]--; + + /* TC - Timer Compare Interrupt + 1 = This bit is set when the counter transitions (off a clock/event falling edge) to the + value in the COM. This bit does not affect the programmed IRQ signal if the IE0 + bit in the CR is cleared. + 0 = This bit is cleared by the timer whenever the RESET signal is asserted on the + IMB, regardless of the mode of operation. This bit may also be cleared by writing + a one to it. Writing a zero to this bit does not alter its contents. This bit is not + affected by disabling the timer (SWR = 0).*/ + if (timer.m_cntr[id] == timer.m_com[id]) // Check COM register + { + timer.m_sr[id] |= (m68340_timer::REG_SR_TC | m68340_timer::REG_SR_COM); + } + } + + LOGINT("%s reached\n", timer.m_cntr_reg[id] == 0 ? "Timeout" : "COM value"); + /* OC1/OC0 - Output Control + These bits select the conditions under which TOUTx changes These + bits may have a different effect when in the input capture/output compare mode.*/ + switch (timer.m_cr[id] & m68340_timer::REG_CR_OC_MASK) + { + case m68340_timer::REG_CR_OC_DISABLED: + /* Disabled - TOUTx is disabled and three-stated TODO: support three-stated level */ + break; + case m68340_timer::REG_CR_OC_TOGGLE: + /* Toggle Mode - If the timer is disabled (SWR = 0) when this encoding is programmed, + TOUTx is immediately set to zero. If the timer is enabled (SWR = 1), timeout events + (counter reaches $0000) toggle TOUTx. + + In the input capture/output compare mode, + TOUTx is immediately set to zero if the timer is disabled (SWR = 0). If the timer is + enabled (SWR = 1), timer compare events toggle TOUTx. (Timer compare events occur + when the counter reaches the value stored in the COM.)*/ + if ((timer.m_cr[id] & m68340_timer::REG_CR_MODE_MASK) == m68340_timer::REG_CR_MODE_ICOC) // Detect Input Capture/Output Compare mode + { + if ((timer.m_sr[id] & m68340_timer::REG_SR_COM) != 0) // timer reached compare value? + { + if (id == 0) + { + m_tout1_out_cb((timer.m_tout[0]++ & 1) != 0 ? ASSERT_LINE : CLEAR_LINE); + } + else + { + m_tout2_out_cb((timer.m_tout[1]++ & 1) != 0 ? ASSERT_LINE : CLEAR_LINE); + } + } + } + else // Any oher mode + { + if (timer.m_cntr_reg[id] == 0) // Counter reached timeout? + { + if (id == 0) + { + m_tout1_out_cb((timer.m_tout[0]++ & 1) != 0 ? ASSERT_LINE : CLEAR_LINE); + } + else + { + m_tout2_out_cb((timer.m_tout[1]++ & 1) != 0 ? ASSERT_LINE : CLEAR_LINE); + } + } + } + break; + case m68340_timer::REG_CR_OC_ZERO: + /* Zero Mode - If the timer is disabled (SWR = 0) when this encoding is programmed, + TOUTx is immediately set to zero. If the timer is enabled (SWR = 1), TOUTx will be set + to zero at the next timeout. + + In the input capture/output compare mode, TOUTx is + immediately set to zero if the timer is disabled (SWR = 0). If the timer is enabled (SWR + = 1), TOUTx will be set to zero at timeouts and set to one at timer compare events. If + the COM is $0000, TOUTx will be set to zero at the timeout/timer compare event.*/ + if ((timer.m_cr[id] & m68340_timer::REG_CR_MODE_MASK) == m68340_timer::REG_CR_MODE_ICOC) // Detect Input Capture/Output Compare mode + { + if ((timer.m_sr[id] & m68340_timer::REG_SR_COM) != 0) // timer reached compare value? + { + if (id == 0) + { + m_tout1_out_cb(ASSERT_LINE); + } + else + { + m_tout2_out_cb(ASSERT_LINE); + } + } + if (timer.m_cntr_reg[id] == 0) // timer reached timeout value? + { + if (id == 0) + { + m_tout1_out_cb(CLEAR_LINE); + } + else + { + m_tout2_out_cb(CLEAR_LINE); + } + } + } + else + { + if (timer.m_cntr_reg[id] == 0) // timer reached timeout value? + { + if (id == 0) + { + m_tout1_out_cb(CLEAR_LINE); + } + else + { + m_tout2_out_cb(CLEAR_LINE); + } + } + } + break; + case m68340_timer::REG_CR_OC_ONE: + /* One Mode - If the timer is disabled (SWR = 0) when this encoding is programmed, + TOUTx is immediately set to one. If the timer is enabled (SWR = 1), TOUTx will be set + to one at the next timeout. + + In the input capture/output compare mode, TOUTx is + immediately set to one if the timer is disabled (SWR = 0). If the timer is enabled (SWR = + 1), TOUTx will be set to one at timeouts and set to zero at timer compare events. If the + COM is $0000, TOUTx will be set to one at the timeout/timer compare event.*/ + if ((timer.m_cr[id] & m68340_timer::REG_CR_MODE_MASK) == m68340_timer::REG_CR_MODE_ICOC) // Detect Input Capture/Output Compare mode + { + if ((timer.m_sr[id] & m68340_timer::REG_SR_COM) != 0) // timer reached compare value? + { + if (id == 0) + { + m_tout1_out_cb(CLEAR_LINE); + } + else + { + m_tout2_out_cb(CLEAR_LINE); + } + } + if (timer.m_cntr_reg[id] == 0) // timer reached timeout value? + { + if (id == 0) + { + m_tout1_out_cb(ASSERT_LINE); + } + else + { + m_tout2_out_cb(ASSERT_LINE); + } + } + } + else + { + if (timer.m_cntr_reg[id] == 0) // timer reached timeout value? + { + if (id == 0) + { + m_tout1_out_cb(ASSERT_LINE); + } + else + { + m_tout2_out_cb(ASSERT_LINE); + } + } + } + break; + default: + LOGTIMER("Wrong TOUT mode, fix the code!\n"); + } + + if (timer.m_cntr_reg[id] == 0) // timer reached timeout value? + { + timer.m_cntr[id] = timer.m_prel1[id]; // TODO: Support prel2 for certain modes + if (timer.m_cr[id] & m68340_timer::REG_CR_IE2) + { + LOGTIMER(" - TO interrupt"); + do_timer_irq(id); + timer.m_sr[id] |= m68340_timer::REG_SR_IRQ; + } + } + if ((timer.m_sr[id] & m68340_timer::REG_SR_COM) != 0) // timer reached compare value? ) + { + if (timer.m_cr[id] & m68340_timer::REG_CR_IE0) + { + LOGTIMER(" - TC interrupt"); + do_timer_irq(id); + timer.m_sr[id] |= m68340_timer::REG_SR_IRQ; + + } + } + } } diff --git a/src/devices/machine/68340tmu.h b/src/devices/machine/68340tmu.h index 911a079c520..813beb80376 100644 --- a/src/devices/machine/68340tmu.h +++ b/src/devices/machine/68340tmu.h @@ -5,11 +5,90 @@ #pragma once - class m68340_timer { public: + // Registers for timer 1 and timer 2 + uint16_t m_mcr[2]; + uint16_t m_ir[2]; + uint16_t m_cr[2]; + uint16_t m_sr[2]; + uint16_t m_cntr[2]; + uint16_t m_cntr_reg[2]; + uint16_t m_prel1[2]; + uint16_t m_prel2[2]; + uint16_t m_com[2]; + uint16_t m_timer_counter[2]; + uint32_t m_tin[2]; + uint32_t m_tgate[2]; + uint32_t m_tout[2]; + emu_timer *m_timer[2]; + void reset(); + + enum { + REG_MCR = 0x00, + REG_IR = 0x04, + REG_CR = 0x06, + REG_SR = 0x08, + REG_CNTR = 0x0a, + REG_PREL1 = 0x0c, + REG_PREL2 = 0x0e, + REG_COM = 0x10, + }; + + enum { + REG_MCR_STP = 0x8000, + REG_MCR_FRZ1 = 0x4000, + REG_MCR_FRZ2 = 0x2000, + REG_MCR_SUPV = 0x0800, + REG_MCR_ARBLV = 0x000f, + }; + + enum { + REG_IR_INTLEV = 0x0700, + REG_IR_INTVEC = 0x00ff, + }; + + enum { + REG_CR_SWR = 0x8000, + REG_CR_INTMSK = 0x7000, + REG_CR_IE0 = 0x4000, + REG_CR_IE1 = 0x2000, + REG_CR_IE2 = 0x1000, + REG_CR_TGE = 0x0800, + REG_CR_PCLK = 0x0400, + REG_CR_CPE = 0x0200, + REG_CR_CLK = 0x0100, + REG_CR_POT_MASK = 0x00e0, + REG_CR_MODE_MASK = 0x001c, // Mode mask + REG_CR_MODE_ICOC = 0x0000, // Input Capture Output Compare + REG_CR_MODE_SQWG = 0x0004, // Square Wave Generator + REG_CR_MODE_VDCSW = 0x0008, // Variable Duty Cycle Square Wave generator + REG_CR_MODE_VWSSPG = 0x000c, // Variable Width Single Shot Pulse Generator + REG_CR_MODE_PWM = 0x0010, // Pulse Width Measurement + REG_CR_MODE_PM = 0x0014, // Period Measurement + REG_CR_MODE_EC = 0x0018, // Event Count + REG_CR_MODE_TB = 0x001c, // Timer Bypass + REG_CR_OC_MASK = 0x0003, + REG_CR_OC_DISABLED = 0x0000, + REG_CR_OC_TOGGLE = 0x0001, + REG_CR_OC_ZERO = 0x0002, + REG_CR_OC_ONE = 0x0003, + }; + + enum { + REG_SR_IRQ = 0x8000, + REG_SR_TO = 0x4000, + REG_SR_TG = 0x2000, + REG_SR_TC = 0x1000, + REG_SR_TGL = 0x0800, + REG_SR_ON = 0x0400, + REG_SR_OUT = 0x0200, + REG_SR_COM = 0x0100, + REG_SR_PSC_OUT = 0x00ff, + }; + }; #endif // MAME_MACHINE_68340TMU_H diff --git a/src/mame/drivers/dbox.cpp b/src/mame/drivers/dbox.cpp index 02067db6c10..84cf98e406d 100644 --- a/src/mame/drivers/dbox.cpp +++ b/src/mame/drivers/dbox.cpp @@ -111,18 +111,33 @@ * SIM40 + 0x0040: 0x003FFFF5 CS0 mask 1 - block size = 4194304 (4MB) * SIM40 + 0x0044: 0x00000003 CS0 base 1 - base addr = 0x000000 * SIM40 + 0x0048: 0x003FFFF5 CS1 mask 1 - block size = 4194304 (4MB) - * SIM40 + 0x004C: 0x00800003 CS1 base 1 - base addr = 0x + * SIM40 + 0x004C: 0x00800003 CS1 base 1 - base addr = 0x800000 * SIM40 + 0x0050: 0x00007FFF CS2 mask 1 - block size = 65536 (64KB) * SIM40 + 0x0054: 0x00700003 CS2 base 1 * SIM40 + 0x0058: 0x000007F2 CS3 mask 1 - block size = 2048 (2KB) * SIM40 + 0x005C: 0x00780003 CS3 base 1 * SIM40 + 0x001F: 0x40 PBARB Port B Pin Assignment * +- 0000007a void m68340_cpu_device::m68340_internal_sim_cs_w(address_space&, offs_t, osd::u32, osd::u32) 00000040, 003ffff5 (ffffffff) - not implemented +- 00000082 void m68340_cpu_device::m68340_internal_sim_cs_w(address_space&, offs_t, osd::u32, osd::u32) 00000044, 00000003 (ffffffff) - not implemented +- 0000008a void m68340_cpu_device::m68340_internal_sim_cs_w(address_space&, offs_t, osd::u32, osd::u32) 00000048, 003ffff5 (ffffffff) - not implemented +- 00000092 void m68340_cpu_device::m68340_internal_sim_cs_w(address_space&, offs_t, osd::u32, osd::u32) 0000004c, 00800003 (ffffffff) - not implemented +- 0000009a void m68340_cpu_device::m68340_internal_sim_cs_w(address_space&, offs_t, osd::u32, osd::u32) 00000050, 00007fff (ffffffff) - not implemented +- 000000a2 void m68340_cpu_device::m68340_internal_sim_cs_w(address_space&, offs_t, osd::u32, osd::u32) 00000054, 00700003 (ffffffff) - not implemented +- 000000aa void m68340_cpu_device::m68340_internal_sim_cs_w(address_space&, offs_t, osd::u32, osd::u32) 00000058, 000007f2 (ffffffff) - not implemented +- 000000b2 void m68340_cpu_device::m68340_internal_sim_cs_w(address_space&, offs_t, osd::u32, osd::u32) 0000005c, 00780003 (ffffffff) - not implemented +... +- 008004d8 void m68340_cpu_device::m68340_internal_sim_cs_w(address_space&, offs_t, osd::u32, osd::u32) 00000044, 00000053 (ffffffff) - not implemented +- 008004e2 void m68340_cpu_device::m68340_internal_sim_cs_w(address_space&, offs_t, osd::u32, osd::u32) 00000040, 003fff05 (ffffffff) - not implemented +- 008004ee void m68340_cpu_device::m68340_internal_sim_cs_w(address_space&, offs_t, osd::u32, osd::u32) 00000040, 003ffff5 (ffffffff) - not implemented +- 008004f8 void m68340_cpu_device::m68340_internal_sim_cs_w(address_space&, offs_t, osd::u32, osd::u32) 00000044, 0000005b (ffffffff) - not implemented + + * ------------------------------------------------------------- * The bootstrap copies the firmware to RAM and jumps to it * ------------------------------------------------------------- * - * --- PC > 0x700000 so probably init of the RTXC tick timer setup?! + * --- PC > 0x700000 * SIM40 + 0x0022: 0x0140 PICR Periodic Interrupt Control Register * SIM40 + 0x0024: 0x0029 PICR Periodic Interrupt Timer Register * @@ -274,6 +289,13 @@ * SIM40 + 0x0640: 0x03 MCR Timer 2 * tbc... * + * // Tricks with the CS0 and the GAL:s + * 008004d8 SIM40 + 0x0044: 0x00000053 CS0 base 1 - base addr = 0x000000, Supervisor Data Space, No CPU Space, Valid CS + * 008004e2 SIM40 + 0x0040: 0x003FFF05 CS0 mask 1 - block size = 4194304 (4MB), + * ... strange series of operations between 800834 and 8008D4, suspecting GAL:s to be involved in some magic here + * 008004ee SIM40 + 0x0040: 0x003FFFF5 CS0 mask 1 - block size = 4194304 (4MB), Mask all accesses + * 008004f8 SIM40 + 0x0044: 0x0000005b CS0 base 1 - base addr = 0x000000, Supervisor Data Space, Write Protect, No CPU Space, Valid CS + * * LED Dot Matrix Display hookup * ------------------------------------- * "DISPLAY CONN ALT" connected to the SDA5708 @@ -306,6 +328,31 @@ * 14 Enable* Q1 74138 pin 14 IP12 * 15 Clear* System reset * + * Address map decoding + * -------------------- + * IP06 GAL16V8 - DRAM + * pin signal connected to + * 1 Q V-FIFO-CLK inverted SCSI_CLK, origin to be found + * 2 I1 SCSI_CLK + * 3 I2 A0 68340 pin 113 IP01 + * 4 I3 CS1 68340 pin 2 IP01 + * 5 I4 A19 68340 pin 62 IP01 + * 6 I5 A21 68340 pin 64 IP01 + * 7 I6 BG 68340 pin 101 IP01 + * 8 I7 SIZ0 68340 pin 105 IP01 + * 9 I8 R/W 68340 pin 107 IP01 + * 11 I9/OE* GND 68340 pin 107 IP01 via an 100R resistor + * 19 O0 FC2 68340 pin 71 IP01 + * 18 O1 I8 GAL168V pin 9 IP07 SCSI GAL + * 17 O2 nc + * 16 O3 RAS1 514260 pin 14 IP10-11 512KB DRAM each (IP11 is empty socket) + * 15 O4 LCAS 514260 pin 29 IP09-11 512KB DRAM each (IP11 is empty socket) + * 14 O5 UCAS 514260 pin 28 IP09-11 512KB DRAM each (IP11 is empty socket) + * 13 O6 RAS0 514260 pin 14 IP09 512KB DRAM + * 12 O7 I2 GAL16V8 pin 3 IP07 SCSI GAL (ANDed with !CS1) DMA_REQ + * I1 GAL16V8 pin 2 IP08 LOGC GAL (ANDed with !CS1) DMA_REQ + * G1 74257 pin 1 IP04-05 MUXes + * * Identified low level drivers in firmware * ---------------------------------------- * 800420..80046C : Some PORT A serialisation routine for the @@ -316,9 +363,11 @@ * Description Device Lvl IRQ * /Board Vector * ---------------------------------------------------------- - * On board Sources + * IRQ7 CTRL20 IP19 circuit + * IRQ6 SCSI/DEMUX INT + * IRQ5 CAM module INT + * IRQ3 Audio/Video INT * - * Off board Sources (other boards) * ---------------------------------------------------------- * * DMAC Channel Assignments @@ -328,6 +377,7 @@ * ---------------------------------------------------------- * * TODO: + * - Dump/understand the address decoder GAL:s IP06-IP08 (3 x 16V8) * - Setup a working address map * - Fix debug terminal * - TBC @@ -388,6 +438,7 @@ class dbox_state : public driver_device void dbox_state::machine_reset() { LOG("%s\n", FUNCNAME); + m_maincpu->tgate2_w(ASSERT_LINE); // Pulled high by resistor when not used as Rx from descrambler device } // TODO: Hookup the reset latch correctly @@ -421,17 +472,21 @@ static INPUT_PORTS_START( dbox ) INPUT_PORTS_END static MACHINE_CONFIG_START( dbox ) - MCFG_CPU_ADD("maincpu", M68340, XTAL_16MHz) + MCFG_CPU_ADD("maincpu", M68340, 0) // The 68340 has an internal VCO as clock source, hence need no CPU clock + MCFG_MC68340_ADD_CRYSTAL(XTAL_32_768kHz) // The dbox uses the VCO and has a crystal as VCO reference and to synthesize internal clocks from MCFG_CPU_PROGRAM_MAP(dbox_map) MCFG_MC68340_PA_OUTPUT_CB(WRITE8(dbox_state, write_pa)) + /* Timer 2 is used to communicate with the descrambler module TODO: Write the descrambler module */ + //MCFG_MC68340_TOUT2_OUTPUT_CB(DEVWRITELINE("dcs", descrambler_device, txd_receiver)) + //MCFG_MC68340_TGATE2_INPUT_CB(DEVREADLINE("dsc", descrambler_device, rxd_receiver)) + /* LED Matrix Display */ MCFG_SDA5708_ADD("display") MCFG_DEFAULT_LAYOUT(layout_sda5708) /* IP16 74256 8 bit latch */ MCFG_LATCH8_ADD("hct259.ip16") MCFG_LATCH8_WRITE_4(DEVWRITELINE("display", sda5708_device, reset_w)) - MACHINE_CONFIG_END DRIVER_INIT_MEMBER(dbox_state, dbox) -- cgit v1.2.3