mirror of
https://github.com/holub/mame
synced 2025-04-24 09:20:02 +03:00
h8_intc: h8h does not have 16-bit iscr, add support for rising edge interrupts
This commit is contained in:
parent
df28e783e1
commit
896f08157c
@ -148,9 +148,8 @@ uint8_t gt913_device::uart_control_r(offs_t offset)
|
||||
|
||||
void gt913_device::syscr_w(uint8_t data)
|
||||
{
|
||||
if(BIT(m_syscr ^ data, 2))
|
||||
// NMI active edge has changed
|
||||
m_intc->set_input(INPUT_LINE_NMI, CLEAR_LINE);
|
||||
// NMI active edge
|
||||
m_intc->set_nmi_type(BIT(data, 2) ? h8_intc_device::EDGE_RISE : h8_intc_device::EDGE_FALL);
|
||||
|
||||
m_syscr = data;
|
||||
}
|
||||
@ -256,11 +255,6 @@ void gt913_device::internal_update(uint64_t current_time)
|
||||
|
||||
void gt913_device::execute_set_input(int inputnum, int state)
|
||||
{
|
||||
if(inputnum == INPUT_LINE_NMI) {
|
||||
if(BIT(m_syscr, 2))
|
||||
state ^= ASSERT_LINE;
|
||||
}
|
||||
|
||||
m_intc->set_input(inputnum, state);
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
TODO:
|
||||
- serial controllers are slightly different, has 3 interrupt sources
|
||||
instead of 4
|
||||
- SYSCR NMI edge invert
|
||||
- HCSR register @ 0xfffe (port 3 handshake)
|
||||
- FNCR register @ 0xffff (16-bit timer noise canceler)
|
||||
|
||||
@ -107,8 +106,8 @@ void h8325_device::map(address_map &map)
|
||||
|
||||
map(0xffc4, 0xffc4).rw(FUNC(h8325_device::syscr_r), FUNC(h8325_device::syscr_w));
|
||||
map(0xffc5, 0xffc5).r(FUNC(h8325_device::mdcr_r));
|
||||
map(0xffc6, 0xffc6).rw(m_intc, FUNC(h8_intc_device::iscr_r), FUNC(h8_intc_device::iscr_w));
|
||||
map(0xffc7, 0xffc7).rw(m_intc, FUNC(h8_intc_device::ier_r), FUNC(h8_intc_device::ier_w));
|
||||
map(0xffc6, 0xffc6).rw(m_intc, FUNC(h8325_intc_device::iscr_r), FUNC(h8325_intc_device::iscr_w));
|
||||
map(0xffc7, 0xffc7).rw(m_intc, FUNC(h8325_intc_device::ier_r), FUNC(h8325_intc_device::ier_w));
|
||||
|
||||
map(0xffc8, 0xffc8).rw(m_timer8_0, FUNC(h8_timer8_channel_device::tcr_r), FUNC(h8_timer8_channel_device::tcr_w));
|
||||
map(0xffc9, 0xffc9).rw(m_timer8_0, FUNC(h8_timer8_channel_device::tcsr_r), FUNC(h8_timer8_channel_device::tcsr_w));
|
||||
@ -214,7 +213,6 @@ uint8_t h8325_device::syscr_r()
|
||||
void h8325_device::syscr_w(uint8_t data)
|
||||
{
|
||||
logerror("syscr = %02x\n", data);
|
||||
m_syscr = data;
|
||||
|
||||
// RAME
|
||||
if (data & 1)
|
||||
@ -222,8 +220,13 @@ void h8325_device::syscr_w(uint8_t data)
|
||||
else
|
||||
m_ram_view.disable();
|
||||
|
||||
// NMIEG
|
||||
m_intc->set_nmi_type((data & 4) ? h8325_intc_device::EDGE_RISE : h8325_intc_device::EDGE_FALL);
|
||||
|
||||
// SSBY
|
||||
m_standby_pending = bool(data & 0x80);
|
||||
|
||||
m_syscr = data;
|
||||
}
|
||||
|
||||
uint8_t h8325_device::mdcr_r()
|
||||
|
@ -7,7 +7,7 @@
|
||||
H8 interrupt controllers family
|
||||
|
||||
TODO:
|
||||
- H8/325 ICSR has bits for inverting the active state (low/high, rise/fall)
|
||||
- why is ISR in the base class? original H8 does not have this register
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
@ -33,7 +33,7 @@ h8_intc_device::h8_intc_device(const machine_config &mconfig, const char *tag, d
|
||||
|
||||
h8_intc_device::h8_intc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
|
||||
device_t(mconfig, type, tag, owner, clock), m_irq_vector_base(0), m_irq_vector_count(0), m_irq_vector_nmi(0),
|
||||
m_cpu(*this, finder_base::DUMMY_TAG), m_nmi_input(false), m_irq_input(0), m_ier(0), m_isr(0), m_iscr(0), m_icr_filter(0), m_ipr_filter(0)
|
||||
m_cpu(*this, finder_base::DUMMY_TAG), m_nmi_type(EDGE_FALL), m_nmi_input(false), m_irq_input(0), m_ier(0), m_isr(0), m_iscr(0), m_icr_filter(0), m_ipr_filter(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -42,6 +42,7 @@ void h8_intc_device::device_start()
|
||||
memset(m_pending_irqs, 0, sizeof(m_pending_irqs));
|
||||
save_item(NAME(m_pending_irqs));
|
||||
save_item(NAME(m_irq_type));
|
||||
save_item(NAME(m_nmi_type));
|
||||
save_item(NAME(m_nmi_input));
|
||||
save_item(NAME(m_irq_input));
|
||||
save_item(NAME(m_ier));
|
||||
@ -54,6 +55,7 @@ void h8_intc_device::device_start()
|
||||
void h8_intc_device::device_reset()
|
||||
{
|
||||
memset(m_irq_type, 0, sizeof(m_irq_type));
|
||||
m_nmi_type = EDGE_FALL;
|
||||
memset(m_pending_irqs, 0, sizeof(m_pending_irqs));
|
||||
m_ier = m_isr = m_irq_input = 0x00;
|
||||
m_iscr = 0x0000;
|
||||
@ -66,8 +68,9 @@ int h8_intc_device::interrupt_taken(int vector)
|
||||
m_pending_irqs[vector >> 5] &= ~(1 << (vector & 31));
|
||||
if(vector >= m_irq_vector_base && vector < m_irq_vector_base + m_irq_vector_count) {
|
||||
int irq = vector - m_irq_vector_base;
|
||||
if(m_irq_type[irq] != IRQ_LEVEL || !(m_irq_input & (1 << irq)))
|
||||
m_isr &= ~(1 << irq);
|
||||
uint8_t mask = 1 << irq;
|
||||
if(m_irq_type[irq] != LEVEL_LOW || !(m_irq_input & mask))
|
||||
m_isr &= ~mask;
|
||||
update_irq_state();
|
||||
return irq;
|
||||
}
|
||||
@ -90,19 +93,27 @@ void h8_intc_device::internal_interrupt(int vector)
|
||||
void h8_intc_device::set_input(int inputnum, int state)
|
||||
{
|
||||
if(inputnum == INPUT_LINE_NMI) {
|
||||
if(state == ASSERT_LINE && !m_nmi_input)
|
||||
bool set = false;
|
||||
switch(m_nmi_type) {
|
||||
case EDGE_FALL: set = state != CLEAR_LINE && !m_nmi_input; break;
|
||||
case EDGE_RISE: set = state == CLEAR_LINE && m_nmi_input; break;
|
||||
default: assert(0); break;
|
||||
}
|
||||
m_nmi_input = state != CLEAR_LINE;
|
||||
if(set) {
|
||||
m_pending_irqs[0] |= 1 << m_irq_vector_nmi;
|
||||
m_nmi_input = state == ASSERT_LINE;
|
||||
update_irq_state();
|
||||
update_irq_state();
|
||||
}
|
||||
} else {
|
||||
bool set = false;
|
||||
bool cur = m_irq_input & (1 << inputnum);
|
||||
switch(m_irq_type[inputnum]) {
|
||||
case IRQ_LEVEL: set = state == ASSERT_LINE; break;
|
||||
case IRQ_EDGE: set = state == ASSERT_LINE && !cur; break;
|
||||
case IRQ_DUAL_EDGE: set = (state == ASSERT_LINE && !cur) || (state == CLEAR_LINE && cur); break;
|
||||
case LEVEL_LOW: set = state != CLEAR_LINE; break;
|
||||
case EDGE_FALL: set = state != CLEAR_LINE && !cur; break;
|
||||
case EDGE_RISE: set = state == CLEAR_LINE && cur; break;
|
||||
case EDGE_DUAL: set = bool(state) != bool(cur); break;
|
||||
}
|
||||
if(state == ASSERT_LINE)
|
||||
if(state != CLEAR_LINE)
|
||||
m_irq_input |= 1 << inputnum;
|
||||
else
|
||||
m_irq_input &= ~(1 << inputnum);
|
||||
@ -137,8 +148,8 @@ void h8_intc_device::check_level_irqs(bool force_update)
|
||||
logerror("irq_input=%02x\n", m_irq_input);
|
||||
bool update = force_update;
|
||||
for(int i=0; i<m_irq_vector_count; i++) {
|
||||
unsigned char mask = 1 << i;
|
||||
if(m_irq_type[i] == IRQ_LEVEL && (m_irq_input & mask) && !(m_isr & mask)) {
|
||||
uint8_t mask = 1 << i;
|
||||
if(m_irq_type[i] == LEVEL_LOW && (m_irq_input & mask) && !(m_isr & mask)) {
|
||||
m_isr |= mask;
|
||||
update = true;
|
||||
}
|
||||
@ -163,12 +174,12 @@ void h8_intc_device::iscr_w(uint8_t data)
|
||||
void h8_intc_device::update_irq_types()
|
||||
{
|
||||
for(int i=0; i<m_irq_vector_count; i++)
|
||||
switch((m_iscr >> (i)) & 1) {
|
||||
switch((m_iscr >> i) & 1) {
|
||||
case 0:
|
||||
m_irq_type[i] = IRQ_LEVEL;
|
||||
m_irq_type[i] = LEVEL_LOW;
|
||||
break;
|
||||
case 1:
|
||||
m_irq_type[i] = IRQ_EDGE;
|
||||
m_irq_type[i] = EDGE_FALL;
|
||||
break;
|
||||
}
|
||||
check_level_irqs();
|
||||
@ -223,6 +234,23 @@ h8325_intc_device::h8325_intc_device(const machine_config &mconfig, const char *
|
||||
m_irq_vector_nmi = 3;
|
||||
}
|
||||
|
||||
void h8325_intc_device::update_irq_types()
|
||||
{
|
||||
for(int i=0; i<m_irq_vector_count; i++)
|
||||
switch(bitswap<2>(m_iscr >> i,0,4)) {
|
||||
case 0: case 1:
|
||||
m_irq_type[i] = LEVEL_LOW;
|
||||
break;
|
||||
case 2:
|
||||
m_irq_type[i] = EDGE_FALL;
|
||||
break;
|
||||
case 3:
|
||||
m_irq_type[i] = EDGE_RISE;
|
||||
break;
|
||||
}
|
||||
check_level_irqs();
|
||||
}
|
||||
|
||||
|
||||
// H8H
|
||||
|
||||
@ -284,47 +312,6 @@ void h8h_intc_device::icrc_w(uint8_t data)
|
||||
icr_w(2, data);
|
||||
}
|
||||
|
||||
uint8_t h8h_intc_device::iscrh_r()
|
||||
{
|
||||
return m_iscr >> 8;
|
||||
}
|
||||
|
||||
void h8h_intc_device::iscrh_w(uint8_t data)
|
||||
{
|
||||
m_iscr = (m_iscr & 0x00ff) | (data << 8);
|
||||
logerror("iscr = %04x\n", m_iscr);
|
||||
update_irq_types();
|
||||
}
|
||||
|
||||
uint8_t h8h_intc_device::iscrl_r()
|
||||
{
|
||||
return m_iscr;
|
||||
}
|
||||
|
||||
void h8h_intc_device::iscrl_w(uint8_t data)
|
||||
{
|
||||
m_iscr = (m_iscr & 0xff00) | data;
|
||||
logerror("iscr = %04x\n", m_iscr);
|
||||
update_irq_types();
|
||||
}
|
||||
|
||||
void h8h_intc_device::update_irq_types()
|
||||
{
|
||||
for(int i=0; i<m_irq_vector_count; i++)
|
||||
switch((m_iscr >> (2*i)) & 3) {
|
||||
case 0:
|
||||
m_irq_type[i] = IRQ_LEVEL;
|
||||
break;
|
||||
case 1: case 2:
|
||||
m_irq_type[i] = IRQ_EDGE;
|
||||
break;
|
||||
case 3:
|
||||
m_irq_type[i] = IRQ_DUAL_EDGE;
|
||||
break;
|
||||
}
|
||||
check_level_irqs();
|
||||
}
|
||||
|
||||
const int h8h_intc_device::vector_to_slot[64] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, // NMI at 7
|
||||
-1, -1, -1, -1, 0, 1, 2, 2, // IRQ 0-3
|
||||
@ -391,6 +378,50 @@ void h8s_intc_device::iprk_w(uint8_t data)
|
||||
ipr_w(10, data);
|
||||
}
|
||||
|
||||
uint8_t h8s_intc_device::iscrh_r()
|
||||
{
|
||||
return m_iscr >> 8;
|
||||
}
|
||||
|
||||
void h8s_intc_device::iscrh_w(uint8_t data)
|
||||
{
|
||||
m_iscr = (m_iscr & 0x00ff) | (data << 8);
|
||||
logerror("iscr = %04x\n", m_iscr);
|
||||
update_irq_types();
|
||||
}
|
||||
|
||||
uint8_t h8s_intc_device::iscrl_r()
|
||||
{
|
||||
return m_iscr;
|
||||
}
|
||||
|
||||
void h8s_intc_device::iscrl_w(uint8_t data)
|
||||
{
|
||||
m_iscr = (m_iscr & 0xff00) | data;
|
||||
logerror("iscr = %04x\n", m_iscr);
|
||||
update_irq_types();
|
||||
}
|
||||
|
||||
void h8s_intc_device::update_irq_types()
|
||||
{
|
||||
for(int i=0; i<m_irq_vector_count; i++)
|
||||
switch((m_iscr >> (2*i)) & 3) {
|
||||
case 0:
|
||||
m_irq_type[i] = LEVEL_LOW;
|
||||
break;
|
||||
case 1:
|
||||
m_irq_type[i] = EDGE_FALL;
|
||||
break;
|
||||
case 2:
|
||||
m_irq_type[i] = EDGE_RISE;
|
||||
break;
|
||||
case 3:
|
||||
m_irq_type[i] = EDGE_DUAL;
|
||||
break;
|
||||
}
|
||||
check_level_irqs();
|
||||
}
|
||||
|
||||
const int h8s_intc_device::vector_to_slot[92] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, // NMI at 7
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
|
@ -17,6 +17,13 @@ class h8_device;
|
||||
|
||||
class h8_intc_device : public device_t {
|
||||
public:
|
||||
enum {
|
||||
LEVEL_LOW, // ASSERT
|
||||
EDGE_FALL, // CLEAR->ASSERT
|
||||
EDGE_RISE, // ASSERT->CLEAR
|
||||
EDGE_DUAL
|
||||
};
|
||||
|
||||
h8_intc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
|
||||
template<typename T> h8_intc_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&cpu) :
|
||||
h8_intc_device(mconfig, tag, owner)
|
||||
@ -28,6 +35,7 @@ public:
|
||||
void internal_interrupt(int vector);
|
||||
void set_input(int inputnum, int state);
|
||||
void set_filter(int icr_filter, int ipr_filter);
|
||||
void set_nmi_type(int type) { m_nmi_type = type; }
|
||||
|
||||
uint8_t ier_r();
|
||||
void ier_w(uint8_t data);
|
||||
@ -35,7 +43,6 @@ public:
|
||||
void iscr_w(uint8_t data);
|
||||
|
||||
protected:
|
||||
enum { IRQ_LEVEL, IRQ_EDGE, IRQ_DUAL_EDGE };
|
||||
enum { MAX_VECTORS = 256 };
|
||||
|
||||
int m_irq_vector_base;
|
||||
@ -45,7 +52,8 @@ protected:
|
||||
required_device<h8_device> m_cpu;
|
||||
|
||||
uint32_t m_pending_irqs[MAX_VECTORS/32];
|
||||
int m_irq_type[8];
|
||||
uint8_t m_irq_type[8];
|
||||
uint8_t m_nmi_type;
|
||||
bool m_nmi_input;
|
||||
uint8_t m_irq_input;
|
||||
uint8_t m_ier;
|
||||
@ -60,7 +68,7 @@ protected:
|
||||
|
||||
virtual void get_priority(int vect, int &icr_pri, int &ipr_pri) const;
|
||||
void update_irq_state();
|
||||
void update_irq_types();
|
||||
virtual void update_irq_types();
|
||||
void check_level_irqs(bool force_update = false);
|
||||
};
|
||||
|
||||
@ -72,6 +80,9 @@ public:
|
||||
{
|
||||
m_cpu.set_tag(std::forward<T>(cpu));
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void update_irq_types() override;
|
||||
};
|
||||
|
||||
class h8h_intc_device : public h8_intc_device {
|
||||
@ -89,10 +100,6 @@ public:
|
||||
void icr_w(offs_t offset, uint8_t data);
|
||||
uint8_t icrc_r();
|
||||
void icrc_w(uint8_t data);
|
||||
uint8_t iscrh_r();
|
||||
void iscrh_w(uint8_t data);
|
||||
uint8_t iscrl_r();
|
||||
void iscrl_w(uint8_t data);
|
||||
|
||||
protected:
|
||||
static const int vector_to_slot[];
|
||||
@ -105,7 +112,6 @@ protected:
|
||||
virtual void device_reset() override;
|
||||
|
||||
virtual void get_priority(int vect, int &icr_pri, int &ipr_pri) const override;
|
||||
void update_irq_types();
|
||||
};
|
||||
|
||||
class h8s_intc_device : public h8h_intc_device {
|
||||
@ -121,12 +127,17 @@ public:
|
||||
void ipr_w(offs_t offset, uint8_t data);
|
||||
uint8_t iprk_r();
|
||||
void iprk_w(uint8_t data);
|
||||
uint8_t iscrh_r();
|
||||
void iscrh_w(uint8_t data);
|
||||
uint8_t iscrl_r();
|
||||
void iscrl_w(uint8_t data);
|
||||
|
||||
private:
|
||||
static const int vector_to_slot[];
|
||||
uint8_t m_ipr[11];
|
||||
|
||||
virtual void get_priority(int vect, int &icr_pri, int &ipr_pri) const override;
|
||||
virtual void update_irq_types() override;
|
||||
virtual void device_reset() override;
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,18 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Olivier Galibert
|
||||
/***************************************************************************
|
||||
|
||||
h8_port.cpp
|
||||
|
||||
H8 8 bits digital port
|
||||
|
||||
TODO:
|
||||
- Many I/O port pins have a double function, eg. for IRQs or timer input
|
||||
strobe. Ideally this device should know the input pin state, instead
|
||||
of having to implement it in the MAME drivers.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "h8_port.h"
|
||||
|
||||
|
@ -6,7 +6,6 @@
|
||||
|
||||
H8 8 bits digital port
|
||||
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef MAME_CPU_H8_H8_PORT_H
|
||||
|
@ -180,7 +180,7 @@ uint8_t h8_sci_device::scmr_r()
|
||||
void h8_sci_device::clock_update()
|
||||
{
|
||||
// Sync: Divider must be the time of a half-period (both edges are used, datarate*2)
|
||||
// Async: Divider must be the time of one period (only raising edge used, datarate*16)
|
||||
// Async: Divider must be the time of one period (only rising edge used, datarate*16)
|
||||
|
||||
m_divider = 2 << (2*(m_smr & SMR_CKS));
|
||||
m_divider *= m_brr+1;
|
||||
|
Loading…
Reference in New Issue
Block a user