h8_intc: h8h does not have 16-bit iscr, add support for rising edge interrupts

This commit is contained in:
hap 2024-02-14 02:39:24 +01:00
parent df28e783e1
commit 896f08157c
7 changed files with 130 additions and 79 deletions

View File

@ -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);
}

View File

@ -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()

View File

@ -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,

View File

@ -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;
};

View File

@ -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"

View File

@ -6,7 +6,6 @@
H8 8 bits digital port
***************************************************************************/
#ifndef MAME_CPU_H8_H8_PORT_H

View File

@ -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;