summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
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
commit159265d832f2cc6f63dfe2a321ae246a963355d7 (patch)
tree24e62949dc2484116cb85f1138280fd229d4143d
parentc13e586e808741be970f611d905b736ab6f5ea2d (diff)
More accurate registration and acknowledgment of pending interrupts within TMP68301 interrupt controller
-rw-r--r--src/devices/machine/tmp68301.cpp171
-rw-r--r--src/devices/machine/tmp68301.h13
-rw-r--r--src/mame/drivers/seta.cpp12
-rw-r--r--src/mame/includes/seta.h4
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);