diff options
Diffstat (limited to 'src/devices/machine/mc68328.cpp')
-rw-r--r-- | src/devices/machine/mc68328.cpp | 6127 |
1 files changed, 3442 insertions, 2685 deletions
diff --git a/src/devices/machine/mc68328.cpp b/src/devices/machine/mc68328.cpp index 4b9e9a8b97e..2451f7359bd 100644 --- a/src/devices/machine/mc68328.cpp +++ b/src/devices/machine/mc68328.cpp @@ -9,359 +9,49 @@ **********************************************************************/ #include "emu.h" -#include "machine/mc68328.h" - - -#define SCR_BETO 0x80 -#define SCR_WPV 0x40 -#define SCR_PRV 0x20 -#define SCR_BETEN 0x10 -#define SCR_SO 0x08 -#define SCR_DMAP 0x04 -#define SCR_WDTH8 0x01 - -#define ICR_POL6 0x0100 -#define ICR_POL3 0x0200 -#define ICR_POL2 0x0400 -#define ICR_POL1 0x0800 -#define ICR_ET6 0x1000 -#define ICR_ET3 0x2000 -#define ICR_ET2 0x4000 -#define ICR_ET1 0x8000 - -#define INT_SPIM 0x000001 -#define INT_TIMER2 0x000002 -#define INT_UART 0x000004 -#define INT_WDT 0x000008 -#define INT_RTC 0x000010 -#define INT_RESERVED 0x000020 -#define INT_KB 0x000040 -#define INT_PWM 0x000080 -#define INT_INT0 0x000100 -#define INT_INT1 0x000200 -#define INT_INT2 0x000400 -#define INT_INT3 0x000800 -#define INT_INT4 0x001000 -#define INT_INT5 0x002000 -#define INT_INT6 0x004000 -#define INT_INT7 0x008000 -#define INT_KBDINTS 0x00ff00 -#define INT_IRQ1 0x010000 -#define INT_IRQ2 0x020000 -#define INT_IRQ3 0x040000 -#define INT_IRQ6 0x080000 -#define INT_PEN 0x100000 -#define INT_SPIS 0x200000 -#define INT_TIMER1 0x400000 -#define INT_IRQ7 0x800000 - -#define INT_M68K_LINE1 (INT_IRQ1) -#define INT_M68K_LINE2 (INT_IRQ2) -#define INT_M68K_LINE3 (INT_IRQ3) -#define INT_M68K_LINE4 (INT_INT0 | INT_INT1 | INT_INT2 | INT_INT3 | INT_INT4 | INT_INT5 | INT_INT6 | INT_INT7 | \ - INT_PWM | INT_KB | INT_RTC | INT_WDT | INT_UART | INT_TIMER2 | INT_SPIM) -#define INT_M68K_LINE5 (INT_PEN) -#define INT_M68K_LINE6 (INT_IRQ6 | INT_TIMER1 | INT_SPIS) -#define INT_M68K_LINE7 (INT_IRQ7) -#define INT_M68K_LINE67 (INT_M68K_LINE6 | INT_M68K_LINE7) -#define INT_M68K_LINE567 (INT_M68K_LINE5 | INT_M68K_LINE6 | INT_M68K_LINE7) -#define INT_M68K_LINE4567 (INT_M68K_LINE4 | INT_M68K_LINE5 | INT_M68K_LINE6 | INT_M68K_LINE7) -#define INT_M68K_LINE34567 (INT_M68K_LINE3 | INT_M68K_LINE4 | INT_M68K_LINE5 | INT_M68K_LINE6 | INT_M68K_LINE7) -#define INT_M68K_LINE234567 (INT_M68K_LINE2 | INT_M68K_LINE3 | INT_M68K_LINE4 | INT_M68K_LINE5 | INT_M68K_LINE6 | INT_M68K_LINE7) - -#define INT_IRQ1_SHIFT 0x000001 -#define INT_IRQ2_SHIFT 0x000002 -#define INT_IRQ3_SHIFT 0x000004 -#define INT_IRQ6_SHIFT 0x000008 -#define INT_PEN_SHIFT 0x000010 -#define INT_SPIS_SHIFT 0x000020 -#define INT_TIMER1_SHIFT 0x000040 -#define INT_IRQ7_SHIFT 0x000080 - -#define INT_ACTIVE 1 -#define INT_INACTIVE 0 - -#define GRPBASE_BASE_ADDR 0xfff0 -#define GRPBASE_VALID 0x0001 - -#define GRPMASK_BASE_MASK 0xfff0 - -#define CSAB_COMPARE 0xff000000 -#define CSAB_BSW 0x00010000 -#define CSAB_MASK 0x0000ff00 -#define CSAB_RO 0x00000008 -#define CSAB_WAIT 0x00000007 - -#define CSCD_COMPARE 0xfff00000 -#define CSCD_BSW 0x00010000 -#define CSCD_MASK 0x0000fff0 -#define CSCD_RO 0x00000008 -#define CSCD_WAIT 0x00000007 - -#define PLLCR_PIXCLK_SEL 0x3800 -#define PLLCR_PIXCLK_SEL_DIV2 0x0000 -#define PLLCR_PIXCLK_SEL_DIV4 0x0800 -#define PLLCR_PIXCLK_SEL_DIV8 0x1000 -#define PLLCR_PIXCLK_SEL_DIV16 0x1800 -#define PLLCR_PIXCLK_SEL_DIV1_0 0x2000 -#define PLLCR_PIXCLK_SEL_DIV1_1 0x2800 -#define PLLCR_PIXCLK_SEL_DIV1_2 0x3000 -#define PLLCR_PIXCLK_SEL_DIV1_3 0x3800 -#define PLLCR_SYSCLK_SEL 0x0700 -#define PLLCR_SYSCLK_SEL_DIV2 0x0000 -#define PLLCR_SYSCLK_SEL_DIV4 0x0100 -#define PLLCR_SYSCLK_SEL_DIV8 0x0200 -#define PLLCR_SYSCLK_SEL_DIV16 0x0300 -#define PLLCR_SYSCLK_SEL_DIV1_0 0x0400 -#define PLLCR_SYSCLK_SEL_DIV1_1 0x0500 -#define PLLCR_SYSCLK_SEL_DIV1_2 0x0600 -#define PLLCR_SYSCLK_SEL_DIV1_3 0x0700 -#define PLLCR_CLKEN 0x0010 -#define PLLCR_DISPLL 0x0008 - -#define PLLFSR_CLK32 0x8000 -#define PLLFSR_PROT 0x4000 -#define PLLFSR_QCNT 0x0f00 -#define PLLFSR_PCNT 0x00ff - -#define PCTLR_PC_EN 0x80 -#define PCTLR_STOP 0x40 -#define PCTLR_WIDTH 0x1f - -#define CXP_CC 0xc000 -#define CXP_CC_XLU 0x0000 -#define CXP_CC_BLACK 0x4000 -#define CXP_CC_INVERSE 0x8000 -#define CXP_CC_INVALID 0xc000 -#define CXP_MASK 0x03ff - -#define CYP_MASK 0x01ff - -#define CWCH_CW 0x1f00 -#define CWCH_CH 0x001f - -#define BLKC_BKEN 0x80 -#define BLKC_BD 0x7f - -#define LPICF_PBSIZ 0x06 -#define LPICF_PBSIZ_1 0x00 -#define LPICF_PBSIZ_2 0x02 -#define LPICF_PBSIZ_4 0x04 -#define LPICF_PBSIZ_INVALID 0x06 - -#define LPOLCF_LCKPOL 0x08 -#define LPOLCF_FLMPOL 0x04 -#define LPOLCF_LPPOL 0x02 -#define LPOLCF_PIXPOL 0x01 - -#define LACDRC_MASK 0x0f - -#define LPXCD_MASK 0x3f - -#define LCKCON_LCDC_EN 0x80 -#define LCKCON_LCDON 0x80 -#define LCKCON_DMA16 0x40 -#define LCKCON_WS 0x30 -#define LCKCON_WS_1 0x00 -#define LCKCON_WS_2 0x10 -#define LCKCON_WS_3 0x20 -#define LCKCON_WS_4 0x30 -#define LCKCON_DWIDTH 0x02 -#define LCKCON_PCDS 0x01 - -#define LBAR_MASK 0x7f - -#define LPOSR_BOS 0x08 -#define LPOSR_POS 0x07 - -#define LFRCM_XMOD 0xf0 -#define LFRCM_YMOD 0x0f - -#define LGPMR_PAL1 0x7000 -#define LGPMR_PAL0 0x0700 -#define LGPMR_PAL3 0x0070 -#define LGPMR_PAL2 0x0007 - -#define RTCHMSR_HOURS 0x1f000000 -#define RTCHMSR_MINUTES 0x003f0000 -#define RTCHMSR_SECONDS 0x0000003f - -#define RTCCTL_38_4 0x0020 -#define RTCCTL_ENABLE 0x0080 - -#define RTCINT_STOPWATCH 0x0001 -#define RTCINT_MINUTE 0x0002 -#define RTCINT_ALARM 0x0004 -#define RTCINT_DAY 0x0008 -#define RTCINT_SECOND 0x0010 - -#define RTCSTPWTCH_MASK 0x003f - -#define TCTL_TEN 0x0001 -#define TCTL_TEN_ENABLE 0x0001 -#define TCTL_CLKSOURCE 0x000e -#define TCTL_CLKSOURCE_STOP 0x0000 -#define TCTL_CLKSOURCE_SYSCLK 0x0002 -#define TCTL_CLKSOURCE_SYSCLK16 0x0004 -#define TCTL_CLKSOURCE_TIN 0x0006 -#define TCTL_CLKSOURCE_32KHZ4 0x0008 -#define TCTL_CLKSOURCE_32KHZ5 0x000a -#define TCTL_CLKSOURCE_32KHZ6 0x000c -#define TCTL_CLKSOURCE_32KHZ7 0x000e -#define TCTL_IRQEN 0x0010 -#define TCTL_IRQEN_ENABLE 0x0010 -#define TCTL_OM 0x0020 -#define TCTL_OM_ACTIVELOW 0x0000 -#define TCTL_OM_TOGGLE 0x0020 -#define TCTL_CAPTURE 0x00c0 -#define TCTL_CAPTURE_NOINT 0x0000 -#define TCTL_CAPTURE_RISING 0x0040 -#define TCTL_CAPTURE_FALLING 0x0080 -#define TCTL_CAPTURE_BOTH 0x00c0 -#define TCTL_FRR 0x0100 -#define TCTL_FRR_RESTART 0x0000 -#define TCTL_FRR_FREERUN 0x0100 - -#define TSTAT_COMP 0x0001 -#define TSTAT_CAPT 0x0002 - -#define WCTLR_WDRST 0x0008 -#define WCTLR_LOCK 0x0004 -#define WCTLR_FI 0x0002 -#define WCTLR_WDEN 0x0001 - -#define USTCNT_UART_EN 0x8000 -#define USTCNT_RX_EN 0x4000 -#define USTCNT_TX_EN 0x2000 -#define USTCNT_RX_CLK_CONT 0x1000 -#define USTCNT_PARITY_EN 0x0800 -#define USTCNT_ODD_EVEN 0x0400 -#define USTCNT_STOP_BITS 0x0200 -#define USTCNT_8_7 0x0100 -#define USTCNT_GPIO_DELTA_EN 0x0080 -#define USTCNT_CTS_DELTA_EN 0x0040 -#define USTCNT_RX_FULL_EN 0x0020 -#define USTCNT_RX_HALF_EN 0x0010 -#define USTCNT_RX_RDY_EN 0x0008 -#define USTCNT_TX_EMPTY_EN 0x0004 -#define USTCNT_TX_HALF_EN 0x0002 -#define USTCNT_TX_AVAIL_EN 0x0001 - -#define UBAUD_GPIO_DELTA 0x8000 -#define UBAUD_GPIO 0x4000 -#define UBAUD_GPIO_DIR 0x2000 -#define UBAUD_GPIO_SRC 0x1000 -#define UBAUD_BAUD_SRC 0x0800 -#define UBAUD_DIVIDE 0x0700 -#define UBAUD_DIVIDE_1 0x0000 -#define UBAUD_DIVIDE_2 0x0100 -#define UBAUD_DIVIDE_4 0x0200 -#define UBAUD_DIVIDE_8 0x0300 -#define UBAUD_DIVIDE_16 0x0400 -#define UBAUD_DIVIDE_32 0x0500 -#define UBAUD_DIVIDE_64 0x0600 -#define UBAUD_DIVIDE_128 0x0700 -#define UBAUD_PRESCALER 0x00ff - -#define URX_FIFO_FULL 0x8000 -#define URX_FIFO_HALF 0x4000 -#define URX_DATA_READY 0x2000 -#define URX_OVRUN 0x0800 -#define URX_FRAME_ERROR 0x0400 -#define URX_BREAK 0x0200 -#define URX_PARITY_ERROR 0x0100 - -#define UTX_FIFO_EMPTY 0x8000 -#define UTX_FIFO_HALF 0x4000 -#define UTX_TX_AVAIL 0x2000 -#define UTX_SEND_BREAK 0x1000 -#define UTX_IGNORE_CTS 0x0800 -#define UTX_CTS_STATUS 0x0200 -#define UTX_CTS_DELTA 0x0100 - -#define UMISC_CLK_SRC 0x4000 -#define UMISC_FORCE_PERR 0x2000 -#define UMISC_LOOP 0x1000 -#define UMISC_RTS_CONT 0x0080 -#define UMISC_RTS 0x0040 -#define UMISC_IRDA_ENABLE 0x0020 -#define UMISC_IRDA_LOOP 0x0010 - -#define SPIS_SPIS_IRQ 0x8000 -#define SPIS_IRQEN 0x4000 -#define SPIS_ENPOL 0x2000 -#define SPIS_DATA_RDY 0x1000 -#define SPIS_OVRWR 0x0800 -#define SPIS_PHA 0x0400 -#define SPIS_POL 0x0200 -#define SPIS_SPISEN 0x0100 - -#define SPIM_CLOCK_COUNT 0x000f -#define SPIM_POL 0x0010 -#define SPIM_POL_HIGH 0x0000 -#define SPIM_POL_LOW 0x0010 -#define SPIM_PHA 0x0020 -#define SPIM_PHA_NORMAL 0x0000 -#define SPIM_PHA_OPPOSITE 0x0020 -#define SPIM_IRQEN 0x0040 -#define SPIM_SPIMIRQ 0x0080 -#define SPIM_XCH 0x0100 -#define SPIM_XCH_IDLE 0x0000 -#define SPIM_XCH_INIT 0x0100 -#define SPIM_SPMEN 0x0200 -#define SPIM_SPMEN_DISABLE 0x0000 -#define SPIM_SPMEN_ENABLE 0x0200 -#define SPIM_RATE 0xe000 -#define SPIM_RATE_4 0x0000 -#define SPIM_RATE_8 0x2000 -#define SPIM_RATE_16 0x4000 -#define SPIM_RATE_32 0x6000 -#define SPIM_RATE_64 0x8000 -#define SPIM_RATE_128 0xa000 -#define SPIM_RATE_256 0xc000 -#define SPIM_RATE_512 0xe000 - -#define PWMC_PWMIRQ 0x8000 -#define PWMC_IRQEN 0x4000 -#define PWMC_LOAD 0x0100 -#define PWMC_PIN 0x0080 -#define PWMC_POL 0x0040 -#define PWMC_PWMEN 0x0010 -#define PWMC_CLKSEL 0x0007 - - -#define VERBOSE_LEVEL (0) - -static inline void ATTR_PRINTF(3,4) verboselog(device_t &device, int n_level, const char *s_fmt, ...) -{ - if (VERBOSE_LEVEL >= n_level) - { - va_list v; - char buf[32768]; - va_start(v, s_fmt); - vsprintf(buf, s_fmt, v); - va_end(v); - device.logerror("%s: %s", device.machine().describe_context(), buf); - } -} - -DEFINE_DEVICE_TYPE(MC68328, mc68328_device, "mc68328", "MC68328 DragonBall Integrated Processor") - - -void mc68328_device::internal_map(address_map &map) -{ - map(0xfff000, 0xffffff).rw(FUNC(mc68328_device::internal_read), FUNC(mc68328_device::internal_write)); -} - -void mc68328_device::cpu_space_map(address_map &map) -{ - map(0xfffff0, 0xffffff).r(FUNC(mc68328_device::irq_callback)).umask16(0x00ff); -} - - -mc68328_device::mc68328_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : m68000_device(mconfig, tag, owner, clock, MC68328, 16, 24, address_map_constructor(FUNC(mc68328_device::internal_map), this)) - , m_rtc(nullptr), m_pwm(nullptr) +#include "mc68328.h" + +#define LOG_SCR (1U << 1) +#define LOG_CS_GRP (1U << 2) +#define LOG_CS_SEL (1U << 3) +#define LOG_PLL (1U << 4) +#define LOG_INTS (1U << 5) +#define LOG_GPIO_A (1U << 6) +#define LOG_GPIO_B (1U << 7) +#define LOG_GPIO_C (1U << 8) +#define LOG_GPIO_D (1U << 9) +#define LOG_GPIO_E (1U << 10) +#define LOG_GPIO_F (1U << 11) +#define LOG_GPIO_G (1U << 12) +#define LOG_GPIO_J (1U << 13) +#define LOG_GPIO_K (1U << 14) +#define LOG_GPIO_M (1U << 15) +#define LOG_PWM (1U << 16) +#define LOG_TIMERS (1U << 17) +#define LOG_TSTAT (1U << 18) +#define LOG_WATCHDOG (1U << 19) +#define LOG_SPIS (1U << 20) +#define LOG_SPIM (1U << 21) +#define LOG_UART (1U << 22) +#define LOG_LCD (1U << 23) +#define LOG_RTC (1U << 24) +#define LOG_ALL (LOG_SCR | LOG_PLL | LOG_INTS | LOG_GPIO_A | LOG_GPIO_B | LOG_GPIO_C | LOG_GPIO_D | LOG_GPIO_E \ + | LOG_GPIO_F | LOG_GPIO_G | LOG_GPIO_J | LOG_GPIO_K | LOG_GPIO_M | LOG_PWM | LOG_TIMERS | LOG_TSTAT | LOG_WATCHDOG | LOG_SPIS \ + | LOG_SPIM | LOG_UART | LOG_LCD | LOG_RTC) +#define VERBOSE (0) +#include "logmacro.h" + + +DEFINE_DEVICE_TYPE(MC68328, mc68328_device, "mc68328", "MC68328 DragonBall Processor") +DEFINE_DEVICE_TYPE(MC68EZ328, mc68ez328_device, "mc68ez328", "MC68EZ328 DragonBall-EZ Processor") + +const u32 mc68328_base_device::VCO_DIVISORS[8] = { 2, 4, 8, 16, 1, 1, 1, 1 }; + +mc68328_base_device::mc68328_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) + : m68000_device(mconfig, type, tag, owner, clock) + , m_pwm(nullptr) + , m_rtc(nullptr) + , m_spim(nullptr) , m_out_port_a_cb(*this) , m_out_port_b_cb(*this) , m_out_port_c_cb(*this) @@ -369,25 +59,262 @@ mc68328_device::mc68328_device(const machine_config &mconfig, const char *tag, d , m_out_port_e_cb(*this) , m_out_port_f_cb(*this) , m_out_port_g_cb(*this) + , m_in_port_a_cb(*this, 0) + , m_in_port_b_cb(*this, 0) + , m_in_port_c_cb(*this, 0) + , m_in_port_d_cb(*this, 0) + , m_in_port_e_cb(*this, 0) + , m_in_port_f_cb(*this, 0) + , m_in_port_g_cb(*this, 0) + , m_out_pwm_cb(*this) + , m_out_spim_cb(*this) + , m_in_spim_cb(*this, 0) + , m_out_flm_cb(*this) + , m_out_llp_cb(*this) + , m_out_lsclk_cb(*this) + , m_out_ld_cb(*this) + , m_lcd_info_changed_cb(*this) +{ +} + +mc68328_device::mc68328_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : mc68328_base_device(mconfig, MC68328, tag, owner, clock) , m_out_port_j_cb(*this) , m_out_port_k_cb(*this) , m_out_port_m_cb(*this) - , m_in_port_a_cb(*this) - , m_in_port_b_cb(*this) - , m_in_port_c_cb(*this) - , m_in_port_d_cb(*this) - , m_in_port_e_cb(*this) - , m_in_port_f_cb(*this) - , m_in_port_g_cb(*this) - , m_in_port_j_cb(*this) - , m_in_port_k_cb(*this) - , m_in_port_m_cb(*this) - , m_out_pwm_cb(*this) - , m_out_spim_cb(*this) - , m_in_spim_cb(*this) - , m_spim_xch_trigger_cb(*this) + , m_in_port_j_cb(*this, 0) + , m_in_port_k_cb(*this, 0) + , m_in_port_m_cb(*this, 0) { m_cpu_space_config.m_internal_map = address_map_constructor(FUNC(mc68328_device::cpu_space_map), this); + auto imap = address_map_constructor(FUNC(mc68328_device::internal_map), this); + m_program_config.m_internal_map = imap; + m_opcodes_config.m_internal_map = imap; + m_uprogram_config.m_internal_map = imap; + m_uopcodes_config.m_internal_map = imap; +} + +mc68ez328_device::mc68ez328_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : mc68328_base_device(mconfig, MC68EZ328, tag, owner, clock) +{ + m_cpu_space_config.m_internal_map = address_map_constructor(FUNC(mc68ez328_device::cpu_space_map), this); + m_cpu_space_config.m_addr_width = 32; + m_program_config.m_addr_width = 32; + m_opcodes_config.m_addr_width = 32; + m_uprogram_config.m_addr_width = 32; + m_uopcodes_config.m_addr_width = 32; + auto imap = address_map_constructor(FUNC(mc68ez328_device::internal_map), this); + m_program_config.m_internal_map = imap; + m_opcodes_config.m_internal_map = imap; + m_uprogram_config.m_internal_map = imap; + m_uopcodes_config.m_internal_map = imap; +} + +void mc68328_base_device::base_internal_map(u32 addr_bits, address_map &map) +{ + map(addr_bits | 0x000, addr_bits | 0x000).rw(FUNC(mc68328_base_device::scr_r), FUNC(mc68328_base_device::scr_w)); + map(addr_bits | 0x100, addr_bits | 0x101).rw(FUNC(mc68328_base_device::grpbasea_r), FUNC(mc68328_base_device::grpbasea_w)); + map(addr_bits | 0x102, addr_bits | 0x103).rw(FUNC(mc68328_base_device::grpbaseb_r), FUNC(mc68328_base_device::grpbaseb_w)); + map(addr_bits | 0x104, addr_bits | 0x105).rw(FUNC(mc68328_base_device::grpbasec_r), FUNC(mc68328_base_device::grpbasec_w)); + map(addr_bits | 0x106, addr_bits | 0x107).rw(FUNC(mc68328_base_device::grpbased_r), FUNC(mc68328_base_device::grpbased_w)); + + map(addr_bits | 0x200, addr_bits | 0x201).rw(FUNC(mc68328_base_device::pllcr_r), FUNC(mc68328_base_device::pllcr_w)); + map(addr_bits | 0x202, addr_bits | 0x203).rw(FUNC(mc68328_base_device::pllfsr_r), FUNC(mc68328_base_device::pllfsr_w)); + map(addr_bits | 0x207, addr_bits | 0x207).rw(FUNC(mc68328_base_device::pctlr_r), FUNC(mc68328_base_device::pctlr_w)); + + map(addr_bits | 0x300, addr_bits | 0x300).rw(FUNC(mc68328_base_device::ivr_r), FUNC(mc68328_base_device::ivr_w)); + map(addr_bits | 0x302, addr_bits | 0x303).rw(FUNC(mc68328_base_device::icr_r), FUNC(mc68328_base_device::icr_w)); + map(addr_bits | 0x304, addr_bits | 0x305).rw(FUNC(mc68328_base_device::imr_msw_r), FUNC(mc68328_base_device::imr_msw_w)); + map(addr_bits | 0x306, addr_bits | 0x307).rw(FUNC(mc68328_base_device::imr_lsw_r), FUNC(mc68328_base_device::imr_lsw_w)); + map(addr_bits | 0x30c, addr_bits | 0x30d).rw(FUNC(mc68328_base_device::isr_msw_r), FUNC(mc68328_base_device::isr_msw_w)); + map(addr_bits | 0x30e, addr_bits | 0x30f).rw(FUNC(mc68328_base_device::isr_lsw_r), FUNC(mc68328_base_device::isr_lsw_w)); + map(addr_bits | 0x310, addr_bits | 0x311).rw(FUNC(mc68328_base_device::ipr_msw_r), FUNC(mc68328_base_device::ipr_msw_w)); + map(addr_bits | 0x312, addr_bits | 0x313).rw(FUNC(mc68328_base_device::ipr_lsw_r), FUNC(mc68328_base_device::ipr_lsw_w)); + + map(addr_bits | 0x400, addr_bits | 0x400).rw(FUNC(mc68328_base_device::padir_r), FUNC(mc68328_base_device::padir_w)); + map(addr_bits | 0x401, addr_bits | 0x401).rw(FUNC(mc68328_base_device::padata_r), FUNC(mc68328_base_device::padata_w)); + map(addr_bits | 0x408, addr_bits | 0x408).rw(FUNC(mc68328_base_device::pbdir_r), FUNC(mc68328_base_device::pbdir_w)); + map(addr_bits | 0x409, addr_bits | 0x409).rw(FUNC(mc68328_base_device::pbdata_r), FUNC(mc68328_base_device::pbdata_w)); + map(addr_bits | 0x40b, addr_bits | 0x40b).rw(FUNC(mc68328_base_device::pbsel_r), FUNC(mc68328_base_device::pbsel_w)); + map(addr_bits | 0x410, addr_bits | 0x410).rw(FUNC(mc68328_base_device::pcdir_r), FUNC(mc68328_base_device::pcdir_w)); + map(addr_bits | 0x411, addr_bits | 0x411).rw(FUNC(mc68328_base_device::pcdata_r), FUNC(mc68328_base_device::pcdata_w)); + map(addr_bits | 0x413, addr_bits | 0x413).rw(FUNC(mc68328_base_device::pcsel_r), FUNC(mc68328_base_device::pcsel_w)); + map(addr_bits | 0x418, addr_bits | 0x418).rw(FUNC(mc68328_base_device::pddir_r), FUNC(mc68328_base_device::pddir_w)); + map(addr_bits | 0x419, addr_bits | 0x419).rw(FUNC(mc68328_base_device::pddata_r), FUNC(mc68328_base_device::pddata_w)); + map(addr_bits | 0x41a, addr_bits | 0x41a).rw(FUNC(mc68328_base_device::pdpuen_r), FUNC(mc68328_base_device::pdpuen_w)); + map(addr_bits | 0x41c, addr_bits | 0x41c).rw(FUNC(mc68328_base_device::pdpol_r), FUNC(mc68328_base_device::pdpol_w)); + map(addr_bits | 0x41d, addr_bits | 0x41d).rw(FUNC(mc68328_base_device::pdirqen_r), FUNC(mc68328_base_device::pdirqen_w)); + map(addr_bits | 0x41f, addr_bits | 0x41f).rw(FUNC(mc68328_base_device::pdirqedge_r), FUNC(mc68328_base_device::pdirqedge_w)); + map(addr_bits | 0x420, addr_bits | 0x420).rw(FUNC(mc68328_base_device::pedir_r), FUNC(mc68328_base_device::pedir_w)); + map(addr_bits | 0x421, addr_bits | 0x421).rw(FUNC(mc68328_base_device::pedata_r), FUNC(mc68328_base_device::pedata_w)); + map(addr_bits | 0x422, addr_bits | 0x422).rw(FUNC(mc68328_base_device::pepuen_r), FUNC(mc68328_base_device::pepuen_w)); + map(addr_bits | 0x423, addr_bits | 0x423).rw(FUNC(mc68328_base_device::pesel_r), FUNC(mc68328_base_device::pesel_w)); + map(addr_bits | 0x428, addr_bits | 0x428).rw(FUNC(mc68328_base_device::pfdir_r), FUNC(mc68328_base_device::pfdir_w)); + map(addr_bits | 0x429, addr_bits | 0x429).rw(FUNC(mc68328_base_device::pfdata_r), FUNC(mc68328_base_device::pfdata_w)); + map(addr_bits | 0x42a, addr_bits | 0x42a).rw(FUNC(mc68328_base_device::pfpuen_r), FUNC(mc68328_base_device::pfpuen_w)); + map(addr_bits | 0x42b, addr_bits | 0x42b).rw(FUNC(mc68328_base_device::pfsel_r), FUNC(mc68328_base_device::pfsel_w)); + map(addr_bits | 0x430, addr_bits | 0x430).rw(FUNC(mc68328_base_device::pgdir_r), FUNC(mc68328_base_device::pgdir_w)); + map(addr_bits | 0x431, addr_bits | 0x431).rw(FUNC(mc68328_base_device::pgdata_r), FUNC(mc68328_base_device::pgdata_w)); + map(addr_bits | 0x432, addr_bits | 0x432).rw(FUNC(mc68328_base_device::pgpuen_r), FUNC(mc68328_base_device::pgpuen_w)); + map(addr_bits | 0x433, addr_bits | 0x433).rw(FUNC(mc68328_base_device::pgsel_r), FUNC(mc68328_base_device::pgsel_w)); + + map(addr_bits | 0x500, addr_bits | 0x501).rw(FUNC(mc68328_base_device::pwmc_r), FUNC(mc68328_base_device::pwmc_w)); + + map(addr_bits | 0x600, addr_bits | 0x601).rw(FUNC(mc68328_base_device::tctl_r<0>), FUNC(mc68328_base_device::tctl_w<0>)); + map(addr_bits | 0x602, addr_bits | 0x603).rw(FUNC(mc68328_base_device::tprer_r<0>), FUNC(mc68328_base_device::tprer_w<0>)); + map(addr_bits | 0x604, addr_bits | 0x605).rw(FUNC(mc68328_base_device::tcmp_r<0>), FUNC(mc68328_base_device::tcmp_w<0>)); + map(addr_bits | 0x606, addr_bits | 0x607).rw(FUNC(mc68328_base_device::tcr_r<0>), FUNC(mc68328_base_device::tcr_w<0>)); + map(addr_bits | 0x608, addr_bits | 0x609).rw(FUNC(mc68328_base_device::tcn_r<0>), FUNC(mc68328_base_device::tcn_w<0>)); + map(addr_bits | 0x60a, addr_bits | 0x60b).rw(FUNC(mc68328_base_device::tstat_r<0>), FUNC(mc68328_base_device::tstat_w<0>)); + + map(addr_bits | 0x800, addr_bits | 0x801).rw(FUNC(mc68328_base_device::spimdata_r), FUNC(mc68328_base_device::spimdata_w)); + map(addr_bits | 0x802, addr_bits | 0x803).rw(FUNC(mc68328_base_device::spimcont_r), FUNC(mc68328_base_device::spimcont_w)); + + map(addr_bits | 0x900, addr_bits | 0x901).rw(FUNC(mc68328_base_device::ustcnt_r), FUNC(mc68328_base_device::ustcnt_w)); + map(addr_bits | 0x902, addr_bits | 0x903).rw(FUNC(mc68328_base_device::ubaud_r), FUNC(mc68328_base_device::ubaud_w)); + map(addr_bits | 0x904, addr_bits | 0x905).rw(FUNC(mc68328_base_device::urx_r), FUNC(mc68328_base_device::urx_w)); + map(addr_bits | 0x906, addr_bits | 0x907).rw(FUNC(mc68328_base_device::utx_r), FUNC(mc68328_base_device::utx_w)); + map(addr_bits | 0x908, addr_bits | 0x909).rw(FUNC(mc68328_base_device::umisc_r), FUNC(mc68328_base_device::umisc_w)); + + map(addr_bits | 0xa00, addr_bits | 0xa01).rw(FUNC(mc68328_base_device::lssa_msw_r), FUNC(mc68328_base_device::lssa_msw_w)); + map(addr_bits | 0xa02, addr_bits | 0xa03).rw(FUNC(mc68328_base_device::lssa_lsw_r), FUNC(mc68328_base_device::lssa_lsw_w)); + map(addr_bits | 0xa05, addr_bits | 0xa05).rw(FUNC(mc68328_base_device::lvpw_r), FUNC(mc68328_base_device::lvpw_w)); + map(addr_bits | 0xa08, addr_bits | 0xa09).rw(FUNC(mc68328_base_device::lxmax_r), FUNC(mc68328_base_device::lxmax_w)); + map(addr_bits | 0xa0a, addr_bits | 0xa0b).rw(FUNC(mc68328_base_device::lymax_r), FUNC(mc68328_base_device::lymax_w)); + map(addr_bits | 0xa18, addr_bits | 0xa19).rw(FUNC(mc68328_base_device::lcxp_r), FUNC(mc68328_base_device::lcxp_w)); + map(addr_bits | 0xa1a, addr_bits | 0xa1b).rw(FUNC(mc68328_base_device::lcyp_r), FUNC(mc68328_base_device::lcyp_w)); + map(addr_bits | 0xa1c, addr_bits | 0xa1d).rw(FUNC(mc68328_base_device::lcwch_r), FUNC(mc68328_base_device::lcwch_w)); + map(addr_bits | 0xa1f, addr_bits | 0xa1f).rw(FUNC(mc68328_base_device::lblkc_r), FUNC(mc68328_base_device::lblkc_w)); + map(addr_bits | 0xa20, addr_bits | 0xa20).rw(FUNC(mc68328_base_device::lpicf_r), FUNC(mc68328_base_device::lpicf_w)); + map(addr_bits | 0xa21, addr_bits | 0xa21).rw(FUNC(mc68328_base_device::lpolcf_r), FUNC(mc68328_base_device::lpolcf_w)); + map(addr_bits | 0xa23, addr_bits | 0xa23).rw(FUNC(mc68328_base_device::lacdrc_r), FUNC(mc68328_base_device::lacdrc_w)); + map(addr_bits | 0xa25, addr_bits | 0xa25).rw(FUNC(mc68328_base_device::lpxcd_r), FUNC(mc68328_base_device::lpxcd_w)); + map(addr_bits | 0xa27, addr_bits | 0xa27).rw(FUNC(mc68328_base_device::lckcon_r), FUNC(mc68328_base_device::lckcon_w)); + map(addr_bits | 0xa2d, addr_bits | 0xa2d).rw(FUNC(mc68328_base_device::lposr_r), FUNC(mc68328_base_device::lposr_w)); + map(addr_bits | 0xa31, addr_bits | 0xa31).rw(FUNC(mc68328_base_device::lfrcm_r), FUNC(mc68328_base_device::lfrcm_w)); + + map(addr_bits | 0xb00, addr_bits | 0xb01).rw(FUNC(mc68328_base_device::hmsr_msw_r), FUNC(mc68328_base_device::hmsr_msw_w)); + map(addr_bits | 0xb02, addr_bits | 0xb03).rw(FUNC(mc68328_base_device::hmsr_lsw_r), FUNC(mc68328_base_device::hmsr_lsw_w)); + map(addr_bits | 0xb04, addr_bits | 0xb05).rw(FUNC(mc68328_base_device::alarm_msw_r), FUNC(mc68328_base_device::alarm_msw_w)); + map(addr_bits | 0xb06, addr_bits | 0xb07).rw(FUNC(mc68328_base_device::alarm_lsw_r), FUNC(mc68328_base_device::alarm_lsw_w)); + map(addr_bits | 0xb0e, addr_bits | 0xb0f).rw(FUNC(mc68328_base_device::rtcisr_r), FUNC(mc68328_base_device::rtcisr_w)); + map(addr_bits | 0xb10, addr_bits | 0xb11).rw(FUNC(mc68328_base_device::rtcienr_r), FUNC(mc68328_base_device::rtcienr_w)); + map(addr_bits | 0xb12, addr_bits | 0xb13).rw(FUNC(mc68328_base_device::stpwtch_r), FUNC(mc68328_base_device::stpwtch_w)); +} + +void mc68328_device::internal_map(address_map &map) +{ + base_internal_map(0xfff000, map); + map(0xfff108, 0xfff109).rw(FUNC(mc68328_device::grpmaska_r), FUNC(mc68328_device::grpmaska_w)); + map(0xfff10a, 0xfff10b).rw(FUNC(mc68328_device::grpmaskb_r), FUNC(mc68328_device::grpmaskb_w)); + map(0xfff10c, 0xfff10d).rw(FUNC(mc68328_device::grpmaskc_r), FUNC(mc68328_device::grpmaskc_w)); + map(0xfff10e, 0xfff10f).rw(FUNC(mc68328_device::grpmaskd_r), FUNC(mc68328_device::grpmaskd_w)); + map(0xfff110, 0xfff111).rw(FUNC(mc68328_device::csa_msw_r<0>), FUNC(mc68328_device::csa_msw_w<0>)); + map(0xfff112, 0xfff113).rw(FUNC(mc68328_device::csa_lsw_r<0>), FUNC(mc68328_device::csa_lsw_w<0>)); + map(0xfff114, 0xfff115).rw(FUNC(mc68328_device::csa_msw_r<1>), FUNC(mc68328_device::csa_msw_w<1>)); + map(0xfff116, 0xfff117).rw(FUNC(mc68328_device::csa_lsw_r<1>), FUNC(mc68328_device::csa_lsw_w<1>)); + map(0xfff118, 0xfff119).rw(FUNC(mc68328_device::csa_msw_r<2>), FUNC(mc68328_device::csa_msw_w<2>)); + map(0xfff11a, 0xfff11b).rw(FUNC(mc68328_device::csa_lsw_r<2>), FUNC(mc68328_device::csa_lsw_w<2>)); + map(0xfff11c, 0xfff11d).rw(FUNC(mc68328_device::csa_msw_r<3>), FUNC(mc68328_device::csa_msw_w<3>)); + map(0xfff11e, 0xfff11f).rw(FUNC(mc68328_device::csa_lsw_r<3>), FUNC(mc68328_device::csa_lsw_w<3>)); + map(0xfff120, 0xfff121).rw(FUNC(mc68328_device::csb_msw_r<0>), FUNC(mc68328_device::csb_msw_w<0>)); + map(0xfff122, 0xfff123).rw(FUNC(mc68328_device::csb_lsw_r<0>), FUNC(mc68328_device::csb_lsw_w<0>)); + map(0xfff124, 0xfff125).rw(FUNC(mc68328_device::csb_msw_r<1>), FUNC(mc68328_device::csb_msw_w<1>)); + map(0xfff126, 0xfff127).rw(FUNC(mc68328_device::csb_lsw_r<1>), FUNC(mc68328_device::csb_lsw_w<1>)); + map(0xfff128, 0xfff129).rw(FUNC(mc68328_device::csb_msw_r<2>), FUNC(mc68328_device::csb_msw_w<2>)); + map(0xfff12a, 0xfff12b).rw(FUNC(mc68328_device::csb_lsw_r<2>), FUNC(mc68328_device::csb_lsw_w<2>)); + map(0xfff12c, 0xfff12d).rw(FUNC(mc68328_device::csb_msw_r<3>), FUNC(mc68328_device::csb_msw_w<3>)); + map(0xfff12e, 0xfff12f).rw(FUNC(mc68328_device::csb_lsw_r<3>), FUNC(mc68328_device::csb_lsw_w<3>)); + map(0xfff130, 0xfff131).rw(FUNC(mc68328_device::csc_msw_r<0>), FUNC(mc68328_device::csc_msw_w<0>)); + map(0xfff132, 0xfff133).rw(FUNC(mc68328_device::csc_lsw_r<0>), FUNC(mc68328_device::csc_lsw_w<0>)); + map(0xfff134, 0xfff135).rw(FUNC(mc68328_device::csc_msw_r<1>), FUNC(mc68328_device::csc_msw_w<1>)); + map(0xfff136, 0xfff137).rw(FUNC(mc68328_device::csc_lsw_r<1>), FUNC(mc68328_device::csc_lsw_w<1>)); + map(0xfff138, 0xfff139).rw(FUNC(mc68328_device::csc_msw_r<2>), FUNC(mc68328_device::csc_msw_w<2>)); + map(0xfff13a, 0xfff13b).rw(FUNC(mc68328_device::csc_lsw_r<2>), FUNC(mc68328_device::csc_lsw_w<2>)); + map(0xfff13c, 0xfff13d).rw(FUNC(mc68328_device::csc_msw_r<3>), FUNC(mc68328_device::csc_msw_w<3>)); + map(0xfff13e, 0xfff13f).rw(FUNC(mc68328_device::csc_lsw_r<3>), FUNC(mc68328_device::csc_lsw_w<3>)); + map(0xfff140, 0xfff141).rw(FUNC(mc68328_device::csd_msw_r<0>), FUNC(mc68328_device::csd_msw_w<0>)); + map(0xfff142, 0xfff143).rw(FUNC(mc68328_device::csd_lsw_r<0>), FUNC(mc68328_device::csd_lsw_w<0>)); + map(0xfff144, 0xfff145).rw(FUNC(mc68328_device::csd_msw_r<1>), FUNC(mc68328_device::csd_msw_w<1>)); + map(0xfff146, 0xfff147).rw(FUNC(mc68328_device::csd_lsw_r<1>), FUNC(mc68328_device::csd_lsw_w<1>)); + map(0xfff148, 0xfff149).rw(FUNC(mc68328_device::csd_msw_r<2>), FUNC(mc68328_device::csd_msw_w<2>)); + map(0xfff14a, 0xfff14b).rw(FUNC(mc68328_device::csd_lsw_r<2>), FUNC(mc68328_device::csd_lsw_w<2>)); + map(0xfff14c, 0xfff14d).rw(FUNC(mc68328_device::csd_msw_r<3>), FUNC(mc68328_device::csd_msw_w<3>)); + map(0xfff14e, 0xfff14f).rw(FUNC(mc68328_device::csd_lsw_r<3>), FUNC(mc68328_device::csd_lsw_w<3>)); + + map(0xfff308, 0xfff309).rw(FUNC(mc68328_device::iwr_msw_r), FUNC(mc68328_device::iwr_msw_w)); + map(0xfff30a, 0xfff30b).rw(FUNC(mc68328_device::iwr_lsw_r), FUNC(mc68328_device::iwr_lsw_w)); + + map(0xfff403, 0xfff403).rw(FUNC(mc68328_device::pasel_r), FUNC(mc68328_device::pasel_w)); + + map(0xfff438, 0xfff438).rw(FUNC(mc68328_device::pjdir_r), FUNC(mc68328_device::pjdir_w)); + map(0xfff439, 0xfff439).rw(FUNC(mc68328_device::pjdata_r), FUNC(mc68328_device::pjdata_w)); + map(0xfff43b, 0xfff43b).rw(FUNC(mc68328_device::pjsel_r), FUNC(mc68328_device::pjsel_w)); + map(0xfff440, 0xfff440).rw(FUNC(mc68328_device::pkdir_r), FUNC(mc68328_device::pkdir_w)); + map(0xfff441, 0xfff441).rw(FUNC(mc68328_device::pkdata_r), FUNC(mc68328_device::pkdata_w)); + map(0xfff442, 0xfff442).rw(FUNC(mc68328_device::pkpuen_r), FUNC(mc68328_device::pkpuen_w)); + map(0xfff443, 0xfff443).rw(FUNC(mc68328_device::pksel_r), FUNC(mc68328_device::pksel_w)); + map(0xfff448, 0xfff448).rw(FUNC(mc68328_device::pmdir_r), FUNC(mc68328_device::pmdir_w)); + map(0xfff449, 0xfff449).rw(FUNC(mc68328_device::pmdata_r), FUNC(mc68328_device::pmdata_w)); + map(0xfff44a, 0xfff44a).rw(FUNC(mc68328_device::pmpuen_r), FUNC(mc68328_device::pmpuen_w)); + map(0xfff44b, 0xfff44b).rw(FUNC(mc68328_device::pmsel_r), FUNC(mc68328_device::pmsel_w)); + + map(0xfff502, 0xfff503).rw(FUNC(mc68328_device::pwmp_r), FUNC(mc68328_device::pwmp_w)); + map(0xfff504, 0xfff505).rw(FUNC(mc68328_device::pwmw_r), FUNC(mc68328_device::pwmw_w)); + map(0xfff506, 0xfff507).rw(FUNC(mc68328_device::pwmcnt_r), FUNC(mc68328_device::pwmcnt_w)); + + map(0xfff60c, 0xfff60d).rw(FUNC(mc68328_device::tctl_r<1>), FUNC(mc68328_device::tctl_w<1>)); + map(0xfff60e, 0xfff60f).rw(FUNC(mc68328_device::tprer_r<1>), FUNC(mc68328_device::tprer_w<1>)); + map(0xfff610, 0xfff611).rw(FUNC(mc68328_device::tcmp_r<1>), FUNC(mc68328_device::tcmp_w<1>)); + map(0xfff612, 0xfff613).rw(FUNC(mc68328_device::tcr_r<1>), FUNC(mc68328_device::tcr_w<1>)); + map(0xfff614, 0xfff615).rw(FUNC(mc68328_device::tcn_r<1>), FUNC(mc68328_device::tcn_w<1>)); + map(0xfff616, 0xfff617).rw(FUNC(mc68328_device::tstat_r<1>), FUNC(mc68328_device::tstat_w<1>)); + map(0xfff618, 0xfff619).rw(FUNC(mc68328_device::wctlr_r), FUNC(mc68328_device::wctlr_w)); + map(0xfff61a, 0xfff61b).rw(FUNC(mc68328_device::wcmpr_r), FUNC(mc68328_device::wcmpr_w)); + map(0xfff61c, 0xfff61d).rw(FUNC(mc68328_device::wcn_r), FUNC(mc68328_device::wcn_w)); + + map(0xfff700, 0xfff701).rw(FUNC(mc68328_device::spisr_r), FUNC(mc68328_device::spisr_w)); + + map(0xfffa29, 0xfffa29).rw(FUNC(mc68328_device::llbar_r), FUNC(mc68328_device::llbar_w)); + map(0xfffa2b, 0xfffa2b).rw(FUNC(mc68328_device::lotcr_r), FUNC(mc68328_device::lotcr_w)); + map(0xfffa32, 0xfffa33).rw(FUNC(mc68328_device::lgpmr_r), FUNC(mc68328_device::lgpmr_w)); + + map(0xfffb0c, 0xfffb0d).rw(FUNC(mc68328_device::rtcctl_r), FUNC(mc68328_device::rtcctl_w)); +} + +void mc68ez328_device::internal_map(address_map &map) +{ + base_internal_map(0xfffff000, map); + + map(0xfffff004, 0xfffff007).r(FUNC(mc68ez328_device::revision_r)); + + map(0xfffff110, 0xfffff111).rw(FUNC(mc68ez328_device::csa_r), FUNC(mc68ez328_device::csa_w)); + map(0xfffff112, 0xfffff113).rw(FUNC(mc68ez328_device::csb_r), FUNC(mc68ez328_device::csb_w)); + map(0xfffff114, 0xfffff115).rw(FUNC(mc68ez328_device::csc_r), FUNC(mc68ez328_device::csc_w)); + map(0xfffff116, 0xfffff117).rw(FUNC(mc68ez328_device::csd_r), FUNC(mc68ez328_device::csd_w)); + map(0xfffff118, 0xfffff119).rw(FUNC(mc68ez328_device::emucs_r), FUNC(mc68ez328_device::emucs_w)); + + map(0xfffff502, 0xfffff503).rw(FUNC(mc68ez328_device::pwms_r), FUNC(mc68ez328_device::pwms_w)); + map(0xfffff504, 0xfffff504).rw(FUNC(mc68ez328_device::pwmp_r), FUNC(mc68ez328_device::pwmp_w)); + map(0xfffff505, 0xfffff505).rw(FUNC(mc68ez328_device::pwmcnt_r), FUNC(mc68ez328_device::pwmcnt_w)); + + map(0xfffffa29, 0xfffffa29).rw(FUNC(mc68ez328_device::lrra_r), FUNC(mc68ez328_device::lrra_w)); + map(0xfffffa36, 0xfffffa37).rw(FUNC(mc68ez328_device::pwmr_r), FUNC(mc68ez328_device::pwmr_w)); + + map(0xfffffb0a, 0xfffffb0b).rw(FUNC(mc68ez328_device::watchdog_r), FUNC(mc68ez328_device::watchdog_w)); + map(0xfffffb0c, 0xfffffb0d).rw(FUNC(mc68ez328_device::rtcctl_r), FUNC(mc68ez328_device::rtcctl_w)); + map(0xfffffb1a, 0xfffffb1b).rw(FUNC(mc68ez328_device::dayr_r), FUNC(mc68ez328_device::dayr_w)); + map(0xfffffb1c, 0xfffffb1d).rw(FUNC(mc68ez328_device::dayalarm_r), FUNC(mc68ez328_device::dayalarm_w)); +} + +void mc68328_device::cpu_space_map(address_map &map) +{ + map(0xfffff0, 0xffffff).r(FUNC(mc68328_device::irq_callback)).umask16(0x00ff); +} + +void mc68ez328_device::cpu_space_map(address_map &map) +{ + map(0xfffffff0, 0xffffffff).r(FUNC(mc68ez328_device::irq_callback)).umask16(0x00ff); } //------------------------------------------------- @@ -396,2825 +323,3655 @@ mc68328_device::mc68328_device(const machine_config &mconfig, const char *tag, d // initial conditions at start time //------------------------------------------------- -void mc68328_device::device_resolve_objects() +void mc68328_base_device::device_resolve_objects() { m68000_device::device_resolve_objects(); - m_out_port_a_cb.resolve(); - m_out_port_b_cb.resolve(); - m_out_port_c_cb.resolve(); - m_out_port_d_cb.resolve(); - m_out_port_e_cb.resolve(); - m_out_port_f_cb.resolve(); - m_out_port_g_cb.resolve(); - m_out_port_j_cb.resolve(); - m_out_port_k_cb.resolve(); - m_out_port_m_cb.resolve(); - - m_in_port_a_cb.resolve(); - m_in_port_b_cb.resolve(); - m_in_port_c_cb.resolve(); - m_in_port_d_cb.resolve(); - m_in_port_e_cb.resolve(); - m_in_port_f_cb.resolve(); - m_in_port_g_cb.resolve(); - m_in_port_j_cb.resolve(); - m_in_port_k_cb.resolve(); - m_in_port_m_cb.resolve(); - - m_out_pwm_cb.resolve(); - - m_out_spim_cb.resolve(); - m_in_spim_cb.resolve(); - - m_spim_xch_trigger_cb.resolve(); + m_lcd_info_changed_cb.resolve_safe(); } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- -void mc68328_device::device_start() +void mc68328_base_device::device_start() { m68000_device::device_start(); - m_gptimer[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc68328_device::timer1_hit),this)); - m_gptimer[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc68328_device::timer2_hit),this)); - m_rtc = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc68328_device::rtc_tick),this)); - m_pwm = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc68328_device::pwm_transition),this)); + m_refclk = timer_alloc(FUNC(mc68328_base_device::refclk_tick), this); + m_pwm = timer_alloc(FUNC(mc68328_base_device::pwm_tick), this); + m_rtc = timer_alloc(FUNC(mc68328_base_device::rtc_tick), this); + m_spim = timer_alloc(FUNC(mc68328_base_device::spim_tick), this); + m_lcd_scan = timer_alloc(FUNC(mc68328_base_device::lcd_scan_tick), this); + + m_lcd_line_buffer = std::make_unique<u16[]>(1024 / 16); // 1024px wide, up to 16 pixels per word register_state_save(); } +void mc68328_device::device_start() +{ + mc68328_base_device::device_start(); + + m_gptimer[0] = timer_alloc(FUNC(mc68328_device::timer_tick<0>), this); + m_gptimer[1] = timer_alloc(FUNC(mc68328_device::timer_tick<1>), this); +} + +void mc68ez328_device::device_start() +{ + mc68328_base_device::device_start(); + + m_gptimer = timer_alloc(FUNC(mc68ez328_device::timer_tick<0>), this); + m_rtc_sample_timer = timer_alloc(FUNC(mc68ez328_device::sample_timer_tick), this); + + m_dayr = 0; + m_dayalarm = 0; + m_sam_cnt = 0; +} + //------------------------------------------------- // device_reset - device-specific reset //------------------------------------------------- -void mc68328_device::device_reset() +void mc68328_base_device::device_reset() { m68000_device::device_reset(); - m_regs.scr = 0x0c; - m_regs.grpbasea = 0x0000; - m_regs.grpbaseb = 0x0000; - m_regs.grpbasec = 0x0000; - m_regs.grpbased = 0x0000; - m_regs.grpmaska = 0x0000; - m_regs.grpmaskb = 0x0000; - m_regs.grpmaskc = 0x0000; - m_regs.grpmaskd = 0x0000; - m_regs.csa0 = 0x00010006; - m_regs.csa1 = 0x00010006; - m_regs.csa2 = 0x00010006; - m_regs.csa3 = 0x00010006; - m_regs.csb0 = 0x00010006; - m_regs.csb1 = 0x00010006; - m_regs.csb2 = 0x00010006; - m_regs.csb3 = 0x00010006; - m_regs.csc0 = 0x00010006; - m_regs.csc1 = 0x00010006; - m_regs.csc2 = 0x00010006; - m_regs.csc3 = 0x00010006; - m_regs.csd0 = 0x00010006; - m_regs.csd1 = 0x00010006; - m_regs.csd2 = 0x00010006; - m_regs.csd3 = 0x00010006; - - m_regs.pllcr = 0x2400; - m_regs.pllfsr = 0x0123; - m_regs.pctlr = 0x1f; - - m_regs.ivr = 0x00; - m_regs.icr = 0x0000; - m_regs.imr = 0x00ffffff; - m_regs.iwr = 0x00ffffff; - m_regs.isr = 0x00000000; - m_regs.ipr = 0x00000000; - - m_regs.padir = 0x00; - m_regs.padata = 0x00; - m_regs.pasel = 0x00; - m_regs.pbdir = 0x00; - m_regs.pbdata = 0x00; - m_regs.pbsel = 0x00; - m_regs.pcdir = 0x00; - m_regs.pcdata = 0x00; - m_regs.pcsel = 0x00; - m_regs.pddir = 0x00; - m_regs.pddata = 0x00; - m_regs.pdpuen = 0xff; - m_regs.pdpol = 0x00; - m_regs.pdirqen = 0x00; - m_regs.pddataedge = 0x00; - m_regs.pdirqedge = 0x00; - m_regs.pedir = 0x00; - m_regs.pedata = 0x00; - m_regs.pepuen = 0x80; - m_regs.pesel = 0x80; - m_regs.pfdir = 0x00; - m_regs.pfdata = 0x00; - m_regs.pfpuen = 0xff; - m_regs.pfsel = 0xff; - m_regs.pgdir = 0x00; - m_regs.pgdata = 0x00; - m_regs.pgpuen = 0xff; - m_regs.pgsel = 0xff; - m_regs.pjdir = 0x00; - m_regs.pjdata = 0x00; - m_regs.pjsel = 0x00; - m_regs.pkdir = 0x00; - m_regs.pkdata = 0x00; - m_regs.pkpuen = 0xff; - m_regs.pksel = 0xff; - m_regs.pmdir = 0x00; - m_regs.pmdata = 0x00; - m_regs.pmpuen = 0xff; - m_regs.pmsel = 0xff; - - m_regs.pwmc = 0x0000; - m_regs.pwmp = 0x0000; - m_regs.pwmw = 0x0000; - m_regs.pwmcnt = 0x0000; - - m_regs.tctl[0] = m_regs.tctl[1] = 0x0000; - m_regs.tprer[0] = m_regs.tprer[1] = 0x0000; - m_regs.tcmp[0] = m_regs.tcmp[1] = 0xffff; - m_regs.tcr[0] = m_regs.tcr[1] = 0x0000; - m_regs.tcn[0] = m_regs.tcn[1] = 0x0000; - m_regs.tstat[0] = m_regs.tstat[1] = 0x0000; - m_regs.wctlr = 0x0000; - m_regs.wcmpr = 0xffff; - m_regs.wcn = 0x0000; - - m_regs.spisr = 0x0000; - - m_regs.spimdata = 0x0000; - m_regs.spimcont = 0x0000; - - m_regs.ustcnt = 0x0000; - m_regs.ubaud = 0x003f; - m_regs.urx = 0x0000; - m_regs.utx = 0x0000; - m_regs.umisc = 0x0000; - - m_regs.lssa = 0x00000000; - m_regs.lvpw = 0xff; - m_regs.lxmax = 0x03ff; - m_regs.lymax = 0x01ff; - m_regs.lcxp = 0x0000; - m_regs.lcyp = 0x0000; - m_regs.lcwch = 0x0101; - m_regs.lblkc = 0x7f; - m_regs.lpicf = 0x00; - m_regs.lpolcf = 0x00; - m_regs.lacdrc = 0x00; - m_regs.lpxcd = 0x00; - m_regs.lckcon = 0x40; - m_regs.llbar = 0x3e; - m_regs.lotcr = 0x3f; - m_regs.lposr = 0x00; - m_regs.lfrcm = 0xb9; - m_regs.lgpmr = 0x1073; - - m_regs.hmsr = 0x00000000; - m_regs.alarm = 0x00000000; - m_regs.rtcctl = 0x00; - m_regs.rtcisr = 0x00; - m_regs.rtcienr = 0x00; - m_regs.stpwtch = 0x00; + m_scr = 0x0c; + m_grpbasea = 0x0000; + m_grpbaseb = 0x0000; + m_grpbasec = 0x0000; + m_grpbased = 0x0000; + + m_refclk->adjust(attotime::from_hz(32768), 0, attotime::from_hz(32768)); + m_pllcr = 0x2400; + m_pllfsr = 0x0123; + m_pctlr = 0x1f; + + m_ivr = 0x00; + m_icr = 0x0000; + m_imr = 0x00ffffff; + m_gisr = 0x00000000; + m_ipr = 0x00000000; + + m_pasel = 0x00; + m_padir = 0x00; + m_padata = 0x00; + m_pbdir = 0x00; + m_pbdata = 0x00; + m_pbsel = 0x00; + m_pcdir = 0x00; + m_pcdata = 0x00; + m_pcsel = 0x00; + m_pddir = 0x00; + m_pddata = 0x00; + m_pdpuen = 0xff; + m_pdpol = 0x00; + m_pdirqen = 0x00; + m_pdirqedge = 0x00; + m_pdindata = 0x00; + m_pedir = 0x00; + m_pedata = 0x00; + m_pepuen = 0x80; + m_pesel = 0x80; + m_pfdir = 0x00; + m_pfdata = 0x00; + m_pfpuen = 0xff; + m_pfsel = 0xff; + m_pgdir = 0x00; + m_pgdata = 0x00; + m_pgpuen = 0xff; + m_pgsel = 0xff; + + m_spimdata = 0x0000; + m_spimcont = 0x0000; + m_spmtxd = false; + m_spmrxd = false; + m_spmclk = false; + m_spim_bit_read_idx = 15; + + m_ustcnt = 0x0000; + m_ubaud = 0x003f; + m_urx = 0x0000; + m_utx = 0x0000; + m_umisc = 0x0000; + + m_lssa = 0x00000000; + m_lssa_end = 0x00000000; + m_lvpw = 0xff; + m_lxmax = 0x03ff; + m_lymax = 0x01ff; + m_lcxp = 0x0000; + m_lcyp = 0x0000; + m_lcwch = 0x0101; + m_lblkc = 0x7f; + m_lpicf = 0x00; + m_lpolcf = 0x00; + m_lacdrc = 0x00; + m_lpxcd = 0x00; + m_lckcon = 0x40; + m_lposr = 0x00; + m_lfrcm = 0xb9; + m_lcd_update_pending = true; + + m_hmsr = 0x00000000; + m_alarm = 0x00000000; + m_rtcctl = 0x00; + + m_rtcisr = 0x0000; + m_rtcienr = 0x0000; + m_stpwtch = 0x0000; + + m_pwm->adjust(attotime::never); + m_pwmo = false; m_rtc->adjust(attotime::from_hz(1), 0, attotime::from_hz(1)); + m_spim->adjust(attotime::never); + m_lcd_scan->adjust(attotime::never); + m_lcd_sysmem_ptr = 0; + m_lssa_end = 0; + m_lcd_line_bit = 0; + m_lcd_line_word = 0; + m_lsclk = false; } +void mc68328_device::device_reset() +{ + mc68328_base_device::device_reset(); + + m_grpmaska = 0x0000; + m_grpmaskb = 0x0000; + m_grpmaskc = 0x0000; + m_grpmaskd = 0x0000; + std::fill(std::begin(m_csa), std::end(m_csa), 0x00010006); + std::fill(std::begin(m_csb), std::end(m_csb), 0x00010006); + std::fill(std::begin(m_csc), std::end(m_csc), 0x00010006); + std::fill(std::begin(m_csd), std::end(m_csd), 0x00010006); + + m_iwr = 0x00ffffff; + + m_pasel = 0xff; + m_pjdir = 0x00; + m_pjdata = 0x00; + m_pjsel = 0x00; + m_pkdir = 0x00; + m_pkdata = 0x00; + m_pkpuen = 0xff; + m_pksel = 0xff; + m_pmdir = 0x00; + m_pmdata = 0x00; + m_pmpuen = 0xff; + m_pmsel = 0xff; + + m_pwmc = 0x0000; + m_pwmp = 0x0000; + m_pwmw = 0x0000; + m_pwmcnt = 0x0000; + + m_timer_regs[0].tctl = m_timer_regs[1].tctl = 0x0000; + m_timer_regs[0].tprer = m_timer_regs[1].tprer = 0x0000; + m_timer_regs[0].tcmp = m_timer_regs[1].tcmp = 0xffff; + m_timer_regs[0].tcr = m_timer_regs[1].tcr = 0x0000; + m_timer_regs[0].tcn = m_timer_regs[1].tcn = 0x0000; + m_timer_regs[0].tstat = m_timer_regs[1].tstat = 0x0000; + m_wctlr = 0x0000; + m_wcmpr = 0xffff; + m_wcn = 0x0000; + m_timer_regs[0].tclear = m_timer_regs[1].tclear = 0; + + m_spisr = 0x0000; + + m_llbar = 0x3e; + m_lotcr = 0x3f; + m_lgpmr = 0x1073; + + m_gptimer[0]->adjust(attotime::never); + m_gptimer[1]->adjust(attotime::never); +} -void mc68328_device::set_interrupt_line(uint32_t line, uint32_t active) +void mc68ez328_device::device_reset() { - if (active) + mc68328_base_device::device_reset(); + + m_csa = 0x00e0; + m_csb = 0x0000; + m_csc = 0x0000; + m_csd = 0x0020; + m_emucs = 0x0060; + + m_pwmc = 0x0020; + m_pwmp = 0xfe; + m_pwmcnt = 0x00; + std::fill(std::begin(m_pwmfifo), std::end(m_pwmfifo), 0x0000); + m_pwmfifo_wr = 0; + m_pwmfifo_rd = 0; + m_pwmfifo_cnt = 0; + m_pwm_rep_cnt = 1; + + m_gptimer->adjust(attotime::never); + + m_lrra = 0xff; + m_pwmr = 0x0000; + + m_rtc_sample_timer->adjust(attotime::from_ticks(64, 32768), 0, attotime::from_ticks(64, 32768)); + m_watchdog = 0x0001; + m_sam_cnt = 0; +} + +void mc68328_base_device::register_state_save() +{ + save_item(NAME(m_scr)); + save_item(NAME(m_grpbasea)); + save_item(NAME(m_grpbaseb)); + save_item(NAME(m_grpbasec)); + save_item(NAME(m_grpbased)); + + save_item(NAME(m_pllcr)); + save_item(NAME(m_pllfsr)); + save_item(NAME(m_pctlr)); + + save_item(NAME(m_ivr)); + save_item(NAME(m_icr)); + save_item(NAME(m_imr)); + save_item(NAME(m_gisr)); + save_item(NAME(m_ipr)); + + save_item(NAME(m_padir)); + save_item(NAME(m_padata)); + save_item(NAME(m_pbdir)); + save_item(NAME(m_pbdata)); + save_item(NAME(m_pbsel)); + save_item(NAME(m_pcdir)); + save_item(NAME(m_pcdata)); + save_item(NAME(m_pcsel)); + save_item(NAME(m_pddir)); + save_item(NAME(m_pddata)); + save_item(NAME(m_pdpuen)); + save_item(NAME(m_pdpol)); + save_item(NAME(m_pdirqen)); + save_item(NAME(m_pdirqedge)); + save_item(NAME(m_pdindata)); + save_item(NAME(m_pedir)); + save_item(NAME(m_pedata)); + save_item(NAME(m_pepuen)); + save_item(NAME(m_pesel)); + save_item(NAME(m_pfdir)); + save_item(NAME(m_pfdata)); + save_item(NAME(m_pfpuen)); + save_item(NAME(m_pfsel)); + save_item(NAME(m_pgdir)); + save_item(NAME(m_pgdata)); + save_item(NAME(m_pgpuen)); + save_item(NAME(m_pgsel)); + + save_item(NAME(m_pwmc)); + save_item(NAME(m_pwmo)); + + save_item(NAME(m_spimdata)); + save_item(NAME(m_spimcont)); + save_item(NAME(m_spmtxd)); + save_item(NAME(m_spmrxd)); + save_item(NAME(m_spmclk)); + save_item(NAME(m_spim_bit_read_idx)); + + save_item(NAME(m_ustcnt)); + save_item(NAME(m_ubaud)); + save_item(NAME(m_urx)); + save_item(NAME(m_utx)); + save_item(NAME(m_umisc)); + + save_item(NAME(m_lssa)); + save_item(NAME(m_lssa_end)); + save_item(NAME(m_lvpw)); + save_item(NAME(m_lxmax)); + save_item(NAME(m_lymax)); + save_item(NAME(m_lcxp)); + save_item(NAME(m_lcyp)); + save_item(NAME(m_lcwch)); + save_item(NAME(m_lblkc)); + save_item(NAME(m_lpicf)); + save_item(NAME(m_lpolcf)); + save_item(NAME(m_lacdrc)); + save_item(NAME(m_lpxcd)); + save_item(NAME(m_lckcon)); + save_item(NAME(m_lposr)); + save_item(NAME(m_lfrcm)); + save_item(NAME(m_lcd_update_pending)); + + save_item(NAME(m_hmsr)); + save_item(NAME(m_alarm)); + save_item(NAME(m_rtcctl)); + save_item(NAME(m_rtcisr)); + save_item(NAME(m_rtcienr)); + save_item(NAME(m_stpwtch)); + + save_item(NAME(m_lcd_sysmem_ptr)); + save_pointer(NAME(m_lcd_line_buffer), 1024 / 8); + save_item(NAME(m_lcd_line_bit)); + save_item(NAME(m_lcd_line_word)); + save_item(NAME(m_lsclk)); +} + +void mc68328_device::register_state_save() +{ + mc68328_base_device::register_state_save(); + + save_item(NAME(m_grpmaska)); + save_item(NAME(m_grpmaskb)); + save_item(NAME(m_grpmaskc)); + save_item(NAME(m_grpmaskd)); + save_item(NAME(m_csa)); + save_item(NAME(m_csb)); + save_item(NAME(m_csc)); + save_item(NAME(m_csd)); + + save_item(NAME(m_iwr)); + + save_item(NAME(m_pasel)); + save_item(NAME(m_pjdir)); + save_item(NAME(m_pjdata)); + save_item(NAME(m_pjsel)); + save_item(NAME(m_pkdir)); + save_item(NAME(m_pkdata)); + save_item(NAME(m_pkpuen)); + save_item(NAME(m_pksel)); + save_item(NAME(m_pmdir)); + save_item(NAME(m_pmdata)); + save_item(NAME(m_pmpuen)); + save_item(NAME(m_pmsel)); + + save_item(NAME(m_pwmp)); + save_item(NAME(m_pwmw)); + save_item(NAME(m_pwmcnt)); + + save_item(STRUCT_MEMBER(m_timer_regs, tctl)); + save_item(STRUCT_MEMBER(m_timer_regs, tprer)); + save_item(STRUCT_MEMBER(m_timer_regs, tcmp)); + save_item(STRUCT_MEMBER(m_timer_regs, tcr)); + save_item(STRUCT_MEMBER(m_timer_regs, tcn)); + save_item(STRUCT_MEMBER(m_timer_regs, tstat)); + save_item(STRUCT_MEMBER(m_timer_regs, tclear)); + save_item(NAME(m_wctlr)); + save_item(NAME(m_wcmpr)); + save_item(NAME(m_wcn)); + + save_item(NAME(m_spisr)); + + save_item(NAME(m_llbar)); + save_item(NAME(m_lotcr)); + save_item(NAME(m_lgpmr)); +} + +void mc68ez328_device::register_state_save() +{ + mc68328_base_device::register_state_save(); + + save_item(NAME(m_pwmp)); + save_item(NAME(m_pwmcnt)); + save_item(NAME(m_pwmfifo)); + save_item(NAME(m_pwmfifo_wr)); + save_item(NAME(m_pwmfifo_rd)); + save_item(NAME(m_pwmfifo_cnt)); + save_item(NAME(m_pwm_rep_cnt)); + + save_item(STRUCT_MEMBER(m_timer_regs, tctl)); + save_item(STRUCT_MEMBER(m_timer_regs, tprer)); + save_item(STRUCT_MEMBER(m_timer_regs, tcmp)); + save_item(STRUCT_MEMBER(m_timer_regs, tcr)); + save_item(STRUCT_MEMBER(m_timer_regs, tcn)); + save_item(STRUCT_MEMBER(m_timer_regs, tstat)); + save_item(STRUCT_MEMBER(m_timer_regs, tclear)); + + save_item(NAME(m_lrra)); + save_item(NAME(m_pwmr)); + + save_item(NAME(m_watchdog)); + save_item(NAME(m_dayr)); + save_item(NAME(m_dayalarm)); + save_item(NAME(m_sam_cnt)); +} + +//------------------------------------------------- +// System control hardware +//------------------------------------------------- + +void mc68328_base_device::scr_w(u8 data) // 0x000 +{ + LOGMASKED(LOG_SCR, "%s: scr_w: SCR = %02x\n", machine().describe_context(), data); +} + +u8 mc68328_base_device::scr_r() // 0x000 +{ + LOGMASKED(LOG_SCR, "%s: scr_r: SCR: %02x\n", machine().describe_context(), m_scr); + return m_scr; +} + + +//------------------------------------------------- +// MMU/chip-select hardware - Standard MC68328 +//------------------------------------------------- + +void mc68328_base_device::grpbasea_w(u16 data) // 0x100 +{ + LOGMASKED(LOG_CS_GRP, "%s: grpbasea_w: GRPBASEA = %04x\n", machine().describe_context(), data); + m_grpbasea = data; +} + +u16 mc68328_base_device::grpbasea_r() // 0x100 +{ + LOGMASKED(LOG_CS_GRP, "%s: grpbasea_r: GRPBASEA: %04x\n", machine().describe_context(), m_grpbasea); + return m_grpbasea; +} + +void mc68328_base_device::grpbaseb_w(u16 data) // 0x102 +{ + LOGMASKED(LOG_CS_GRP, "%s: grpbaseb_w: GRPBASEB = %04x\n", machine().describe_context(), data); + m_grpbaseb = data; +} + +u16 mc68328_base_device::grpbaseb_r() // 0x102 +{ + LOGMASKED(LOG_CS_GRP, "%s: grpbaseb_r: GRPBASEB: %04x\n", machine().describe_context(), m_grpbaseb); + return m_grpbaseb; +} + +void mc68328_base_device::grpbasec_w(u16 data) // 0x104 +{ + LOGMASKED(LOG_CS_GRP, "%s: grpbasec_w: GRPBASEC = %04x\n", machine().describe_context(), data); + m_grpbasec = data; +} + +u16 mc68328_base_device::grpbasec_r() // 0x104 +{ + LOGMASKED(LOG_CS_GRP, "%s: grpbasec_r: GRPBASEC: %04x\n", machine().describe_context(), m_grpbasec); + return m_grpbasec; +} + +void mc68328_base_device::grpbased_w(u16 data) // 0x106 +{ + LOGMASKED(LOG_CS_GRP, "%s: grpbased_w: GRPBASED = %04x\n", machine().describe_context(), data); + m_grpbased = data; +} + +u16 mc68328_base_device::grpbased_r() // 0x106 +{ + LOGMASKED(LOG_CS_GRP, "%s: grpbased_r: GRPBASED: %04x\n", machine().describe_context(), m_grpbased); + return m_grpbased; +} + +void mc68328_device::grpmaska_w(u16 data) // 0x108 +{ + LOGMASKED(LOG_CS_GRP, "%s: grpmaska_w: GRPMASKA = %04x\n", machine().describe_context(), data); + m_grpmaska = data; +} + +u16 mc68328_device::grpmaska_r() // 0x108 +{ + LOGMASKED(LOG_CS_GRP, "%s: grpmaska_r: GRPMASKA: %04x\n", machine().describe_context(), m_grpmaska); + return m_grpmaska; +} + +void mc68328_device::grpmaskb_w(u16 data) // 0x10a +{ + LOGMASKED(LOG_CS_GRP, "%s: grpmaskb_w: GRPMASKB = %04x\n", machine().describe_context(), data); + m_grpmaskb = data; +} + +u16 mc68328_device::grpmaskb_r() // 0x10a +{ + LOGMASKED(LOG_CS_GRP, "%s: grpmaskb_r: GRPMASKB: %04x\n", machine().describe_context(), m_grpmaskb); + return m_grpmaskb; +} + +void mc68328_device::grpmaskc_w(u16 data) // 0x10c +{ + LOGMASKED(LOG_CS_GRP, "%s: grpmaskc_w: GRPMASKC = %04x\n", machine().describe_context(), data); + m_grpmaskc = data; +} + +u16 mc68328_device::grpmaskc_r() // 0x10c +{ + LOGMASKED(LOG_CS_GRP, "%s: grpmaskc_r: GRPMASKC: %04x\n", machine().describe_context(), m_grpmaskc); + return m_grpmaskc; +} + +void mc68328_device::grpmaskd_w(u16 data) // 0x10e +{ + LOGMASKED(LOG_CS_GRP, "%s: grpmaskd_w: GRPMASKD = %04x\n", machine().describe_context(), data); + m_grpmaskd = data; +} + +u16 mc68328_device::grpmaskd_r() // 0x10e +{ + LOGMASKED(LOG_CS_GRP, "%s: grpmaskd_r: GRPMASKD: %04x\n", machine().describe_context(), m_grpmaskd); + return m_grpmaskd; +} + +template<int ChipSelect> +void mc68328_device::csa_msw_w(offs_t offset, u16 data, u16 mem_mask) // 0x110, 0x114, 0x118, 0x11c +{ + LOGMASKED(LOG_CS_SEL, "%s: csa_msw_w<%d>: CSA%d(16) = %04x\n", machine().describe_context(), ChipSelect, ChipSelect, data); + m_csa[ChipSelect] &= 0xffff0000 | (~mem_mask); + m_csa[ChipSelect] |= data & mem_mask; +} + +template<int ChipSelect> +u16 mc68328_device::csa_msw_r() // 0x110, 0x120, 0x130, 0x140 +{ + LOGMASKED(LOG_CS_SEL, "%s: csa_msw_r: CSA%d(MSW): %04x\n", machine().describe_context(), ChipSelect, (u16)(m_csa[ChipSelect] >> 16)); + return (u16)(m_csa[ChipSelect] >> 16); +} + +template<int ChipSelect> +void mc68328_device::csa_lsw_w(offs_t offset, u16 data, u16 mem_mask) // 0x112, 0x116, 0x11a, 0x11e +{ + LOGMASKED(LOG_CS_SEL, "%s: csa_lsw_w<%d>: CSA%d(0) = %04x\n", machine().describe_context(), ChipSelect, ChipSelect, data); + m_csa[ChipSelect] &= ~(mem_mask << 16); + m_csa[ChipSelect] |= (data & mem_mask) << 16; +} + +template<int ChipSelect> +u16 mc68328_device::csa_lsw_r() // 0x112, 0x122, 0x132, 0x142 +{ + LOGMASKED(LOG_CS_SEL, "%s: csa_lsw_r: CSA%d(LSW): %04x\n", machine().describe_context(), ChipSelect, (u16)m_csa[ChipSelect]); + return (u16)m_csa[ChipSelect]; +} + +template<int ChipSelect> +void mc68328_device::csb_msw_w(offs_t offset, u16 data, u16 mem_mask) // 0x120, 0x124, 0x128, 0x12c +{ + LOGMASKED(LOG_CS_SEL, "%s: csb_msw_w<%d>: CSB%d(MSW) = %04x\n", machine().describe_context(), ChipSelect, ChipSelect, data); + m_csb[ChipSelect] &= 0xffff0000 | (~mem_mask); + m_csb[ChipSelect] |= data & mem_mask; +} + +template<int ChipSelect> +u16 mc68328_device::csb_msw_r() // 0x114, 0x124, 0x134, 0x144 +{ + LOGMASKED(LOG_CS_SEL, "%s: csb_msw_r: CSB%d(MSW): %04x\n", machine().describe_context(), ChipSelect, (u16)(m_csb[ChipSelect] >> 16)); + return (u16)(m_csb[ChipSelect] >> 16); +} + +template<int ChipSelect> +void mc68328_device::csb_lsw_w(offs_t offset, u16 data, u16 mem_mask) // 0x122, 0x126, 0x12a, 0x12e +{ + LOGMASKED(LOG_CS_SEL, "%s: csb_lsw_w<%d>: CSB%d(LSW) = %04x\n", machine().describe_context(), ChipSelect, ChipSelect, data); + m_csb[ChipSelect] &= ~(mem_mask << 16); + m_csb[ChipSelect] |= (data & mem_mask) << 16; +} + +template<int ChipSelect> +u16 mc68328_device::csb_lsw_r() // 0x116, 0x126, 0x136, 0x146 +{ + LOGMASKED(LOG_CS_SEL, "%s: csb_lsw_r: CSB%d(LSW): %04x\n", machine().describe_context(), ChipSelect, (u16)m_csb[ChipSelect]); + return (u16)m_csb[ChipSelect]; +} + +template<int ChipSelect> +void mc68328_device::csc_msw_w(offs_t offset, u16 data, u16 mem_mask) // 0x130, 0x134, 0x138, 0x13c +{ + LOGMASKED(LOG_CS_SEL, "%s: csc_msw_w<%d>: CSC%d(MSW) = %04x\n", machine().describe_context(), ChipSelect, ChipSelect, data); + m_csc[ChipSelect] &= 0xffff0000 | (~mem_mask); + m_csc[ChipSelect] |= data & mem_mask; +} + +template<int ChipSelect> +u16 mc68328_device::csc_msw_r() // 0x118, 0x128, 0x138, 0x148 +{ + LOGMASKED(LOG_CS_SEL, "%s: csc_msw_r: CSC%d(MSW): %04x\n", machine().describe_context(), ChipSelect, (u16)(m_csc[ChipSelect] >> 16)); + return (u16)(m_csc[ChipSelect] >> 16); +} + +template<int ChipSelect> +void mc68328_device::csc_lsw_w(offs_t offset, u16 data, u16 mem_mask) // 0x132, 0x136, 0x13a, 0x13e +{ + LOGMASKED(LOG_CS_SEL, "%s: csc_lsw_w<%d>: CSC%d(LSW) = %04x\n", machine().describe_context(), ChipSelect, ChipSelect, data); + m_csc[ChipSelect] &= ~(mem_mask << 16); + m_csc[ChipSelect] |= (data & mem_mask) << 16; +} + +template<int ChipSelect> +u16 mc68328_device::csc_lsw_r() // 0x11a, 0x12a, 0x13a, 0x14a +{ + LOGMASKED(LOG_CS_SEL, "%s: csc_lsw_r: CSC%d(LSW): %04x\n", machine().describe_context(), ChipSelect, (u16)m_csc[ChipSelect]); + return (u16)m_csc[ChipSelect]; +} + +template<int ChipSelect> +void mc68328_device::csd_msw_w(offs_t offset, u16 data, u16 mem_mask) // 0x140, 0x144, 0x148, 0x14c +{ + LOGMASKED(LOG_CS_SEL, "%s: csd_msw_w<%d>: CSD%d(MSW) = %04x\n", machine().describe_context(), ChipSelect, ChipSelect, data); + m_csd[ChipSelect] &= 0xffff0000 | (~mem_mask); + m_csd[ChipSelect] |= data & mem_mask; +} + +template<int ChipSelect> +u16 mc68328_device::csd_msw_r() // 0x11c, 0x12c, 0x13c, 0x14c +{ + LOGMASKED(LOG_CS_SEL, "%s: csd_msw_r: CSD%d(MSW): %04x\n", machine().describe_context(), ChipSelect, (u16)(m_csd[ChipSelect] >> 16)); + return (u16)(m_csd[ChipSelect] >> 16); +} + +template<int ChipSelect> +void mc68328_device::csd_lsw_w(offs_t offset, u16 data, u16 mem_mask) // 0x142, 0x146, 0x14a, 0x14e +{ + LOGMASKED(LOG_CS_SEL, "%s: csd_lsw_w<%d>: CSD%d(LSW) = %04x\n", machine().describe_context(), ChipSelect, ChipSelect, data); + m_csd[ChipSelect] &= ~(mem_mask << 16); + m_csd[ChipSelect] |= (data & mem_mask) << 16; +} + +template<int ChipSelect> +u16 mc68328_device::csd_lsw_r() // 0x11e, 0x12e, 0x13e, 0x14e +{ + LOGMASKED(LOG_CS_SEL, "%s: csd_lsw_r: CSD%d(LSW): %04x\n", machine().describe_context(), ChipSelect, (u16)m_csd[ChipSelect]); + return (u16)m_csd[ChipSelect]; +} + + +//------------------------------------------------- +// MMU/chip-select hardware - EZ variant +//------------------------------------------------- + +void mc68ez328_device::scr_w(u8 data) +{ + if (data & SCR_WDTH8) { - m_regs.ipr |= line; + m_pasel = 0xff; + } + mc68328_base_device::scr_w(data); +} - if (!(m_regs.imr & line) && !(m_regs.isr & line)) - { - m_regs.isr |= line; +u8 mc68ez328_device::revision_r(offs_t offset) +{ + LOGMASKED(LOG_PLL, "%s: revision_r: Silicon Revision[%d] = %02x\n", machine().describe_context(), offset, 0x01); + return 0x01; +} - if (m_regs.isr & INT_M68K_LINE7) - { - set_input_line(M68K_IRQ_7, ASSERT_LINE); - } - else if (m_regs.isr & INT_M68K_LINE6) - { - set_input_line(M68K_IRQ_6, ASSERT_LINE); - } - else if (m_regs.isr & INT_M68K_LINE5) - { - set_input_line(M68K_IRQ_5, ASSERT_LINE); - } - else if (m_regs.isr & INT_M68K_LINE4) - { - set_input_line(M68K_IRQ_4, ASSERT_LINE); - } - else if (m_regs.isr & INT_M68K_LINE3) - { - set_input_line(M68K_IRQ_3, ASSERT_LINE); - } - else if (m_regs.isr & INT_M68K_LINE2) - { - set_input_line(M68K_IRQ_2, ASSERT_LINE); - } - else if (m_regs.isr & INT_M68K_LINE1) - { - set_input_line(M68K_IRQ_1, ASSERT_LINE); - } +void mc68ez328_device::csa_w(offs_t offset, u16 data, u16 mem_mask) +{ + static const char *const SIZ_NAMES[8] = { "128K", "256K", "512K", "1M", "2M", "4M", "8M", "16M" }; + static const char *const WS_NAMES[8] = { "None", "1", "2", "3", "4", "5", "6", "External /DTACK" }; + LOGMASKED(LOG_CS_SEL, "%s: csa_w: CSA = %04x\n", machine().describe_context(), data); + LOGMASKED(LOG_CS_SEL, "%s: Enable: %d\n", machine().describe_context(), BIT(data, CS_EN_BIT)); + LOGMASKED(LOG_CS_SEL, "%s: Chip-Select Size: %s\n", machine().describe_context(), SIZ_NAMES[(data & CS_SIZ_MASK) >> CS_SIZ_SHIFT]); + LOGMASKED(LOG_CS_SEL, "%s: Wait States: %s\n", machine().describe_context(), WS_NAMES[(data & CS_WS_MASK) >> CS_WS_SHIFT]); + LOGMASKED(LOG_CS_SEL, "%s: Bus Width: %d Bits\n", machine().describe_context(), BIT(data, CS_BSW_BIT) ? 16 : 8); + LOGMASKED(LOG_CS_SEL, "%s: Delay /LWE and /UWE for Flash: %s\n", machine().describe_context(), BIT(data, CS_FLASH_BIT) ? "Yes" : "No"); + LOGMASKED(LOG_CS_SEL, "%s: Read-Only: %d\n", machine().describe_context(), BIT(data, CS_RO_BIT)); + m_csa = data; +} + +u16 mc68ez328_device::csa_r() +{ + LOGMASKED(LOG_CS_SEL, "%s: csa_r: CSA: %04x\n", machine().describe_context(), m_csa); + return m_csa; +} + +void mc68ez328_device::csb_w(offs_t offset, u16 data, u16 mem_mask) +{ + static const char *const SIZ_NAMES[8] = { "128K", "256K", "512K", "1M", "2M", "4M", "8M", "16M" }; + static const char *const WS_NAMES[8] = { "None", "1", "2", "3", "4", "5", "6", "External /DTACK" }; + LOGMASKED(LOG_CS_SEL, "%s: csb_w: CSB = %04x\n", machine().describe_context(), data); + LOGMASKED(LOG_CS_SEL, "%s: Enable: %d\n", machine().describe_context(), BIT(data, CS_EN_BIT)); + LOGMASKED(LOG_CS_SEL, "%s: Chip-Select Size: %s\n", machine().describe_context(), SIZ_NAMES[(data & CS_SIZ_MASK) >> CS_SIZ_SHIFT]); + LOGMASKED(LOG_CS_SEL, "%s: Wait States: %s\n", machine().describe_context(), WS_NAMES[(data & CS_WS_MASK) >> CS_WS_SHIFT]); + LOGMASKED(LOG_CS_SEL, "%s: Bus Width: %d Bits\n", machine().describe_context(), BIT(data, CS_BSW_BIT) ? 16 : 8); + LOGMASKED(LOG_CS_SEL, "%s: Delay /LWE and /UWE for Flash: %s\n", machine().describe_context(), BIT(data, CS_FLASH_BIT) ? "Yes" : "No"); + LOGMASKED(LOG_CS_SEL, "%s: Unprotected Block Size: %dK\n", machine().describe_context(), 32 << ((data & CS_UPSIZ_MASK) >> CS_UPSIZ_SHIFT)); + LOGMASKED(LOG_CS_SEL, "%s: Read-Only for Protected Block: %d\n", machine().describe_context(), BIT(data, CS_ROP_BIT)); + LOGMASKED(LOG_CS_SEL, "%s: Supervisor-Only for Protected Block: %d\n", machine().describe_context(), BIT(data, CS_SOP_BIT)); + LOGMASKED(LOG_CS_SEL, "%s: Read-Only: %d\n", machine().describe_context(), BIT(data, CS_RO_BIT)); + m_csb = data; +} + +u16 mc68ez328_device::csb_r() +{ + LOGMASKED(LOG_CS_SEL, "%s: csb_r: CSB: %04x\n", machine().describe_context(), m_csb); + return m_csb; +} + +void mc68ez328_device::csc_w(offs_t offset, u16 data, u16 mem_mask) +{ + static const char *const SIZ_NAMES[8] = { "32K", "64K", "128K", "256K", "512K", "1M", "2M", "4M" }; + static const char *const WS_NAMES[8] = { "None", "1", "2", "3", "4", "5", "6", "External /DTACK" }; + LOGMASKED(LOG_CS_SEL, "%s: csc_w: CSC = %04x\n", machine().describe_context(), data); + LOGMASKED(LOG_CS_SEL, "%s: Enable: %d\n", machine().describe_context(), BIT(data, CS_EN_BIT)); + LOGMASKED(LOG_CS_SEL, "%s: Chip-Select Size: %s\n", machine().describe_context(), SIZ_NAMES[(data & CS_SIZ_MASK) >> CS_SIZ_SHIFT]); + LOGMASKED(LOG_CS_SEL, "%s: Wait States: %s\n", machine().describe_context(), WS_NAMES[(data & CS_WS_MASK) >> CS_WS_SHIFT]); + LOGMASKED(LOG_CS_SEL, "%s: Bus Width: %d Bits\n", machine().describe_context(), BIT(data, CS_BSW_BIT) ? 16 : 8); + LOGMASKED(LOG_CS_SEL, "%s: Delay /LWE and /UWE for Flash: %s\n", machine().describe_context(), BIT(data, CS_FLASH_BIT) ? "Yes" : "No"); + LOGMASKED(LOG_CS_SEL, "%s: Unprotected Block Size: %dK\n", machine().describe_context(), 32 << ((data & CS_UPSIZ_MASK) >> CS_UPSIZ_SHIFT)); + LOGMASKED(LOG_CS_SEL, "%s: Read-Only for Protected Block: %d\n", machine().describe_context(), BIT(data, CS_ROP_BIT)); + LOGMASKED(LOG_CS_SEL, "%s: Supervisor-Only for Protected Block: %d\n", machine().describe_context(), BIT(data, CS_SOP_BIT)); + LOGMASKED(LOG_CS_SEL, "%s: Read-Only: %d\n", machine().describe_context(), BIT(data, CS_RO_BIT)); + m_csc = data; +} + +u16 mc68ez328_device::csc_r() +{ + LOGMASKED(LOG_CS_SEL, "%s: csc_r: CSC: %04x\n", machine().describe_context(), m_csc); + return m_csc; +} + +void mc68ez328_device::csd_w(offs_t offset, u16 data, u16 mem_mask) +{ + static const char *const SIZ_NAMES[8] = { "32K", "64K", "128K", "256K", "512K", "1M", "2M", "4M" }; + static const char *const WS_NAMES[8] = { "None", "1", "2", "3", "4", "5", "6", "External /DTACK" }; + LOGMASKED(LOG_CS_SEL, "%s: csd_w: CSD = %04x\n", machine().describe_context(), data); + LOGMASKED(LOG_CS_SEL, "%s: Enable: %d\n", machine().describe_context(), BIT(data, CS_EN_BIT)); + LOGMASKED(LOG_CS_SEL, "%s: Chip-Select Size: %s\n", machine().describe_context(), SIZ_NAMES[(data & CS_SIZ_MASK) >> CS_SIZ_SHIFT]); + LOGMASKED(LOG_CS_SEL, "%s: Wait States: %s\n", machine().describe_context(), WS_NAMES[(data & CS_WS_MASK) >> CS_WS_SHIFT]); + LOGMASKED(LOG_CS_SEL, "%s: Bus Width: %d Bits\n", machine().describe_context(), BIT(data, CS_BSW_BIT) ? 16 : 8); + LOGMASKED(LOG_CS_SEL, "%s: Delay /LWE and /UWE for Flash: %s\n", machine().describe_context(), BIT(data, CS_FLASH_BIT) ? "Yes" : "No"); + LOGMASKED(LOG_CS_SEL, "%s: DRAM Selection: %s\n", machine().describe_context(), BIT(data, CS_DRAM_BIT) ? "Select /CAS and /RAS" : "Select /CSC[1:0] and /CSD[1:0]"); + LOGMASKED(LOG_CS_SEL, "%s: Use /RAS0 for /RAS1: %s\n", machine().describe_context(), BIT(data, CS_COMB_BIT) ? "Yes" : "No"); + LOGMASKED(LOG_CS_SEL, "%s: Unprotected Block Size: %dK\n", machine().describe_context(), 32 << ((data & CS_UPSIZ_MASK) >> CS_UPSIZ_SHIFT)); + LOGMASKED(LOG_CS_SEL, "%s: Read-Only for Protected Block: %d\n", machine().describe_context(), BIT(data, CS_ROP_BIT)); + LOGMASKED(LOG_CS_SEL, "%s: Supervisor-Only for Protected Block: %d\n", machine().describe_context(), BIT(data, CS_SOP_BIT)); + LOGMASKED(LOG_CS_SEL, "%s: Read-Only: %d\n", machine().describe_context(), BIT(data, CS_RO_BIT)); + m_csd = data; +} + +u16 mc68ez328_device::csd_r() +{ + LOGMASKED(LOG_CS_SEL, "%s: csd_r: CSD: %04x\n", machine().describe_context(), m_csd); + return m_csd; +} + +void mc68ez328_device::emucs_w(offs_t offset, u16 data, u16 mem_mask) +{ + static const char *const WS_NAMES[8] = { "None", "1", "2", "3", "4", "5", "6", "External /DTACK" }; + LOGMASKED(LOG_CS_SEL, "%s: emucs_w: EMUCS = %04x\n", machine().describe_context(), data); + LOGMASKED(LOG_CS_SEL, "%s: Wait States: %s\n", machine().describe_context(), WS_NAMES[(data & CS_WS_MASK) >> CS_WS_SHIFT]); + m_emucs = data; +} + +u16 mc68ez328_device::emucs_r() +{ + LOGMASKED(LOG_CS_SEL, "%s: emucs_r: EMUCS: %04x\n", machine().describe_context(), m_emucs); + return m_emucs; +} + + +//------------------------------------------------- +// PLL/power hardware +//------------------------------------------------- + +TIMER_CALLBACK_MEMBER(mc68328_base_device::refclk_tick) +{ + m_pllfsr ^= 0x8000; +} + +void mc68328_base_device::pllcr_w(u16 data) // 0x200 +{ + LOGMASKED(LOG_PLL, "%s: pllcr_w: PLLCR = %04x\n", machine().describe_context(), data); + m_pllcr = data; +} + +u16 mc68328_base_device::pllcr_r() // 0x200 +{ + LOGMASKED(LOG_PLL, "%s: pllcr_r: PLLCR: %04x\n", machine().describe_context(), m_pllcr); + return m_pllcr; +} + +void mc68328_base_device::pllfsr_w(u16 data) // 0x202 +{ + LOGMASKED(LOG_PLL, "%s: pllfsr_w: PLLFSR = %04x\n", machine().describe_context(), data); + m_pllfsr = data; +} + +u16 mc68328_base_device::pllfsr_r() // 0x202 +{ + LOGMASKED(LOG_PLL, "%s: pllfsr_r: PLLFSR: %04x\n", machine().describe_context(), m_pllfsr); + return m_pllfsr; +} + +void mc68328_base_device::pctlr_w(u8 data) // 0x207 +{ + LOGMASKED(LOG_PLL, "%s: pctlr_w: PCTLR = %02x\n", machine().describe_context(), data); + m_pctlr = data; +} + +u8 mc68328_base_device::pctlr_r() // 0x207 +{ + LOGMASKED(LOG_PLL, "%s: pctlr_r: PCTLR: %02x\n", machine().describe_context(), m_pctlr); + return m_pctlr; +} + + +//------------------------------------------------- +// Interrupt-related hardware - standard MC68328 +//------------------------------------------------- + +void mc68328_base_device::update_ipr_state(u32 changed_mask) +{ + const int irq_level = get_irq_level_for_mask(changed_mask); + const u32 irq_mask = get_irq_mask_for_level(irq_level); + + if (!irq_level || !irq_mask) + { + return; + } + + if (m_ipr & changed_mask) + { + // If a pending interrupt has changed, it's not masked, and it's not currently in service, raise the corresponding 68k IRQ line and mark it as + // in-service. + if ((~m_imr & irq_mask) && !(m_gisr & changed_mask)) + { + m_gisr |= changed_mask; + set_input_line(irq_level, ASSERT_LINE); } } else { - m_regs.isr &= ~line; + m_gisr &= ~changed_mask; - if ((line & INT_M68K_LINE7) && !(m_regs.isr & INT_M68K_LINE7)) + // If there are no other pending, unmasked interrupts at this level, lower the corresponding 68k IRQ line. + if (!(m_ipr & ~m_imr & irq_mask)) { - set_input_line(M68K_IRQ_7, CLEAR_LINE); + set_input_line(irq_level, CLEAR_LINE); } - if ((line & INT_M68K_LINE6) && !(m_regs.isr & INT_M68K_LINE6)) - { - set_input_line(M68K_IRQ_6, CLEAR_LINE); - } - if ((line & INT_M68K_LINE5) && !(m_regs.isr & INT_M68K_LINE5)) - { - set_input_line(M68K_IRQ_5, CLEAR_LINE); - } - if ((line & INT_M68K_LINE4) && !(m_regs.isr & INT_M68K_LINE4)) - { - set_input_line(M68K_IRQ_4, CLEAR_LINE); - } - if ((line & INT_M68K_LINE3) && !(m_regs.isr & INT_M68K_LINE3)) - { - set_input_line(M68K_IRQ_3, CLEAR_LINE); - } - if ((line & INT_M68K_LINE2) && !(m_regs.isr & INT_M68K_LINE2)) + } +} + +void mc68328_base_device::update_imr_state(u32 changed_mask) +{ + int irq_level = get_irq_level_for_mask(changed_mask); + u32 irq_mask = get_irq_mask_for_level(irq_level); + u32 level_mask = irq_mask & changed_mask; + + while (irq_level && irq_mask) + { + if (m_ipr & ~m_gisr & ~m_imr & level_mask) { - set_input_line(M68K_IRQ_2, CLEAR_LINE); + // If a newly-unmasked interrupt is pending and not currently in-service, raise the relevant line. + m_gisr |= level_mask; + set_input_line(irq_level, ASSERT_LINE); } - if ((line & INT_M68K_LINE1) && !(m_regs.isr & INT_M68K_LINE1)) + else if (m_gisr & m_imr & level_mask) { - set_input_line(M68K_IRQ_1, CLEAR_LINE); + // If a newly-masked interrupt is in-service, lower the relevant line. + set_input_line(irq_level, CLEAR_LINE); } + + changed_mask &= ~irq_mask; + irq_level = get_irq_level_for_mask(changed_mask); + irq_mask = get_irq_mask_for_level(irq_level); + level_mask = irq_mask & changed_mask; } } -void mc68328_device::poll_port_d_interrupts() +void mc68328_base_device::set_interrupt_line(u32 line, u32 active) { - uint8_t line_transitions = m_regs.pddataedge & m_regs.pdirqedge; - uint8_t line_holds = m_regs.pddata &~ m_regs.pdirqedge; - uint8_t line_interrupts = (line_transitions | line_holds) & m_regs.pdirqen; + const u32 mask = 1 << line; - if (line_interrupts) + if (active) { - set_interrupt_line(line_interrupts << 8, 1); + m_ipr |= mask; } else { - set_interrupt_line(INT_KBDINTS, 0); + m_ipr &= ~mask; } + + update_ipr_state(mask); } -WRITE_LINE_MEMBER( mc68328_device::set_penirq_line ) +int mc68328_device::get_irq_level_for_mask(u32 mask) { - if (state) + constexpr u32 IRQ_MASKS[8] = { - set_interrupt_line(INT_PEN, 1); - } - else + 0, + INT_IRQ1_MASK, + INT_IRQ2_MASK, + INT_IRQ3_MASK, + INT_INT0_MASK | INT_INT1_MASK | INT_INT2_MASK | INT_INT3_MASK | INT_INT4_MASK | INT_INT5_MASK | INT_INT6_MASK | INT_INT7_MASK + | INT_PWM_MASK | INT_KB_MASK | INT_RTC_MASK | INT_WDT_MASK | INT_UART_MASK | INT_TIMER2_MASK | INT_SPIM_MASK, + INT_IRQ5_MASK, + INT_IRQ6_MASK | INT_TIMER1_MASK | INT_SPIS_MASK, + INT_IRQ7_MASK + }; + + for (int level = 7; level >= 1; level--) { - m_regs.ipr &= ~INT_PEN; - set_interrupt_line(INT_PEN, 0); + if (IRQ_MASKS[level] & mask) + { + return level; + } } + return 0; } -void mc68328_device::set_port_d_lines(uint8_t state, int bit) +u32 mc68328_device::get_irq_mask_for_level(int level) { - uint8_t old_button_state = m_regs.pddata; - - if (state & (1 << bit)) + constexpr u32 IRQ_MASKS[8] = { - m_regs.pddata |= (1 << bit); - } - else + 0, + INT_IRQ1_MASK, + INT_IRQ2_MASK, + INT_IRQ3_MASK, + INT_INT0_MASK | INT_INT1_MASK | INT_INT2_MASK | INT_INT3_MASK | INT_INT4_MASK | INT_INT5_MASK | INT_INT6_MASK | INT_INT7_MASK + | INT_PWM_MASK | INT_KB_MASK | INT_RTC_MASK | INT_WDT_MASK | INT_UART_MASK | INT_TIMER2_MASK | INT_SPIM_MASK, + INT_IRQ5_MASK, + INT_IRQ6_MASK | INT_TIMER1_MASK | INT_SPIS_MASK, + INT_IRQ7_MASK + }; + if (level >= 0 && level <= 7) { - m_regs.pddata &= ~(1 << bit); + return IRQ_MASKS[level]; } + return 0; +} - m_regs.pddataedge |= ~old_button_state & m_regs.pddata; +void mc68328_base_device::irq5_w(int state) +{ + set_interrupt_line(INT_IRQ5, state); +} - poll_port_d_interrupts(); +u8 mc68328_base_device::irq_callback(offs_t offset) +{ + return m_ivr | offset; } -uint8_t mc68328_device::irq_callback(offs_t offset) +void mc68328_base_device::ivr_w(u8 data) // 0x300 { - return m_regs.ivr | offset; + LOGMASKED(LOG_INTS, "%s: ivr_w: IVR = %02x\n", machine().describe_context(), data); + m_ivr = data; } -uint32_t mc68328_device::get_timer_frequency(uint32_t index) +u8 mc68328_base_device::ivr_r() // 0x300 { - uint32_t frequency = 0; + LOGMASKED(LOG_INTS, "%s: ivr_r: IVR: %02x\n", machine().describe_context(), m_ivr); + return m_ivr; +} - switch (m_regs.tctl[index] & TCTL_CLKSOURCE) - { - case TCTL_CLKSOURCE_SYSCLK: - frequency = 32768 * 506; - break; +void mc68328_base_device::icr_w(u8 data) // 0x302 +{ + LOGMASKED(LOG_INTS, "%s: icr_w: ICR = %02x\n", machine().describe_context(), data); + m_icr = data; +} - case TCTL_CLKSOURCE_SYSCLK16: - frequency = (32768 * 506) / 16; - break; +u16 mc68328_base_device::icr_r() // 0x302 +{ + LOGMASKED(LOG_INTS, "%s: icr_r: ICR: %04x\n", machine().describe_context(), m_icr); + return m_icr; +} - case TCTL_CLKSOURCE_32KHZ4: - case TCTL_CLKSOURCE_32KHZ5: - case TCTL_CLKSOURCE_32KHZ6: - case TCTL_CLKSOURCE_32KHZ7: - frequency = 32768; - break; - } - frequency /= (m_regs.tprer[index] + 1); +void mc68328_base_device::imr_msw_w(offs_t offset, u16 data, u16 mem_mask) // 0x304 +{ + const u32 imr_old = m_imr; + LOGMASKED(LOG_INTS, "%s: imr_msw_w: IMR(MSW) = %04x\n", machine().describe_context(), data); + m_imr &= ~(mem_mask << 16); + m_imr |= (data & mem_mask) << 16; - return frequency; + update_imr_state(imr_old ^ m_imr); } -void mc68328_device::maybe_start_timer(uint32_t index, uint32_t new_enable) +u16 mc68328_base_device::imr_msw_r() // 0x304 { - if ((m_regs.tctl[index] & TCTL_TEN) == TCTL_TEN_ENABLE && (m_regs.tctl[index] & TCTL_CLKSOURCE) > TCTL_CLKSOURCE_STOP) - { - if ((m_regs.tctl[index] & TCTL_CLKSOURCE) == TCTL_CLKSOURCE_TIN) - { - m_gptimer[index]->adjust(attotime::never); - } - else if (m_regs.tcmp[index] == 0) - { - m_gptimer[index]->adjust(attotime::never); - } - else - { - uint32_t frequency = get_timer_frequency(index); - attotime period = (attotime::from_hz(frequency) * m_regs.tcmp[index]); + LOGMASKED(LOG_INTS, "%s: imr_msw_r: IMR(MSW): %04x\n", machine().describe_context(), (u16)(m_imr >> 16)); + return (u16)(m_imr >> 16); +} - if (new_enable) - { - m_regs.tcn[index] = 0x0000; - } +void mc68328_base_device::imr_lsw_w(offs_t offset, u16 data, u16 mem_mask) // 0x306 +{ + const u32 imr_old = m_imr; + LOGMASKED(LOG_INTS, "%s: imr_lsw_w: IMR(LSW) = %04x\n", machine().describe_context(), data); + m_imr &= 0xffff0000 | (~mem_mask); + m_imr |= data & mem_mask; - m_gptimer[index]->adjust(period); - } - } - else - { - m_gptimer[index]->adjust(attotime::never); - } + update_imr_state(imr_old ^ m_imr); +} + +u16 mc68328_base_device::imr_lsw_r() // 0x306 +{ + LOGMASKED(LOG_INTS, "%s: imr_lsw_r: IMR(LSW): %04x\n", machine().describe_context(), (u16)m_imr); + return (u16)m_imr; } -void mc68328_device::timer_compare_event(uint32_t index) +void mc68328_device::iwr_msw_w(offs_t offset, u16 data, u16 mem_mask) // 0x308 { - m_regs.tcn[index] = m_regs.tcmp[index]; - m_regs.tstat[index] |= TSTAT_COMP; + LOGMASKED(LOG_INTS, "%s: iwr_msw_w: IWR(MSW) = %04x\n", machine().describe_context(), data); + m_iwr &= ~(mem_mask << 16); + m_iwr |= (data & mem_mask) << 16; +} - if ((m_regs.tctl[index] & TCTL_FRR) == TCTL_FRR_RESTART) - { - uint32_t frequency = get_timer_frequency(index); +u16 mc68328_device::iwr_msw_r() // 0x308 +{ + LOGMASKED(LOG_INTS, "%s: iwr_msw_r: IWR(MSW): %04x\n", machine().describe_context(), (u16)(m_iwr >> 16)); + return (u16)(m_iwr >> 16); +} - if (frequency > 0) - { - attotime period = attotime::from_hz(frequency) * m_regs.tcmp[index]; +void mc68328_device::iwr_lsw_w(offs_t offset, u16 data, u16 mem_mask) // 0x30a +{ + LOGMASKED(LOG_INTS, "%s: iwr_lsw_w: IWR(LSW) = %04x\n", machine().describe_context(), data); + m_iwr &= 0xffff0000 | (~mem_mask); + m_iwr |= data & mem_mask; +} - m_regs.tcn[index] = 0x0000; +u16 mc68328_device::iwr_lsw_r() // 0x30a +{ + LOGMASKED(LOG_INTS, "%s: iwr_lsw_r: IWR(LSW): %04x\n", machine().describe_context(), (u16)m_iwr); + return (u16)m_iwr; +} - m_gptimer[index]->adjust(period); - } - else - { - m_gptimer[index]->adjust(attotime::never); - } +void mc68328_base_device::isr_msw_w(offs_t offset, u16 data, u16 mem_mask) // 0x30c +{ + LOGMASKED(LOG_INTS, "%s: isr_msw_w: ISR(MSW) = %04x\n", machine().describe_context(), data); + // Clear edge-triggered IRQ1 + if ((m_icr & ICR_ET1) == ICR_ET1 && ((data << 16) & INT_IRQ1_MASK) == INT_IRQ1_MASK) + { + m_gisr &= ~INT_IRQ1_MASK; } - else + + // Clear edge-triggered IRQ2 + if ((m_icr & ICR_ET2) == ICR_ET2 && ((data << 16) & INT_IRQ2_MASK) == INT_IRQ2_MASK) { - uint32_t frequency = get_timer_frequency(index); + m_gisr &= ~INT_IRQ2_MASK; + } - if (frequency > 0) - { - attotime period = attotime::from_hz(frequency) * 0x10000; + // Clear edge-triggered IRQ3 + if ((m_icr & ICR_ET3) == ICR_ET3 && ((data << 16) & INT_IRQ3_MASK) == INT_IRQ3_MASK) + { + m_gisr &= ~INT_IRQ3_MASK; + } - m_gptimer[index]->adjust(period); - } - else - { - m_gptimer[index]->adjust(attotime::never); - } + // Clear edge-triggered IRQ6 + if ((m_icr & ICR_ET6) == ICR_ET6 && ((data << 16) & INT_IRQ6_MASK) == INT_IRQ6_MASK) + { + m_gisr &= ~INT_IRQ6_MASK; } - if ((m_regs.tctl[index] & TCTL_IRQEN) == TCTL_IRQEN_ENABLE) + + // Clear edge-triggered IRQ7 + if (((data << 16) & INT_IRQ7_MASK) == INT_IRQ7_MASK) { - set_interrupt_line((index == 0) ? INT_TIMER1 : INT_TIMER2, 1); + m_gisr &= ~INT_IRQ7_MASK; } } -TIMER_CALLBACK_MEMBER( mc68328_device::timer1_hit ) +u16 mc68328_base_device::isr_msw_r() // 0x30c { - timer_compare_event(0); + LOGMASKED(LOG_INTS, "%s: isr_msw_r: ISR(MSW): %04x\n", machine().describe_context(), (u16)(m_gisr >> 16)); + return (u16)(m_gisr >> 16); } -TIMER_CALLBACK_MEMBER( mc68328_device::timer2_hit ) +void mc68328_base_device::isr_lsw_w(offs_t offset, u16 data, u16 mem_mask) // 0x30e { - timer_compare_event(1); + LOGMASKED(LOG_INTS, "%s: isr_lsw_w: ISR(LSW) = %04x (Ignored)\n", machine().describe_context(), data); } -TIMER_CALLBACK_MEMBER( mc68328_device::pwm_transition ) +u16 mc68328_base_device::isr_lsw_r() // 0x30e { - if (m_regs.pwmw >= m_regs.pwmp || m_regs.pwmw == 0 || m_regs.pwmp == 0) - { - m_pwm->adjust(attotime::never); - return; - } + LOGMASKED(LOG_INTS, "%s: isr_lsw_r: ISR(LSW): %04x\n", machine().describe_context(), (u16)m_gisr); + return (u16)m_gisr; +} - if (((m_regs.pwmc & PWMC_POL) == 0 && (m_regs.pwmc & PWMC_PIN) != 0) || - ((m_regs.pwmc & PWMC_POL) != 0 && (m_regs.pwmc & PWMC_PIN) == 0)) - { - uint32_t frequency = 32768 * 506; - uint32_t divisor = 4 << (m_regs.pwmc & PWMC_CLKSEL); // ?? Datasheet says 2 <<, but then we're an octave higher than CoPilot. - attotime period; +void mc68328_base_device::ipr_msw_w(offs_t offset, u16 data, u16 mem_mask) // 0x310 +{ + LOGMASKED(LOG_INTS, "%s: ipr_msw_w: IPR(MSW) = %04x (Ignored)\n", machine().describe_context(), data); +} - frequency /= divisor; - period = attotime::from_hz(frequency) * (m_regs.pwmp - m_regs.pwmw); +u16 mc68328_base_device::ipr_msw_r() // 0x310 +{ + LOGMASKED(LOG_INTS, "%s: ipr_msw_r: IPR(MSW): %04x\n", machine().describe_context(), (u16)(m_ipr >> 16)); + return (u16)(m_ipr >> 16); +} - m_pwm->adjust(period); +void mc68328_base_device::ipr_lsw_w(offs_t offset, u16 data, u16 mem_mask) // 0x312 +{ + LOGMASKED(LOG_INTS, "%s: ipr_lsw_w: IPR(LSW) = %04x (Ignored)\n", machine().describe_context(), data); +} + +u16 mc68328_base_device::ipr_lsw_r() // 0x312 +{ + LOGMASKED(LOG_INTS, "%s: ipr_lsw_r: IPR(LSW): %04x\n", machine().describe_context(), (u16)m_ipr); + return (u16)m_ipr; +} - if (m_regs.pwmc & PWMC_IRQEN) + +//------------------------------------------------- +// Interrupt-related hardware - EZ variant +//------------------------------------------------- + +int mc68ez328_device::get_irq_level_for_mask(u32 mask) +{ + constexpr u32 IRQ_MASKS[8] = + { + 0, + INT_IRQ1_MASK, + INT_IRQ2_MASK, + INT_IRQ3_MASK, + INT_INT0_MASK | INT_INT1_MASK | INT_INT2_MASK | INT_INT3_MASK | INT_INT4_MASK | INT_INT5_MASK | INT_INT6_MASK | INT_INT7_MASK + | INT_KB_MASK | INT_RTC_MASK | INT_WDT_MASK | INT_UART_MASK | INT_SPIM_MASK, + INT_IRQ5_MASK, + INT_PWM_MASK | INT_TIMER2_MASK | INT_SPIS_MASK, + INT_MEMIQ_MASK, + }; + + for (int level = 1; level <= 7; level++) + { + if (IRQ_MASKS[level] & mask) { - set_interrupt_line(INT_PWM, 1); + return level; } } - else + return 0; +} + +u32 mc68ez328_device::get_irq_mask_for_level(int level) +{ + constexpr u32 IRQ_MASKS[8] = + { + 0, + INT_IRQ1_MASK, + INT_IRQ2_MASK, + INT_IRQ3_MASK, + INT_INT0_MASK | INT_INT1_MASK | INT_INT2_MASK | INT_INT3_MASK | INT_INT4_MASK | INT_INT5_MASK | INT_INT6_MASK | INT_INT7_MASK + | INT_KB_MASK | INT_RTC_MASK | INT_WDT_MASK | INT_UART_MASK | INT_SPIM_MASK, + INT_IRQ5_MASK, + INT_PWM_MASK | INT_TIMER2_MASK | INT_SPIS_MASK, + INT_MEMIQ_MASK, + }; + if (level >= 0 && level <= 7) { - uint32_t frequency = 32768 * 506; - uint32_t divisor = 4 << (m_regs.pwmc & PWMC_CLKSEL); // ?? Datasheet says 2 <<, but then we're an octave higher than CoPilot. - attotime period; + return IRQ_MASKS[level]; + } + return 0; +} - frequency /= divisor; - period = attotime::from_hz(frequency) * m_regs.pwmw; - m_pwm->adjust(period); - } +//------------------------------------------------- +// GPIO hardware - Port A +//------------------------------------------------- - m_regs.pwmc ^= PWMC_PIN; +void mc68328_base_device::padir_w(u8 data) // 0x400 +{ + LOGMASKED(LOG_GPIO_A, "%s: padir_w: PADIR = %02x\n", machine().describe_context(), data); + m_padir = data; +} - if (!m_out_pwm_cb.isnull()) - { - m_out_pwm_cb((offs_t)0, (m_regs.pwmc & PWMC_PIN) ? 1 : 0); - } +u8 mc68328_base_device::padir_r() // 0x400 +{ + LOGMASKED(LOG_GPIO_A, "%s: mc68328_r: PADIR: %02x\n", machine().describe_context(), m_padir); + return m_padir; } -TIMER_CALLBACK_MEMBER( mc68328_device::rtc_tick ) +void mc68328_base_device::padata_w(u8 data) // 0x401 { - if (m_regs.rtcctl & RTCCTL_ENABLE) + LOGMASKED(LOG_GPIO_A, "%s: padata_w: PADATA = %02x\n", machine().describe_context(), data); + m_padata = data; + for (int i = 0; i < 8; i++) { - uint32_t set_int = 0; - - m_regs.hmsr++; - - if (m_regs.rtcienr & RTCINT_SECOND) + if (BIT(m_padir & m_pasel, i)) { - set_int = 1; - m_regs.rtcisr |= RTCINT_SECOND; + m_out_port_a_cb[i](BIT(m_padata, i)); } + } +} - if ((m_regs.hmsr & 0x0000003f) == 0x0000003c) +u8 mc68328_base_device::padata_r() // 0x401 +{ + u8 data = 0; + for (int i = 0; i < 8; i++) + { + if (BIT(m_pasel, i)) { - m_regs.hmsr &= 0xffffffc0; - m_regs.hmsr += 0x00010000; - - if (m_regs.rtcienr & RTCINT_MINUTE) + if (BIT(m_padir, i)) { - set_int = 1; - m_regs.rtcisr |= RTCINT_MINUTE; + data |= m_padata & (1 << i); } - - if ((m_regs.hmsr & 0x003f0000) == 0x003c0000) + else if (!m_in_port_a_cb[i].isunset()) { - m_regs.hmsr &= 0xffc0ffff; - m_regs.hmsr += 0x0100000; + data |= m_in_port_a_cb[i]() << i; + } + } + } + LOGMASKED(LOG_GPIO_A, "%s: padata_r: PADATA: %02x\n", machine().describe_context(), data); + return data; +} - if ((m_regs.hmsr & 0x1f000000) == 0x18000000) - { - m_regs.hmsr &= 0xe0ffffff; +void mc68328_device::pasel_w(u8 data) // 0x403 +{ + LOGMASKED(LOG_GPIO_A, "%s: pasel_w: PASEL = %02x\n", machine().describe_context(), data); + m_pasel = data; +} - if (m_regs.rtcienr & RTCINT_DAY) - { - set_int = 1; - m_regs.rtcisr |= RTCINT_DAY; - } - } - } +u8 mc68328_device::pasel_r() // 0x403 +{ + LOGMASKED(LOG_GPIO_A, "%s: mc68328_r: PASEL: %02x\n", machine().describe_context(), m_pasel); + return m_pasel; +} - if (m_regs.stpwtch != 0x003f) - { - m_regs.stpwtch--; - m_regs.stpwtch &= 0x003f; - if (m_regs.stpwtch == 0x003f) - { - if (m_regs.rtcienr & RTCINT_STOPWATCH) - { - set_int = 1; - m_regs.rtcisr |= RTCINT_STOPWATCH; - } - } - } +//------------------------------------------------- +// GPIO hardware - Port B +//------------------------------------------------- + +void mc68328_base_device::pbdir_w(u8 data) // 0x408 +{ + LOGMASKED(LOG_GPIO_B, "%s: pbdir_w: PBDIR = %02x\n", machine().describe_context(), data); + m_pbdir = data; +} + +u8 mc68328_base_device::pbdir_r() // 0x408 +{ + LOGMASKED(LOG_GPIO_B, "%s: pbdir_r: PBDIR: %02x\n", machine().describe_context(), m_pbdir); + return m_pbdir; +} + +void mc68328_base_device::pbdata_w(u8 data) // 0x409 +{ + LOGMASKED(LOG_GPIO_B, "%s: pbdata_w: PBDATA = %02x (outputing %02x)\n", machine().describe_context(), data, data & m_pbdir & m_pbsel); + m_pbdata = data; + for (int i = 0; i < 8; i++) + { + if (BIT(m_pbdir & m_pbsel, i)) + { + m_out_port_b_cb[i](BIT(m_pbdata, i)); } + } +} - if (m_regs.hmsr == m_regs.alarm) +u8 mc68328_base_device::pbdata_r() // 0x409 +{ + u8 data = 0; + for (int i = 0; i < 8; i++) + { + if (BIT(m_pbsel, i)) { - if (m_regs.rtcienr & RTCINT_ALARM) + if (BIT(m_pbdir, i)) { - set_int = 1; - m_regs.rtcisr |= RTCINT_STOPWATCH; + data |= m_pbdata & (1 << i); + } + else if (!m_in_port_b_cb[i].isunset()) + { + data |= m_in_port_b_cb[i]() << i; } } + } + LOGMASKED(LOG_GPIO_B, "%s: pbdata_r: PBDATA: %02x\n", machine().describe_context(), data); + return data; +} + +void mc68328_base_device::pbsel_w(u8 data) // 0x40b +{ + LOGMASKED(LOG_GPIO_B, "%s: pbsel_w: PBSEL = %02x\n", machine().describe_context(), data); + m_pbsel = data; +} + +u8 mc68328_base_device::pbsel_r() // 0x40b +{ + LOGMASKED(LOG_GPIO_B, "%s: pbsel_r: PBSEL: %02x\n", machine().describe_context(), m_pbsel); + return m_pbsel; +} + + +//------------------------------------------------- +// GPIO hardware - Port C +//------------------------------------------------- - if (set_int) +void mc68328_base_device::pcdir_w(u8 data) // 0x410 +{ + LOGMASKED(LOG_GPIO_C, "%s: pcdir_w: PCDIR = %02x\n", machine().describe_context(), data); + m_pcdir = data; +} + +u8 mc68328_base_device::pcdir_r() // 0x410 +{ + LOGMASKED(LOG_GPIO_C, "%s: pcdir_r: PCDIR: %02x\n", machine().describe_context(), m_pcdir); + return m_pcdir; +} + +void mc68328_base_device::pcdata_w(u8 data) // 0x411 +{ + LOGMASKED(LOG_GPIO_C, "%s: pcdata_w: PCDATA = %02x (outputing %02x)\n", machine().describe_context(), data, data & m_pcdir & m_pcsel); + m_pcdata = data; + for (int i = 0; i < 8; i++) + { + if (BIT(m_pcdir & m_pcsel, i)) { - set_interrupt_line(INT_RTC, 1); + m_out_port_c_cb[i](BIT(m_pcdata, i)); } - else + else if (BIT(~m_pcdir & m_pcsel, i)) { - set_interrupt_line(INT_RTC, 0); + m_out_port_c_cb[i](1); } } } -void mc68328_device::internal_write(offs_t offset, uint16_t data, uint16_t mem_mask) +u8 mc68328_base_device::pcdata_r() // 0x411 { - uint32_t address = offset << 1; - uint16_t temp16[4] = { 0 }; - uint32_t imr_old = m_regs.imr, imr_diff; - - switch (address) + u8 data = 0; + for (int i = 0; i < 8; i++) { - case 0x000: - if (mem_mask & 0x00ff) + if (BIT(m_pcsel, i)) + { + if (BIT(m_pcdir, i)) { - verboselog( *this, 2, "mc68328_w: Unknown address (0xfff001) = %02x\n", data & 0x00ff); + data |= m_pcdata & (1 << i); } - else + else if (!m_in_port_c_cb[i].isunset()) { - verboselog( *this, 2, "mc68328_w: SCR = %02x\n", (data >> 8) & 0x00ff); + data |= m_in_port_c_cb[i]() << i; } - break; - - case 0x100: - verboselog( *this, 2, "mc68328_w: GRPBASEA = %04x\n", data); - m_regs.grpbasea = data; - break; - - case 0x102: - verboselog( *this, 2, "mc68328_w: GRPBASEB = %04x\n", data); - m_regs.grpbaseb = data; - break; - - case 0x104: - verboselog( *this, 2, "mc68328_w: GRPBASEC = %04x\n", data); - m_regs.grpbasec = data; - break; - - case 0x106: - verboselog( *this, 2, "mc68328_w: GRPBASED = %04x\n", data); - m_regs.grpbased = data; - break; - - case 0x108: - verboselog( *this, 2, "mc68328_w: GRPMASKA = %04x\n", data); - m_regs.grpmaska = data; - break; + } + } + LOGMASKED(LOG_GPIO_C, "%s: pcdata_r: PCDATA: %02x\n", machine().describe_context(), data); + return data; +} - case 0x10a: - verboselog( *this, 2, "mc68328_w: GRPMASKB = %04x\n", data); - m_regs.grpmaskb = data; - break; +void mc68328_base_device::pcsel_w(u8 data) // 0x413 +{ + LOGMASKED(LOG_GPIO_C, "%s: pcsel_w: PCSEL = %02x\n", machine().describe_context(), data); + m_pcsel = data; +} - case 0x10c: - verboselog( *this, 2, "mc68328_w: GRPMASKC = %04x\n", data); - m_regs.grpmaskc = data; - break; +u8 mc68328_base_device::pcsel_r() // 0x413 +{ + LOGMASKED(LOG_GPIO_C, "%s: pcsel_r: PCSEL: %02x\n", machine().describe_context(), m_pcsel); + return m_pcsel; +} - case 0x10e: - verboselog( *this, 2, "mc68328_w: GRPMASKD = %04x\n", data); - m_regs.grpmaskd = data; - break; - case 0x110: - verboselog( *this, 5, "mc68328_w: CSA0(0) = %04x\n", data); - m_regs.csa0 &= 0xffff0000 | (~mem_mask); - m_regs.csa0 |= data & mem_mask; - break; +//------------------------------------------------- +// GPIO hardware - Port D +//------------------------------------------------- - case 0x112: - verboselog( *this, 5, "mc68328_w: CSA0(16) = %04x\n", data); - m_regs.csa0 &= ~(mem_mask << 16); - m_regs.csa0 |= (data & mem_mask) << 16; - break; +void mc68328_base_device::port_d_in_w(int state, int bit) +{ + const u8 old_state = m_pdindata; + m_pdindata &= ~(1 << bit); + m_pdindata |= state << bit; - case 0x114: - verboselog( *this, 5, "mc68328_w: CSA1(0) = %04x\n", data); - m_regs.csa1 &= 0xffff0000 | (~mem_mask); - m_regs.csa1 |= data & mem_mask; - break; + // If no bit has changed state, there's nothing to do. + if (old_state == m_pdindata) + { + return; + } - case 0x116: - verboselog( *this, 5, "mc68328_w: CSA1(16) = %04x\n", data); - m_regs.csa1 &= ~(mem_mask << 16); - m_regs.csa1 |= (data & mem_mask) << 16; - break; + // If we're not edge-triggered, handle potential level-sensitive interrupts. + if (!BIT(m_pdirqedge, bit)) + { + // If the new state is low while PDPOL is active-low (0) or vice-versa, assert the interrupt for this bit. + // Otherwise, clear it. + set_interrupt_line(INT_KBDINTS + bit, (int)(state == BIT(m_pdpol, bit))); + return; + } - case 0x118: - verboselog( *this, 5, "mc68328_w: CSA2(0) = %04x\n", data); - m_regs.csa2 &= 0xffff0000 | (~mem_mask); - m_regs.csa2 |= data & mem_mask; - break; + set_interrupt_line(INT_KBDINTS + bit, 1); +} - case 0x11a: - verboselog( *this, 5, "mc68328_w: CSA2(16) = %04x\n", data); - m_regs.csa2 &= ~(mem_mask << 16); - m_regs.csa2 |= (data & mem_mask) << 16; - break; +void mc68328_base_device::pddir_w(u8 data) // 0x418 +{ + LOGMASKED(LOG_GPIO_D, "%s: pddir_w: PDDIR = %02x\n", machine().describe_context(), data); + m_pddir = data; +} - case 0x11c: - verboselog( *this, 5, "mc68328_w: CSA3(0) = %04x\n", data); - m_regs.csa3 &= 0xffff0000 | (~mem_mask); - m_regs.csa3 |= data & mem_mask; - break; +u8 mc68328_base_device::pddir_r() // 0x418 +{ + LOGMASKED(LOG_GPIO_D, "%s: pddir_r: PDDIR: %02x\n", machine().describe_context(), m_pddir); + return m_pddir; +} - case 0x11e: - verboselog( *this, 5, "mc68328_w: CSA3(16) = %04x\n", data); - m_regs.csa3 &= ~(mem_mask << 16); - m_regs.csa3 |= (data & mem_mask) << 16; - break; +void mc68328_base_device::pddata_w(u8 data) // 0x419 +{ + LOGMASKED(LOG_GPIO_D, "%s: pddata_w: PDDATA = %02x (outputing %02x)\n", machine().describe_context(), data, data & m_pddir); + m_pddata = data; - case 0x120: - verboselog( *this, 5, "mc68328_w: CSB0(0) = %04x\n", data); - m_regs.csb0 &= 0xffff0000 | (~mem_mask); - m_regs.csb0 |= data & mem_mask; - break; + for (int bit = 0; bit < 4; bit++) + { + if (BIT(m_pdirqedge & data, bit)) + { + set_interrupt_line(INT_KBDINTS + bit, 0); + } + } - case 0x122: - verboselog( *this, 5, "mc68328_w: CSB0(16) = %04x\n", data); - m_regs.csb0 &= ~(mem_mask << 16); - m_regs.csb0 |= (data & mem_mask) << 16; - break; + for (int i = 0; i < 8; i++) + { + if (BIT(m_pddir, i)) + { + m_out_port_d_cb[i](BIT(m_pddata, i)); + } + } +} - case 0x124: - verboselog( *this, 5, "mc68328_w: CSB1(0) = %04x\n", data); - m_regs.csb1 &= 0xffff0000 | (~mem_mask); - m_regs.csb1 |= data & mem_mask; - break; +u8 mc68328_base_device::pddata_r() // 0x419 +{ + u8 data = 0; + for (int i = 0; i < 8; i++) + { + if (BIT(m_pddir, i)) + { + data |= m_pddata & (1 << i); + } + else if (!m_in_port_d_cb[i].isunset()) + { + data |= m_in_port_d_cb[i]() << i; + } + else + { + data |= m_pdpuen & (1 << i); + } + } + LOGMASKED(LOG_GPIO_D, "%s: pddata_r: PDDATA: %02x\n", machine().describe_context(), data); + return data; +} - case 0x126: - verboselog( *this, 5, "mc68328_w: CSB1(16) = %04x\n", data); - m_regs.csb1 &= ~(mem_mask << 16); - m_regs.csb1 |= (data & mem_mask) << 16; - break; +void mc68328_base_device::pdpuen_w(u8 data) // 0x41a +{ + LOGMASKED(LOG_GPIO_D, "%s: pdpuen_w: PDPUEN = %02x\n", machine().describe_context(), data); + m_pdpuen = data; +} - case 0x128: - verboselog( *this, 5, "mc68328_w: CSB2(0) = %04x\n", data); - m_regs.csb2 &= 0xffff0000 | (~mem_mask); - m_regs.csb2 |= data & mem_mask; - break; +u8 mc68328_base_device::pdpuen_r() // 0x41a +{ + LOGMASKED(LOG_GPIO_D, "%s: pdpuen_r: PDPUEN: %02x\n", machine().describe_context(), m_pdpuen); + return m_pdpuen; +} - case 0x12a: - verboselog( *this, 5, "mc68328_w: CSB2(16) = %04x\n", data); - m_regs.csb2 &= ~(mem_mask << 16); - m_regs.csb2 |= (data & mem_mask) << 16; - break; +void mc68328_base_device::pdpol_w(u8 data) // 0x41c +{ + LOGMASKED(LOG_GPIO_D, "%s: pdpol_w: PDPOL = %02x\n", machine().describe_context(), data); + m_pdpol = data; +} - case 0x12c: - verboselog( *this, 5, "mc68328_w: CSB3(0) = %04x\n", data); - m_regs.csb3 &= 0xffff0000 | (~mem_mask); - m_regs.csb3 |= data & mem_mask; - break; +u8 mc68328_base_device::pdpol_r() // 0x41c +{ + LOGMASKED(LOG_GPIO_D, "%s: pdpol_r: PDPOL: %02x\n", machine().describe_context(), m_pdpol); + return m_pdpol; +} - case 0x12e: - verboselog( *this, 5, "mc68328_w: CSB3(16) = %04x\n", data); - m_regs.csb3 &= ~(mem_mask << 16); - m_regs.csb3 |= (data & mem_mask) << 16; - break; +void mc68328_base_device::pdirqen_w(u8 data) // 0x41d +{ + LOGMASKED(LOG_GPIO_D, "%s: pdirqen_w: PDIRQEN = %02x\n", machine().describe_context(), data); + m_pdirqen = data & 0x00ff; +} - case 0x130: - verboselog( *this, 5, "mc68328_w: CSC0(0) = %04x\n", data); - m_regs.csc0 &= 0xffff0000 | (~mem_mask); - m_regs.csc0 |= data & mem_mask; - break; +u8 mc68328_base_device::pdirqen_r() // 0x41d +{ + LOGMASKED(LOG_GPIO_D, "%s: pdirqen_r: PDIRQEN: %02x\n", machine().describe_context(), m_pdirqen); + return m_pdirqen; +} - case 0x132: - verboselog( *this, 5, "mc68328_w: CSC0(16) = %04x\n", data); - m_regs.csc0 &= ~(mem_mask << 16); - m_regs.csc0 |= (data & mem_mask) << 16; - break; +void mc68328_base_device::pdirqedge_w(u8 data) // 0x41f +{ + LOGMASKED(LOG_GPIO_D, "%s: pdirqedge_w: PDIRQEDGE = %02x\n", machine().describe_context(), data); + m_pdirqedge = data; +} - case 0x134: - verboselog( *this, 5, "mc68328_w: CSC1(0) = %04x\n", data); - m_regs.csc1 &= 0xffff0000 | (~mem_mask); - m_regs.csc1 |= data & mem_mask; - break; +u8 mc68328_base_device::pdirqedge_r() // 0x41f +{ + LOGMASKED(LOG_GPIO_D, "%s: pdirqedge_r: PDIRQEDGE: %02x\n", machine().describe_context(), m_pdirqedge); + return m_pdirqedge; +} - case 0x136: - verboselog( *this, 5, "mc68328_w: CSC1(16) = %04x\n", data); - m_regs.csc1 &= ~(mem_mask << 16); - m_regs.csc1 |= (data & mem_mask) << 16; - break; - case 0x138: - verboselog( *this, 5, "mc68328_w: CSC2(0) = %04x\n", data); - m_regs.csc2 &= 0xffff0000 | (~mem_mask); - m_regs.csc2 |= data & mem_mask; - break; +//------------------------------------------------- +// GPIO hardware - Port E +//------------------------------------------------- - case 0x13a: - verboselog( *this, 5, "mc68328_w: CSC2(16) = %04x\n", data); - m_regs.csc2 &= ~(mem_mask << 16); - m_regs.csc2 |= (data & mem_mask) << 16; - break; +void mc68328_base_device::pedir_w(u8 data) // 0x420 +{ + LOGMASKED(LOG_GPIO_E, "%s: pedir_w: PEDIR = %02x\n", machine().describe_context(), data); + m_pedir = data; +} - case 0x13c: - verboselog( *this, 5, "mc68328_w: CSC3(0) = %04x\n", data); - m_regs.csc3 &= 0xffff0000 | (~mem_mask); - m_regs.csc3 |= data & mem_mask; - break; +u8 mc68328_base_device::pedir_r() // 0x420 +{ + LOGMASKED(LOG_GPIO_E, "%s: pedir_r: PEDIR: %02x\n", machine().describe_context(), m_pedir); + return m_pedir; +} - case 0x13e: - verboselog( *this, 5, "mc68328_w: CSC3(16) = %04x\n", data); - m_regs.csc3 &= ~(mem_mask << 16); - m_regs.csc3 |= (data & mem_mask) << 16; - break; +void mc68328_base_device::pedata_w(u8 data) // 0x421 +{ + LOGMASKED(LOG_GPIO_E, "%s: pedata_w: PEDATA = %02x (outputing %02x)\n", machine().describe_context(), data, data & m_pedir & m_pesel); + m_pedata = data; + for (int i = 0; i < 8; i++) + { + if (BIT(m_pedir & m_pesel, i)) + { + m_out_port_e_cb[i](BIT(m_pedata, i)); + } + } +} - case 0x140: - verboselog( *this, 5, "mc68328_w: CSD0(0) = %04x\n", data); - m_regs.csd0 &= 0xffff0000 | (~mem_mask); - m_regs.csd0 |= data & mem_mask; - break; +u8 mc68328_base_device::pedata_r() // 0x421 +{ + u8 data = 0; + for (int i = 0; i < 8; i++) + { + if (BIT(m_pesel, i)) + { + if (BIT(m_pedir, i)) + { + data |= m_pedata & (1 << i); + } + else if (!m_in_port_e_cb[i].isunset()) + { + data |= m_in_port_e_cb[i]() << i; + } + else + { + data |= m_pepuen & (1 << i); + } + } + } + LOGMASKED(LOG_GPIO_E, "%s: pedata_r: PEDATA: %02x\n", machine().describe_context(), data); + return data; +} - case 0x142: - verboselog( *this, 5, "mc68328_w: CSD0(16) = %04x\n", data); - m_regs.csd0 &= ~(mem_mask << 16); - m_regs.csd0 |= (data & mem_mask) << 16; - break; +void mc68328_base_device::pepuen_w(u8 data) // 0x422 +{ + LOGMASKED(LOG_GPIO_E, "%s: pepuen_w: PEPUEN = %02x\n", machine().describe_context(), data); + m_pepuen = data; +} - case 0x144: - verboselog( *this, 5, "mc68328_w: CSD1(0) = %04x\n", data); - m_regs.csd1 &= 0xffff0000 | (~mem_mask); - m_regs.csd1 |= data & mem_mask; - break; +u8 mc68328_base_device::pepuen_r() // 0x422 +{ + LOGMASKED(LOG_GPIO_E, "%s: pepuen_r: PEPUEN: %02x\n", machine().describe_context(), m_pepuen); + return m_pepuen; +} - case 0x146: - verboselog( *this, 5, "mc68328_w: CSD1(16) = %04x\n", data); - m_regs.csd1 &= ~(mem_mask << 16); - m_regs.csd1 |= (data & mem_mask) << 16; - break; +void mc68328_base_device::pesel_w(u8 data) // 0x423 +{ + LOGMASKED(LOG_GPIO_E, "%s: pesel_w: PESEL = %02x\n", machine().describe_context(), data); + m_pesel = data; +} - case 0x148: - verboselog( *this, 5, "mc68328_w: CSD2(0) = %04x\n", data); - m_regs.csd2 &= 0xffff0000 | (~mem_mask); - m_regs.csd2 |= data & mem_mask; - break; +u8 mc68328_base_device::pesel_r() // 0x423 +{ + LOGMASKED(LOG_GPIO_E, "%s: pesel_r: PESEL: %02x\n", machine().describe_context(), m_pesel); + return m_pesel; +} - case 0x14a: - verboselog( *this, 5, "mc68328_w: CSD2(16) = %04x\n", data); - m_regs.csd2 &= ~(mem_mask << 16); - m_regs.csd2 |= (data & mem_mask) << 16; - break; - case 0x14c: - verboselog( *this, 5, "mc68328_w: CSD3(0) = %04x\n", data); - m_regs.csd3 &= 0xffff0000 | (~mem_mask); - m_regs.csd3 |= data & mem_mask; - break; +//------------------------------------------------- +// GPIO hardware - Port F +//------------------------------------------------- - case 0x14e: - verboselog( *this, 5, "mc68328_w: CSD3(16) = %04x\n", data); - m_regs.csd3 &= ~(mem_mask << 16); - m_regs.csd3 |= (data & mem_mask) << 16; - break; +void mc68328_base_device::pfdir_w(u8 data) // 0x428 +{ + LOGMASKED(LOG_GPIO_F, "%s: pfdir_w: PFDIR = %02x\n", machine().describe_context(), data); + m_pfdir = data; +} - case 0x200: - verboselog( *this, 2, "mc68328_w: PLLCR = %04x\n", data); - m_regs.pllcr = data; - break; +u8 mc68328_base_device::pfdir_r() // 0x428 +{ + LOGMASKED(LOG_GPIO_F, "%s: pfdir_r: PFDIR: %02x\n", machine().describe_context(), m_pfdir); + return m_pfdir; +} - case 0x202: - verboselog( *this, 2, "mc68328_w: PLLFSR = %04x\n", data); - m_regs.pllfsr = data; - break; +void mc68328_base_device::pfdata_w(u8 data) // 0x429 +{ + LOGMASKED(LOG_GPIO_F, "%s: pfdata_w: PFDATA = %02x (outputing %02x)\n", machine().describe_context(), data, data & m_pfdir & m_pfsel); + m_pfdata = data; + for (int i = 0; i < 8; i++) + { + if (BIT(m_pfdir & m_pfsel, i)) + { + m_out_port_f_cb[i](BIT(m_pfdata, i)); + } + } +} - case 0x206: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: PCTLR = %02x\n", data & 0x00ff); - m_regs.pctlr = data & 0x00ff; - } - else +u8 mc68328_base_device::pfdata_r() // 0x429 +{ + u8 data = 0; + for (int i = 0; i < 8; i++) + { + if (BIT(m_pfsel, i)) + { + if (BIT(m_pfdir, i)) { - verboselog( *this, 2, "mc68328_w: Unknown address (0xfff206) = %02x\n", (data >> 8) & 0x00ff); + data |= m_pfdata & (1 << i); } - break; - - case 0x300: - if (mem_mask & 0x00ff) + else if (!m_in_port_f_cb[i].isunset()) { - verboselog( *this, 2, "mc68328_w: Unknown address (0xfff301) = %02x\n", data & 0x00ff); + data |= m_in_port_f_cb[i]() << i; } else { - verboselog( *this, 2, "mc68328_w: IVR = %02x\n", (data >> 8) & 0x00f8); - m_regs.ivr = (data >> 8) & 0x00f8; + data |= m_pfpuen & (1 << i); } - break; + } + } + LOGMASKED(LOG_GPIO_F, "%s: pfdata_r: PFDATA: %02x\n", machine().describe_context(), data); + return data; +} - case 0x302: - verboselog( *this, 2, "mc68328_w: ICR = %04x\n", data); - m_regs.icr = data; - break; +void mc68328_base_device::pfpuen_w(u8 data) // 0x42a +{ + LOGMASKED(LOG_GPIO_F, "%s: pfpuen_w: PFPUEN = %02x\n", machine().describe_context(), data); + m_pfpuen = data; +} - case 0x304: - verboselog( *this, 2, "mc68328_w: IMR(16) = %04x\n", data); - m_regs.imr &= ~(mem_mask << 16); - m_regs.imr |= (data & mem_mask) << 16; - m_regs.isr &= ~((data & mem_mask) << 16); +u8 mc68328_base_device::pfpuen_r() // 0x42a +{ + LOGMASKED(LOG_GPIO_F, "%s: pfpuen_r: PFPUEN: %02x\n", machine().describe_context(), m_pfpuen); + return m_pfpuen; +} - imr_diff = imr_old ^ m_regs.imr; - set_interrupt_line(imr_diff, 0); - break; +void mc68328_base_device::pfsel_w(u8 data) // 0x42b +{ + LOGMASKED(LOG_GPIO_F, "%s: pfsel_w: PFSEL = %02x\n", machine().describe_context(), data); + m_pfsel = data; +} - case 0x306: - verboselog( *this, 2, "mc68328_w: IMR(0) = %04x\n", data); - m_regs.imr &= 0xffff0000 | (~mem_mask); - m_regs.imr |= data & mem_mask; - m_regs.isr &= ~(data & mem_mask); +u8 mc68328_base_device::pfsel_r() // 0x42b +{ + LOGMASKED(LOG_GPIO_F, "%s: pfsel_r: PFSEL: %02x\n", machine().describe_context(), m_pfsel); + return m_pfsel; +} - imr_diff = imr_old ^ m_regs.imr; - set_interrupt_line(imr_diff, 0); - break; - case 0x308: - verboselog( *this, 2, "mc68328_w: IWR(16) = %04x\n", data); - m_regs.iwr &= ~(mem_mask << 16); - m_regs.iwr |= (data & mem_mask) << 16; - break; +//------------------------------------------------- +// GPIO hardware - Port G +//------------------------------------------------- - case 0x30a: - verboselog( *this, 2, "mc68328_w: IWR(0) = %04x\n", data); - m_regs.iwr &= 0xffff0000 | (~mem_mask); - m_regs.iwr |= data & mem_mask; - break; +void mc68328_base_device::pgdir_w(u8 data) // 0x430 +{ + LOGMASKED(LOG_GPIO_G, "%s: pgdir_w: PGDIR = %02x\n", machine().describe_context(), data); + m_pgdir = data; +} - case 0x30c: - verboselog( *this, 2, "mc68328_w: ISR(16) = %04x\n", data); - // Clear edge-triggered IRQ1 - if ((m_regs.icr & ICR_ET1) == ICR_ET1 && (data & INT_IRQ1_SHIFT) == INT_IRQ1_SHIFT) - { - m_regs.isr &= ~INT_IRQ1; - } +u8 mc68328_base_device::pgdir_r() // 0x430 +{ + LOGMASKED(LOG_GPIO_G, "%s: pgdir_r: PGDIR: %02x\n", machine().describe_context(), m_pgdir); + return m_pgdir; +} - // Clear edge-triggered IRQ2 - if ((m_regs.icr & ICR_ET2) == ICR_ET2 && (data & INT_IRQ2_SHIFT) == INT_IRQ2_SHIFT) - { - m_regs.isr &= ~INT_IRQ2; - } +void mc68328_base_device::pgdata_w(u8 data) // 0x431 +{ + LOGMASKED(LOG_GPIO_G, "%s: pgdata_w: PGDATA = %02x (outputing %02x)\n", machine().describe_context(), data, data & m_pgdir & m_pgsel); + m_pgdata = data; + for (int i = 0; i < 8; i++) + { + if (BIT(m_pgdir & m_pgsel, i)) + { + m_out_port_g_cb[i](BIT(m_pgdata, i)); + } + } +} - // Clear edge-triggered IRQ3 - if ((m_regs.icr & ICR_ET3) == ICR_ET3 && (data & INT_IRQ3_SHIFT) == INT_IRQ3_SHIFT) +u8 mc68328_base_device::pgdata_r() // 0x431 +{ + u8 data = 0; + for (int i = 0; i < 8; i++) + { + if (BIT(m_pgsel, i)) + { + if (BIT(m_pgdir, i)) { - m_regs.isr &= ~INT_IRQ3; + data |= m_pgdata & (1 << i); } - - // Clear edge-triggered IRQ6 - if ((m_regs.icr & ICR_ET6) == ICR_ET6 && (data & INT_IRQ6_SHIFT) == INT_IRQ6_SHIFT) + else if (!m_in_port_g_cb[i].isunset()) { - m_regs.isr &= ~INT_IRQ6; + data |= m_in_port_g_cb[i]() << i; } - - // Clear edge-triggered IRQ7 - if ((data & INT_IRQ7_SHIFT) == INT_IRQ7_SHIFT) + else { - m_regs.isr &= ~INT_IRQ7; + data |= m_pgpuen & (1 << i); } - break; + } + } + LOGMASKED(LOG_GPIO_G, "%s: pgdata_r: PGDATA: %02x\n", machine().describe_context(), data); + return data; +} - case 0x30e: - verboselog( *this, 2, "mc68328_w: ISR(0) = %04x (Ignored)\n", data); - break; +void mc68328_base_device::pgpuen_w(u8 data) // 0x432 +{ + LOGMASKED(LOG_GPIO_G, "%s: pgpuen_w: PGPUEN = %02x\n", machine().describe_context(), data); + m_pgpuen = data; +} - case 0x310: - verboselog( *this, 2, "mc68328_w: IPR(16) = %04x (Ignored)\n", data); - break; +u8 mc68328_base_device::pgpuen_r() // 0x432 +{ + LOGMASKED(LOG_GPIO_G, "%s: pgpuen_r: PGPUEN: %02x\n", machine().describe_context(), m_pgpuen); + return m_pgpuen; +} - case 0x312: - verboselog( *this, 2, "mc68328_w: IPR(0) = %04x (Ignored)\n", data); - break; +void mc68328_base_device::pgsel_w(u8 data) // 0x433 +{ + LOGMASKED(LOG_GPIO_G, "%s: pgsel_w: PGSEL = %02x\n", machine().describe_context(), data); + m_pgsel = data; +} - case 0x400: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: PADATA = %02x\n", data & 0x00ff); - m_regs.padata = data & 0x00ff; - if (!m_out_port_a_cb.isnull()) - { - m_out_port_a_cb((offs_t)0, data & 0x00ff); - } - } - else - { - verboselog( *this, 2, "mc68328_w: PADIR = %02x\n", (data >> 8) & 0x00ff); - m_regs.padir = (data >> 8) & 0x00ff; - } - break; +u8 mc68328_base_device::pgsel_r() // 0x433 +{ + LOGMASKED(LOG_GPIO_G, "%s: pgsel_r: PGSEL: %02x\n", machine().describe_context(), m_pgsel); + return m_pgsel; +} - case 0x402: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: PASEL = %02x\n", data & 0x00ff); - m_regs.pasel = data & 0x00ff; - } - else - { - verboselog( *this, 2, "mc68328_w: Unknown address (0xfff402) = %02x\n", (data >> 8) & 0x00ff); - } - break; - case 0x408: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: PBDATA = %02x\n", data & 0x00ff); - m_regs.pbdata = data & 0x00ff; - if (!m_out_port_b_cb.isnull()) - { - m_out_port_b_cb((offs_t)0, data & 0x00ff); - } - } - else - { - verboselog( *this, 2, "mc68328_w: PBDIR = %02x\n", (data >> 8) & 0x00ff); - m_regs.pbdir = (data >> 8) & 0x00ff; - } - break; +//------------------------------------------------- +// GPIO hardware - Port J +//------------------------------------------------- - case 0x40a: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: PBSEL = %02x\n", data & 0x00ff); - m_regs.pbsel = data & 0x00ff; - } - else - { - verboselog( *this, 2, "mc68328_w: Unknown address (0xfff40a) = %02x\n", (data >> 8) & 0x00ff); - } - break; +void mc68328_device::pjdir_w(u8 data) // 0x438 +{ + LOGMASKED(LOG_GPIO_J, "%s: pjdir_w: PJDIR = %02x\n", machine().describe_context(), data); + m_pjdir = data; +} - case 0x410: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: PCDATA = %02x\n", data & 0x00ff); - m_regs.pcdata = data & 0x00ff; - if (!m_out_port_c_cb.isnull()) - { - m_out_port_c_cb((offs_t)0, data & 0x00ff); - } - } - else - { - verboselog( *this, 2, "mc68328_w: PCDIR = %02x\n", (data >> 8) & 0x00ff); - m_regs.pcdir = (data >> 8) & 0x00ff; - } - break; +u8 mc68328_device::pjdir_r() // 0x438 +{ + LOGMASKED(LOG_GPIO_J, "%s: pjdir_r: PJDIR: %02x\n", machine().describe_context(), m_pjdir); + return m_pjdir; +} - case 0x412: - if (mem_mask & 0x00ff) +void mc68328_device::pjdata_w(u8 data) // 0x439 +{ + LOGMASKED(LOG_GPIO_J, "%s: pjdata_w: PJDATA = %02x\n", machine().describe_context(), data); + m_pjdata = data; + for (int i = 0; i < 8; i++) + { + if (BIT(m_pjdir & m_pjsel, i)) + { + m_out_port_j_cb[i](BIT(m_pjdata, i)); + } + } +} + +u8 mc68328_device::pjdata_r() // 0x439 +{ + u8 data = 0; + for (int i = 0; i < 8; i++) + { + if (BIT(m_pjsel, i)) + { + if (BIT(m_pjdir, i)) { - verboselog( *this, 2, "mc68328_w: PCSEL = %02x\n", data & 0x00ff); - m_regs.pcsel = data & 0x00ff; + data |= m_pjdata & (1 << i); } - else + else if (!m_in_port_j_cb[i].isunset()) { - verboselog( *this, 2, "mc68328_w: Unknown address (0xfff412) = %02x\n", (data >> 8) & 0x00ff); + data |= m_in_port_j_cb[i]() << i; } - break; + } + } + LOGMASKED(LOG_GPIO_J, "%s: pjdata_r: PJDATA: %02x\n", machine().describe_context(), data); + return data; +} - case 0x418: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: PDDATA = %02x\n", data & 0x00ff); +void mc68328_device::pjsel_w(u8 data) // 0x43b +{ + LOGMASKED(LOG_GPIO_J, "%s: pjsel_w: PJSEL = %02x\n", machine().describe_context(), data); + m_pjsel = data; +} - m_regs.pddataedge &= ~(data & 0x00ff); - poll_port_d_interrupts(); - } - else - { - verboselog( *this, 2, "mc68328_w: PDDIR = %02x\n", (data >> 8) & 0x00ff); - m_regs.pddir = (data >> 8) & 0x00ff; - } - break; +u8 mc68328_device::pjsel_r() // 0x43b +{ + LOGMASKED(LOG_GPIO_J, "%s: pjsel_r: PJSEL: %02x\n", machine().describe_context(), m_pjsel); + return m_pjsel; +} - case 0x41a: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: Unknown address (0xfff41b) = %02x\n", data & 0x00ff); - } - else - { - verboselog( *this, 2, "mc68328_w: PDPUEN = %02x\n", (data >> 8) & 0x00ff); - m_regs.pdpuen = (data >> 8) & 0x00ff; - } - break; - case 0x41c: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: PDIRQEN = %02x\n", data & 0x00ff); - m_regs.pdirqen = data & 0x00ff; +//------------------------------------------------- +// GPIO hardware - Port K +//------------------------------------------------- - poll_port_d_interrupts(); - } - else - { - verboselog( *this, 2, "mc68328_w: PDPOL = %02x\n", (data >> 8) & 0x00ff); - m_regs.pdpol = (data >> 8) & 0x00ff; - } - break; +void mc68328_device::pkdir_w(u8 data) // 0x440 +{ + LOGMASKED(LOG_GPIO_K, "%s: pkdir_w: PKDIR = %02x\n", machine().describe_context(), data); + m_pkdir = data; +} - case 0x41e: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: PDIRQEDGE = %02x\n", data & 0x00ff); - m_regs.pdirqedge = data & 0x00ff; - } - else - { - verboselog( *this, 2, "mc68328_w: Unknown address (0xfff41e) = %02x\n", (data >> 8) & 0x00ff); - } - break; +u8 mc68328_device::pkdir_r() // 0x440 +{ + LOGMASKED(LOG_GPIO_K, "%s: pkdir_r: PKDIR: %02x\n", machine().describe_context(), m_pkdir); + return m_pkdir; +} - case 0x420: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: PEDATA = %02x\n", data & 0x00ff); - m_regs.pedata = data & 0x00ff; - if (!m_out_port_e_cb.isnull()) - { - m_out_port_e_cb((offs_t)0, data & 0x00ff); - } - } - else - { - verboselog( *this, 2, "mc68328_w: PEDIR = %02x\n", (data >> 8) & 0x00ff); - m_regs.pedir = (data >> 8) & 0x00ff; - } - break; +void mc68328_device::pkdata_w(u8 data) // 0x441 +{ + LOGMASKED(LOG_GPIO_K, "%s: pkdata_w: PKDATA = %02x\n", machine().describe_context(), data); + m_pkdata = data; + for (int i = 0; i < 8; i++) + { + if (BIT(m_pkdir & m_pksel, i)) + { + m_out_port_k_cb[i](BIT(m_pkdata, i)); + } + } +} - case 0x422: - if (mem_mask & 0x00ff) +u8 mc68328_device::pkdata_r() // 0x441 +{ + u8 data = 0; + for (int i = 0; i < 8; i++) + { + if (BIT(m_pksel, i)) + { + if (BIT(m_pkdir, i)) { - verboselog( *this, 2, "mc68328_w: PESEL = %02x\n", data & 0x00ff); - m_regs.pesel = data & 0x00ff; + data |= m_pkdata & (1 << i); } - else + else if (!m_in_port_k_cb[i].isunset()) { - verboselog( *this, 2, "mc68328_w: PEPUEN = %02x\n", (data >> 8) & 0x00ff); - m_regs.pepuen = (data >> 8) & 0x00ff; - m_regs.pedata |= m_regs.pepuen; - } - break; - - case 0x428: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: PFDATA = %02x\n", data & 0x00ff); - m_regs.pfdata = data & 0x00ff; - if (!m_out_port_f_cb.isnull()) - { - m_out_port_f_cb((offs_t)0, data & 0x00ff); - } + data |= m_in_port_k_cb[i]() << i; } else { - verboselog( *this, 2, "mc68328_w: PFDIR = %02x\n", (data >> 8) & 0x00ff); - m_regs.pfdir = (data >> 8) & 0x00ff; + data |= m_pkpuen & (1 << i); } - break; + } + } + LOGMASKED(LOG_GPIO_K, "%s: pkdata_r: PKDATA: %02x\n", machine().describe_context(), data); + return data; +} - case 0x42a: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: PFSEL = %02x\n", data & 0x00ff); - m_regs.pfsel = data & 0x00ff; - } - else - { - verboselog( *this, 2, "mc68328_w: PFPUEN = %02x\n", (data >> 8) & 0x00ff); - m_regs.pfpuen = (data >> 8) & 0x00ff; - } - break; +void mc68328_device::pkpuen_w(u8 data) // 0x442 +{ + LOGMASKED(LOG_GPIO_K, "%s: pkpuen_w: PKPUEN = %02x\n", machine().describe_context(), data); + m_pkpuen = data; +} - case 0x430: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: PGDATA = %02x\n", data & 0x00ff); - m_regs.pgdata = data & 0x00ff; - if (!m_out_port_g_cb.isnull()) - { - m_out_port_g_cb((offs_t)0, data & 0x00ff); - } - } - else - { - verboselog( *this, 2, "mc68328_w: PGDIR = %02x\n", (data >> 8) & 0x00ff); - m_regs.pgdir = (data >> 8) & 0x00ff; - } - break; +u8 mc68328_device::pkpuen_r() // 0x442 +{ + LOGMASKED(LOG_GPIO_K, "%s: pkpuen_r: PKPUEN: %02x\n", machine().describe_context(), m_pkpuen); + return m_pkpuen; +} - case 0x432: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: PGSEL = %02x\n", data & 0x00ff); - m_regs.pgsel = data & 0x00ff; - } - else - { - verboselog( *this, 2, "mc68328_w: PGPUEN = %02x\n", (data >> 8) & 0x00ff); - m_regs.pgpuen = (data >> 8) & 0x00ff; - } - break; +void mc68328_device::pksel_w(u8 data) // 0x443 +{ + LOGMASKED(LOG_GPIO_K, "%s: pksel_w: PKSEL = %02x\n", machine().describe_context(), data); + m_pksel = data; +} - case 0x438: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: PJDATA = %02x\n", data & 0x00ff); - m_regs.pjdata = data & 0x00ff; - if (!m_out_port_j_cb.isnull()) - { - m_out_port_j_cb((offs_t)0, data & 0x00ff); - } - } - else - { - verboselog( *this, 2, "mc68328_w: PJDIR = %02x\n", (data >> 8) & 0x00ff); - m_regs.pjdir = (data >> 8) & 0x00ff; - } - break; +u8 mc68328_device::pksel_r() // 0x443 +{ + LOGMASKED(LOG_GPIO_K, "%s: pksel_r: PKSEL: %02x\n", machine().describe_context(), m_pksel); + return m_pksel; +} - case 0x43a: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: PJSEL = %02x\n", data & 0x00ff); - m_regs.pjsel = data & 0x00ff; - } - else - { - verboselog( *this, 2, "mc68328_w: Unknown address (0xfff43a) = %02x\n", (data >> 8) & 0x00ff); - } - break; - case 0x440: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: PKDATA = %02x\n", data & 0x00ff); - m_regs.pkdata = data & 0x00ff; - if (!m_out_port_k_cb.isnull()) - { - m_out_port_k_cb((offs_t)0, data & 0x00ff); - } - } - else - { - verboselog( *this, 2, "mc68328_w: PKDIR = %02x\n", (data >> 8) & 0x00ff); - m_regs.pkdir = (data >> 8) & 0x00ff; - } - break; +//------------------------------------------------- +// GPIO hardware - Port M +//------------------------------------------------- - case 0x442: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: PKSEL = %02x\n", data & 0x00ff); - m_regs.pksel = data & 0x00ff; - } - else - { - verboselog( *this, 2, "mc68328_w: PKPUEN = %02x\n", (data >> 8) & 0x00ff); - m_regs.pgpuen = (data >> 8) & 0x00ff; - } - break; +void mc68328_device::pmdir_w(u8 data) // 0x448 +{ + LOGMASKED(LOG_GPIO_M, "%s: pmdir_w: PMDIR = %02x\n", machine().describe_context(), data); + m_pmdir = data; +} - case 0x448: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: PMDATA = %02x\n", data & 0x00ff); - m_regs.pmdata = data & 0x00ff; - if (!m_out_port_m_cb.isnull()) - { - m_out_port_m_cb((offs_t)0, data & 0x00ff); - } - } - else +u8 mc68328_device::pmdir_r() // 0x448 +{ + LOGMASKED(LOG_GPIO_M, "%s: pmdir_r: PMDIR: %02x\n", machine().describe_context(), m_pmdir); + return m_pmdir; +} + +void mc68328_device::pmdata_w(u8 data) // 0x449 +{ + LOGMASKED(LOG_GPIO_M, "%s: pmdata_w: PMDATA = %02x\n", machine().describe_context(), data); + m_pmdata = data; + for (int i = 0; i < 8; i++) + { + if (BIT(m_pmdir & m_pmsel, i)) + { + m_out_port_m_cb[i](BIT(m_pmdata, i)); + } + } +} + +u8 mc68328_device::pmdata_r() // 0x449 +{ + u8 data = 0; + for (int i = 0; i < 8; i++) + { + if (BIT(m_pmsel, i)) + { + if (BIT(m_pmdir, i)) { - verboselog( *this, 2, "mc68328_w: PMDIR = %02x\n", (data >> 8) & 0x00ff); - m_regs.pmdir = (data >> 8) & 0x00ff; + data |= m_pmdata & (1 << i); } - break; - - case 0x44a: - if (mem_mask & 0x00ff) + else if (!m_in_port_m_cb[i].isunset()) { - verboselog( *this, 2, "mc68328_w: PMSEL = %02x\n", data & 0x00ff); - m_regs.pmsel = data & 0x00ff; + data |= m_in_port_m_cb[i]() << i; } else { - verboselog( *this, 2, "mc68328_w: PMPUEN = %02x\n", (data >> 8) & 0x00ff); - m_regs.pmpuen = (data >> 8) & 0x00ff; + data |= m_pmpuen & (1 << i); } - break; + } + } + LOGMASKED(LOG_GPIO_M, "%s: pmdata_r: PMDATA: %02x\n", machine().describe_context(), data); + return data; +} - case 0x500: - verboselog( *this, 2, "mc68328_w: PWMC = %04x\n", data); +void mc68328_device::pmpuen_w(u8 data) // 0x44a +{ + LOGMASKED(LOG_GPIO_M, "%s: pmpuen_w: PMPUEN = %02x\n", machine().describe_context(), data); + m_pmpuen = data; +} - m_regs.pwmc = data; +u8 mc68328_device::pmpuen_r() // 0x44a +{ + LOGMASKED(LOG_GPIO_M, "%s: pmpuen_r: PMPUEN: %02x\n", machine().describe_context(), m_pmpuen); + return m_pmpuen; +} - if (m_regs.pwmc & PWMC_PWMIRQ) - { - set_interrupt_line(INT_PWM, 1); - } +void mc68328_device::pmsel_w(u8 data) // 0x44b +{ + LOGMASKED(LOG_GPIO_M, "%s: pmsel_w: PMSEL = %02x\n", machine().describe_context(), data); + m_pmsel = data; +} - m_regs.pwmc &= ~PWMC_LOAD; +u8 mc68328_device::pmsel_r() // 0x44b +{ + LOGMASKED(LOG_GPIO_M, "%s: pmsel_r: PMSEL: %02x\n", machine().describe_context(), m_pmsel); + return m_pmsel; +} - if ((m_regs.pwmc & PWMC_PWMEN) != 0 && m_regs.pwmw != 0 && m_regs.pwmp != 0) - { - uint32_t frequency = 32768 * 506; - uint32_t divisor = 4 << (m_regs.pwmc & PWMC_CLKSEL); // ?? Datasheet says 2 <<, but then we're an octave higher than CoPilot. - attotime period; - frequency /= divisor; - period = attotime::from_hz(frequency) * m_regs.pwmw; - m_pwm->adjust(period); - if (m_regs.pwmc & PWMC_IRQEN) - { - set_interrupt_line(INT_PWM, 1); - } - m_regs.pwmc ^= PWMC_PIN; - } - else - { - m_pwm->adjust(attotime::never); - } - break; - case 0x502: - verboselog( *this, 2, "mc68328_w: PWMP = %04x\n", data); - m_regs.pwmp = data; - break; +//------------------------------------------------- +// PWM hardware - Standard MC68328 +//------------------------------------------------- - case 0x504: - verboselog( *this, 2, "mc68328_w: PWMW = %04x\n", data); - m_regs.pwmw = data; - break; +TIMER_CALLBACK_MEMBER(mc68328_device::pwm_tick) +{ + if (m_pwmw >= m_pwmp || !m_pwmw || !m_pwmp) + { + m_pwm->adjust(attotime::never); + return; + } - case 0x506: - verboselog( *this, 2, "mc68328_w: PWMCNT = %04x\n", data); - m_regs.pwmcnt = 0; - break; + const u32 divisor = 4 << (m_pwmc & PWMC_CLKSEL); - case 0x600: - verboselog( *this, 2, "mc68328_w: TCTL1 = %04x\n", data); - temp16[0] = m_regs.tctl[0]; - m_regs.tctl[0] = data; - if ((temp16[0] & TCTL_TEN) == (m_regs.tctl[0] & TCTL_TEN)) - { - maybe_start_timer(0, 0); - } - else if ((temp16[0] & TCTL_TEN) != TCTL_TEN_ENABLE && (m_regs.tctl[0] & TCTL_TEN) == TCTL_TEN_ENABLE) - { - maybe_start_timer(0, 1); - } - break; + if (((m_pwmc & PWMC_POL) == 0 && (m_pwmc & PWMC_PIN) != 0) || + ((m_pwmc & PWMC_POL) != 0 && (m_pwmc & PWMC_PIN) == 0)) + { + attotime period = attotime::from_ticks((m_pwmp - m_pwmw) * divisor, clock()); + m_pwm->adjust(period); - case 0x602: - verboselog( *this, 2, "mc68328_w: TPRER1 = %04x\n", data); - m_regs.tprer[0] = data; - maybe_start_timer(0, 0); - break; + if (m_pwmc & PWMC_IRQ_EN) + { + set_interrupt_line(INT_PWM, 1); + } + } + else + { + attotime period = attotime::from_ticks(m_pwmw * divisor, clock()); + m_pwm->adjust(period); + } - case 0x604: - verboselog( *this, 2, "mc68328_w: TCMP1 = %04x\n", data); - m_regs.tcmp[0] = data; - maybe_start_timer(0, 0); - break; + m_pwmc ^= PWMC_PIN; - case 0x606: - verboselog( *this, 2, "mc68328_w: TCR1 = %04x (Ignored)\n", data); - break; + m_out_pwm_cb((m_pwmc & PWMC_PIN) ? 1 : 0); +} - case 0x608: - verboselog( *this, 2, "mc68328_w: TCN1 = %04x (Ignored)\n", data); - break; +void mc68328_device::pwmc_w(u16 data) // 0x500 +{ + LOGMASKED(LOG_PWM, "%s: pwmc_w: PWMC = %04x\n", machine().describe_context(), data); - case 0x60a: - verboselog( *this, 5, "mc68328_w: TSTAT1 = %04x\n", data); - m_regs.tstat[0] &= ~m_regs.tclear[0]; - if (!(m_regs.tstat[0] & TSTAT_COMP)) - { - set_interrupt_line(INT_TIMER1, 0); - } - break; + const u16 old_pwmc = m_pwmc; + m_pwmc = data; + const u16 changed = m_pwmc ^ old_pwmc; - case 0x60c: - verboselog( *this, 2, "mc68328_w: TCTL2 = %04x\n", data); - temp16[0] = m_regs.tctl[1]; - m_regs.tctl[1] = data; - if ((temp16[0] & TCTL_TEN) == (m_regs.tctl[1] & TCTL_TEN)) - { - maybe_start_timer(1, 0); - } - else if ((temp16[0] & TCTL_TEN) != TCTL_TEN_ENABLE && (m_regs.tctl[1] & TCTL_TEN) == TCTL_TEN_ENABLE) + if (m_pwmc & PWMC_IRQ) + { + set_interrupt_line(INT_PWM, 1); + } + + if (changed & (PWMC_EN | PWMC_CLKSEL | PWMC_LOAD)) + { + const bool enable_or_update = (changed & m_pwmc & PWMC_EN) || (m_pwmc & PWMC_LOAD); + if (enable_or_update && m_pwmw && m_pwmp) + { + const u32 divisor = 4 << (m_pwmc & PWMC_CLKSEL); + attotime period = attotime::from_ticks(m_pwmw * divisor, clock()); + m_pwm->adjust(period); + if (m_pwmc & PWMC_IRQ_EN) { - maybe_start_timer(1, 1); + set_interrupt_line(INT_PWM, 1); } - break; + m_pwmc |= PWMC_PIN; + } + else + { + m_pwm->adjust(attotime::never); + } + } - case 0x60e: - verboselog( *this, 2, "mc68328_w: TPRER2 = %04x\n", data); - m_regs.tprer[1] = data; - maybe_start_timer(1, 0); - break; + m_pwmc &= ~PWMC_LOAD; +} - case 0x610: - verboselog( *this, 2, "mc68328_w: TCMP2 = %04x\n", data); - m_regs.tcmp[1] = data; - maybe_start_timer(1, 0); - break; +u16 mc68328_device::pwmc_r() // 0x500 +{ + const u16 data = m_pwmc; + LOGMASKED(LOG_PWM, "%s: pwmc_r: PWMC: %04x\n", machine().describe_context(), data); + if (m_pwmc & PWMC_IRQ) + { + m_pwmc &= ~PWMC_IRQ; + if (m_pwmc & PWMC_IRQ_EN) + { + set_interrupt_line(INT_PWM, 0); + } + } + return data; +} - case 0x612: - verboselog( *this, 2, "mc68328_w: TCR2 = %04x (Ignored)\n", data); - break; +void mc68328_device::pwmp_w(u16 data) // 0x502 +{ + LOGMASKED(LOG_PWM, "%s: pwmp_w: PWMP = %04x\n", machine().describe_context(), data); + m_pwmp = data; +} - case 0x614: - verboselog( *this, 2, "mc68328_w: TCN2 = %04x (Ignored)\n", data); - break; +u16 mc68328_device::pwmp_r() // 0x502 +{ + LOGMASKED(LOG_PWM, "%s: pwmp_r: PWMP: %04x\n", machine().describe_context(), m_pwmp); + return m_pwmp; +} - case 0x616: - verboselog( *this, 2, "mc68328_w: TSTAT2 = %04x\n", data); - m_regs.tstat[1] &= ~m_regs.tclear[1]; - if (!(m_regs.tstat[1] & TSTAT_COMP)) - { - set_interrupt_line(INT_TIMER2, 0); - } - break; +void mc68328_device::pwmw_w(u16 data) // 0x504 +{ + LOGMASKED(LOG_PWM, "%s: pwmw_w: PWMW = %04x\n", machine().describe_context(), data); + m_pwmw = data; +} - case 0x618: - verboselog( *this, 2, "mc68328_w: WCTLR = %04x\n", data); - m_regs.wctlr = data; - break; +u16 mc68328_device::pwmw_r() // 0x504 +{ + LOGMASKED(LOG_PWM, "%s: pwmw_r: PWMW: %04x\n", machine().describe_context(), m_pwmw); + return m_pwmw; +} - case 0x61a: - verboselog( *this, 2, "mc68328_w: WCMPR = %04x\n", data); - m_regs.wcmpr = data; - break; +void mc68328_device::pwmcnt_w(u16 data) // 0x506 +{ + LOGMASKED(LOG_PWM, "%s: pwmcnt_w: PWMCNT = %04x\n", machine().describe_context(), data); + m_pwmcnt = 0; +} - case 0x61c: - verboselog( *this, 2, "mc68328_w: WCN = %04x (Ignored)\n", data); - break; +u16 mc68328_device::pwmcnt_r() // 0x506 +{ + LOGMASKED(LOG_PWM, "%s: pwmcnt_r: PWMCNT: %04x\n", machine().describe_context(), m_pwmcnt); + return m_pwmcnt; +} - case 0x700: - verboselog( *this, 2, "mc68328_w: SPISR = %04x\n", data); - m_regs.spisr = data; - break; - case 0x800: - verboselog( *this, 2, "mc68328_w: SPIMDATA = %04x\n", data); - if (!m_out_spim_cb.isnull()) - { - m_out_spim_cb(0, data, 0xffff); - } - else - { - m_regs.spimdata = data; - } - break; +//------------------------------------------------- +// PWM hardware - EZ variant +//------------------------------------------------- - case 0x802: - verboselog( *this, 2, "mc68328_w: SPIMCONT = %04x\n", data); - verboselog( *this, 3, " Count = %d\n", data & SPIM_CLOCK_COUNT); - verboselog( *this, 3, " Polarity = %s\n", (data & SPIM_POL) ? "Inverted" : "Active-high"); - verboselog( *this, 3, " Phase = %s\n", (data & SPIM_PHA) ? "Opposite" : "Normal"); - verboselog( *this, 3, " IRQ Enable = %s\n", (data & SPIM_IRQEN) ? "Enable" : "Disable"); - verboselog( *this, 3, " IRQ Pending = %s\n", (data & SPIM_SPIMIRQ) ? "Yes" : "No"); - verboselog( *this, 3, " Exchange = %s\n", (data & SPIM_XCH) ? "Initiate" : "Idle"); - verboselog( *this, 3, " SPIM Enable = %s\n", (data & SPIM_SPMEN) ? "Enable" : "Disable"); - verboselog( *this, 3, " Data Rate = Divide By %d\n", 1 << ((((data & SPIM_RATE) >> 13) & 0x0007) + 2) ); - m_regs.spimcont = data; - // $$HACK$$ We should probably emulate the ADS7843 A/D device properly. - if (data & SPIM_XCH) - { - m_regs.spimcont &= ~SPIM_XCH; - if (!m_spim_xch_trigger_cb.isnull()) - { - m_spim_xch_trigger_cb(0); - } - if (data & SPIM_IRQEN) - { - m_regs.spimcont |= SPIM_SPIMIRQ; - verboselog( *this, 3, "Triggering SPIM Interrupt\n" ); - set_interrupt_line(INT_SPIM, 1); - } - } - if (!(data & SPIM_IRQEN)) - { - set_interrupt_line(INT_SPIM, 0); - } - break; +TIMER_CALLBACK_MEMBER(mc68ez328_device::pwm_tick) +{ + if (!(m_pwmc & PWMC_EN)) + { + return; + } - case 0x900: - verboselog( *this, 2, "mc68328_w: USTCNT = %04x\n", data); - m_regs.ustcnt = data; - break; + if (!param) + { + m_pwm_rep_cnt--; + if (!m_pwm_rep_cnt) + { + m_pwm_rep_cnt = 1 << ((m_pwmc & PWMC_REPEAT) >> PWMC_REPEAT_SHIFT); + pwm_fifo_pop(); + } + } - case 0x902: - verboselog( *this, 2, "mc68328_w: UBAUD = %04x\n", data); - m_regs.ubaud = data; - break; + m_pwmo = param; + update_pwm_period(!m_pwmo); + m_out_pwm_cb((int)m_pwmo); +} - case 0x904: - verboselog( *this, 2, "mc68328_w: URX = %04x\n", data); - break; +void mc68ez328_device::update_pwm_period(bool high_cycle) +{ + const u32 frequency = (m_pwmc & PWMC_CLK_SRC) ? 32768 : clock(); + const u32 prescale = ((m_pwmc & PWMC_PRESCALE) >> PWMC_PRESCALE_SHIFT) + 1; + const u32 divisor = 2 << (m_pwmc & PWMC_CLKSEL); + const u32 period_reg = (u32)std::min(m_pwmp + 1u, 0xffu); + u32 sample_period = period_reg; + if (m_pwmfifo[m_pwmfifo_rd] <= period_reg) + { + sample_period = high_cycle ? (period_reg - m_pwmfifo[m_pwmfifo_rd]) : m_pwmfifo[m_pwmfifo_rd]; + sample_period++; + } + attotime period = attotime::from_ticks(prescale * divisor * sample_period, frequency); + m_pwm->adjust(period, (int)high_cycle); +} - case 0x906: - verboselog( *this, 2, "mc68328_w: UTX = %04x\n", data); - break; +void mc68ez328_device::pwm_fifo_push(u8 data) +{ + if (m_pwmfifo_cnt >= std::size(m_pwmfifo)) + { + return; + } + m_pwmfifo[m_pwmfifo_wr] = data; + m_pwmfifo_wr = (m_pwmfifo_wr + 1) % std::size(m_pwmfifo); + const u8 old_cnt = m_pwmfifo_cnt; + m_pwmfifo_cnt++; + if (m_pwmfifo_cnt == std::size(m_pwmfifo)) + { + m_pwmc &= ~PWMC_FIFO_AV; + } + else if (old_cnt <= 1 && m_pwmfifo_cnt > 1) + { + if (m_pwmc & PWMC_IRQ) + { + m_pwmc &= ~PWMC_IRQ; + set_interrupt_line(INT_PWM, 0); + } + } +} - case 0x908: - verboselog( *this, 2, "mc68328_w: UMISC = %04x\n", data); - m_regs.umisc = data; - break; +void mc68ez328_device::pwm_fifo_pop() +{ + if (m_pwmfifo_cnt > 0) + { + m_pwmfifo_rd = (m_pwmfifo_rd + 1) % std::size(m_pwmfifo); + m_pwmfifo_cnt--; - case 0xa00: - verboselog( *this, 2, "mc68328_w: LSSA(16) = %04x\n", data); - m_regs.lssa &= ~(mem_mask << 16); - m_regs.lssa |= (data & mem_mask) << 16; - verboselog( *this, 3, " Address: %08x\n", m_regs.lssa); - break; + m_pwmc |= PWMC_FIFO_AV; + } - case 0xa02: - verboselog( *this, 2, "mc68328_w: LSSA(0) = %04x\n", data); - m_regs.lssa &= 0xffff0000 | (~mem_mask); - m_regs.lssa |= data & mem_mask; - verboselog( *this, 3, " Address: %08x\n", m_regs.lssa); - break; + if (m_pwmfifo_cnt <= 1) + { + if (!(m_pwmc & PWMC_IRQ)) + { + m_pwmc |= PWMC_IRQ; + set_interrupt_line(INT_PWM, 1); + } + } +} - case 0xa04: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: LVPW = %02x\n", data & 0x00ff); - m_regs.lvpw = data & 0x00ff; - verboselog( *this, 3, " Page Width: %d\n", (m_regs.lvpw + 1) * ((m_regs.lpicf & 0x01) ? 8 : 16)); - } - else - { - verboselog( *this, 2, "mc68328_w: Unknown address (0xfffa04) = %02x\n", (data >> 8) & 0x00ff); - } - break; +void mc68ez328_device::pwmc_w(u16 data) // 0x500 +{ + LOGMASKED(LOG_PWM, "%s: pwmc_w: PWMC = %04x\n", machine().describe_context(), data); - case 0xa08: - verboselog( *this, 2, "mc68328_w: LXMAX = %04x\n", data); - m_regs.lxmax = data; - verboselog( *this, 3, " Width: %d\n", (data & 0x03ff) + 1); - break; + const u16 old = m_pwmc; + m_pwmc = (m_pwmc & PWMC_FIFO_AV) | (data & ~PWMC_FIFO_AV); + const u16 changed = old ^ m_pwmc; + if (!changed) + { + return; + } - case 0xa0a: - verboselog( *this, 2, "mc68328_w: LYMAX = %04x\n", data); - m_regs.lymax = data; - verboselog( *this, 3, " Height: %d\n", (data & 0x03ff) + 1); - break; + bool set_irq = false; + if (m_pwmc & PWMC_IRQ_EN) + { + if (m_pwmc & PWMC_IRQ) + { + set_irq = true; + } + } + else if (old & PWMC_IRQ_EN) + { + set_interrupt_line(INT_PWM, 0); + } - case 0xa18: - verboselog( *this, 2, "mc68328_w: LCXP = %04x\n", data); - m_regs.lcxp = data; - verboselog( *this, 3, " X Position: %d\n", data & 0x03ff); - switch (m_regs.lcxp >> 14) + const bool recalculate = (changed & PWMC_RECALC_MASK); + if (recalculate) + { + if (m_pwmc & PWMC_EN) + { + if (changed & PWMC_EN) { - case 0: - verboselog( *this, 3, " Cursor Control: Transparent\n"); - break; + set_irq = true; + m_pwmc |= PWMC_FIFO_AV; + } + m_pwmo = true; + m_out_pwm_cb((int)m_pwmo); + update_pwm_period(false); + m_pwm_rep_cnt = 1 << ((m_pwmc & PWMC_REPEAT) >> PWMC_REPEAT_SHIFT); + } + else + { + m_pwmfifo_cnt = 0; + m_pwmo = false; + m_pwm->adjust(attotime::never); + } + } - case 1: - verboselog( *this, 3, " Cursor Control: Black\n"); - break; + if (set_irq && (m_pwmc & PWMC_IRQ_EN)) + { + m_pwmc |= PWMC_IRQ; + set_interrupt_line(INT_PWM, BIT(m_pwmc, PWMC_IRQ_BIT)); + } +} - case 2: - verboselog( *this, 3, " Cursor Control: Reverse\n"); - break; +u16 mc68ez328_device::pwmc_r() // 0x500 +{ + const u16 data = m_pwmc; + LOGMASKED(LOG_PWM, "%s: pwmc_r: PWMC: %04x\n", machine().describe_context(), data); + if (m_pwmc & PWMC_IRQ) + { + m_pwmc &= ~PWMC_IRQ; + set_interrupt_line(INT_PWM, 0); + } + return data; +} - case 3: - verboselog( *this, 3, " Cursor Control: Invalid\n"); - break; - } - break; +void mc68ez328_device::pwms_w(offs_t offset, u16 data, u16 mem_mask) // 0x502 +{ + LOGMASKED(LOG_PWM, "%s: pwms_w: PWMS = %04x & %04x\n", machine().describe_context(), data, mem_mask); + if (mem_mask == 0xffff) + { + pwm_fifo_push((u8)(data >> 8)); + pwm_fifo_push((u8)data); + } + else if (mem_mask == 0x00ff) + { + pwm_fifo_push((u8)data); + } +} - case 0xa1a: - verboselog( *this, 2, "mc68328_w: LCYP = %04x\n", data); - m_regs.lcyp = data; - verboselog( *this, 3, " Y Position: %d\n", data & 0x01ff); - break; +u16 mc68ez328_device::pwms_r() // 0x502 +{ + LOGMASKED(LOG_PWM, "%s: pwms_r: PWMS: %04x\n", machine().describe_context(), m_pwmfifo[m_pwmfifo_rd]); + return m_pwmfifo[m_pwmfifo_rd]; +} - case 0xa1c: - verboselog( *this, 2, "mc68328_w: LCWCH = %04x\n", data); - m_regs.lcwch = data; - verboselog( *this, 3, " Width: %d\n", (data >> 8) & 0x1f); - verboselog( *this, 3, " Height: %d\n", data & 0x1f); - break; +void mc68ez328_device::pwmp_w(u8 data) // 0x504 +{ + LOGMASKED(LOG_PWM, "%s: pwmp_w: PWMP = %02x\n", machine().describe_context(), data); + const bool changed = (data != m_pwmp); + m_pwmp = data; + if (changed && (m_pwmc & PWMC_EN)) + { + update_pwm_period(false); + } +} - case 0xa1e: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: LBLKC = %02x\n", data & 0x00ff); - m_regs.lblkc = data & 0x00ff; - verboselog( *this, 3, " Blink Enable: %d\n", m_regs.lblkc >> 7); - verboselog( *this, 3, " Blink Divisor: %d\n", m_regs.lblkc & 0x7f); - } - else - { - verboselog( *this, 2, "mc68328_w: Unknown address (0xfffa1e) = %02x\n", (data >> 8) & 0x00ff); - } - break; +u8 mc68ez328_device::pwmp_r() // 0x504 +{ + LOGMASKED(LOG_PWM, "%s: pwmp_r: PWMP: %02x\n", machine().describe_context(), m_pwmp); + return m_pwmp; +} - case 0xa20: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: LPOLCF = %02x\n", data & 0x00ff); - m_regs.lpolcf = data & 0x00ff; - verboselog( *this, 3, " LCD Shift Clock Polarity: %s\n", (m_regs.lpicf & 0x08) ? "Active positive edge of LCLK" : "Active negative edge of LCLK"); - verboselog( *this, 3, " First-line marker polarity: %s\n", (m_regs.lpicf & 0x04) ? "Active Low" : "Active High"); - verboselog( *this, 3, " Line-pulse polarity: %s\n", (m_regs.lpicf & 0x02) ? "Active Low" : "Active High"); - verboselog( *this, 3, " Pixel polarity: %s\n", (m_regs.lpicf & 0x01) ? "Active Low" : "Active High"); - } - else - { - verboselog( *this, 2, "mc68328_w: LPICF = %02x\n", (data >> 8) & 0x00ff); - m_regs.lpicf = (data >> 8) & 0x00ff; - switch((m_regs.lpicf >> 1) & 0x03) - { - case 0: - verboselog( *this, 3, " Bus Size: 1-bit\n"); - break; +void mc68ez328_device::pwmcnt_w(u8 data) // 0x505 +{ + LOGMASKED(LOG_PWM, "%s: pwmcnt_w: PWMCNT = %04x (Ignored)\n", machine().describe_context(), data); +} - case 1: - verboselog( *this, 3, " Bus Size: 2-bit\n"); - break; +u8 mc68ez328_device::pwmcnt_r() // 0x505 +{ + u8 data = 0; + if (m_pwmc & PWMC_EN) + { + const u32 frequency = (m_pwmc & PWMC_CLK_SRC) ? 32768 : clock(); + const u32 prescale = (m_pwmc & PWMC_PRESCALE) >> PWMC_PRESCALE_SHIFT; + const u32 divisor = 2 << (m_pwmc & PWMC_CLKSEL); + const u8 period = std::min(m_pwmp + 1u, 0xffu); + data = period - (u8)m_pwm->remaining().as_ticks(frequency) / (prescale * divisor); + } - case 2: - verboselog( *this, 3, " Bus Size: 4-bit\n"); - break; + LOGMASKED(LOG_PWM, "%s: pwmcnt_r: PWMCNT: %02x\n", machine().describe_context(), data); + return data; +} - case 3: - verboselog( *this, 3, " Bus Size: unused\n"); - break; - } - verboselog( *this, 3, " Gray scale enable: %d\n", m_regs.lpicf & 0x01); - } - break; - case 0xa22: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: LACDRC = %02x\n", data & 0x00ff); - m_regs.lacdrc = data & 0x00ff; - } - else - { - verboselog( *this, 2, "mc68328_w: Unknown address (0xfffa22) = %02x\n", (data >> 8) & 0x00ff); - } - break; +//------------------------------------------------- +// Timer/Watchdog hardware +//------------------------------------------------- - case 0xa24: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: LPXCD = %02x\n", data & 0x00ff); - m_regs.lpxcd = data & 0x00ff; - verboselog( *this, 3, " Clock Divisor: %d\n", m_regs.lpxcd + 1); - } - else - { - verboselog( *this, 2, "mc68328_w: Unknown address (0xfffa24) = %02x\n", (data >> 8) & 0x00ff); - } - break; +emu_timer *mc68328_device::get_timer(int timer) +{ + return m_gptimer[timer]; +} - case 0xa26: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: LCKCON = %02x\n", data & 0x00ff); - m_regs.lckcon = data & 0x00ff; - verboselog( *this, 3, " LCDC Enable: %d\n", (m_regs.lckcon >> 7) & 0x01); - verboselog( *this, 3, " DMA Burst Length: %d\n", ((m_regs.lckcon >> 6) & 0x01) ? 16 : 8); - verboselog( *this, 3, " DMA Bursting Clock Control: %d\n", ((m_regs.lckcon >> 4) & 0x03) + 1); - verboselog( *this, 3, " Bus Width: %d\n", ((m_regs.lckcon >> 1) & 0x01) ? 8 : 16); - verboselog( *this, 3, " Pixel Clock Divider Source: %s\n", (m_regs.lckcon & 0x01) ? "PIX" : "SYS"); - } - else - { - verboselog( *this, 2, "mc68328_w: Unknown address (0xfffa26) = %02x\n", (data >> 8) & 0x00ff); - } - break; +emu_timer *mc68ez328_device::get_timer(int timer) +{ + return m_gptimer; +} - case 0xa28: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: LLBAR = %02x\n", data & 0x00ff); - m_regs.llbar = data & 0x00ff; - verboselog( *this, 3, " Address: %d\n", (m_regs.llbar & 0x7f) * ((m_regs.lpicf & 0x01) ? 8 : 16)); - } - else - { - verboselog( *this, 2, "mc68328_w: Unknown address (0xfffa28) = %02x\n", (data >> 8) & 0x00ff); - } - break; +mc68328_base_device::timer_regs &mc68328_device::get_timer_regs(int timer) +{ + return m_timer_regs[timer]; +} - case 0xa2a: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: LOTCR = %02x\n", data & 0x00ff); - } - else - { - verboselog( *this, 2, "mc68328_w: Unknown address (0xfffa2a) = %02x\n", (data >> 8) & 0x00ff); - } - break; +mc68328_base_device::timer_regs &mc68ez328_device::get_timer_regs(int timer) +{ + return m_timer_regs; +} - case 0xa2c: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: LPOSR = %02x\n", data & 0x00ff); - m_regs.lposr = data & 0x00ff; - verboselog( *this, 3, " Byte Offset: %d\n", (m_regs.lposr >> 3) & 0x01); - verboselog( *this, 3, " Pixel Offset: %d\n", m_regs.lposr & 0x07); - } - else - { - verboselog( *this, 2, "mc68328_w: Unknown address (0xfffa2c) = %02x\n", (data >> 8) & 0x00ff); - } - break; +u32 mc68328_device::get_timer_int(int timer) +{ + constexpr u32 TIMER_INTS[2] = { INT_TIMER1, INT_TIMER2 }; + return TIMER_INTS[timer]; +} - case 0xa30: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_w: LFRCM = %02x\n", data & 0x00ff); - m_regs.lfrcm = data & 0x00ff; - verboselog( *this, 3, " X Modulation: %d\n", (m_regs.lfrcm >> 4) & 0x0f); - verboselog( *this, 3, " Y Modulation: %d\n", m_regs.lfrcm & 0x0f); - } - else - { - verboselog( *this, 2, "mc68328_w: Unknown address (0xfffa30) = %02x\n", (data >> 8) & 0x00ff); - } - break; +u32 mc68ez328_device::get_timer_int(int timer) +{ + return INT_TIMER2; +} - case 0xa32: - verboselog( *this, 2, "mc68328_w: LGPMR = %04x\n", data); - m_regs.lgpmr = data; - verboselog( *this, 3, " Palette 0: %d\n", (m_regs.lgpmr >> 8) & 0x07); - verboselog( *this, 3, " Palette 1: %d\n", (m_regs.lgpmr >> 12) & 0x07); - verboselog( *this, 3, " Palette 2: %d\n", (m_regs.lgpmr >> 0) & 0x07); - verboselog( *this, 3, " Palette 3: %d\n", (m_regs.lgpmr >> 4) & 0x07); - break; +template <int Timer> +u32 mc68328_base_device::get_timer_frequency() +{ + timer_regs ®s = get_timer_regs(Timer); + u32 frequency = 0; - case 0xb00: - verboselog( *this, 2, "mc68328_w: HMSR(0) = %04x\n", data); - m_regs.hmsr &= ~(mem_mask << 16); - m_regs.hmsr |= (data & mem_mask) << 16; - m_regs.hmsr &= 0x1f3f003f; + switch (regs.tctl & TCTL_CLKSOURCE) + { + case TCTL_CLKSOURCE_SYSCLK: + frequency = clock(); break; - case 0xb02: - verboselog( *this, 2, "mc68328_w: HMSR(16) = %04x\n", data); - m_regs.hmsr &= 0xffff0000 | (~mem_mask); - m_regs.hmsr |= data & mem_mask; - m_regs.hmsr &= 0x1f3f003f; + case TCTL_CLKSOURCE_SYSCLK16: + frequency = clock() / 16; break; - case 0xb04: - verboselog( *this, 2, "mc68328_w: ALARM(0) = %04x\n", data); - m_regs.alarm &= ~(mem_mask << 16); - m_regs.alarm |= (data & mem_mask) << 16; - m_regs.alarm &= 0x1f3f003f; + case TCTL_CLKSOURCE_32KHZ4: + case TCTL_CLKSOURCE_32KHZ5: + case TCTL_CLKSOURCE_32KHZ6: + case TCTL_CLKSOURCE_32KHZ7: + frequency = 32768; break; + } + frequency /= (regs.tprer + 1); - case 0xb06: - verboselog( *this, 2, "mc68328_w: ALARM(16) = %04x\n", data); - m_regs.alarm &= 0xffff0000 | (~mem_mask); - m_regs.alarm |= data & mem_mask; - m_regs.alarm &= 0x1f3f003f; - break; + return frequency; +} - case 0xb0c: - verboselog( *this, 2, "mc68328_w: RTCCTL = %04x\n", data); - m_regs.rtcctl = data & 0x00a0; - break; +template <int Timer> +void mc68328_base_device::update_gptimer_state() +{ + timer_regs ®s = get_timer_regs(Timer); + emu_timer *timer = get_timer(Timer); + if (BIT(regs.tctl, TCTL_TEN_BIT) && (regs.tctl & TCTL_CLKSOURCE) > TCTL_CLKSOURCE_STOP) + { + if ((regs.tctl & TCTL_CLKSOURCE) == TCTL_CLKSOURCE_TIN || regs.tcmp == 0) + { + timer->adjust(attotime::never); + } + else + { + timer->adjust(attotime::from_hz(get_timer_frequency<Timer>())); + } + } + else + { + timer->adjust(attotime::never); + } +} - case 0xb0e: - verboselog( *this, 2, "mc68328_w: RTCISR = %04x\n", data); - m_regs.rtcisr &= ~data; - if (m_regs.rtcisr == 0) - { - set_interrupt_line(INT_RTC, 0); - } - break; +template <int Timer> +TIMER_CALLBACK_MEMBER(mc68328_base_device::timer_tick) +{ + timer_regs ®s = get_timer_regs(Timer); + emu_timer *timer = get_timer(Timer); - case 0xb10: - verboselog( *this, 2, "mc68328_w: RTCIENR = %04x\n", data); - m_regs.rtcienr = data & 0x001f; - break; + u32 frequency = get_timer_frequency<Timer>(); + if (frequency > 0) + { + attotime period = attotime::from_hz(frequency); + timer->adjust(period); + } + else + { + timer->adjust(attotime::never); + } - case 0xb12: - verboselog( *this, 2, "mc68328_w: STPWTCH = %04x\n", data); - m_regs.stpwtch = data & 0x003f; - break; + regs.tcn++; + if (regs.tcn == regs.tcmp) + { + regs.tstat |= TSTAT_COMP; + if ((regs.tctl & TCTL_FRR) == TCTL_FRR_RESTART) + { + regs.tcn = 0x0000; + } - default: - verboselog( *this, 0, "mc68328_w: Unknown address (0x%06x) = %04x (%04x)\n", 0xfff000 + address, data, mem_mask); - break; + if ((regs.tctl & TCTL_IRQEN) == TCTL_IRQEN_ENABLE) + { + set_interrupt_line(get_timer_int(Timer), 1); + } } } -uint16_t mc68328_device::internal_read(offs_t offset, uint16_t mem_mask) +template <int Timer> +void mc68328_base_device::tctl_w(u16 data) // 0x600, 0x60c { - uint16_t temp16; - uint32_t address = offset << 1; + timer_regs ®s = get_timer_regs(Timer); + LOGMASKED(LOG_TIMERS, "%s: tctl_w<%d>: TCTL%d = %04x\n", machine().describe_context(), Timer, Timer + 1, data); + const u16 old_tctl = regs.tctl; + regs.tctl = data; + + const bool old_enable = BIT(old_tctl, TCTL_TEN_BIT); + const bool new_enable = BIT(regs.tctl, TCTL_TEN_BIT); + if (!old_enable && new_enable) + { + regs.tcn = 0x0000; + } + update_gptimer_state<Timer>(); +} + +template <int Timer> +u16 mc68328_base_device::tctl_r() // 0x600, 0x60c +{ + timer_regs ®s = get_timer_regs(Timer); + LOGMASKED(LOG_TIMERS, "%s: tctl_r: TCTL%d: %04x\n", machine().describe_context(), Timer + 1, regs.tctl); + return regs.tctl; +} - switch (address) +template <int Timer> +void mc68328_base_device::tprer_w(u16 data) // 0x602, 0x60e +{ + timer_regs ®s = get_timer_regs(Timer); + LOGMASKED(LOG_TIMERS, "%s: tprer_w<%d>: TPRER%d = %04x\n", machine().describe_context(), Timer, Timer + 1, data); + regs.tprer = data; + update_gptimer_state<Timer>(); +} + +template <int Timer> +u16 mc68328_base_device::tprer_r() // 0x602, 0x60e +{ + timer_regs ®s = get_timer_regs(Timer); + LOGMASKED(LOG_TIMERS, "%s: tprer_r: TPRER%d: %04x\n", machine().describe_context(), Timer + 1, regs.tprer); + return regs.tprer; +} + +template <int Timer> +void mc68328_base_device::tcmp_w(u16 data) // 0x604, 0x610 +{ + timer_regs ®s = get_timer_regs(Timer); + LOGMASKED(LOG_TIMERS, "%s: tcmp_w<%d>: TCMP%d = %04x\n", machine().describe_context(), Timer, Timer + 1, data); + regs.tcmp = data; + update_gptimer_state<Timer>(); +} + +template <int Timer> +u16 mc68328_base_device::tcmp_r() // 0x604, 0x610 +{ + timer_regs ®s = get_timer_regs(Timer); + LOGMASKED(LOG_TIMERS, "%s: tcmp_r: TCMP%d: %04x\n", machine().describe_context(), Timer + 1, regs.tcmp); + return regs.tcmp; +} + +template <int Timer> +void mc68328_base_device::tcr_w(u16 data) // 0x606, 0x612 +{ + LOGMASKED(LOG_TIMERS, "%s: tcr_w<%d>: TCR%d = %04x (Ignored)\n", machine().describe_context(), Timer, Timer + 1, data); +} + +template <int Timer> +u16 mc68328_base_device::tcr_r() // 0x606, 0x612 +{ + timer_regs ®s = get_timer_regs(Timer); + LOGMASKED(LOG_TIMERS, "%s: tcr_r: TCR%d: %04x\n", machine().describe_context(), Timer + 1, regs.tcr); + return regs.tcr; +} + +template <int Timer> +void mc68328_base_device::tcn_w(u16 data) // 0x608, 0x614 +{ + LOGMASKED(LOG_TIMERS, "%s: tcn_w<%d>: TCN%d = %04x (Ignored)\n", machine().describe_context(), Timer, Timer + 1, data); +} + +template <int Timer> +u16 mc68328_base_device::tcn_r() // 0x608, 0x614 +{ + timer_regs ®s = get_timer_regs(Timer); + LOGMASKED(LOG_TIMERS, "%s: tcn_r: TCN%d: %04x\n", machine().describe_context(), Timer + 1, regs.tcn); + return regs.tcn; +} + +template <int Timer> +void mc68328_base_device::tstat_w(u16 data) // 0x60a, 0x616 +{ + timer_regs ®s = get_timer_regs(Timer); + LOGMASKED(LOG_TSTAT, "%s: tstat_w<%d>: TSTAT%d = %04x\n", machine().describe_context(), Timer, Timer + 1, data); + regs.tstat &= ~regs.tclear; + if (!(regs.tstat & TSTAT_COMP)) { - case 0x000: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfff001)\n", mem_mask); - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): SCR = %02x\n", mem_mask, m_regs.scr); - return m_regs.scr << 8; - } - break; + set_interrupt_line(get_timer_int(Timer), 0); + } +} - case 0x100: - verboselog( *this, 2, "mc68328_r (%04x): GRPBASEA = %04x\n", mem_mask, m_regs.grpbasea); - return m_regs.grpbasea; +template <int Timer> +u16 mc68328_base_device::tstat_r() // 0x60a, 0x616 +{ + timer_regs ®s = get_timer_regs(Timer); + LOGMASKED(LOG_TIMERS, "%s: tstat_r: TSTAT%d: %04x\n", machine().describe_context(), Timer + 1, regs.tstat); + regs.tclear |= regs.tstat; + return regs.tstat; +} - case 0x102: - verboselog( *this, 2, "mc68328_r (%04x): GRPBASEB = %04x\n", mem_mask, m_regs.grpbaseb); - return m_regs.grpbaseb; +void mc68328_device::wctlr_w(u16 data) // 0x618 +{ + LOGMASKED(LOG_WATCHDOG, "%s: wctlr_w: WCTLR = %04x\n", machine().describe_context(), data); + m_wctlr = data; +} - case 0x104: - verboselog( *this, 2, "mc68328_r (%04x): GRPBASEC = %04x\n", mem_mask, m_regs.grpbasec); - return m_regs.grpbasec; +u16 mc68328_device::wctlr_r() // 0x618 +{ + LOGMASKED(LOG_WATCHDOG, "%s: wctlr_r: WCTLR: %04x\n", machine().describe_context(), m_wctlr); + return m_wctlr; +} - case 0x106: - verboselog( *this, 2, "mc68328_r (%04x): GRPBASED = %04x\n", mem_mask, m_regs.grpbased); - return m_regs.grpbased; +void mc68328_device::wcmpr_w(u16 data) // 0x61a +{ + LOGMASKED(LOG_WATCHDOG, "%s: wcmpr_w: WCMPR = %04x\n", machine().describe_context(), data); + m_wcmpr = data; +} - case 0x108: - verboselog( *this, 2, "mc68328_r (%04x): GRPMASKA = %04x\n", mem_mask, m_regs.grpmaska); - return m_regs.grpmaska; +u16 mc68328_device::wcmpr_r() // 0x61a +{ + LOGMASKED(LOG_WATCHDOG, "%s: wcmpr_r: WCMPR: %04x\n", machine().describe_context(), m_wcmpr); + return m_wcmpr; +} - case 0x10a: - verboselog( *this, 2, "mc68328_r (%04x): GRPMASKB = %04x\n", mem_mask, m_regs.grpmaskb); - return m_regs.grpmaskb; +void mc68328_device::wcn_w(u16 data) // 0x61c +{ + LOGMASKED(LOG_WATCHDOG, "%s: wcn_w: WCN = %04x (Ignored)\n", machine().describe_context(), data); +} - case 0x10c: - verboselog( *this, 2, "mc68328_r (%04x): GRPMASKC = %04x\n", mem_mask, m_regs.grpmaskc); - return m_regs.grpmaskc; +u16 mc68328_device::wcn_r() // 0x61c +{ + LOGMASKED(LOG_WATCHDOG, "%s: wcn_r: WCN: %04x\n", machine().describe_context(), m_wcn); + return m_wcn; +} - case 0x10e: - verboselog( *this, 2, "mc68328_r (%04x): GRPMASKD = %04x\n", mem_mask, m_regs.grpmaskd); - return m_regs.grpmaskd; - case 0x110: - verboselog( *this, 5, "mc68328_r (%04x): CSA0(0) = %04x\n", mem_mask, m_regs.csa0 & 0x0000ffff); - return m_regs.csa0 & 0x0000ffff; +//------------------------------------------------- +// SPIS hardware +//------------------------------------------------- + +void mc68328_device::spisr_w(u16 data) // 0x700 +{ + LOGMASKED(LOG_SPIS, "%s: spisr_w: SPISR = %04x\n", machine().describe_context(), data); + m_spisr = data; +} - case 0x112: - verboselog( *this, 5, "mc68328_r (%04x): CSA0(16) = %04x\n", mem_mask, m_regs.csa0 >> 16); - return m_regs.csa0 >> 16; +u16 mc68328_device::spisr_r() // 0x700 +{ + LOGMASKED(LOG_SPIS, "%s: spisr_r: SPISR: %04x\n", machine().describe_context(), m_spisr); + return m_spisr; +} - case 0x114: - verboselog( *this, 5, "mc68328_r (%04x): CSA1(0) = %04x\n", mem_mask, m_regs.csa1 & 0x0000ffff); - return m_regs.csa1 & 0x0000ffff; - case 0x116: - verboselog( *this, 5, "mc68328_r (%04x): CSA1(16) = %04x\n", mem_mask, m_regs.csa1 >> 16); - return m_regs.csa1 >> 16; +//------------------------------------------------- +// SPIM hardware +//------------------------------------------------- - case 0x118: - verboselog( *this, 5, "mc68328_r (%04x): CSA2(0) = %04x\n", mem_mask, m_regs.csa2 & 0x0000ffff); - return m_regs.csa2 & 0x0000ffff; +TIMER_CALLBACK_MEMBER(mc68328_base_device::spim_tick) +{ + m_spmclk = !m_spmclk; + const bool idle_state = BIT(m_spimcont, SPIM_POL_BIT); + const bool invert_phase = BIT(m_spimcont, SPIM_PHA_BIT); - case 0x11a: - verboselog( *this, 5, "mc68328_r (%04x): CSA2(16) = %04x\n", mem_mask, m_regs.csa2 >> 16); - return m_regs.csa2 >> 16; + u16 spim_bit_index = m_spimcont & SPIM_BIT_COUNT; - case 0x11c: - verboselog( *this, 5, "mc68328_r (%04x): CSA3(0) = %04x\n", mem_mask, m_regs.csa3 & 0x0000ffff); - return m_regs.csa3 & 0x0000ffff; + LOGMASKED(LOG_SPIM, "SPIM Tick:\n"); + LOGMASKED(LOG_SPIM, " CLK state: %d\n", m_spmclk); + LOGMASKED(LOG_SPIM, " Bit index: %d\n", spim_bit_index); + LOGMASKED(LOG_SPIM, " Data before: %04x\n", m_spimdata); - case 0x11e: - verboselog( *this, 5, "mc68328_r (%04x): CSA3(16) = %04x\n", mem_mask, m_regs.csa3 >> 16); - return m_regs.csa3 >> 16; + const bool clock_txd = (m_spmclk == idle_state && invert_phase) || (m_spmclk != idle_state && !invert_phase); + if (clock_txd) + { + m_spmtxd = BIT(m_spimdata, m_spim_bit_read_idx); + LOGMASKED(LOG_SPIM, " Clocking TxD: %d\n", m_spmtxd); + m_out_spim_cb(m_spmtxd); + } + else + { + m_spmrxd = m_in_spim_cb(); + LOGMASKED(LOG_SPIM, " Clocking RxD: %d\n", m_spmrxd); + LOGMASKED(LOG_SPIM, " Shifting\n"); + m_spimdata = (m_spimdata << 1) | m_spmrxd; + } + LOGMASKED(LOG_SPIM, " Data after: %04x\n", m_spimdata); - case 0x120: - verboselog( *this, 5, "mc68328_r (%04x): CSB0(0) = %04x\n", mem_mask, m_regs.csb0 & 0x0000ffff); - return m_regs.csb0 & 0x0000ffff; + if (m_spmclk == idle_state) + { + if (spim_bit_index == 0) + { + LOGMASKED(LOG_SPIM, " Bit 0 clocked out, ending transfer\n"); + m_spim->adjust(attotime::never); - case 0x122: - verboselog( *this, 5, "mc68328_r (%04x): CSB0(16) = %04x\n", mem_mask, m_regs.csb0 >> 16); - return m_regs.csb0 >> 16; + if (BIT(m_spimcont, SPIM_IRQEN_BIT)) + { + m_spimcont |= (1 << SPIM_SPIMIRQ_BIT); + LOGMASKED(LOG_SPIM, "Triggering SPIM Interrupt\n" ); + set_interrupt_line(INT_SPIM, 1); + } + } + else + { + spim_bit_index--; + m_spimcont &= ~SPIM_BIT_COUNT; + m_spimcont |= spim_bit_index; + } + } +} - case 0x124: - verboselog( *this, 5, "mc68328_r (%04x): CSB1(0) = %04x\n", mem_mask, m_regs.csb1 & 0x0000ffff); - return m_regs.csb1 & 0x0000ffff; +void mc68328_base_device::spimdata_w(u16 data) // 0x800 +{ + LOGMASKED(LOG_SPIM, "%s: spimdata_w: SPIMDATA = %04x\n", machine().describe_context(), data); + m_spimdata = data; +} - case 0x126: - verboselog( *this, 5, "mc68328_r (%04x): CSB1(16) = %04x\n", mem_mask, m_regs.csb1 >> 16); - return m_regs.csb1 >> 16; +u16 mc68328_base_device::spimdata_r() // 0x800 +{ + LOGMASKED(LOG_SPIM, "%s: spimdata_r: SPIMDATA: %04x\n", machine().describe_context(), m_spimdata); + return m_spimdata; +} - case 0x128: - verboselog( *this, 5, "mc68328_r (%04x): CSB2(0) = %04x\n", mem_mask, m_regs.csb2 & 0x0000ffff); - return m_regs.csb2 & 0x0000ffff; +void mc68328_base_device::spimcont_w(u16 data) // 0x802 +{ + LOGMASKED(LOG_SPIM, "%s: spimcont_w: SPIMCONT = %04x\n", machine().describe_context(), data); + LOGMASKED(LOG_SPIM, "%s: Count = %d\n", machine().describe_context(), data & SPIM_BIT_COUNT); + LOGMASKED(LOG_SPIM, "%s: Polarity = %s\n", machine().describe_context(), BIT(data, SPIM_POL_BIT) ? "Inverted" : "Active-high"); + LOGMASKED(LOG_SPIM, "%s: Phase = %s\n", machine().describe_context(), BIT(data, SPIM_PHA_BIT) ? "Opposite" : "Normal"); + LOGMASKED(LOG_SPIM, "%s: IRQ Enable = %s\n", machine().describe_context(), BIT(data, SPIM_IRQEN_BIT) ? "Enable" : "Disable"); + LOGMASKED(LOG_SPIM, "%s: IRQ Pending = %s\n", machine().describe_context(), BIT(data, SPIM_SPIMIRQ_BIT) ? "Yes" : "No"); + LOGMASKED(LOG_SPIM, "%s: Exchange = %s\n", machine().describe_context(), BIT(data, SPIM_XCH_BIT) ? "Initiate" : "Idle"); + LOGMASKED(LOG_SPIM, "%s: SPIM Enable = %s\n", machine().describe_context(), BIT(data, SPIM_SPMEN_BIT) ? "Enable" : "Disable"); + LOGMASKED(LOG_SPIM, "%s: Data Rate = Divide By %d\n", machine().describe_context(), 4 << ((data & SPIM_RATE_MASK) >> SPIM_RATE_SHIFT) ); + + const u16 old = m_spimcont; + m_spimcont = data; + + if (BIT(data, SPIM_SPMEN_BIT) && BIT(data, SPIM_XCH_BIT) && !BIT(old, SPIM_XCH_BIT)) + { + const uint64_t divisor = 2 << ((data & SPIM_RATE_MASK) >> SPIM_RATE_SHIFT); + const attotime rate = attotime::from_ticks(divisor, clock()); + m_spim_bit_read_idx = m_spimcont & SPIM_BIT_COUNT; + m_spim->adjust(rate, 0, rate); - case 0x12a: - verboselog( *this, 5, "mc68328_r (%04x): CSB2(16) = %04x\n", mem_mask, m_regs.csb2 >> 16); - return m_regs.csb2 >> 16; + m_spimcont &= ~(1 << SPIM_XCH_BIT); + } - case 0x12c: - verboselog( *this, 5, "mc68328_r (%04x): CSB3(0) = %04x\n", mem_mask, m_regs.csb3 & 0x0000ffff); - return m_regs.csb3 & 0x0000ffff; + if (!BIT(data, SPIM_IRQEN_BIT) || !BIT(data, SPIM_SPIMIRQ_BIT)) + { + set_interrupt_line(INT_SPIM, 0); + } + else + { + set_interrupt_line(INT_SPIM, 1); + } +} - case 0x12e: - verboselog( *this, 5, "mc68328_r (%04x): CSB3(16) = %04x\n", mem_mask, m_regs.csb3 >> 16); - return m_regs.csb3 >> 16; +u16 mc68328_base_device::spimcont_r() // 0x802 +{ + LOGMASKED(LOG_SPIM, "%s: spimcont_r: SPIMCONT: %04x\n", machine().describe_context(), m_spimcont); + return m_spimcont; +} - case 0x130: - verboselog( *this, 5, "mc68328_r (%04x): CSC0(0) = %04x\n", mem_mask, m_regs.csc0 & 0x0000ffff); - return m_regs.csc0 & 0x0000ffff; - case 0x132: - verboselog( *this, 5, "mc68328_r (%04x): CSC0(16) = %04x\n", mem_mask, m_regs.csc0 >> 16); - return m_regs.csc0 >> 16; +//------------------------------------------------- +// UART hardware +//------------------------------------------------- - case 0x134: - verboselog( *this, 5, "mc68328_r (%04x): CSC1(0) = %04x\n", mem_mask, m_regs.csc1 & 0x0000ffff); - return m_regs.csc1 & 0x0000ffff; +void mc68328_base_device::ustcnt_w(u16 data) // 0x900 +{ + LOGMASKED(LOG_UART, "%s: ustcnt_w: USTCNT = %04x\n", machine().describe_context(), data); + m_ustcnt = data; +} - case 0x136: - verboselog( *this, 5, "mc68328_r (%04x): CSC1(16) = %04x\n", mem_mask, m_regs.csc1 >> 16); - return m_regs.csc1 >> 16; +u16 mc68328_base_device::ustcnt_r() // 0x900 +{ + LOGMASKED(LOG_UART, "%s: ustcnt_r: USTCNT: %04x\n", machine().describe_context(), m_ustcnt); + return m_ustcnt; +} - case 0x138: - verboselog( *this, 5, "mc68328_r (%04x): CSC2(0) = %04x\n", mem_mask, m_regs.csc2 & 0x0000ffff); - return m_regs.csc2 & 0x0000ffff; +void mc68328_base_device::ubaud_w(u16 data) // 0x902 +{ + LOGMASKED(LOG_UART, "%s: ubaud_w: UBAUD = %04x\n", machine().describe_context(), data); + m_ubaud = data; +} - case 0x13a: - verboselog( *this, 5, "mc68328_r (%04x): CSC2(16) = %04x\n", mem_mask, m_regs.csc2 >> 16); - return m_regs.csc2 >> 16; +u16 mc68328_base_device::ubaud_r() // 0x902 +{ + LOGMASKED(LOG_UART, "%s: ubaud_r: UBAUD: %04x\n", machine().describe_context(), m_ubaud); + return m_ubaud; +} - case 0x13c: - verboselog( *this, 5, "mc68328_r (%04x): CSC3(0) = %04x\n", mem_mask, m_regs.csc3 & 0x0000ffff); - return m_regs.csc3 & 0x0000ffff; +void mc68328_base_device::urx_w(u16 data) // 0x904 +{ + LOGMASKED(LOG_UART, "%s: urx_w: URX = %04x (Not Yet Implemented)\n", machine().describe_context(), data); +} - case 0x13e: - verboselog( *this, 5, "mc68328_r (%04x): CSC3(16) = %04x\n", mem_mask, m_regs.csc3 >> 16); - return m_regs.csc3 >> 16; +u16 mc68328_base_device::urx_r() // 0x904 +{ + LOGMASKED(LOG_UART, "%s: urx_r: URX: %04x\n", machine().describe_context(), m_urx); + return m_urx; +} - case 0x140: - verboselog( *this, 5, "mc68328_r (%04x): CSD0(0) = %04x\n", mem_mask, m_regs.csd0 & 0x0000ffff); - return m_regs.csd0 & 0x0000ffff; +void mc68328_base_device::utx_w(u16 data) // 0x906 +{ + LOGMASKED(LOG_UART, "%s: utx_w: UTX = %04x (Not Yet Implemented)\n", machine().describe_context(), data); +} - case 0x142: - verboselog( *this, 5, "mc68328_r (%04x): CSD0(16) = %04x\n", mem_mask, m_regs.csd0 >> 16); - return m_regs.csd0 >> 16; +u16 mc68328_base_device::utx_r() // 0x906 +{ + u16 data = m_utx | UTX_FIFO_EMPTY | UTX_FIFO_HALF | UTX_TX_AVAIL; + LOGMASKED(LOG_UART, "%s: utx_r: UTX: %04x\n", machine().describe_context(), data); + return data; +} - case 0x144: - verboselog( *this, 5, "mc68328_r (%04x): CSD1(0) = %04x\n", mem_mask, m_regs.csd1 & 0x0000ffff); - return m_regs.csd1 & 0x0000ffff; +void mc68328_base_device::umisc_w(u16 data) // 0x908 +{ + LOGMASKED(LOG_UART, "%s: umisc_w: UMISC = %04x (Not Yet Implemented)\n", machine().describe_context(), data); + m_umisc = data; +} - case 0x146: - verboselog( *this, 5, "mc68328_r (%04x): CSD1(16) = %04x\n", mem_mask, m_regs.csd1 >> 16); - return m_regs.csd1 >> 16; +u16 mc68328_base_device::umisc_r() // 0x908 +{ + LOGMASKED(LOG_UART, "%s: umisc_r: UMISC: %04x\n", machine().describe_context(), m_umisc); + return m_umisc; +} - case 0x148: - verboselog( *this, 5, "mc68328_r (%04x): CSD2(0) = %04x\n", mem_mask, m_regs.csd2 & 0x0000ffff); - return m_regs.csd2 & 0x0000ffff; - case 0x14a: - verboselog( *this, 5, "mc68328_r (%04x): CSD2(16) = %04x\n", mem_mask, m_regs.csd2 >> 16); - return m_regs.csd2 >> 16; +//------------------------------------------------- +// LCD hardware - Shared and Standard MC68328 +//------------------------------------------------- - case 0x14c: - verboselog( *this, 5, "mc68328_r (%04x): CSD3(0) = %04x\n", mem_mask, m_regs.csd3 & 0x0000ffff); - return m_regs.csd3 & 0x0000ffff; +void mc68328_device::lcd_update_info() +{ + if (!m_lcd_update_pending) + { + return; + } + const u32 sysclk_divisor = VCO_DIVISORS[(m_pllcr & PLLCR_SYSCLK_SEL) >> PLLCR_SYSCLK_SHIFT]; + attotime lcd_dma_duration = attotime::from_ticks(lcd_get_line_word_count() * sysclk_divisor, clock()); + attotime lcd_scan_duration = lcd_get_line_rate(); + attotime lcd_frame_duration = (lcd_scan_duration + lcd_dma_duration) * (m_lymax + 1); + LOGMASKED(LOG_LCD, "lxmax %d, lymax %d, divisor %d, lrra %02x, lpxcd %02x\n", m_lxmax, m_lymax + 1, sysclk_divisor, m_lpxcd + 1); - case 0x14e: - verboselog( *this, 5, "mc68328_r (%04x): CSD3(16) = %04x\n", mem_mask, m_regs.csd3 >> 16); - return m_regs.csd3 >> 16; + constexpr u8 BIT_WIDTHS[4] = { 1, 2, 4, 0xff }; + m_lcd_info_changed_cb(lcd_frame_duration.as_hz(), lcd_get_width(), m_lymax + 1, BIT_WIDTHS[(m_lpicf & LPICF_PBSIZ) >> LPICF_PBSIZ_SHIFT], BIT_WIDTHS[m_lpicf & LPICF_GS]); - case 0x200: - verboselog( *this, 2, "mc68328_r (%04x): PLLCR = %04x\n", mem_mask, m_regs.pllcr); - return m_regs.pllcr; + m_lcd_update_pending = false; +} - case 0x202: - verboselog( *this, 2, "mc68328_r (%04x): PLLFSR = %04x\n", mem_mask, m_regs.pllfsr); - m_regs.pllfsr ^= 0x8000; - return m_regs.pllfsr; +u16 mc68328_device::lcd_get_lxmax_mask() +{ + constexpr u16 LXMAX_MASK = 0x03ff; + return LXMAX_MASK; +} - case 0x206: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfff206)\n", mem_mask); - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): PCTLR = %02x\n", mem_mask, m_regs.pctlr); - return m_regs.pctlr << 8; - } - break; +int mc68328_device::lcd_get_width() +{ + return (m_lxmax & lcd_get_lxmax_mask()) + 1; +} - case 0x300: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfff301)\n", mem_mask); - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): IVR = %02x\n", mem_mask, m_regs.ivr); - return m_regs.ivr << 8; - } - break; +u32 mc68328_device::lcd_get_line_word_count() +{ + return m_lvpw != m_llbar ? (m_llbar + 1) : m_llbar; +} - case 0x302: - verboselog( *this, 2, "mc68328_r (%04x): ICR = %04x\n", mem_mask, m_regs.icr); - return m_regs.icr; +attotime mc68328_device::lcd_get_line_rate() +{ + const u32 sysclk_divisor = VCO_DIVISORS[(m_pllcr & PLLCR_SYSCLK_SEL) >> PLLCR_SYSCLK_SHIFT]; + return attotime::from_ticks(m_llbar, clock() / sysclk_divisor); +} - case 0x304: - verboselog( *this, 2, "mc68328_r (%04x): IMR(16) = %04x\n", mem_mask, m_regs.imr >> 16); - return m_regs.imr >> 16; +u8 mc68328_device::lcd_get_panel_bit_size() +{ + constexpr u8 BIT_WIDTHS[4] = { 1, 2, 4, 0xff }; + return BIT_WIDTHS[(m_lpicf & LPICF_PBSIZ) >> LPICF_PBSIZ_SHIFT]; +} - case 0x306: - verboselog( *this, 2, "mc68328_r (%04x): IMR(0) = %04x\n", mem_mask, m_regs.imr & 0x0000ffff); - return m_regs.imr & 0x0000ffff; +attotime mc68328_device::get_pixclk_rate() +{ + u32 divisor = 1; + if (BIT(m_lckcon, LCKCON_PCDS_BIT)) // Use PIXCLK from PLL + divisor = VCO_DIVISORS[(m_pllcr & PLLCR_PIXCLK_SEL) >> PLLCR_PIXCLK_SHIFT]; + else // Use SYSCLK from PLL + divisor = VCO_DIVISORS[(m_pllcr & PLLCR_SYSCLK_SEL) >> PLLCR_SYSCLK_SHIFT]; - case 0x308: - verboselog( *this, 2, "mc68328_r (%04x): IWR(16) = %04x\n", mem_mask, m_regs.iwr >> 16); - return m_regs.iwr >> 16; + return attotime::from_ticks((m_lpxcd & LPXCD_MASK) + 1, clock() / divisor); +} - case 0x30a: - verboselog( *this, 2, "mc68328_r (%04x): IWR(0) = %04x\n", mem_mask, m_regs.iwr & 0x0000ffff); - return m_regs.iwr & 0x0000ffff; +void mc68328_base_device::fill_lcd_dma_buffer() +{ + if (m_lcd_sysmem_ptr == m_lssa) + { + lcd_update_info(); + m_out_flm_cb(BIT(m_lpolcf, LPOLCF_FLMPOL_BIT) ? 0 : 1); + m_lssa_end = m_lssa + ((m_lvpw * (m_lymax + 1)) << 1); + } + else + { + m_out_flm_cb(BIT(m_lpolcf, LPOLCF_FLMPOL_BIT) ? 1 : 0); + } + m_out_llp_cb(BIT(m_lpolcf, LPOLCF_LPPOL_BIT) ? 0 : 1); - case 0x30c: - verboselog( *this, 2, "mc68328_r (%04x): ISR(16) = %04x\n", mem_mask, m_regs.isr >> 16); - return m_regs.isr >> 16; + attotime buffer_duration = lcd_get_line_rate(); + m_lcd_scan->adjust(buffer_duration); - case 0x30e: - verboselog( *this, 2, "mc68328_r (%04x): ISR(0) = %04x\n", mem_mask, m_regs.isr & 0x0000ffff); - return m_regs.isr & 0x0000ffff; + address_space &prg_space = space(AS_PROGRAM); + const u32 word_count = lcd_get_line_word_count(); + for (u32 word_index = 0; word_index < word_count; word_index++) + { + m_lcd_line_buffer[word_index] = prg_space.read_word(m_lcd_sysmem_ptr + (word_index << 1)); + } - case 0x310: - verboselog( *this, 2, "mc68328_r (%04x): IPR(16) = %04x\n", mem_mask, m_regs.ipr >> 16); - return m_regs.ipr >> 16; + m_lcd_sysmem_ptr += m_lvpw << 1; + if (m_lcd_sysmem_ptr >= m_lssa_end) + { + m_lcd_sysmem_ptr = m_lssa; + } - case 0x312: - verboselog( *this, 2, "mc68328_r (%04x): IPR(0) = %04x\n", mem_mask, m_regs.ipr & 0x0000ffff); - return m_regs.ipr & 0x0000ffff; + m_lcd_line_bit = 15; + m_lcd_line_word = 0; +} - case 0x400: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): PADATA = %02x\n", mem_mask, m_regs.padata); - if (!m_in_port_a_cb.isnull()) - { - return m_in_port_a_cb(0); - } - else - { - return m_regs.padata; - } - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): PADIR = %02x\n", mem_mask, m_regs.padir); - return m_regs.padir << 8; - } +TIMER_CALLBACK_MEMBER(mc68328_base_device::lcd_scan_tick) +{ + m_out_llp_cb(BIT(m_lpolcf, LPOLCF_LPPOL_BIT) ? 1 : 0); + m_lsclk = !m_lsclk; - case 0x402: - if (mem_mask & 0x00ff) + if (m_lsclk) + { + u8 data = 0; + switch (lcd_get_panel_bit_size()) + { + case 1: + data = BIT(m_lcd_line_buffer[m_lcd_line_word], m_lcd_line_bit); + if (m_lcd_line_bit == 0) { - verboselog( *this, 2, "mc68328_r (%04x): PASEL = %02x\n", mem_mask, m_regs.pasel); - return m_regs.pasel; + m_lcd_line_bit = 15; + m_lcd_line_word++; } else { - verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfff402)\n", mem_mask); + m_lcd_line_bit--; } break; - - case 0x408: - if (mem_mask & 0x00ff) + case 2: + data = (m_lcd_line_buffer[m_lcd_line_word] >> (m_lcd_line_bit - 1)) & 3; + if (m_lcd_line_bit <= 1) { - verboselog( *this, 2, "mc68328_r (%04x): PBDATA = %02x\n", mem_mask, m_regs.pbdata); - if (!m_in_port_b_cb.isnull()) - { - return m_in_port_b_cb(0); - } - else - { - return m_regs.pbdata; - } + m_lcd_line_bit = 15; + m_lcd_line_word++; } else { - verboselog( *this, 2, "mc68328_r (%04x): PBDIR = %02x\n", mem_mask, m_regs.pbdir); - return m_regs.pbdir << 8; + m_lcd_line_bit -= 2; } - - case 0x40a: - if (mem_mask & 0x00ff) + break; + case 4: + data = (m_lcd_line_buffer[m_lcd_line_word] >> (m_lcd_line_bit - 3)) & 15; + if (m_lcd_line_bit <= 3) { - verboselog( *this, 2, "mc68328_r (%04x): PBSEL = %02x\n", mem_mask, m_regs.pbsel); - return m_regs.pbsel; + m_lcd_line_bit = 15; + m_lcd_line_word++; } else { - verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfff40a)\n", mem_mask); + m_lcd_line_bit -= 4; } break; + default: + // Invalid mode; don't send anything + break; + } + m_out_ld_cb(data); + } + m_out_lsclk_cb(m_lsclk); - case 0x410: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): PCDATA = %02x\n", mem_mask, m_regs.pcdata); - if (!m_in_port_c_cb.isnull()) - { - return m_in_port_c_cb(0); - } - else - { - return m_regs.pcdata; - } - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): PCDIR = %02x\n", mem_mask, m_regs.pcdir); - return m_regs.pcdir << 8; - } + if (m_lcd_line_word == lcd_get_line_word_count()) + { + fill_lcd_dma_buffer(); + } + else + { + m_lcd_scan->adjust(get_pixclk_rate()); + } +} - case 0x412: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): PCSEL = %02x\n", mem_mask, m_regs.pcsel); - return m_regs.pcsel; - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfff412)\n", mem_mask); - } - break; +void mc68328_base_device::lssa_msw_w(offs_t offset, u16 data, u16 mem_mask) // 0xa00 +{ + LOGMASKED(LOG_LCD, "%s: lssa_msw_w: LSSA(MSW) = %04x\n", machine().describe_context(), data); + m_lssa &= ~(mem_mask << 16); + m_lssa |= (data & mem_mask) << 16; + LOGMASKED(LOG_LCD, "%s: Address: %08x\n", machine().describe_context(), m_lssa); +} - case 0x418: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): PDDATA = %02x\n", mem_mask, m_regs.pddata); - if (!m_in_port_d_cb.isnull()) - { - return m_in_port_d_cb(0); - } - else - { - return m_regs.pddata; - } - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): PDDIR = %02x\n", mem_mask, m_regs.pddir); - return m_regs.pddir << 8; - } +u16 mc68328_base_device::lssa_msw_r() // 0xa00 +{ + LOGMASKED(LOG_LCD, "%s: lssa_msw_r: LSSA(MSW): %04x\n", machine().describe_context(), (u16)(m_lssa >> 16)); + return (u16)(m_lssa >> 16); +} - case 0x41a: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfff41b)\n", mem_mask); - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): PDPUEN = %02x\n", mem_mask, m_regs.pdpuen); - return m_regs.pdpuen << 8; - } +void mc68328_base_device::lssa_lsw_w(offs_t offset, u16 data, u16 mem_mask) // 0xa02 +{ + LOGMASKED(LOG_LCD, "%s: lssa_lsw_w: LSSA(LSW) = %04x\n", machine().describe_context(), data); + m_lssa &= 0xffff0000 | (~mem_mask); + m_lssa |= data & mem_mask; + LOGMASKED(LOG_LCD, " Address: %08x\n", machine().describe_context(), m_lssa); +} + +u16 mc68328_base_device::lssa_lsw_r() // 0xa02 +{ + LOGMASKED(LOG_LCD, "%s: lssa_lsw_r: LSSA(LSW): %04x\n", machine().describe_context(), (u16)m_lssa); + return (u16)m_lssa; +} + +void mc68328_base_device::lvpw_w(u8 data) // 0xa05 +{ + LOGMASKED(LOG_LCD, "%s: lvpw_w: LVPW = %02x\n", machine().describe_context(), data); + m_lvpw = data; + LOGMASKED(LOG_LCD, "%s: Virtual Page Width: %d words\n", machine().describe_context(), m_lvpw); +} + +u8 mc68328_base_device::lvpw_r() // 0xa05 +{ + LOGMASKED(LOG_LCD, "%s: lvpw_r: LVPW: %02x\n", machine().describe_context(), m_lvpw); + return m_lvpw; +} + +void mc68328_base_device::lxmax_w(u16 data) // 0xa08 +{ + m_lcd_update_pending = m_lcd_update_pending || (m_lxmax != (data & lcd_get_lxmax_mask())); + LOGMASKED(LOG_LCD, "%s: lxmax_w: LXMAX = %04x\n", machine().describe_context(), data); + m_lxmax = data & lcd_get_lxmax_mask(); + LOGMASKED(LOG_LCD, "%s: Width: %d\n", machine().describe_context(), lcd_get_width()); +} + +u16 mc68328_base_device::lxmax_r() // 0xa08 +{ + LOGMASKED(LOG_LCD, "%s: lxmax_r: LXMAX: %04x\n", machine().describe_context(), m_lxmax); + return m_lxmax; +} + +void mc68328_base_device::lymax_w(u16 data) // 0xa0a +{ + m_lcd_update_pending = m_lcd_update_pending || (m_lxmax != (data & LYMAX_MASK)); + LOGMASKED(LOG_LCD, "%s: lymax_w: LYMAX = %04x\n", machine().describe_context(), data); + m_lymax = data & LYMAX_MASK; + LOGMASKED(LOG_LCD, "%s: Height: %d\n", machine().describe_context(), (data & 0x03ff) + 1); +} + +u16 mc68328_base_device::lymax_r() // 0xa0a +{ + LOGMASKED(LOG_LCD, "%s: lymax_r: LYMAX: %04x\n", machine().describe_context(), m_lymax); + return m_lymax; +} + +void mc68328_base_device::lcxp_w(u16 data) // 0xa18 +{ + LOGMASKED(LOG_LCD, "%s: lcxp_w: LCXP = %04x\n", machine().describe_context(), data); + m_lcxp = data; + LOGMASKED(LOG_LCD, "%s: X Position: %d\n", machine().describe_context(), data & 0x03ff); + switch (m_lcxp >> 14) + { + case 0: + LOGMASKED(LOG_LCD, "%s: Cursor Control: Transparent\n", machine().describe_context()); break; - case 0x41c: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): PDIRQEN = %02x\n", mem_mask, m_regs.pdirqen); - return m_regs.pdirqen; - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): PDPOL = %02x\n", mem_mask, m_regs.pdpol); - return m_regs.pdpol << 8; - } + case 1: + LOGMASKED(LOG_LCD, "%s: Cursor Control: Black\n", machine().describe_context()); + break; - case 0x41e: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): PDIRQEDGE = %02x\n", mem_mask, m_regs.pdirqedge); - return m_regs.pdirqedge; - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfff41e)\n", mem_mask); - } + case 2: + LOGMASKED(LOG_LCD, "%s: Cursor Control: Reverse\n", machine().describe_context()); break; - case 0x420: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): PEDATA = %02x\n", mem_mask, m_regs.pedata); - if (!m_in_port_e_cb.isnull()) - { - return m_in_port_e_cb(0); - } - else - { - return m_regs.pedata; - } - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): PEDIR = %02x\n", mem_mask, m_regs.pedir); - return m_regs.pedir << 8; - } + case 3: + LOGMASKED(LOG_LCD, "%s: Cursor Control: Invalid\n", machine().describe_context()); + break; + } +} - case 0x422: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): PESEL = %02x\n", mem_mask, m_regs.pesel); - return m_regs.pesel; - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): PEPUEN = %02x\n", mem_mask, m_regs.pepuen); - return m_regs.pepuen << 8; - } +u16 mc68328_base_device::lcxp_r() // 0xa18 +{ + LOGMASKED(LOG_LCD, "%s: lcxp_r: LCXP: %04x\n", machine().describe_context(), m_lcxp); + return m_lcxp; +} - case 0x428: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): PFDATA = %02x\n", mem_mask, m_regs.pfdata); - if (!m_in_port_f_cb.isnull()) - { - return m_in_port_f_cb(0); - } - else - { - return m_regs.pfdata; - } - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): PFDIR = %02x\n", mem_mask, m_regs.pfdir); - return m_regs.pfdir << 8; - } +void mc68328_base_device::lcyp_w(u16 data) // 0xa1a +{ + LOGMASKED(LOG_LCD, "%s: lcyp_w: LCYP = %04x\n", machine().describe_context(), data); + m_lcyp = data; + LOGMASKED(LOG_LCD, "%s: Y Position: %d\n", machine().describe_context(), data & 0x01ff); +} - case 0x42a: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): PFSEL = %02x\n", mem_mask, m_regs.pfsel); - return m_regs.pfsel; - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): PFPUEN = %02x\n", mem_mask, m_regs.pfpuen); - return m_regs.pfpuen << 8; - } +u16 mc68328_base_device::lcyp_r() // 0xa1a +{ + LOGMASKED(LOG_LCD, "%s: lcyp_r: LCYP: %04x\n", machine().describe_context(), m_lcyp); + return m_lcyp; +} - case 0x430: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): PGDATA = %02x\n", mem_mask, m_regs.pgdata); - if (!m_in_port_g_cb.isnull()) - { - return m_in_port_g_cb(0); - } - else - { - return m_regs.pgdata; - } - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): PGDIR = %02x\n", mem_mask, m_regs.pgdir); - return m_regs.pgdir << 8; - } +void mc68328_base_device::lcwch_w(u16 data) // 0xa1c +{ + LOGMASKED(LOG_LCD, "%s: lcwch_w: LCWCH = %04x\n", machine().describe_context(), data); + m_lcwch = data; + LOGMASKED(LOG_LCD, "%s: Width: %d\n", machine().describe_context(), (data >> 8) & 0x1f); + LOGMASKED(LOG_LCD, "%s: Height: %d\n", machine().describe_context(), data & 0x1f); +} - case 0x432: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): PGSEL = %02x\n", mem_mask, m_regs.pgsel); - return m_regs.pgsel; - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): PGPUEN = %02x\n", mem_mask, m_regs.pgpuen); - return m_regs.pgpuen << 8; - } +u16 mc68328_base_device::lcwch_r() // 0xa1c +{ + LOGMASKED(LOG_LCD, "%s: lcwch_r: LCWCH: %04x\n", machine().describe_context(), m_lcwch); + return m_lcwch; +} - case 0x438: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): PJDATA = %02x\n", mem_mask, m_regs.pjdata); - if (!m_in_port_j_cb.isnull()) - { - return m_in_port_j_cb(0); - } - else - { - return m_regs.pjdata; - } - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): PJDIR = %02x\n", mem_mask, m_regs.pjdir); - return m_regs.pjdir << 8; - } +void mc68328_base_device::lblkc_w(u8 data) // 0xa1f +{ + LOGMASKED(LOG_LCD, "%s: lblkc_w: LBLKC = %02x\n", machine().describe_context(), data); + m_lblkc = data; + LOGMASKED(LOG_LCD, "%s: Blink Enable: %d\n", machine().describe_context(), m_lblkc >> 7); + LOGMASKED(LOG_LCD, "%s: Blink Divisor: %d\n", machine().describe_context(), m_lblkc & 0x7f); +} - case 0x43a: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): PJSEL = %02x\n", mem_mask, m_regs.pjsel); - return m_regs.pjsel; - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfff43a)\n", mem_mask); - } - break; +u8 mc68328_base_device::lblkc_r() // 0xa1f +{ + LOGMASKED(LOG_LCD, "%s: lblkc_r: LBLKC: %02x\n", machine().describe_context(), m_lblkc); + return m_lblkc; +} - case 0x440: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): PKDATA = %02x\n", mem_mask, m_regs.pkdata); - if (!m_in_port_k_cb.isnull()) - { - return m_in_port_k_cb(0); - } - else - { - return m_regs.pkdata; - } - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): PKDIR = %02x\n", mem_mask, m_regs.pkdir); - return m_regs.pkdir << 8; - } +void mc68328_device::lpicf_w(u8 data) // 0xa20 +{ + static const char *const PBSIZ_NAMES[4] = { "1-bit", "2-bit", "4-bit", "Invalid" }; + LOGMASKED(LOG_LCD, "%s: lpicf_w: LPICF = %02x\n", machine().describe_context(), data); + LOGMASKED(LOG_LCD, "%s: Grayscale Mode: %d\n", machine().describe_context(), data & LPICF_GS); + LOGMASKED(LOG_LCD, "%s: Bus Size: %s\n", machine().describe_context(), PBSIZ_NAMES[(data & LPICF_PBSIZ) >> LPICF_PBSIZ_SHIFT]); + m_lpicf = data; +} - case 0x442: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): PKSEL = %02x\n", mem_mask, m_regs.pksel); - return m_regs.pksel; - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): PKPUEN = %02x\n", mem_mask, m_regs.pkpuen); - return m_regs.pkpuen << 8; - } +u8 mc68328_base_device::lpicf_r() // 0xa20 +{ + LOGMASKED(LOG_LCD, "%s: lpicf_r: LPICF: %02x\n", machine().describe_context(), m_lpicf); + return m_lpicf; +} - case 0x448: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): PMDATA = %02x\n", mem_mask, m_regs.pmdata); - if (!m_in_port_m_cb.isnull()) - { - return m_in_port_m_cb(0); - } - else - { - return m_regs.pmdata; - } - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): PMDIR = %02x\n", mem_mask, m_regs.pmdir); - return m_regs.pmdir << 8; - } +void mc68328_base_device::lpolcf_w(u8 data) // 0xa21 +{ + LOGMASKED(LOG_LCD, "%s: lpolcf_w: LPOLCF = %02x\n", machine().describe_context(), data); + m_lpolcf = data; + LOGMASKED(LOG_LCD, "%s: LCD Shift Clock Polarity: %s\n", machine().describe_context(), (m_lpicf & 0x08) ? "Active positive edge of LCLK" : "Active negative edge of LCLK"); + LOGMASKED(LOG_LCD, "%s: First-line marker polarity: %s\n", machine().describe_context(), (m_lpicf & 0x04) ? "Active Low" : "Active High"); + LOGMASKED(LOG_LCD, "%s: Line-pulse polarity: %s\n", machine().describe_context(), (m_lpicf & 0x02) ? "Active Low" : "Active High"); + LOGMASKED(LOG_LCD, "%s: Pixel polarity: %s\n", machine().describe_context(), (m_lpicf & 0x01) ? "Active Low" : "Active High"); +} - case 0x44a: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): PMSEL = %02x\n", mem_mask, m_regs.pmsel); - return m_regs.pmsel; - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): PMPUEN = %02x\n", mem_mask, m_regs.pmpuen); - return m_regs.pmpuen << 8; - } +u8 mc68328_base_device::lpolcf_r() // 0xa21 +{ + LOGMASKED(LOG_LCD, "%s: lpolcf_r: LPOLCF: %02x\n", machine().describe_context(), m_lpolcf); + return m_lpolcf; +} - case 0x500: - verboselog( *this, 2, "mc68328_r (%04x): PWMC = %04x\n", mem_mask, m_regs.pwmc); - temp16 = m_regs.pwmc; - if (m_regs.pwmc & PWMC_PWMIRQ) - { - m_regs.pwmc &= ~PWMC_PWMIRQ; - set_interrupt_line(INT_PWM, 0); - } - return temp16; +void mc68328_base_device::lacdrc_w(u8 data) // 0xa23 +{ + LOGMASKED(LOG_LCD, "%s: lacdrc_w: LACDRC = %02x\n", machine().describe_context(), data); + m_lacdrc = data; +} - case 0x502: - verboselog( *this, 2, "mc68328_r (%04x): PWMP = %04x\n", mem_mask, m_regs.pwmp); - return m_regs.pwmp; +u8 mc68328_base_device::lacdrc_r() // 0xa23 +{ + LOGMASKED(LOG_LCD, "%s: lacdrc_r: LACDRC: %02x\n", machine().describe_context(), m_lacdrc); + return m_lacdrc; +} - case 0x504: - verboselog( *this, 2, "mc68328_r (%04x): PWMW = %04x\n", mem_mask, m_regs.pwmw); - return m_regs.pwmw; +void mc68328_base_device::lpxcd_w(u8 data) // 0xa25 +{ + LOGMASKED(LOG_LCD, "%s: lpxcd_w: LPXCD = %02x\n", machine().describe_context(), data); + m_lpxcd = data; + LOGMASKED(LOG_LCD, "%s: Clock Divisor: %d\n", machine().describe_context(), m_lpxcd + 1); +} - case 0x506: - verboselog( *this, 2, "mc68328_r (%04x): PWMCNT = %04x\n", mem_mask, m_regs.pwmcnt); - return m_regs.pwmcnt; +u8 mc68328_base_device::lpxcd_r() // 0xa25 +{ + LOGMASKED(LOG_LCD, "%s: lpxcd_r: LPXCD: %02x\n", machine().describe_context(), m_lpxcd); + return m_lpxcd; +} - case 0x600: - verboselog( *this, 2, "mc68328_r (%04x): TCTL1 = %04x\n", mem_mask, m_regs.tctl[0]); - return m_regs.tctl[0]; +void mc68328_device::lckcon_w(u8 data) // 0xa27 +{ + LOGMASKED(LOG_LCD, "%s: lckcon_w: LCKCON = %02x\n", machine().describe_context(), data); + LOGMASKED(LOG_LCD, "%s: LCDC Enable: %d\n", machine().describe_context(), BIT(data, LCKCON_LCDON_BIT)); + LOGMASKED(LOG_LCD, "%s: DMA Burst Length: %d\n", machine().describe_context(), BIT(data, LCKCON_DMA16_BIT) ? 16 : 8); + LOGMASKED(LOG_LCD, "%s: DMA Bursting Clock Control: %d\n", machine().describe_context(), ((data & LCKCON_WS) >> LCKCON_WS_SHIFT) + 1); + LOGMASKED(LOG_LCD, "%s: Bus Width: %d\n", machine().describe_context(), BIT(data, LCKCON_DWIDTH_BIT) ? 8 : 16); + LOGMASKED(LOG_LCD, "%s: Pixel Clock Divider Source: %s\n", machine().describe_context(), BIT(data, LCKCON_PCDS_BIT) ? "PIX" : "SYS"); + + const u16 old = m_lckcon; + m_lckcon = data; + + lcd_update_info(); + if (BIT(old, LCKCON_LCDON_BIT) && !BIT(m_lckcon, LCKCON_LCDON_BIT)) + { + m_lcd_scan->adjust(attotime::never); + } + else if (!BIT(old, LCKCON_LCDON_BIT) && BIT(m_lckcon, LCKCON_LCDON_BIT)) + { + m_lcd_scan->adjust(attotime::never); + m_lcd_sysmem_ptr = m_lssa; + fill_lcd_dma_buffer(); + } +} - case 0x602: - verboselog( *this, 2, "mc68328_r (%04x): TPRER1 = %04x\n", mem_mask, m_regs.tprer[0]); - return m_regs.tprer[0]; +u8 mc68328_base_device::lckcon_r() // 0xa27 +{ + LOGMASKED(LOG_LCD, "%s: lckcon_r: LCKCON: %02x\n", machine().describe_context(), m_lckcon); + return m_lckcon; +} - case 0x604: - verboselog( *this, 2, "mc68328_r (%04x): TCMP1 = %04x\n", mem_mask, m_regs.tcmp[0]); - return m_regs.tcmp[0]; +void mc68328_device::llbar_w(u8 data) // 0xa29 +{ + LOGMASKED(LOG_LCD, "%s: llbar_w: LLBAR = %02x\n", machine().describe_context(), data); + m_llbar = data; + LOGMASKED(LOG_LCD, "%s: Address: %d\n", machine().describe_context(), m_llbar << (BIT(m_lpicf, LPICF_GS_BIT) ? 4 : 5)); +} - case 0x606: - verboselog( *this, 2, "mc68328_r (%04x): TCR1 = %04x\n", mem_mask, m_regs.tcr[0]); - return m_regs.tcr[0]; +u8 mc68328_device::llbar_r() // 0xa29 +{ + LOGMASKED(LOG_LCD, "%s: llbar_r: LLBAR: %02x\n", machine().describe_context(), m_llbar); + return m_llbar; +} - case 0x608: - verboselog( *this, 2, "mc68328_r (%04x): TCN1 = %04x\n", mem_mask, m_regs.tcn[0]); - return m_regs.tcn[0]; +void mc68328_device::lotcr_w(u8 data) // 0xa2b +{ + LOGMASKED(LOG_LCD, "%s: lotcr_w: LOTCR = %02x (Ignored)\n", machine().describe_context(), data); +} - case 0x60a: - verboselog( *this, 5, "mc68328_r (%04x): TSTAT1 = %04x\n", mem_mask, m_regs.tstat[0]); - m_regs.tclear[0] |= m_regs.tstat[0]; - return m_regs.tstat[0]; +u8 mc68328_device::lotcr_r() // 0xa2b +{ + LOGMASKED(LOG_LCD, "%s: lotcr_r: LOTCR: %02x\n", machine().describe_context(), m_lotcr); + return m_lotcr; +} - case 0x60c: - verboselog( *this, 2, "mc68328_r (%04x): TCTL2 = %04x\n", mem_mask, m_regs.tctl[1]); - return m_regs.tctl[1]; +void mc68328_base_device::lposr_w(u8 data) // 0xa2d +{ + LOGMASKED(LOG_LCD, "%s: lposr_w: LPOSR = %02x\n", machine().describe_context(), data); + m_lposr = data; + LOGMASKED(LOG_LCD, "%s: Byte Offset: %d\n", machine().describe_context(), (m_lposr >> 3) & 0x01); + LOGMASKED(LOG_LCD, "%s: Pixel Offset: %d\n", machine().describe_context(), m_lposr & 0x07); +} - case 0x60e: - verboselog( *this, 2, "mc68328_r (%04x): TPREP2 = %04x\n", mem_mask, m_regs.tprer[1]); - return m_regs.tprer[1]; +u8 mc68328_base_device::lposr_r() // 0xa2d +{ + LOGMASKED(LOG_LCD, "%s: lposr_r: LPOSR: %02x\n", machine().describe_context(), m_lposr); + return m_lposr; +} - case 0x610: - verboselog( *this, 2, "mc68328_r (%04x): TCMP2 = %04x\n", mem_mask, m_regs.tcmp[1]); - return m_regs.tcmp[1]; +void mc68328_base_device::lfrcm_w(u8 data) // 0xa31 +{ + LOGMASKED(LOG_LCD, "%s: lfrcm_w: LFRCM = %02x\n", machine().describe_context(), data); + m_lfrcm = data; + LOGMASKED(LOG_LCD, "%s: X Modulation: %d\n", machine().describe_context(), (m_lfrcm >> 4) & 0x0f); + LOGMASKED(LOG_LCD, "%s: Y Modulation: %d\n", machine().describe_context(), m_lfrcm & 0x0f); +} - case 0x612: - verboselog( *this, 2, "mc68328_r (%04x): TCR2 = %04x\n", mem_mask, m_regs.tcr[1]); - return m_regs.tcr[1]; +u8 mc68328_base_device::lfrcm_r() // 0xa31 +{ + LOGMASKED(LOG_LCD, "%s: lfrcm_r: LFRCM: %02x\n", machine().describe_context(), m_lfrcm); + return m_lfrcm; +} - case 0x614: - verboselog( *this, 2, "mc68328_r (%04x): TCN2 = %04x\n", mem_mask, m_regs.tcn[1]); - return m_regs.tcn[1]; +void mc68328_device::lgpmr_w(u8 data) // 0xa32 +{ + LOGMASKED(LOG_LCD, "%s: lgpmr_w: LGPMR = %04x\n", machine().describe_context(), data); + m_lgpmr = data; + LOGMASKED(LOG_LCD, "%s: Palette 0: %d\n", machine().describe_context(), (m_lgpmr >> 8) & 0x07); + LOGMASKED(LOG_LCD, "%s: Palette 1: %d\n", machine().describe_context(), (m_lgpmr >> 12) & 0x07); + LOGMASKED(LOG_LCD, "%s: Palette 2: %d\n", machine().describe_context(), (m_lgpmr >> 0) & 0x07); + LOGMASKED(LOG_LCD, "%s: Palette 3: %d\n", machine().describe_context(), (m_lgpmr >> 4) & 0x07); +} - case 0x616: - verboselog( *this, 2, "mc68328_r (%04x): TSTAT2 = %04x\n", mem_mask, m_regs.tstat[1]); - m_regs.tclear[1] |= m_regs.tstat[1]; - return m_regs.tstat[1]; +u16 mc68328_device::lgpmr_r() // 0xa32 +{ + LOGMASKED(LOG_LCD, "%s: lgpmr_r: LGPMR: %04x\n", machine().describe_context(), m_lgpmr); + return m_lgpmr; +} - case 0x618: - verboselog( *this, 2, "mc68328_r (%04x): WCTLR = %04x\n", mem_mask, m_regs.wctlr); - return m_regs.wctlr; - case 0x61a: - verboselog( *this, 2, "mc68328_r (%04x): WCMPR = %04x\n", mem_mask, m_regs.wcmpr); - return m_regs.wcmpr; +//------------------------------------------------- +// LCD hardware - EZ variant +//------------------------------------------------- - case 0x61c: - verboselog( *this, 2, "mc68328_r (%04x): WCN = %04x\n", mem_mask, m_regs.wcn); - return m_regs.wcn; +void mc68ez328_device::lcd_update_info() +{ + if (!m_lcd_update_pending) + { + return; + } - case 0x700: - verboselog( *this, 2, "mc68328_r (%04x): SPISR = %04x\n", mem_mask, m_regs.spisr); - return m_regs.spisr; + const u32 sysclk_divisor = VCO_DIVISORS[(m_pllcr & PLLCR_SYSCLK_SEL) >> PLLCR_SYSCLK_SHIFT]; + attotime lcd_dma_duration = attotime::from_ticks(lcd_get_line_word_count() * sysclk_divisor, clock()); + attotime lcd_scan_duration = lcd_get_line_rate(); + attotime lcd_frame_duration = (lcd_scan_duration + lcd_dma_duration) * (m_lymax + 1) * 2; - case 0x800: - verboselog( *this, 2, "mc68328_r (%04x): SPIMDATA = %04x\n", mem_mask, m_regs.spimdata); - if (!m_in_spim_cb.isnull()) - { - return m_in_spim_cb(0, 0xffff); - } - return m_regs.spimdata; + constexpr u8 BIT_WIDTHS[4] = { 1, 2, 4, 0xff }; + m_lcd_info_changed_cb(lcd_frame_duration.as_hz(), lcd_get_width(), m_lymax + 1, BIT_WIDTHS[(m_lpicf & LPICF_PBSIZ) >> LPICF_PBSIZ_SHIFT], BIT_WIDTHS[m_lpicf & LPICF_GS]); - case 0x802: - verboselog( *this, 2, "mc68328_r (%04x): SPIMCONT = %04x\n", mem_mask, m_regs.spimcont); - if (m_regs.spimcont & SPIM_XCH) - { - m_regs.spimcont &= ~SPIM_XCH; - m_regs.spimcont |= SPIM_SPIMIRQ; - return ((m_regs.spimcont | SPIM_XCH) &~ SPIM_SPIMIRQ); - } - return m_regs.spimcont; + m_lcd_update_pending = false; +} - case 0x900: - verboselog( *this, 2, "mc68328_r (%04x): USTCNT = %04x\n", mem_mask, m_regs.ustcnt); - return m_regs.ustcnt; +u16 mc68ez328_device::lcd_get_lxmax_mask() +{ + constexpr u16 LXMAX_MASK = 0x03f0; + return LXMAX_MASK; +} - case 0x902: - verboselog( *this, 2, "mc68328_r (%04x): UBAUD = %04x\n", mem_mask, m_regs.ubaud); - return m_regs.ubaud; +int mc68ez328_device::lcd_get_width() +{ + return m_lxmax & lcd_get_lxmax_mask(); +} - case 0x904: - verboselog( *this, 5, "mc68328_r (%04x): URX = %04x\n", mem_mask, m_regs.urx); - return m_regs.urx; +u32 mc68ez328_device::lcd_get_line_word_count() +{ + const u32 pixels_per_word = 16 / (1 << (m_lpicf & LPICF_GS)); + const u32 data = (m_lxmax & lcd_get_lxmax_mask()) / pixels_per_word; + return data; +} - case 0x906: - verboselog( *this, 5, "mc68328_r (%04x): UTX = %04x\n", mem_mask, m_regs.utx); - return m_regs.utx | UTX_FIFO_EMPTY | UTX_FIFO_HALF | UTX_TX_AVAIL; +attotime mc68ez328_device::lcd_get_line_rate() +{ + const u32 pixclk_divisor = VCO_DIVISORS[(m_pllcr & PLLCR_PIXCLK_SEL) >> PLLCR_PIXCLK_SHIFT]; + const u32 pxcd = (m_lpxcd & LPXCD_MASK) + 1; + const u32 lrra_factor = 6 + m_lrra + (m_lxmax & lcd_get_lxmax_mask()) * 4; + const u32 ticks = lrra_factor * pxcd * pixclk_divisor; + return attotime::from_ticks(ticks, clock()); +} - case 0x908: - verboselog( *this, 2, "mc68328_r (%04x): UMISC = %04x\n", mem_mask, m_regs.umisc); - return m_regs.umisc; +u8 mc68ez328_device::lcd_get_panel_bit_size() +{ + constexpr u8 BIT_WIDTHS[4] = { 1, 2, 4, 1 }; + return BIT_WIDTHS[(m_lpicf & LPICF_PBSIZ) >> LPICF_PBSIZ_SHIFT]; +} - case 0xa00: - verboselog( *this, 2, "mc68328_r (%04x): LSSA(16) = %04x\n", mem_mask, m_regs.lssa >> 16); - return m_regs.lssa >> 16; +attotime mc68ez328_device::get_pixclk_rate() +{ + u32 divisor = VCO_DIVISORS[(m_pllcr & PLLCR_PIXCLK_SEL) >> PLLCR_PIXCLK_SHIFT]; + return attotime::from_ticks((m_lpxcd & LPXCD_MASK) + 1, clock() / divisor); +} - case 0xa02: - verboselog( *this, 2, "mc68328_r (%04x): LSSA(0) = %04x\n", mem_mask, m_regs.lssa & 0x0000ffff); - return m_regs.lssa & 0x0000ffff; +void mc68ez328_device::lpicf_w(u8 data) // 0xa20 +{ + static const char *const PBSIZ_NAMES[4] = { "1-bit", "2-bit", "4-bit", "Invalid" }; + static const char *const GS_NAMES[4] = { "Monochrome", "4-level Grayscale", "16-level Grayscale", "Invalid" }; + LOGMASKED(LOG_LCD, "%s: lpicf_w: LPICF = %02x\n", machine().describe_context(), data); + LOGMASKED(LOG_LCD, "%s: Grayscale Mode: %d\n", machine().describe_context(), GS_NAMES[data & LPICF_GS]); + LOGMASKED(LOG_LCD, "%s: Bus Size: %s\n", machine().describe_context(), PBSIZ_NAMES[(data & LPICF_PBSIZ) >> LPICF_PBSIZ_SHIFT]); + m_lcd_update_pending = m_lcd_update_pending || (m_lpicf != data); + m_lpicf = data; +} - case 0xa04: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): LVPW = %02x\n", mem_mask, m_regs.lvpw); - return m_regs.lvpw; - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfffa04)\n", mem_mask); - } - break; +void mc68ez328_device::lckcon_w(u8 data) // 0xa27 +{ + LOGMASKED(LOG_LCD, "%s: lckcon_w: LCKCON = %02x\n", machine().describe_context(), data); + LOGMASKED(LOG_LCD, "%s: LCDC Enable: %d\n", machine().describe_context(), BIT(data, LCKCON_LCDON_BIT)); + LOGMASKED(LOG_LCD, "%s: Display Wait States: %d\n", machine().describe_context(), ((data & LCKCON_DWS) >> LCKCON_DWS_SHIFT) + 1); + LOGMASKED(LOG_LCD, "%s: Bus Width: %d\n", machine().describe_context(), BIT(data, LCKCON_DWIDTH_BIT) ? 8 : 16); - case 0xa08: - verboselog( *this, 2, "mc68328_r (%04x): LXMAX = %04x\n", mem_mask, m_regs.lxmax); - return m_regs.lxmax; + const u16 old = m_lckcon; + m_lckcon = data; - case 0xa0a: - verboselog( *this, 2, "mc68328_r (%04x): LYMAX = %04x\n", mem_mask, m_regs.lymax); - return m_regs.lymax; + lcd_update_info(); + if (BIT(old, LCKCON_LCDON_BIT) && !BIT(m_lckcon, LCKCON_LCDON_BIT)) + { + m_lcd_scan->adjust(attotime::never); + } + else if (!BIT(old, LCKCON_LCDON_BIT) && BIT(m_lckcon, LCKCON_LCDON_BIT)) + { + m_lcd_scan->adjust(attotime::never); + m_lcd_sysmem_ptr = m_lssa; + fill_lcd_dma_buffer(); + } +} - case 0xa18: - verboselog( *this, 2, "mc68328_r (%04x): LCXP = %04x\n", mem_mask, m_regs.lcxp); - return m_regs.lcxp; +void mc68ez328_device::lrra_w(u8 data) // 0xa29 +{ + LOGMASKED(LOG_LCD, "%s: lrra_w: LRRA = %02x\n", machine().describe_context(), data); + m_lcd_update_pending = m_lcd_update_pending || (m_lrra != data); + m_lrra = data; +} - case 0xa1a: - verboselog( *this, 2, "mc68328_r (%04x): LCYP = %04x\n", mem_mask, m_regs.lcyp); - return m_regs.lcyp; +u8 mc68ez328_device::lrra_r() // 0xa29 +{ + LOGMASKED(LOG_LCD, "%s: lrra_r: LRRA: %02x\n", machine().describe_context(), m_lrra); + return m_lrra; +} - case 0xa1c: - verboselog( *this, 2, "mc68328_r (%04x): LCWCH = %04x\n", mem_mask, m_regs.lcwch); - return m_regs.lcwch; +void mc68ez328_device::pwmr_w(offs_t offset, u16 data, u16 mem_mask) // 0xa36 +{ + LOGMASKED(LOG_LCD, "%s: pwmr_w: PWMR = %04x\n", machine().describe_context(), data); + m_pwmr = data; +} - case 0xa1e: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): LBLKC = %02x\n", mem_mask, m_regs.lblkc); - return m_regs.lblkc; - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfffa1e)\n", mem_mask); - } - break; +u16 mc68ez328_device::pwmr_r() // 0xa36 +{ + LOGMASKED(LOG_LCD, "%s: pwmr_r: PWMR: %04x\n", machine().describe_context(), m_lrra); + return m_pwmr; +} - case 0xa20: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): LPOLCF = %02x\n", mem_mask, m_regs.lpolcf); - return m_regs.lpolcf; - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): LPICF = %02x\n", mem_mask, m_regs.lpicf); - return m_regs.lpicf << 8; - } - case 0xa22: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): LACDRC = %02x\n", mem_mask, m_regs.lacdrc); - return m_regs.lacdrc; - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfffa22)\n", mem_mask); - } - break; +//------------------------------------------------- +// RTC/alarm hardware - Standard MC68328 +//------------------------------------------------- - case 0xa24: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): LPXCD = %02x\n", mem_mask, m_regs.lpxcd); - return m_regs.lpxcd; - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfffa24)\n", mem_mask); - } - break; +TIMER_CALLBACK_MEMBER(mc68328_base_device::rtc_tick) +{ + if (BIT(m_rtcctl, RTCCTL_ENABLE_BIT)) + { + const bool rtc_int_was_active = rtc_int_is_active(); - case 0xa26: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): LCKCON = %02x\n", mem_mask, m_regs.lckcon); - return m_regs.lckcon; - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfffa26)\n", mem_mask); - } - break; + rtc_advance_seconds(); - case 0xa28: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): LLBAR = %02x\n", mem_mask, m_regs.llbar); - return m_regs.llbar; - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfffa28)\n", mem_mask); - } - break; + if (rtc_get_alarm_match()) + { + m_rtcisr |= RTCINT_ALARM; + } - case 0xa2a: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): LOTCR = %02x\n", mem_mask, m_regs.lotcr); - return m_regs.lotcr; - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfffa2a)\n", mem_mask); - } - break; + if (!rtc_int_was_active && rtc_int_is_active()) + { + set_interrupt_line(INT_RTC, 1); + } + } +} - case 0xa2c: - if (mem_mask & 0x00ff) - { - verboselog( *this, 2, "mc68328_r (%04x): LPOSR = %02x\n", mem_mask, m_regs.lposr); - return m_regs.lposr; - } - else - { - verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfffa2c)\n", mem_mask); - } - break; +void mc68328_base_device::rtc_advance_seconds() +{ + m_hmsr++; + + if (m_rtcienr & RTCINT_SECOND) + { + m_rtcisr |= RTCINT_SECOND; + } + + if ((m_hmsr & RTCHMSR_SECONDS) == 0x0000003c) + { + m_hmsr &= ~RTCHMSR_SECONDS; + m_hmsr += 1 << RTCHMSR_MINUTES_SHIFT; + + if (m_rtcienr & RTCINT_MINUTE) + { + m_rtcisr |= RTCINT_MINUTE; + } + + if ((m_hmsr & RTCHMSR_MINUTES) == 0x003c0000) + { + m_hmsr &= ~RTCHMSR_MINUTES; + m_hmsr += 1 << RTCHMSR_HOURS_SHIFT; - case 0xa30: - if (mem_mask & 0x00ff) + if ((m_hmsr & RTCHMSR_HOURS) == 0x18000000) { - verboselog( *this, 2, "mc68328_r (%04x): LFRCM = %02x\n", mem_mask, m_regs.lfrcm); - return m_regs.lfrcm; + m_hmsr &= ~RTCHMSR_HOURS; + + if (m_rtcienr & RTCINT_DAY) + { + m_rtcisr |= RTCINT_DAY; + } } - else + } + + if (m_stpwtch != RTCSTPWTCH_MASK) + { + m_stpwtch--; + m_stpwtch &= RTCSTPWTCH_MASK; + + if (m_stpwtch == RTCSTPWTCH_MASK) { - verboselog( *this, 2, "mc68328_r (%04x): Unknown address (0xfffa30)\n", mem_mask); + m_rtcisr |= RTCINT_STOPWATCH; } - break; + } + } +} - case 0xa32: - verboselog( *this, 2, "mc68328_r (%04x): LGPMR = %04x\n", mem_mask, m_regs.lgpmr); - return m_regs.lgpmr; +bool mc68328_device::rtc_int_is_active() +{ + return m_rtcisr & m_rtcienr; +} - case 0xb00: - verboselog( *this, 2, "mc68328_r (%04x): HMSR(0) = %04x\n", mem_mask, m_regs.hmsr & 0x0000ffff); - return m_regs.hmsr & 0x0000ffff; +u16 mc68328_device::rtc_get_int_mask() +{ + constexpr u16 RTCIENR_MASK = 0x001f; + return RTCIENR_MASK; +} - case 0xb02: - verboselog( *this, 2, "mc68328_r (%04x): HMSR(16) = %04x\n", mem_mask, m_regs.hmsr >> 16); - return m_regs.hmsr >> 16; +bool mc68328_device::rtc_get_alarm_match() +{ + return m_hmsr == m_alarm; +} - case 0xb04: - verboselog( *this, 2, "mc68328_r (%04x): ALARM(0) = %04x\n", mem_mask, m_regs.alarm & 0x0000ffff); - return m_regs.alarm & 0x0000ffff; +void mc68328_base_device::hmsr_msw_w(offs_t offset, u16 data, u16 mem_mask) // 0xb00 +{ + LOGMASKED(LOG_RTC, "%s: hmsr_msw_w: HMSR(MSW) = %04x\n", machine().describe_context(), data); + m_hmsr &= ~(mem_mask << 16); + m_hmsr |= (data & mem_mask) << 16; + m_hmsr &= (RTCHMSR_SECONDS | RTCHMSR_MINUTES | RTCHMSR_HOURS); +} - case 0xb06: - verboselog( *this, 2, "mc68328_r (%04x): ALARM(16) = %04x\n", mem_mask, m_regs.alarm >> 16); - return m_regs.alarm >> 16; +u16 mc68328_base_device::hmsr_msw_r() // 0xb00 +{ + LOGMASKED(LOG_RTC, "%s: hmsr_msw_r: HMSR(MSW): %04x\n", machine().describe_context(), (u16)(m_hmsr >> 16)); + return (u16)(m_hmsr >> 16); +} - case 0xb0c: - verboselog( *this, 2, "mc68328_r (%04x): RTCCTL = %04x\n", mem_mask, m_regs.rtcctl); - return m_regs.rtcctl; +void mc68328_base_device::hmsr_lsw_w(offs_t offset, u16 data, u16 mem_mask) // 0xb02 +{ + LOGMASKED(LOG_RTC, "%s: hmsr_lsw_w: HMSR(LSW) = %04x\n", machine().describe_context(), data); + m_hmsr &= 0xffff0000 | (~mem_mask); + m_hmsr |= data & mem_mask; + m_hmsr &= (RTCHMSR_SECONDS | RTCHMSR_MINUTES | RTCHMSR_HOURS); +} - case 0xb0e: - verboselog( *this, 2, "mc68328_r (%04x): RTCISR = %04x\n", mem_mask, m_regs.rtcisr); - return m_regs.rtcisr; +u16 mc68328_base_device::hmsr_lsw_r() // 0xb02 +{ + LOGMASKED(LOG_RTC, "%s: hmsr_lsw_r: HMSR(LSW): %04x\n", machine().describe_context(), (u16)m_hmsr); + return (u16)m_hmsr; +} - case 0xb10: - verboselog( *this, 2, "mc68328_r (%04x): RTCIENR = %04x\n", mem_mask, m_regs.rtcienr); - return m_regs.rtcienr; +void mc68328_base_device::alarm_msw_w(offs_t offset, u16 data, u16 mem_mask) // 0xb04 +{ + LOGMASKED(LOG_RTC, "%s: alarm_msw_w: ALARM(MSW) = %04x\n", machine().describe_context(), data); + m_alarm &= ~(mem_mask << 16); + m_alarm |= (data & mem_mask) << 16; + m_alarm &= (RTCHMSR_SECONDS | RTCHMSR_MINUTES | RTCHMSR_HOURS); +} - case 0xb12: - verboselog( *this, 2, "mc68328_r (%04x): STPWTCH = %04x\n", mem_mask, m_regs.stpwtch); - return m_regs.stpwtch; +u16 mc68328_base_device::alarm_msw_r() // 0xb04 +{ + LOGMASKED(LOG_RTC, "%s: alarm_msw_r: ALARM(MSW): %04x\n", machine().describe_context(), (u16)(m_alarm >> 16)); + return (u16)(m_alarm >> 16); +} - default: - verboselog( *this, 0, "mc68328_r (%04x): Unknown address (0x%06x)\n", mem_mask, 0xfff000 + address); - break; +void mc68328_base_device::alarm_lsw_w(offs_t offset, u16 data, u16 mem_mask) // 0xb06 +{ + LOGMASKED(LOG_RTC, "%s: alarm_lsw_w: ALARM(LSW) = %04x\n", machine().describe_context(), data); + m_alarm &= 0xffff0000 | (~mem_mask); + m_alarm |= data & mem_mask; + m_alarm &= (RTCHMSR_SECONDS | RTCHMSR_MINUTES | RTCHMSR_HOURS); +} + +u16 mc68328_base_device::alarm_lsw_r() // 0xb06 +{ + LOGMASKED(LOG_RTC, "%s: alarm_lsw_r: ALARM(LSW): %04x\n", machine().describe_context(), (u16)m_alarm); + return (u16)m_alarm; +} + +void mc68328_base_device::rtcctl_w(offs_t offset, u16 data, u16 mem_mask) // 0xb0c +{ + LOGMASKED(LOG_RTC, "%s: rtcctl_w: RTCCTL = %04x\n", machine().describe_context(), data); + m_rtcctl = data & RTCCTL_MASK; +} + +u16 mc68328_base_device::rtcctl_r() // 0xb0c +{ + LOGMASKED(LOG_RTC, "%s: rtcctl_r: RTCCTL: %04x\n", machine().describe_context(), m_rtcctl); + return m_rtcctl; +} + +void mc68328_base_device::rtcisr_w(offs_t offset, u16 data, u16 mem_mask) // 0xb0e +{ + const bool rtc_int_was_active = rtc_int_is_active(); + LOGMASKED(LOG_RTC, "%s: rtcisr_w: RTCISR = %04x\n", machine().describe_context(), data); + m_rtcisr &= ~data; + + if (rtc_int_was_active && !rtc_int_is_active()) + { + set_interrupt_line(INT_RTC, 0); } - return 0; } -/* THIS IS PRETTY MUCH TOTALLY WRONG AND DOESN'T REFLECT THE MC68328'S INTERNAL FUNCTIONALITY AT ALL! */ -uint32_t mc68328_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +u16 mc68328_base_device::rtcisr_r() // 0xb0e +{ + LOGMASKED(LOG_RTC, "%s: rtcisr_r: RTCISR: %04x\n", machine().describe_context(), m_rtcisr); + return m_rtcisr; +} + +void mc68328_base_device::rtcienr_w(offs_t offset, u16 data, u16 mem_mask) // 0xb10 +{ + const bool rtc_int_was_active = rtc_int_is_active(); + + LOGMASKED(LOG_RTC, "%s: rtcienr_w: RTCIENR = %04x\n", machine().describe_context(), data); + m_rtcienr = data & rtc_get_int_mask(); + + const bool is_active = rtc_int_is_active(); + if (rtc_int_was_active != is_active) + { + set_interrupt_line(INT_RTC, (int)is_active); + } +} + +u16 mc68328_base_device::rtcienr_r() // 0xb10 +{ + LOGMASKED(LOG_RTC, "%s: rtcienr_r: RTCIENR: %04x\n", machine().describe_context(), m_rtcienr); + return m_rtcienr; +} + +void mc68328_base_device::stpwtch_w(offs_t offset, u16 data, u16 mem_mask) // 0xb12 +{ + LOGMASKED(LOG_RTC, "%s: stpwtch_w: STPWTCH = %04x\n", machine().describe_context(), data); + m_stpwtch = data & 0x003f; +} + +u16 mc68328_base_device::stpwtch_r() // 0xb12 +{ + LOGMASKED(LOG_RTC, "%s: stpwtch_r: STPWTCH: %04x\n", machine().describe_context(), m_stpwtch); + return m_stpwtch; +} + + +//------------------------------------------------- +// RTC/alarm hardware - EZ variant +//------------------------------------------------- + +bool mc68ez328_device::rtc_int_is_active() +{ + return (m_rtcisr & m_rtcienr) & RTCINT_RTCIRQ_MASK; +} + +void mc68ez328_device::rtc_advance_seconds() { - auto mcache = space(AS_PROGRAM).cache<1, 0, ENDIANNESS_BIG>(); - uint32_t vram_addr = m_regs.lssa & 0x00fffffe; - uint16_t word; - uint16_t *line; - int y, x, b; + LOGMASKED(LOG_RTC, "EZ advancing seconds!\n"); + const u32 old_hmsr = m_hmsr; + mc68328_base_device::rtc_advance_seconds(); - if (m_regs.lckcon & LCKCON_LCDC_EN) + if ((old_hmsr & RTCHMSR_HOURS) != (m_hmsr & RTCHMSR_HOURS)) { - for (y = 0; y < 160; y++) + m_rtcisr |= RTCINT_HOUR; + + if (((m_hmsr & RTCHMSR_HOURS) >> RTCHMSR_HOURS_SHIFT) == 0) { - line = &bitmap.pix16(y); + m_dayr = (m_dayr + 1) & RTC_DAYS_MASK; + } + } - for (x = 0; x < 160; x += 16, vram_addr += 2) + if (BIT(m_watchdog, WATCHDOG_EN_BIT)) + { + m_watchdog += 1 << WATCHDOG_CNT_SHIFT; + m_watchdog &= (WATCHDOG_MASK | WATCHDOG_CNT_MASK); + if (((m_watchdog & WATCHDOG_CNT_MASK) >> WATCHDOG_CNT_SHIFT) == 2) + { + if (BIT(m_watchdog, WATCHDOG_ISEL_BIT)) { - word = mcache->read_word(vram_addr); - for (b = 0; b < 16; b++) - { - line[x + b] = (word >> (15 - b)) & 0x0001; - } + set_interrupt_line(INT_WDT, 1); + } + else + { + reset(); } } } - else +} + +TIMER_CALLBACK_MEMBER(mc68ez328_device::sample_timer_tick) +{ + if (!BIT(m_rtcctl, RTCCTL_ENABLE_BIT) && !BIT(m_watchdog, WATCHDOG_EN_BIT)) + { + return; + } + + const u8 old_sam_cnt = m_sam_cnt; + m_sam_cnt++; + + const bool rtc_int_was_active = rtc_int_is_active(); + + m_rtcisr |= RTCINT_SAM0; + for (u8 i = 0; i < 7; i++) { - for (y = 0; y < 160; y++) + if (BIT(old_sam_cnt, i) && !BIT(m_sam_cnt, i)) { - line = &bitmap.pix16(y); + m_rtcisr |= RTCINT_SAM1 << i; + } + } - for (x = 0; x < 160; x++) - { - line[x] = 0; - } + if (!rtc_int_was_active && rtc_int_is_active()) + { + set_interrupt_line(INT_RTC, 1); + } +} + +u16 mc68ez328_device::rtc_get_int_mask() +{ + constexpr u16 RTCIENR_MASK = 0xff3f; + return RTCIENR_MASK; +} + +bool mc68ez328_device::rtc_get_alarm_match() +{ + return m_hmsr == m_alarm && m_dayr == m_dayalarm; +} + +void mc68ez328_device::watchdog_w(offs_t offset, u16 data, u16 mem_mask) +{ + LOGMASKED(LOG_RTC, "%s: watchdog_w: WATCHDOG = %04x\n", machine().describe_context(), data); + const u16 old_watchdog = m_watchdog; + m_watchdog = data & WATCHDOG_MASK; + if (BIT(data, WATCHDOG_INTF_BIT)) + { + m_watchdog &= ~WATCHDOG_INTF; + if (BIT(old_watchdog, WATCHDOG_INTF_BIT)) + { + set_interrupt_line(INT_WDT, 0); } } - return 0; } +u16 mc68ez328_device::watchdog_r() +{ + LOGMASKED(LOG_RTC, "%s: watchdog_r: WATCHDOG: %04x\n", machine().describe_context(), m_watchdog); + return m_watchdog; +} -void mc68328_device::register_state_save() +void mc68ez328_device::rtcctl_w(offs_t offset, u16 data, u16 mem_mask) // 0xb0c +{ + const u16 old_rtcctl = m_rtcctl; + mc68328_base_device::rtcctl_w(offset, data, mem_mask); + + if (BIT(old_rtcctl, RTCCTL_38_4_BIT) != BIT(m_rtcctl, RTCCTL_38_4_BIT)) + { + const u32 frequency = BIT(m_rtcctl, RTCCTL_38_4_BIT) ? 38400 : 32768; + m_rtc_sample_timer->adjust(attotime::from_ticks(64, frequency), 0, attotime::from_ticks(64, frequency)); + } +} + +void mc68ez328_device::dayr_w(offs_t offset, u16 data, u16 mem_mask) // 0xb1a +{ + LOGMASKED(LOG_RTC, "%s: dayr_w: DAYR = %04x\n", machine().describe_context(), data); + m_dayr = data & RTC_DAYS_MASK; +} + +void mc68ez328_device::dayalarm_w(offs_t offset, u16 data, u16 mem_mask) // 0xb1c +{ + LOGMASKED(LOG_RTC, "%s: dayalarm_w: DAYALARM = %04x\n", machine().describe_context(), data); + m_dayalarm = data & RTC_DAYS_MASK; +} + +u16 mc68ez328_device::dayr_r() // 0xb1a +{ + LOGMASKED(LOG_RTC, "%s: dayalarm_r: DAYR: %04x\n", machine().describe_context(), m_dayr); + return m_dayr; +} + +u16 mc68ez328_device::dayalarm_r() // 0xb1c { - save_item(NAME(m_regs.scr)); - save_item(NAME(m_regs.grpbasea)); - save_item(NAME(m_regs.grpbaseb)); - save_item(NAME(m_regs.grpbasec)); - save_item(NAME(m_regs.grpbased)); - save_item(NAME(m_regs.grpmaska)); - save_item(NAME(m_regs.grpmaskb)); - save_item(NAME(m_regs.grpmaskc)); - save_item(NAME(m_regs.grpmaskd)); - save_item(NAME(m_regs.csa0)); - save_item(NAME(m_regs.csa1)); - save_item(NAME(m_regs.csa2)); - save_item(NAME(m_regs.csa3)); - save_item(NAME(m_regs.csb0)); - save_item(NAME(m_regs.csb1)); - save_item(NAME(m_regs.csb2)); - save_item(NAME(m_regs.csb3)); - save_item(NAME(m_regs.csc0)); - save_item(NAME(m_regs.csc1)); - save_item(NAME(m_regs.csc2)); - save_item(NAME(m_regs.csc3)); - save_item(NAME(m_regs.csd0)); - save_item(NAME(m_regs.csd1)); - save_item(NAME(m_regs.csd2)); - save_item(NAME(m_regs.csd3)); - - save_item(NAME(m_regs.pllcr)); - save_item(NAME(m_regs.pllfsr)); - save_item(NAME(m_regs.pctlr)); - - save_item(NAME(m_regs.ivr)); - save_item(NAME(m_regs.icr)); - save_item(NAME(m_regs.imr)); - save_item(NAME(m_regs.iwr)); - save_item(NAME(m_regs.isr)); - save_item(NAME(m_regs.ipr)); - - save_item(NAME(m_regs.padir)); - save_item(NAME(m_regs.padata)); - save_item(NAME(m_regs.pasel)); - save_item(NAME(m_regs.pbdir)); - save_item(NAME(m_regs.pbdata)); - save_item(NAME(m_regs.pbsel)); - save_item(NAME(m_regs.pcdir)); - save_item(NAME(m_regs.pcdata)); - save_item(NAME(m_regs.pcsel)); - save_item(NAME(m_regs.pddir)); - save_item(NAME(m_regs.pddata)); - save_item(NAME(m_regs.pdpuen)); - save_item(NAME(m_regs.pdpol)); - save_item(NAME(m_regs.pdirqen)); - save_item(NAME(m_regs.pddataedge)); - save_item(NAME(m_regs.pdirqedge)); - save_item(NAME(m_regs.pedir)); - save_item(NAME(m_regs.pedata)); - save_item(NAME(m_regs.pepuen)); - save_item(NAME(m_regs.pesel)); - save_item(NAME(m_regs.pfdir)); - save_item(NAME(m_regs.pfdata)); - save_item(NAME(m_regs.pfpuen)); - save_item(NAME(m_regs.pfsel)); - save_item(NAME(m_regs.pgdir)); - save_item(NAME(m_regs.pgdata)); - save_item(NAME(m_regs.pgpuen)); - save_item(NAME(m_regs.pgsel)); - save_item(NAME(m_regs.pjdir)); - save_item(NAME(m_regs.pjdata)); - save_item(NAME(m_regs.pjsel)); - save_item(NAME(m_regs.pkdir)); - save_item(NAME(m_regs.pkdata)); - save_item(NAME(m_regs.pkpuen)); - save_item(NAME(m_regs.pksel)); - save_item(NAME(m_regs.pmdir)); - save_item(NAME(m_regs.pmdata)); - save_item(NAME(m_regs.pmpuen)); - save_item(NAME(m_regs.pmsel)); - - save_item(NAME(m_regs.pwmc)); - save_item(NAME(m_regs.pwmp)); - save_item(NAME(m_regs.pwmw)); - save_item(NAME(m_regs.pwmcnt)); - - save_item(NAME(m_regs.tctl[0])); - save_item(NAME(m_regs.tctl[1])); - save_item(NAME(m_regs.tprer[0])); - save_item(NAME(m_regs.tprer[1])); - save_item(NAME(m_regs.tcmp[0])); - save_item(NAME(m_regs.tcmp[1])); - save_item(NAME(m_regs.tcr[0])); - save_item(NAME(m_regs.tcr[1])); - save_item(NAME(m_regs.tcn[0])); - save_item(NAME(m_regs.tcn[1])); - save_item(NAME(m_regs.tstat[0])); - save_item(NAME(m_regs.tstat[1])); - save_item(NAME(m_regs.wctlr)); - save_item(NAME(m_regs.wcmpr)); - save_item(NAME(m_regs.wcn)); - - save_item(NAME(m_regs.spisr)); - - save_item(NAME(m_regs.spimdata)); - save_item(NAME(m_regs.spimcont)); - - save_item(NAME(m_regs.ustcnt)); - save_item(NAME(m_regs.ubaud)); - save_item(NAME(m_regs.urx)); - save_item(NAME(m_regs.utx)); - save_item(NAME(m_regs.umisc)); - - save_item(NAME(m_regs.lssa)); - save_item(NAME(m_regs.lvpw)); - save_item(NAME(m_regs.lxmax)); - save_item(NAME(m_regs.lymax)); - save_item(NAME(m_regs.lcxp)); - save_item(NAME(m_regs.lcyp)); - save_item(NAME(m_regs.lcwch)); - save_item(NAME(m_regs.lblkc)); - save_item(NAME(m_regs.lpicf)); - save_item(NAME(m_regs.lpolcf)); - save_item(NAME(m_regs.lacdrc)); - save_item(NAME(m_regs.lpxcd)); - save_item(NAME(m_regs.lckcon)); - save_item(NAME(m_regs.llbar)); - save_item(NAME(m_regs.lotcr)); - save_item(NAME(m_regs.lposr)); - save_item(NAME(m_regs.lfrcm)); - save_item(NAME(m_regs.lgpmr)); - - save_item(NAME(m_regs.hmsr)); - save_item(NAME(m_regs.alarm)); - save_item(NAME(m_regs.rtcctl)); - save_item(NAME(m_regs.rtcisr)); - save_item(NAME(m_regs.rtcienr)); - save_item(NAME(m_regs.stpwtch)); + LOGMASKED(LOG_RTC, "%s: dayalarm_r: DAYALARM: %04x\n", machine().describe_context(), m_dayalarm); + return m_dayalarm; } |