diff options
author | AJR <ajrhacker@users.noreply.github.com> | 2018-11-27 22:52:20 -0500 |
---|---|---|
committer | AJR <ajrhacker@users.noreply.github.com> | 2018-11-27 22:52:54 -0500 |
commit | 159265d832f2cc6f63dfe2a321ae246a963355d7 (patch) | |
tree | 24e62949dc2484116cb85f1138280fd229d4143d | |
parent | c13e586e808741be970f611d905b736ab6f5ea2d (diff) |
More accurate registration and acknowledgment of pending interrupts within TMP68301 interrupt controller
-rw-r--r-- | src/devices/machine/tmp68301.cpp | 171 | ||||
-rw-r--r-- | src/devices/machine/tmp68301.h | 13 | ||||
-rw-r--r-- | src/mame/drivers/seta.cpp | 12 | ||||
-rw-r--r-- | src/mame/includes/seta.h | 4 |
4 files changed, 110 insertions, 90 deletions
diff --git a/src/devices/machine/tmp68301.cpp b/src/devices/machine/tmp68301.cpp index da003ae3480..2add964e4e5 100644 --- a/src/devices/machine/tmp68301.cpp +++ b/src/devices/machine/tmp68301.cpp @@ -1,5 +1,5 @@ // license:BSD-3-Clause -// copyright-holders:Luca Elia +// copyright-holders:Luca Elia, AJR /*************************************************************************** TMP68301 basic emulation + Interrupt Handling @@ -9,7 +9,7 @@ all integrated in a single chip. TODO: - - Interrupt generation: handle pending / in-service mechanisms + - Interrupt generation: edge detection, input expansion (INT3-INT9) - Parallel port: handle timing latency - Serial port: not done at all - (and many other things) @@ -27,6 +27,7 @@ void tmp68301_device::tmp68301_regs(address_map &map) map(0x080, 0x093).rw(FUNC(tmp68301_device::icr_r), FUNC(tmp68301_device::icr_w)).umask16(0x00ff); map(0x094, 0x095).rw(FUNC(tmp68301_device::imr_r), FUNC(tmp68301_device::imr_w)); + map(0x096, 0x097).rw(FUNC(tmp68301_device::ipr_r), FUNC(tmp68301_device::ipr_w)); map(0x098, 0x099).rw(FUNC(tmp68301_device::iisr_r), FUNC(tmp68301_device::iisr_w)); /* Parallel Port */ @@ -37,7 +38,7 @@ void tmp68301_device::tmp68301_regs(address_map &map) map(0x18e, 0x18f).rw(FUNC(tmp68301_device::scr_r), FUNC(tmp68301_device::scr_w)); } -// IRQ Mask register, 0x94 +// IRQ Mask register READ16_MEMBER(tmp68301_device::imr_r) { return m_imr; @@ -46,6 +47,20 @@ READ16_MEMBER(tmp68301_device::imr_r) WRITE16_MEMBER(tmp68301_device::imr_w) { COMBINE_DATA(&m_imr); + update_ipl(); +} + +// IRQ Pending Register +READ16_MEMBER(tmp68301_device::ipr_r) +{ + return m_ipr; +} + +WRITE16_MEMBER(tmp68301_device::ipr_w) +{ + // software writes only clear bits + m_ipr &= data | ~mem_mask; + update_ipl(); } // IRQ In-Service Register @@ -56,7 +71,8 @@ READ16_MEMBER(tmp68301_device::iisr_r) WRITE16_MEMBER(tmp68301_device::iisr_w) { - COMBINE_DATA(&m_iisr); + // software writes only clear bits + m_iisr &= data | ~mem_mask; } // Serial Control Register (TODO: 8-bit wide) @@ -123,7 +139,9 @@ tmp68301_device::tmp68301_device(const machine_config &mconfig, const char *tag, m_cpu(*this, finder_base::DUMMY_TAG), m_in_parallel_cb(*this), m_out_parallel_cb(*this), + m_ipl(0), m_imr(0), + m_ipr(0), m_iisr(0), m_scr(0), m_pdir(0), @@ -132,7 +150,6 @@ tmp68301_device::tmp68301_device(const machine_config &mconfig, const char *tag, { memset(m_regs, 0, sizeof(m_regs)); memset(m_icr, 0, sizeof(m_icr)); - memset(m_irq_vector, 0, sizeof(m_irq_vector)); } @@ -151,8 +168,9 @@ void tmp68301_device::device_start() save_item(NAME(m_regs)); save_item(NAME(m_icr)); - save_item(NAME(m_irq_vector)); + save_item(NAME(m_ipl)); save_item(NAME(m_imr)); + save_item(NAME(m_ipr)); save_item(NAME(m_iisr)); save_item(NAME(m_scr)); save_item(NAME(m_pdir)); @@ -165,8 +183,11 @@ void tmp68301_device::device_start() void tmp68301_device::device_reset() { + m_ipr = 0; m_iisr = 0; m_imr = 0x7f7; // mask all irqs + std::fill(std::begin(m_icr), std::end(m_icr), 0x07); + update_ipl(); } //------------------------------------------------- @@ -205,31 +226,50 @@ inline void tmp68301_device::write_word(offs_t address, uint16_t data) IRQ_CALLBACK_MEMBER(tmp68301_device::irq_callback) { - int vector = m_irq_vector[irqline]; -// logerror("%s: irq callback returns %04X for level %x\n",machine().describe_context(),vector,int_level); - return vector; + uint8_t IVNR = m_regs[0x9a/2] & 0xe0; // Interrupt Vector Number Register (IVNR) + + for (int src : { 0, 7, 3, 1, 8, 4, 5, 9, 2 }) + { + // check if the IPL matches + if (irqline == (m_icr[src] & 0x07)) + { + // check if interrupt is pending and not masked out + u16 mask = (src > 2 ? 2 : 1) << src; + if ((m_ipr & mask) != 0 && (m_imr & mask) == 0) + { + // add cause to interrupt in-service register + m_iisr |= mask; + + // no longer pending + m_ipr &= ~mask; + update_ipl(); + + // vary vector number by type + if (src > 6) + return IVNR | (src - 3); + else if (src > 2) + return IVNR | (src - 1) << 2 | serial_interrupt_cause(src - 3); + else /*if (BIT(m_icr[src], 5))*/ // TODO: use external vector otherwise + return IVNR | src; + } + } + } + + // default vector + return IVNR | 0x1f; } -TIMER_CALLBACK_MEMBER( tmp68301_device::timer_callback ) +TIMER_CALLBACK_MEMBER(tmp68301_device::timer_callback) { int i = param; uint16_t TCR = m_regs[(0x200 + i * 0x20)/2]; - uint16_t ICR = m_regs[0x8e/2+i]; // Interrupt Controller Register (ICR7..9) - uint16_t IVNR = m_regs[0x9a/2]; // Interrupt Vector Number Register (IVNR) // logerror("s: callback timer %04X, j = %d\n",machine().describe_context(),i,tcount); - if ( (TCR & 0x0004) && // INT - !(m_imr & (0x100<<i)) - ) + if (TCR & 0x0004) // INT { - int level = ICR & 0x0007; - - // Interrupt Vector Number Register (IVNR) - m_irq_vector[level] = IVNR & 0x00e0; - m_irq_vector[level] += 4+i; - - m_cpu->set_input_line(level,HOLD_LINE); + m_ipr |= 0x100 << i; + update_ipl(); } if (TCR & 0x0080) // N/1 @@ -243,7 +283,7 @@ TIMER_CALLBACK_MEMBER( tmp68301_device::timer_callback ) } } -void tmp68301_device::update_timer( int i ) +void tmp68301_device::update_timer(int i) { uint16_t TCR = m_regs[(0x200 + i * 0x20)/2]; uint16_t MAX1 = m_regs[(0x204 + i * 0x20)/2]; @@ -289,71 +329,38 @@ void tmp68301_device::update_timer( int i ) } /* Update the IRQ state based on all possible causes */ -void tmp68301_device::update_irq_state(uint16_t cause) +void tmp68301_device::update_ipl() { - int i; - - /* Take care of external interrupts */ + uint8_t new_ipl = 0; - uint16_t IVNR = m_regs[0x9a/2]; // Interrupt Vector Number Register (IVNR) - // add cause to interrupt in-service register - m_iisr |= cause; - - for (i = 0; i < 3; i++) + for (int src = 0; src < 10; src++) { - if ((m_iisr & 1 << i) && !(m_imr & (1<<i))) - { - uint8_t current_ICR = m_icr[i]; // Interrupt Controller Register (ICR0..2) - - // Interrupt Controller Register (ICR0..2) - int level = current_ICR & 0x0007; + u16 mask = (src > 2 ? 2 : 1) << src; + if ((m_ipr & mask) != 0 && (m_imr & mask) == 0 && new_ipl < (m_icr[src] & 0x07)) + new_ipl = m_icr[src] & 0x07; + } - // Interrupt Vector Number Register (IVNR) - m_irq_vector[level] = IVNR & 0x00e0; - m_irq_vector[level] += i; + if (new_ipl != m_ipl) + { + if (m_ipl != 0) + m_cpu->set_input_line(m_ipl, CLEAR_LINE); + if (new_ipl != 0) + m_cpu->set_input_line(new_ipl, ASSERT_LINE); - m_cpu->set_input_line(level,HOLD_LINE); - } + m_ipl = new_ipl; } } -void tmp68301_device::update_irq_serial(uint16_t cause, uint8_t type) +uint8_t tmp68301_device::serial_interrupt_cause(int channel) { - int i; - const uint8_t serial_irq_vector[3] = { 8, 0xc, 0x10 }; - - /* Take care of external interrupts */ - - uint16_t IVNR = m_regs[0x9a/2]; // Interrupt Vector Number Register (IVNR) - // add cause to interrupt in-service register - m_iisr |= cause; - - for (i = 4; i < 7; i++) - { - if ((m_iisr & 1 << i) && !(m_imr & (1<<i))) - { - uint8_t current_ICR = m_icr[i-1]; // Interrupt Controller Register (ICR0..2) - - // Interrupt Controller Register (ICR0..2) - int level = current_ICR & 0x0007; - - // Interrupt Vector Number Register (IVNR) - m_irq_vector[level] = IVNR & 0x00e0; - /* - * channel number - */ - m_irq_vector[level] += serial_irq_vector[i-4]; - /* - * 00 error occurred - * 01 receive completed - * 10 transmit ready - * 11 interrupt cause cleared while interrupt pending - */ - m_irq_vector[level] += type; - - m_cpu->set_input_line(level,HOLD_LINE); - } - } + /* + * 00 error occurred + * 01 receive completed + * 10 transmit ready + * 11 interrupt cause cleared while interrupt pending + */ + (void)channel; + return 3; } @@ -387,6 +394,6 @@ WRITE16_MEMBER( tmp68301_device::regs_w ) } } -void tmp68301_device::external_interrupt_0() { update_irq_state(EXT_IRQ0); } -void tmp68301_device::external_interrupt_1() { update_irq_state(EXT_IRQ1); } -void tmp68301_device::external_interrupt_2() { update_irq_state(EXT_IRQ2); } +void tmp68301_device::external_interrupt_0() { m_ipr |= EXT_IRQ0; update_ipl(); } +void tmp68301_device::external_interrupt_1() { m_ipr |= EXT_IRQ1; update_ipl(); } +void tmp68301_device::external_interrupt_2() { m_ipr |= EXT_IRQ2; update_ipl(); } diff --git a/src/devices/machine/tmp68301.h b/src/devices/machine/tmp68301.h index 5b936ebc88b..e019387802b 100644 --- a/src/devices/machine/tmp68301.h +++ b/src/devices/machine/tmp68301.h @@ -40,6 +40,8 @@ public: private: DECLARE_READ16_MEMBER(imr_r); DECLARE_WRITE16_MEMBER(imr_w); + DECLARE_READ16_MEMBER(ipr_r); + DECLARE_WRITE16_MEMBER(ipr_w); DECLARE_READ16_MEMBER(iisr_r); DECLARE_WRITE16_MEMBER(iisr_w); DECLARE_READ16_MEMBER(scr_r); @@ -60,10 +62,10 @@ protected: virtual space_config_vector memory_space_config() const override; private: - TIMER_CALLBACK_MEMBER( timer_callback ); - void update_timer( int i ); - void update_irq_state(uint16_t cause); - void update_irq_serial(uint16_t cause, uint8_t type); + TIMER_CALLBACK_MEMBER(timer_callback); + void update_timer(int i); + void update_ipl(); + uint8_t serial_interrupt_cause(int channel); static constexpr uint16_t EXT_IRQ0 = 1 << 0; static constexpr uint16_t EXT_IRQ1 = 1 << 1; @@ -89,9 +91,10 @@ private: emu_timer *m_tmp68301_timer[3]; // 3 Timers - uint16_t m_irq_vector[8]; + uint8_t m_ipl; // internal interrupt level uint16_t m_imr; + uint16_t m_ipr; uint16_t m_iisr; uint16_t m_scr; uint16_t m_pdir; diff --git a/src/mame/drivers/seta.cpp b/src/mame/drivers/seta.cpp index 7baae74fc45..cd45860f5d4 100644 --- a/src/mame/drivers/seta.cpp +++ b/src/mame/drivers/seta.cpp @@ -1378,7 +1378,6 @@ Note: on screen copyright is (c)1998 Coinmaster. #include "machine/msm6242.h" #include "machine/nvram.h" #include "machine/pit8253.h" -#include "machine/tmp68301.h" #include "machine/watchdog.h" #include "sound/2203intf.h" #include "sound/2612intf.h" @@ -9255,13 +9254,19 @@ MACHINE_CONFIG_END Pro Mahjong Kiwame ***************************************************************************/ +WRITE_LINE_MEMBER(seta_state::kiwame_vblank) +{ + if (state) + m_tmp68301->external_interrupt_0(); +} + MACHINE_CONFIG_START(seta_state::kiwame) /* basic machine hardware */ MCFG_DEVICE_ADD(m_maincpu, M68000, 16000000) /* 16 MHz */ MCFG_DEVICE_PROGRAM_MAP(kiwame_map) - /* lev 1-7 are the same. WARNING: the interrupt table is written to. */ - MCFG_DEVICE_VBLANK_INT_DRIVER("screen", seta_state, irq1_line_hold) + MCFG_DEVICE_IRQ_ACKNOWLEDGE_DEVICE("tmp68301", tmp68301_device, irq_callback) + tmp68301_device &tmp68301(TMP68301(config, "tmp68301", 0)); tmp68301.set_cputag(m_maincpu); tmp68301.out_parallel_callback().set(FUNC(seta_state::kiwame_row_select_w)); @@ -9280,6 +9285,7 @@ MACHINE_CONFIG_START(seta_state::kiwame) MCFG_SCREEN_VISIBLE_AREA(0*8, 56*8-1, 1*8, 31*8-1) MCFG_SCREEN_UPDATE_DRIVER(seta_state, screen_update_seta_no_layers) MCFG_SCREEN_PALETTE("palette") + MCFG_SCREEN_VBLANK_CALLBACK(WRITELINE(*this, seta_state, kiwame_vblank)) MCFG_DEVICE_ADD("gfxdecode", GFXDECODE, "palette", gfx_tndrcade) MCFG_PALETTE_ADD("palette", 512) /* sprites only */ diff --git a/src/mame/includes/seta.h b/src/mame/includes/seta.h index 55542a7c7ed..61a4ee41b2a 100644 --- a/src/mame/includes/seta.h +++ b/src/mame/includes/seta.h @@ -16,6 +16,7 @@ #include "machine/gen_latch.h" #include "machine/ticket.h" #include "machine/timer.h" +#include "machine/tmp68301.h" #include "machine/upd4701.h" #include "machine/upd4992.h" #include "sound/x1_010.h" @@ -45,6 +46,7 @@ public: seta_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag), m_maincpu(*this,"maincpu"), + m_tmp68301(*this, "tmp68301"), m_audiocpu(*this, "audiocpu"), m_subcpu(*this,"sub"), m_seta001(*this, "spritegen"), @@ -147,6 +149,7 @@ public: protected: required_device<cpu_device> m_maincpu; + optional_device<tmp68301_device> m_tmp68301; optional_device<cpu_device> m_audiocpu; optional_device<cpu_device> m_subcpu; required_device<seta001_device> m_seta001; @@ -300,6 +303,7 @@ protected: TIMER_DEVICE_CALLBACK_MEMBER(tndrcade_sub_interrupt); TIMER_DEVICE_CALLBACK_MEMBER(calibr50_interrupt); TIMER_DEVICE_CALLBACK_MEMBER(crazyfgt_interrupt); + DECLARE_WRITE_LINE_MEMBER(kiwame_vblank); void set_pens(); void usclssic_set_pens(); void draw_tilemap_palette_effect(bitmap_ind16 &bitmap, const rectangle &cliprect, tilemap_t *tilemap, int scrollx, int scrolly, int gfxnum, int flipscreen); |