mirror of
https://github.com/holub/mame
synced 2025-05-31 01:51:46 +03:00
Atmel AIC: implement most of features
This commit is contained in:
parent
0932b9c2ae
commit
8255459e5d
@ -5,10 +5,13 @@
|
||||
ARM AIC (Advanced Interrupt Controller) from Atmel
|
||||
typically integrated into the AM91SAM series of chips
|
||||
|
||||
see http://sam7-ex256.narod.ru/include/HTML/AT91SAM7X256_AIC.html
|
||||
current implementation only handles basics needed for pgm2 (pgm2.cpp)
|
||||
current implementation was tested in pgm2 (pgm2.cpp) only, there might be mistakes if more advanced usage.
|
||||
if this peripheral is not available as a standalone chip it could also be moved to
|
||||
the CPU folder alongside the ARM instead
|
||||
TODO:
|
||||
low/high input source types
|
||||
check if level/edge input source types logic correct
|
||||
FIQ output
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
@ -22,29 +25,61 @@ DEVICE_ADDRESS_MAP_START( regs_map, 32, arm_aic_device )
|
||||
AM_RANGE(0x080, 0x0ff) AM_READWRITE(aic_svr_r, aic_svr_w) // AIC_SVR[32] (AIC_SVR) Source Vector Register
|
||||
AM_RANGE(0x100, 0x103) AM_READ(irq_vector_r) // AIC_IVR IRQ Vector Register
|
||||
AM_RANGE(0x104, 0x107) AM_READ(firq_vector_r) // AIC_FVR FIQ Vector Register
|
||||
// 0x108 AIC_ISR Interrupt Status Register
|
||||
// 0x10C AIC_IPR Interrupt Pending Register
|
||||
// 0x110 AIC_IMR Interrupt Mask Register
|
||||
// 0x114 AIC_CISR Core Interrupt Status Register
|
||||
AM_RANGE(0x120, 0x123) AM_WRITE(aic_iecr_w) // 0x120 AIC_IECR Interrupt Enable Command Register
|
||||
AM_RANGE(0x124, 0x127) AM_WRITE(aic_idcr_w) // 0x124 AIC_IDCR Interrupt Disable Command Register
|
||||
AM_RANGE(0x128, 0x12b) AM_WRITE(aic_iccr_w) // 0x128 AIC_ICCR Interrupt Clear Command Register
|
||||
// 0x12C AIC_ISCR Interrupt Set Command Register
|
||||
AM_RANGE(0x130, 0x133) AM_WRITE(aic_eoicr_w) // 0x130 AIC_EOICR End of Interrupt Command Register
|
||||
// 0x134 AIC_SPU Spurious Vector Register
|
||||
// 0x138 AIC_DCR Debug Control Register (Protect)
|
||||
// 0x140 AIC_FFER Fast Forcing Enable Register
|
||||
// 0x144 AIC_FFDR Fast Forcing Disable Register
|
||||
// 0x148 AIC_FFSR Fast Forcing Status Register
|
||||
AM_RANGE(0x108, 0x10b) AM_READ(aic_isr_r) // AIC_ISR Interrupt Status Register
|
||||
AM_RANGE(0x10c, 0x10f) AM_READ(aic_ipr_r) // AIC_IPR Interrupt Pending Register
|
||||
AM_RANGE(0x110, 0x113) AM_READ(aic_imr_r) // AIC_IMR Interrupt Mask Register
|
||||
AM_RANGE(0x114, 0x117) AM_READ(aic_cisr_r) // AIC_CISR Core Interrupt Status Register
|
||||
AM_RANGE(0x120, 0x123) AM_WRITE(aic_iecr_w) // AIC_IECR Interrupt Enable Command Register
|
||||
AM_RANGE(0x124, 0x127) AM_WRITE(aic_idcr_w) // AIC_IDCR Interrupt Disable Command Register
|
||||
AM_RANGE(0x128, 0x12b) AM_WRITE(aic_iccr_w) // AIC_ICCR Interrupt Clear Command Register
|
||||
AM_RANGE(0x12c, 0x12f) AM_WRITE(aic_iscr_w) // AIC_ISCR Interrupt Set Command Register
|
||||
AM_RANGE(0x130, 0x133) AM_WRITE(aic_eoicr_w) // AIC_EOICR End of Interrupt Command Register
|
||||
AM_RANGE(0x134, 0x137) AM_WRITE(aic_spu_w) // AIC_SPU Spurious Vector Register
|
||||
AM_RANGE(0x138, 0x13b) AM_WRITE(aic_dcr_w) // AIC_DCR Debug Control Register (Protect)
|
||||
AM_RANGE(0x140, 0x143) AM_WRITE(aic_ffer_w) // AIC_FFER Fast Forcing Enable Register
|
||||
AM_RANGE(0x144, 0x147) AM_WRITE(aic_ffdr_w) // AIC_FFDR Fast Forcing Disable Register
|
||||
AM_RANGE(0x144, 0x147) AM_READ(aic_ffsr_r) // AIC_FFSR Fast Forcing Status Register
|
||||
ADDRESS_MAP_END
|
||||
|
||||
READ32_MEMBER(arm_aic_device::irq_vector_r)
|
||||
{
|
||||
uint32_t mask = m_irqs_enabled & m_irqs_pending & ~m_fast_irqs;
|
||||
m_current_irq_vector = m_spurious_vector;
|
||||
if (mask)
|
||||
{
|
||||
// looking for highest level pending interrupt, bigger than current
|
||||
int pri = get_level();
|
||||
int midx = -1;
|
||||
do
|
||||
{
|
||||
uint8_t idx = 31 - count_leading_zeros(mask);
|
||||
if ((int)(m_aic_smr[idx] & 7) >= pri)
|
||||
{
|
||||
midx = idx;
|
||||
pri = m_aic_smr[idx] & 7;
|
||||
}
|
||||
mask ^= 1 << idx;
|
||||
} while (mask);
|
||||
|
||||
if (midx > 0)
|
||||
{
|
||||
m_status = midx;
|
||||
m_current_irq_vector = m_aic_svr[midx];
|
||||
// note: Debug PROTect mode not implemented (new level pushed on stack and pending line clear only when this register writen after read)
|
||||
push_level(m_aic_smr[midx] & 7);
|
||||
if (m_aic_smr[midx] & 0x20) // auto clear pending if edge trigger mode
|
||||
m_irqs_pending ^= 1 << midx;
|
||||
}
|
||||
}
|
||||
|
||||
m_core_status &= ~2;
|
||||
set_lines();
|
||||
return m_current_irq_vector;
|
||||
}
|
||||
|
||||
READ32_MEMBER(arm_aic_device::firq_vector_r)
|
||||
{
|
||||
m_current_firq_vector = (m_irqs_enabled & m_irqs_pending & m_fast_irqs) ? m_aic_svr[0] : m_spurious_vector;
|
||||
return m_current_firq_vector;
|
||||
}
|
||||
|
||||
@ -56,9 +91,16 @@ void arm_aic_device::device_start()
|
||||
save_item(NAME(m_irqs_pending));
|
||||
save_item(NAME(m_current_irq_vector));
|
||||
save_item(NAME(m_current_firq_vector));
|
||||
save_item(NAME(m_status));
|
||||
save_item(NAME(m_core_status));
|
||||
save_item(NAME(m_spurious_vector));
|
||||
save_item(NAME(m_debug));
|
||||
save_item(NAME(m_fast_irqs));
|
||||
save_item(NAME(m_lvlidx));
|
||||
|
||||
save_item(NAME(m_aic_smr));
|
||||
save_item(NAME(m_aic_svr));
|
||||
save_item(NAME(m_level_stack));
|
||||
}
|
||||
|
||||
void arm_aic_device::device_reset()
|
||||
@ -67,43 +109,54 @@ void arm_aic_device::device_reset()
|
||||
m_irqs_pending = 0;
|
||||
m_current_irq_vector = 0;
|
||||
m_current_firq_vector = 0;
|
||||
m_status = 0;
|
||||
m_core_status = 0;
|
||||
m_spurious_vector = 0;
|
||||
m_debug = 0;
|
||||
m_fast_irqs = 1;
|
||||
m_lvlidx = 0;
|
||||
|
||||
for(auto & elem : m_aic_smr) { elem = 0; }
|
||||
for(auto & elem : m_aic_svr) { elem = 0; }
|
||||
for(auto & elem : m_level_stack) { elem = 0; }
|
||||
m_level_stack[0] = -1;
|
||||
}
|
||||
|
||||
void arm_aic_device::set_irq(int line, int state)
|
||||
{
|
||||
// note: configurable edge / level logic is not simulated, TODO
|
||||
// note: might be incorrect if edge triggered mode set
|
||||
if (state == ASSERT_LINE)
|
||||
m_irqs_pending |= 1 << line;
|
||||
else
|
||||
m_irqs_pending &= ~(1 << line);
|
||||
recalc_irqs();
|
||||
if (m_aic_smr[line] & 0x40)
|
||||
m_irqs_pending &= ~(1 << line);
|
||||
|
||||
check_irqs();
|
||||
}
|
||||
|
||||
void arm_aic_device::recalc_irqs()
|
||||
void arm_aic_device::check_irqs()
|
||||
{
|
||||
uint32_t mask = m_irqs_enabled & m_irqs_pending;
|
||||
m_core_status = 0;
|
||||
|
||||
uint32_t mask = m_irqs_enabled & m_irqs_pending & ~m_fast_irqs;
|
||||
if (mask)
|
||||
{
|
||||
int pri = -1;
|
||||
uint8_t midx = 0;
|
||||
// check if we have pending interrupt with level more than current
|
||||
int pri = get_level();
|
||||
do
|
||||
{
|
||||
uint8_t idx = 31 - count_leading_zeros(mask);
|
||||
if ((int)(m_aic_smr[idx] & 7) > pri)
|
||||
{
|
||||
midx = idx;
|
||||
pri = m_aic_smr[idx] & 7;
|
||||
m_core_status |= 2;
|
||||
break;
|
||||
}
|
||||
mask &= ~(1 << idx);
|
||||
mask ^= 1 << idx;
|
||||
} while (mask);
|
||||
|
||||
// handle FIQ (idx 0) case ??
|
||||
m_current_irq_vector = m_aic_svr[midx];
|
||||
m_irq_out(ASSERT_LINE);
|
||||
}
|
||||
else
|
||||
m_irq_out(CLEAR_LINE);
|
||||
|
||||
if (m_irqs_enabled & m_irqs_pending & m_fast_irqs)
|
||||
m_core_status |= 1;
|
||||
|
||||
set_lines();
|
||||
}
|
||||
|
@ -31,17 +31,27 @@ public:
|
||||
|
||||
DECLARE_READ32_MEMBER(irq_vector_r);
|
||||
DECLARE_READ32_MEMBER(firq_vector_r);
|
||||
DECLARE_READ32_MEMBER(aic_isr_r) { return m_status; };
|
||||
DECLARE_READ32_MEMBER(aic_cisr_r) { return m_core_status; };
|
||||
DECLARE_READ32_MEMBER(aic_ipr_r) { return m_irqs_pending; };
|
||||
DECLARE_READ32_MEMBER(aic_imr_r) { return m_irqs_enabled; };
|
||||
DECLARE_READ32_MEMBER(aic_ffsr_r) { return m_fast_irqs; };
|
||||
|
||||
// can't use AM_RAM and AM_SHARE in device submaps
|
||||
DECLARE_READ32_MEMBER(aic_smr_r) { return m_aic_smr[offset]; };
|
||||
DECLARE_READ32_MEMBER(aic_svr_r) { return m_aic_svr[offset]; };
|
||||
DECLARE_WRITE32_MEMBER(aic_smr_w) { COMBINE_DATA(&m_aic_smr[offset]); };
|
||||
DECLARE_WRITE32_MEMBER(aic_svr_w) { COMBINE_DATA(&m_aic_svr[offset]); };
|
||||
DECLARE_WRITE32_MEMBER(aic_spu_w) { COMBINE_DATA(&m_spurious_vector); };
|
||||
DECLARE_WRITE32_MEMBER(aic_dcr_w) { COMBINE_DATA(&m_debug); check_irqs(); };
|
||||
DECLARE_WRITE32_MEMBER(aic_ffer_w) { m_fast_irqs |= data & mem_mask; check_irqs(); };
|
||||
DECLARE_WRITE32_MEMBER(aic_ffdr_w) { m_fast_irqs &= ~(data & mem_mask) | 1; check_irqs(); };
|
||||
|
||||
DECLARE_WRITE32_MEMBER(aic_iecr_w) { m_irqs_enabled |= data & mem_mask; recalc_irqs(); };
|
||||
DECLARE_WRITE32_MEMBER(aic_idcr_w) { m_irqs_enabled &= ~(data & mem_mask); recalc_irqs(); };
|
||||
DECLARE_WRITE32_MEMBER(aic_iccr_w) { m_irqs_pending &= ~(data & mem_mask); recalc_irqs(); };
|
||||
DECLARE_WRITE32_MEMBER(aic_eoicr_w){ /*logerror("%s: aic_eoicr_w (End of Interrupt Command Register)\n", machine().describe_context().c_str());*/ }; // value doesn't matter
|
||||
DECLARE_WRITE32_MEMBER(aic_iecr_w) { m_irqs_enabled |= data & mem_mask; check_irqs(); };
|
||||
DECLARE_WRITE32_MEMBER(aic_idcr_w) { m_irqs_enabled &= ~(data & mem_mask); check_irqs(); };
|
||||
DECLARE_WRITE32_MEMBER(aic_iccr_w) { m_irqs_pending &= ~(data & mem_mask); check_irqs(); };
|
||||
DECLARE_WRITE32_MEMBER(aic_iscr_w) { m_irqs_pending |= data & mem_mask; check_irqs(); };
|
||||
DECLARE_WRITE32_MEMBER(aic_eoicr_w) { m_status = 0; pop_level(); check_irqs(); };
|
||||
|
||||
void set_irq(int line, int state);
|
||||
|
||||
@ -54,12 +64,24 @@ private:
|
||||
uint32_t m_irqs_pending;
|
||||
uint32_t m_current_irq_vector;
|
||||
uint32_t m_current_firq_vector;
|
||||
uint32_t m_status;
|
||||
uint32_t m_core_status;
|
||||
uint32_t m_spurious_vector;
|
||||
uint32_t m_debug;
|
||||
uint32_t m_fast_irqs;
|
||||
int m_lvlidx;
|
||||
int m_level_stack[9];
|
||||
|
||||
uint32_t m_aic_smr[32];
|
||||
uint32_t m_aic_svr[32];
|
||||
|
||||
devcb_write_line m_irq_out;
|
||||
void recalc_irqs();
|
||||
void check_irqs();
|
||||
void set_lines() { m_irq_out((m_core_status & ~m_debug & 2) ? ASSERT_LINE : CLEAR_LINE); }; // TODO FIQ
|
||||
|
||||
void push_level(int lvl) { m_level_stack[++m_lvlidx] = lvl; };
|
||||
void pop_level() { if (m_lvlidx) --m_lvlidx; };
|
||||
int get_level() { return m_level_stack[m_lvlidx]; };
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -76,13 +76,13 @@
|
||||
08 - fg scroll x
|
||||
0a - fg scroll y
|
||||
0e - resolution, 0 - low (kof98), 1 - high (rest of games)
|
||||
10 - ? orleg2 - 0x13, kov2nl, kof - 0x14 at init (sprite related?)
|
||||
10 - ? orleg2 - 0x13, kov2nl, kof98 - 0x14 at init
|
||||
14 - sprite enable ? set to 0 before spriteram update, to 1 after
|
||||
16 - enable access to vrams/palettes/etc ? (bitmask)
|
||||
18 - vblank ack
|
||||
1a - ? 0 at init
|
||||
1c - ? orleg2 - 5, kov2nl, kof - 7 at init (sprite related?)
|
||||
1e - ? 2 at init (sprite related?)
|
||||
1c - ? orleg2 - 5, kov2nl, kof - 7 at init
|
||||
1e - ? 2 at init
|
||||
32 - shared RAM bank
|
||||
34, 36 - ? 0 at init, some unused xor feature ?
|
||||
38, 3a - sprite mask xor key
|
||||
@ -388,11 +388,11 @@ static ADDRESS_MAP_START( pgm2_map, AS_PROGRAM, 32, pgm2_state )
|
||||
AM_RANGE(0x40000000, 0x40000003) AM_DEVREADWRITE8("ymz774", ymz774_device, read, write, 0xffffffff)
|
||||
|
||||
// internal to IGS036? - various other writes down here on startup too - could be other standard ATMEL peripherals like the ARM_AIC mixed with custom bits
|
||||
AM_RANGE(0xffffec00, 0xffffec5f) AM_RAM
|
||||
AM_RANGE(0xffffec00, 0xffffec5f) AM_RAM // SMC controller
|
||||
AM_RANGE(0xfffffc00, 0xfffffcff) AM_READWRITE8(encryption_r,encryption_w, 0xffffffff) // confirmed as encryption table for main program rom (see code at 3950)
|
||||
|
||||
AM_RANGE(0xfffff000, 0xfffff14b) AM_DEVICE("arm_aic", arm_aic_device, regs_map)
|
||||
|
||||
// PIOA (gpio)
|
||||
AM_RANGE(0xfffff430, 0xfffff433) AM_WRITENOP // often
|
||||
AM_RANGE(0xfffff434, 0xfffff437) AM_WRITENOP // often
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user