summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--scripts/src/machine.lua12
-rw-r--r--scripts/target/mame/mess.lua1
-rw-r--r--src/devices/machine/am9519.cpp305
-rw-r--r--src/devices/machine/am9519.h93
-rw-r--r--src/mame/drivers/olyboss.cpp10
5 files changed, 420 insertions, 1 deletions
diff --git a/scripts/src/machine.lua b/scripts/src/machine.lua
index c59f39b69a6..7e55d344f92 100644
--- a/scripts/src/machine.lua
+++ b/scripts/src/machine.lua
@@ -625,6 +625,18 @@ end
---------------------------------------------------
--
+--@src/devices/machine/am9519.h,MACHINES["AM9519"] = true
+---------------------------------------------------
+
+if (MACHINES["AM9519"]~=null) then
+ files {
+ MAME_DIR .. "src/devices/machine/am9519.cpp",
+ MAME_DIR .. "src/devices/machine/am9519.h",
+ }
+end
+
+---------------------------------------------------
+--
--@src/devices/machine/amigafdc.h,MACHINES["AMIGAFDC"] = true
---------------------------------------------------
diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua
index bf08e0d8f44..c38eb46c82b 100644
--- a/scripts/target/mame/mess.lua
+++ b/scripts/target/mame/mess.lua
@@ -382,6 +382,7 @@ MACHINES["AM2847"] = true
MACHINES["AM53CF96"] = true
MACHINES["AM9513"] = true
MACHINES["AM9517A"] = true
+MACHINES["AM9519"] = true
MACHINES["AMIGAFDC"] = true
MACHINES["AT_KEYBC"] = true
MACHINES["AT28C16"] = true
diff --git a/src/devices/machine/am9519.cpp b/src/devices/machine/am9519.cpp
new file mode 100644
index 00000000000..99fde6fc1c1
--- /dev/null
+++ b/src/devices/machine/am9519.cpp
@@ -0,0 +1,305 @@
+// license:BSD-3-Clause
+// copyright-holders:Wilbert Pol,Carl
+
+#include "emu.h"
+#include "machine/am9519.h"
+
+#define LOG_GENERAL (1U << 0)
+
+//#define VERBOSE (LOG_GENERAL)
+#include "logmacro.h"
+
+void am9519_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ if(!BIT(m_mode, 7)) // chip disabled
+ return;
+
+ /* check the various IRQs */
+ for(int n = 0, irq = m_prio; n < 8; n++, irq = (irq + 1) & 7)
+ {
+ u8 mask = 1 << irq;
+
+ /* is this IRQ in service and not cascading and sfnm? */
+ if(m_isr & mask)
+ {
+ LOG("am9519_timerproc(): PIC IRQ #%d still in service\n", irq);
+ break;
+ }
+
+ bool active = !(BIT(m_mode, 4) ^ BIT(m_irr, irq));
+
+ /* is this IRQ pending and enabled? */
+ if(active && !(m_imr & mask))
+ {
+ LOG("am9519_timerproc(): PIC triggering IRQ #%d\n", irq);
+ if(BIT(m_mode, 4))
+ m_out_int_func(1);
+ return;
+ }
+ }
+ m_out_int_func(0);
+}
+
+
+void am9519_device::set_irq_line(int irq, int state)
+{
+ u8 mask = (1 << irq);
+
+ if(state)
+ {
+ /* setting IRQ line */
+ LOG("am9519_set_irq_line(): PIC set IRQ line #%d\n", irq);
+
+ if(!(m_irq_lines & mask)) // edge trig only
+ m_irr |= mask;
+ m_irq_lines |= mask;
+ }
+ else
+ {
+ /* clearing IRQ line */
+ LOG("am9519_device::set_irq_line(): PIC cleared IRQ line #%d\n", irq);
+
+ m_irq_lines &= ~mask;
+ m_irr &= ~mask;
+ }
+ set_timer();
+}
+
+
+u32 am9519_device::acknowledge()
+{
+ for(int n = 0, irq = m_prio; n < 8; n++, irq = (irq + 1) & 7)
+ {
+ u8 mask = 1 << irq;
+
+ /* is this IRQ pending and enabled? */
+ if((m_irr & mask) && !(m_imr & mask))
+ {
+ LOG("am9519_acknowledge(): PIC acknowledge IRQ #%d\n", irq);
+
+ if(!(mask & m_aclear))
+ m_isr |= mask;
+
+ set_timer();
+
+ u32 ret = 0;
+ int irqr = BIT(m_mode, 1) ? 0 : irq;
+ for(int i = 0; i < m_count[irqr]; i++)
+ ret = (ret << 8) | m_resp[irqr][i];
+
+ return ret;
+ }
+ }
+ logerror("Spurious IRQ\n");
+ return 0;
+}
+
+
+IRQ_CALLBACK_MEMBER(am9519_device::iack_cb)
+{
+ return acknowledge();
+}
+
+
+READ8_MEMBER( am9519_device::stat_r )
+{
+ u8 stat = 0;
+ for(int n = 0, irq = m_prio; n < 8; n++, irq = (irq + 1) & 7)
+ {
+ u8 mask = 1 << irq;
+ if((m_irr & mask) && !(m_imr & mask))
+ {
+ stat = 0x80 | irq;
+ break;
+ }
+ }
+ stat |= BIT(m_mode, 7) << 3;
+ stat |= BIT(m_mode, 2) << 4;
+ stat |= BIT(m_mode, 0) << 5;
+ return stat;
+}
+
+READ8_MEMBER( am9519_device::data_r )
+{
+ switch((m_mode & 0x60) >> 5)
+ {
+ case 0:
+ return m_isr;
+ case 1:
+ return m_imr;
+ case 2:
+ return m_irr;
+ case 3:
+ return m_aclear;
+ }
+ return 0;
+}
+
+WRITE8_MEMBER( am9519_device::cmd_w )
+{
+ m_cmd = data;
+ switch(data >> 3)
+ {
+ case 0:
+ reset();
+ break;
+ case 2:
+ m_irr = m_imr = 0;
+ break;
+ case 3:
+ m_irr &= ~(1 << (data & 7));
+ m_imr &= ~(1 << (data & 7));
+ break;
+ case 4:
+ m_imr = 0;
+ break;
+ case 5:
+ m_imr &= ~(1 << (data & 7));
+ break;
+ case 6:
+ m_imr = 0xff;
+ break;
+ case 7:
+ m_imr |= 1 << (data & 7);
+ break;
+ case 8:
+ m_irr = 0;
+ break;
+ case 9:
+ m_irr &= ~(1 << (data & 7));
+ break;
+ case 10:
+ m_irr = 0xff;
+ break;
+ case 11:
+ m_irr |= 1 << (data & 7);
+ break;
+ case 12:
+ case 13:
+ {
+ for(int n = 0, irq = m_prio; n < 8; n++, irq = (irq + 1) & 7)
+ {
+ if(m_isr & (1 << irq))
+ m_isr &= ~(1 << irq);
+ }
+ break;
+ }
+ case 14:
+ m_isr = 0;
+ break;
+ case 15:
+ m_isr &= ~(1 << (data & 7));
+ break;
+ case 16:
+ case 17:
+ case 18:
+ case 19:
+ m_mode = (m_mode & 0xe0) | (data & 0x1f);
+ break;
+ case 20:
+ case 21:
+ m_mode = (m_mode & 0x9f) | (data & 0x60);
+ switch(data & 3)
+ {
+ case 1:
+ m_mode |= 0x80;
+ break;
+ case 2:
+ m_mode &= 0x7f;
+ break;
+ }
+ break;
+ case 28:
+ case 29:
+ case 30:
+ case 31:
+ m_count[m_cmd & 7] = ((data >> 3) & 3) + 1;
+ m_curcnt = 0;
+ break;
+ }
+ set_timer();
+}
+
+WRITE8_MEMBER( am9519_device::data_w )
+{
+ if((m_cmd & 0xf0) > 0xb0)
+ {
+ switch(m_cmd >> 4)
+ {
+ case 11:
+ m_imr = data;
+ break;
+ case 12:
+ m_aclear = data;
+ break;
+ case 14:
+ case 15:
+ if(m_curcnt < m_count[m_cmd & 7])
+ {
+ m_resp[m_cmd & 7][m_curcnt] = data;
+ m_curcnt++;
+ return;
+ }
+ break;
+ }
+ m_cmd = 0;
+ }
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void am9519_device::device_start()
+{
+ // resolve callbacks
+ m_out_int_func.resolve_safe();
+
+ // Register save state items
+ save_item(NAME(m_isr));
+ save_item(NAME(m_irr));
+ save_item(NAME(m_prio));
+ save_item(NAME(m_imr));
+ save_item(NAME(m_irq_lines));
+ save_item(NAME(m_mode));
+ save_item(NAME(m_count));
+ save_item(NAME(m_resp));
+ save_item(NAME(m_aclear));
+ save_item(NAME(m_cmd));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void am9519_device::device_reset()
+{
+ m_isr = 0;
+ m_irr = 0;
+ m_irq_lines = 0;
+ m_prio = 0;
+ m_imr = 0xff;
+ m_mode = 0;
+ m_aclear = 0;
+ m_cmd = 0;
+ m_curcnt = 0;
+ for(int i = 0; i < 8; i++)
+ {
+ m_count[i] = 0;
+ m_resp[i][0] = 0;
+ m_resp[i][1] = 0;
+ m_resp[i][2] = 0;
+ m_resp[i][3] = 0;
+ }
+}
+
+DEFINE_DEVICE_TYPE(AM9519, am9519_device, "am9519", "AMD AM9519 Universal Interrupt Controller")
+
+am9519_device::am9519_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : device_t(mconfig, AM9519, tag, owner, clock)
+ , m_out_int_func(*this)
+ , m_irr(0)
+ , m_irq_lines(0)
+{
+}
diff --git a/src/devices/machine/am9519.h b/src/devices/machine/am9519.h
new file mode 100644
index 00000000000..2bfa9e89fe8
--- /dev/null
+++ b/src/devices/machine/am9519.h
@@ -0,0 +1,93 @@
+// license:BSD-3-Clause
+// copyright-holders:Wilbert Pol,Carl
+/***************************************************************************
+
+ AMD AM9519
+
+ Universal Interrupt Controller
+
+ _____ _____
+ _CS 1 |* \_/ | 28 VCC
+ _WR 2 | | 27 C/_D
+ _RD 3 | | 26 _IACK
+ DB7 4 | | 25 IREQ7
+ DB6 5 | | 24 IREQ6
+ DB5 6 | | 23 IREQ5
+ DB4 7 | AM9519 | 22 IREQ4
+ DB3 8 | | 21 IREQ3
+ DB2 9 | | 20 IREQ2
+ DB1 10 | | 19 IREQ1
+ DB0 11 | | 18 IREQ0
+ _RIP 12 | | 17 GINT
+ EI 13 | | 16 _EO
+ GND 14 |_____________| 15 _PAUSE
+
+***************************************************************************/
+
+#ifndef MAME_MACHINE_AM9519_H
+#define MAME_MACHINE_AM9519_H
+
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+#define MCFG_AM9519_OUT_INT_CB(_devcb) \
+ devcb = &am9519_device::static_set_out_int_callback(*device, DEVCB_##_devcb);
+
+
+class am9519_device : public device_t
+{
+public:
+ am9519_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ template <class Object> static devcb_base &static_set_out_int_callback(device_t &device, Object &&cb) { return downcast<am9519_device &>(device).m_out_int_func.set_callback(std::forward<Object>(cb)); }
+
+ DECLARE_READ8_MEMBER( stat_r );
+ DECLARE_READ8_MEMBER( data_r );
+ DECLARE_WRITE8_MEMBER( cmd_w );
+ DECLARE_WRITE8_MEMBER( data_w );
+ u32 acknowledge();
+
+ DECLARE_WRITE_LINE_MEMBER( ireq0_w ) { set_irq_line(0, state); }
+ DECLARE_WRITE_LINE_MEMBER( ireq1_w ) { set_irq_line(1, state); }
+ DECLARE_WRITE_LINE_MEMBER( ireq2_w ) { set_irq_line(2, state); }
+ DECLARE_WRITE_LINE_MEMBER( ireq3_w ) { set_irq_line(3, state); }
+ DECLARE_WRITE_LINE_MEMBER( ireq4_w ) { set_irq_line(4, state); }
+ DECLARE_WRITE_LINE_MEMBER( ireq5_w ) { set_irq_line(5, state); }
+ DECLARE_WRITE_LINE_MEMBER( ireq6_w ) { set_irq_line(6, state); }
+ DECLARE_WRITE_LINE_MEMBER( ireq7_w ) { set_irq_line(7, state); }
+
+ IRQ_CALLBACK_MEMBER(iack_cb);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+private:
+ static constexpr device_timer_id TIMER_CHECK_IRQ = 0;
+
+ inline void set_timer() { timer_set(attotime::zero, TIMER_CHECK_IRQ); }
+ void set_irq_line(int irq, int state);
+
+ devcb_write_line m_out_int_func;
+
+ u8 m_isr;
+ u8 m_irr;
+ u8 m_prio;
+ u8 m_imr;
+ u8 m_irq_lines;
+
+ u8 m_curcnt;
+ u8 m_mode;
+ u8 m_cmd;
+ u8 m_aclear;
+ u8 m_count[8];
+ u8 m_resp[8][4];
+};
+
+DECLARE_DEVICE_TYPE(AM9519, am9519_device)
+
+#endif // MAME_MACHINE_AM9519_H
diff --git a/src/mame/drivers/olyboss.cpp b/src/mame/drivers/olyboss.cpp
index f40b517d4f9..843bb2d08cc 100644
--- a/src/mame/drivers/olyboss.cpp
+++ b/src/mame/drivers/olyboss.cpp
@@ -38,6 +38,7 @@
#include "machine/keyboard.h"
#include "video/upd3301.h"
#include "machine/i8257.h"
+#include "machine/am9519.h"
#include "screen.h"
#define Z80_TAG "z80"
@@ -108,7 +109,10 @@ static ADDRESS_MAP_START(olyboss_io, AS_IO, 8, olyboss_state)
ADDRESS_MAP_GLOBAL_MASK(0xff)
ADDRESS_MAP_UNMAP_HIGH
AM_RANGE(0x0, 0x8) AM_DEVREADWRITE(I8257_TAG, i8257_device, read, write)
- AM_RANGE(0x9, 0x7f) AM_READWRITE(port_read,port_write)
+ AM_RANGE(0x9, 0x2f) AM_READWRITE(port_read,port_write)
+ AM_RANGE(0x30, 0x30) AM_DEVREADWRITE("uic", am9519_device, data_r, data_w)
+ AM_RANGE(0x31, 0x31) AM_DEVREADWRITE("uic", am9519_device, stat_r, cmd_w)
+ AM_RANGE(0x32, 0x7f) AM_READWRITE(port_read,port_write)
AM_RANGE(0x80, 0x81) AM_DEVREADWRITE(UPD3301_TAG, upd3301_device, read, write)
AM_RANGE(0x82, 0xff) AM_READWRITE(port_read,port_write)
ADDRESS_MAP_END
@@ -285,6 +289,7 @@ MACHINE_CONFIG_START( olyboss_state::olybossd )
MCFG_CPU_ADD(Z80_TAG, Z80, 4_MHz_XTAL)
MCFG_CPU_PROGRAM_MAP(olyboss_mem)
MCFG_CPU_IO_MAP(olyboss_io)
+ MCFG_CPU_IRQ_ACKNOWLEDGE_DEVICE("uic", am9519_device, iack_cb)
/* video hardware */
@@ -296,6 +301,9 @@ MACHINE_CONFIG_START( olyboss_state::olybossd )
/* devices */
+ MCFG_DEVICE_ADD("uic", AM9519, 0)
+ MCFG_AM9519_OUT_INT_CB(INPUTLINE(Z80_TAG, 0))
+
MCFG_DEVICE_ADD(I8257_TAG, I8257, XTAL(4'000'000))
MCFG_I8257_OUT_HRQ_CB(WRITELINE(olyboss_state, hrq_w))
MCFG_I8257_IN_MEMR_CB(READ8(olyboss_state, dma_mem_r))