Merge pull request #2576 from JoakimLarsson/m68340_1

m68340: Added implementations for VCO clock synthesizer and Timer mod…
This commit is contained in:
R. Belmont 2017-08-23 22:04:06 -04:00 committed by GitHub
commit 2d0121d7d2
7 changed files with 1251 additions and 240 deletions

View File

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

View File

@ -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 <class Object> static devcb_base &set_pa_out_callback (device_t &device, Object &&cb){ return downcast<m68340_cpu_device &>(device).m_pa_out_cb.set_callback (std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_pb_in_callback (device_t &device, Object &&cb){ return downcast<m68340_cpu_device &>(device).m_pb_in_cb.set_callback (std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_pb_out_callback (device_t &device, Object &&cb){ return downcast<m68340_cpu_device &>(device).m_pb_out_cb.set_callback (std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_tout1_out_callback (device_t &device, Object &&cb){ return downcast<m68340_cpu_device &>(device).m_tout1_out_cb.set_callback (std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_tin1_in_callback (device_t &device, Object &&cb) { return downcast<m68340_cpu_device &>(device).m_tin1_in_cb.set_callback (std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_tgate1_in_callback (device_t &device, Object &&cb){ return downcast<m68340_cpu_device &>(device).m_tgate1_in_cb.set_callback (std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_tout2_out_callback (device_t &device, Object &&cb){ return downcast<m68340_cpu_device &>(device).m_tout2_out_cb.set_callback (std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_tin2_in_callback (device_t &device, Object &&cb) { return downcast<m68340_cpu_device &>(device).m_tin2_in_cb.set_callback (std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_tgate2_in_callback (device_t &device, Object &&cb){ return downcast<m68340_cpu_device &>(device).m_tgate2_in_cb.set_callback (std::forward<Object>(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<m68340_cpu_device &>(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)

View File

@ -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;
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;
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<char const *, 8> {{"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 )
{
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<char const *, 8> {{"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;
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 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_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");
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();
// 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_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_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_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_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<char const *, 8> {{"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_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();
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_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_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)));
}
break;
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<char const *, 16>
@ -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,66 @@ 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<char const *, 16>
{{"", "PORTA", "", "DDRA", "", "PPRA1", "", "PPRA2", "", "PORTB","", "PORTB1", "", "DDRB", "", "PPARB"}}[offset - 0x10]);
LOGSETUP(" * Reg %02x <- %02x - %s\n", offset, data, std::array<char const *, 8>
{{"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;
}
}
WRITE32_MEMBER( m68340_cpu_device::m68340_internal_sim_cs_w )
READ32_MEMBER( m68340_cpu_device::m68340_internal_sim_cs_r )
{
LOGSETUP("%s\n", FUNCNAME);
offset += m68340SIM_AM_CS0>>2;
LOGR("%s\n", FUNCNAME);
offset += m68340_sim::REG_AM_CS0>>2;
assert(m68340SIM);
m68340_sim &sim = *m68340SIM;
@ -364,54 +356,87 @@ WRITE32_MEMBER( m68340_cpu_device::m68340_internal_sim_cs_w )
switch (offset<<2)
{
case m68340SIM_AM_CS0:
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 )
{
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;
int pc = space.device().safe_pc();
switch (offset<<2)
{
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();
}
}

View File

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

View File

@ -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
//**************************************************************************
READ32_MEMBER( m68340_cpu_device::m68340_internal_timer_r )
//#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__)
#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);
return 0x00000000;
int id = (offset * 2) < 0x40 ? 0 : 1; // Timer1 or Timer2
/*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<char const *, 9> {{"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<char const *, 9>
{{"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<char const *, 8>
{{ "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<char const *, 4>{{"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;
}
}
}
}

View File

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

View File

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