mirror of
https://github.com/holub/mame
synced 2025-04-16 05:24:54 +03:00
ns32202: new device (wip)
This commit is contained in:
parent
29fc166c54
commit
e67a06058f
@ -4568,3 +4568,14 @@ if (MACHINES["NS32081"]~=null) then
|
||||
MAME_DIR .. "src/devices/machine/ns32081.h",
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/machine/ns32202.h,MACHINES["NS32202"] = true
|
||||
---------------------------------------------------
|
||||
if (MACHINES["NS32202"]~=null) then
|
||||
files {
|
||||
MAME_DIR .. "src/devices/machine/ns32202.cpp",
|
||||
MAME_DIR .. "src/devices/machine/ns32202.h",
|
||||
}
|
||||
end
|
||||
|
@ -781,6 +781,7 @@ MACHINES["WTL3132"] = true
|
||||
MACHINES["CXD1185"] = true
|
||||
MACHINES["BL_HANDHELDS_MENUCONTROL"] = true
|
||||
MACHINES["NS32081"] = true
|
||||
MACHINES["NS32202"] = true
|
||||
|
||||
--------------------------------------------------
|
||||
-- specify available bus cores
|
||||
|
698
src/devices/machine/ns32202.cpp
Normal file
698
src/devices/machine/ns32202.cpp
Normal file
@ -0,0 +1,698 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Patrick Mackinlay
|
||||
|
||||
/*
|
||||
* National Semiconductor NS32202 Interrupt Control Unit (ICU).
|
||||
*
|
||||
* Sources:
|
||||
*
|
||||
* http://bitsavers.org/components/national/_dataBooks/1989_National_Microprocessor_Databook_32000_NSC800.pdf
|
||||
*
|
||||
* TODO
|
||||
* - timer/counter
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
#include "ns32202.h"
|
||||
|
||||
#define LOG_GENERAL (1U << 0)
|
||||
#define LOG_STATE (1U << 1)
|
||||
#define LOG_REGW (1U << 2)
|
||||
#define LOG_REGR (1U << 3)
|
||||
|
||||
//#define VERBOSE (LOG_GENERAL|LOG_STATE|LOG_REGW|LOG_REGR)
|
||||
#include "logmacro.h"
|
||||
|
||||
DEFINE_DEVICE_TYPE(NS32202, ns32202_device, "ns32202", "NS32202 Interrupt Control Unit")
|
||||
|
||||
enum mctl_mask : u8
|
||||
{
|
||||
MCTL_T16N8 = 0x01, // data bus mode
|
||||
MCTL_NTAR = 0x02, // not auto-rotate mode
|
||||
MCTL_FRZ = 0x08, // freeze interrupt pending
|
||||
MCTL_CLKM = 0x10, // clock mode (square wave/pulsed)
|
||||
MCTL_COUTM = 0x20, // cout mode (square wave/pulsed)
|
||||
MCTL_COUTD = 0x40, // cout/scin input/output
|
||||
MCTL_CFRZ = 0x80, // freeze counter readings
|
||||
};
|
||||
|
||||
enum cctl_mask : u8
|
||||
{
|
||||
CCTL_CDCRL = 0x01, // decrement l-counter
|
||||
CCTL_CDCRH = 0x02, // decrement h-counter
|
||||
CCTL_CRUNL = 0x04, // l-counter running
|
||||
CCTL_CRUNH = 0x08, // h-counter running
|
||||
CCTL_COUT0 = 0x10, // zero detect l-counter
|
||||
CCTL_COUT1 = 0x20, // zero detect h-counter
|
||||
CCTL_CFNPS = 0x40, // clock not prescaled
|
||||
CCTL_CCON = 0x80, // counters concatenated
|
||||
};
|
||||
|
||||
enum cictl_mask : u8
|
||||
{
|
||||
CICTL_WENL = 0x01, // l-counter write enable
|
||||
CICTL_CIEL = 0x02, // l-counter interrupt enable
|
||||
CICTL_CIRL = 0x04, // l-counter interrupt request
|
||||
CICTL_CERL = 0x08, // l-counter error flag
|
||||
CICTL_WENH = 0x10, // h-counter write enable
|
||||
CICTL_CIEH = 0x20, // h-counter interrupt enable
|
||||
CICTL_CIRH = 0x40, // h-counter interrupt request
|
||||
CICTL_CERH = 0x80, // h-counter error flag
|
||||
};
|
||||
|
||||
ns32202_device::ns32202_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock)
|
||||
: device_t(mconfig, NS32202, tag, owner, clock)
|
||||
, m_out_int(*this)
|
||||
, m_out_cout(*this)
|
||||
, m_out_port(*this)
|
||||
, m_line_state(0xffff)
|
||||
, m_out_int_state(false)
|
||||
, m_out_cout_state(false)
|
||||
{
|
||||
}
|
||||
|
||||
void ns32202_device::device_start()
|
||||
{
|
||||
m_out_int.resolve_safe();
|
||||
m_out_cout.resolve_safe();
|
||||
m_out_port.resolve_safe();
|
||||
|
||||
save_item(NAME(m_hvct));
|
||||
save_item(NAME(m_eltg));
|
||||
save_item(NAME(m_tpl));
|
||||
save_item(NAME(m_ipnd));
|
||||
save_item(NAME(m_isrv));
|
||||
save_item(NAME(m_imsk));
|
||||
save_item(NAME(m_csrc));
|
||||
save_item(NAME(m_fprt));
|
||||
save_item(NAME(m_mctl));
|
||||
save_item(NAME(m_ocasn));
|
||||
save_item(NAME(m_ciptr));
|
||||
save_item(NAME(m_pdat));
|
||||
save_item(NAME(m_ips));
|
||||
save_item(NAME(m_pdir));
|
||||
save_item(NAME(m_cctl));
|
||||
save_item(NAME(m_cictl));
|
||||
save_item(NAME(m_csv));
|
||||
save_item(NAME(m_ccv));
|
||||
|
||||
save_item(NAME(m_isrv_count));
|
||||
|
||||
save_item(NAME(m_line_state));
|
||||
save_item(NAME(m_out_int_state));
|
||||
save_item(NAME(m_out_cout_state));
|
||||
|
||||
m_interrupt = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ns32202_device::interrupt), this));
|
||||
m_counter[0] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ns32202_device::counter<0>), this));
|
||||
m_counter[1] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ns32202_device::counter<1>), this));
|
||||
}
|
||||
|
||||
void ns32202_device::device_reset()
|
||||
{
|
||||
m_eltg = 0xffff;
|
||||
m_tpl = 0;
|
||||
m_ipnd = 0;
|
||||
m_isrv = 0;
|
||||
m_imsk = 0xffff;
|
||||
m_csrc = 0;
|
||||
m_fprt = 0x0001;
|
||||
|
||||
m_mctl = MCTL_COUTD;
|
||||
m_ocasn = 0;
|
||||
m_ciptr = 0xff;
|
||||
m_ips = 0xff;
|
||||
m_pdir = 0xff;
|
||||
m_cictl = 0;
|
||||
}
|
||||
|
||||
void ns32202_device::set_int(bool int_state)
|
||||
{
|
||||
if (int_state != m_out_int_state)
|
||||
{
|
||||
LOGMASKED(LOG_STATE, "int %s\n", int_state ? "asserted" : "cleared");
|
||||
|
||||
m_out_int_state = int_state;
|
||||
m_out_int(!m_out_int_state);
|
||||
}
|
||||
}
|
||||
|
||||
void ns32202_device::set_cout(bool cout_state)
|
||||
{
|
||||
if (cout_state != m_out_cout_state)
|
||||
{
|
||||
LOGMASKED(LOG_STATE, "cout %s\n", cout_state ? "asserted" : "cleared");
|
||||
|
||||
m_out_cout_state = cout_state;
|
||||
m_out_cout(!m_out_cout_state);
|
||||
}
|
||||
}
|
||||
|
||||
template <unsigned ST1> void ns32202_device::map(address_map &map)
|
||||
{
|
||||
map(0x00, 0x00).r(&ns32202_device::hvct_r<ST1, true>, "ns32202_device::hvct_r");
|
||||
map(0x01, 0x01).rw(&ns32202_device::hvct_r<ST1, false>, "ns32202_device::svct_r", FUNC(ns32202_device::svct_w));
|
||||
map(0x02, 0x02).rw(FUNC(ns32202_device::eltgl_r), FUNC(ns32202_device::eltgl_w));
|
||||
map(0x03, 0x03).rw(FUNC(ns32202_device::eltgh_r), FUNC(ns32202_device::eltgh_w));
|
||||
map(0x04, 0x04).rw(FUNC(ns32202_device::tpll_r), FUNC(ns32202_device::tpll_w));
|
||||
map(0x05, 0x05).rw(FUNC(ns32202_device::tplh_r), FUNC(ns32202_device::tplh_w));
|
||||
map(0x06, 0x06).rw(FUNC(ns32202_device::ipndl_r), FUNC(ns32202_device::ipndl_w));
|
||||
map(0x07, 0x07).rw(FUNC(ns32202_device::ipndh_r), FUNC(ns32202_device::ipndh_w));
|
||||
map(0x08, 0x08).rw(FUNC(ns32202_device::isrvl_r), FUNC(ns32202_device::isrvl_w));
|
||||
map(0x09, 0x09).rw(FUNC(ns32202_device::isrvh_r), FUNC(ns32202_device::isrvh_w));
|
||||
map(0x0a, 0x0a).rw(FUNC(ns32202_device::imskl_r), FUNC(ns32202_device::imskl_w));
|
||||
map(0x0b, 0x0b).rw(FUNC(ns32202_device::imskh_r), FUNC(ns32202_device::imskh_w));
|
||||
map(0x0c, 0x0c).rw(FUNC(ns32202_device::csrcl_r), FUNC(ns32202_device::csrcl_w));
|
||||
map(0x0d, 0x0d).rw(FUNC(ns32202_device::csrch_r), FUNC(ns32202_device::csrch_w));
|
||||
map(0x0e, 0x0e).rw(FUNC(ns32202_device::fprtl_r), FUNC(ns32202_device::fprtl_w));
|
||||
map(0x0f, 0x0f).rw(FUNC(ns32202_device::fprth_r), FUNC(ns32202_device::fprth_w));
|
||||
map(0x10, 0x10).rw(FUNC(ns32202_device::mctl_r), FUNC(ns32202_device::mctl_w));
|
||||
map(0x11, 0x11).rw(FUNC(ns32202_device::ocasn_r), FUNC(ns32202_device::ocasn_w));
|
||||
map(0x12, 0x12).rw(FUNC(ns32202_device::ciptr_r), FUNC(ns32202_device::ciptr_w));
|
||||
map(0x13, 0x13).rw(FUNC(ns32202_device::pdat_r), FUNC(ns32202_device::pdat_w));
|
||||
map(0x14, 0x14).rw(FUNC(ns32202_device::ips_r), FUNC(ns32202_device::ips_w));
|
||||
map(0x15, 0x15).rw(FUNC(ns32202_device::pdir_r), FUNC(ns32202_device::pdir_w));
|
||||
map(0x16, 0x16).rw(FUNC(ns32202_device::cctl_r), FUNC(ns32202_device::cctl_w));
|
||||
map(0x17, 0x17).rw(FUNC(ns32202_device::cictl_r), FUNC(ns32202_device::cictl_w));
|
||||
map(0x18, 0x18).rw(FUNC(ns32202_device::csvl_r<0>), FUNC(ns32202_device::csvl_w<0>));
|
||||
map(0x19, 0x19).rw(FUNC(ns32202_device::csvh_r<0>), FUNC(ns32202_device::csvh_w<0>));
|
||||
map(0x1a, 0x1a).rw(FUNC(ns32202_device::csvl_r<1>), FUNC(ns32202_device::csvl_w<1>));
|
||||
map(0x1b, 0x1b).rw(FUNC(ns32202_device::csvh_r<1>), FUNC(ns32202_device::csvh_w<1>));
|
||||
map(0x1c, 0x1c).rw(FUNC(ns32202_device::lccvl_r), FUNC(ns32202_device::lccvl_w));
|
||||
map(0x1d, 0x1d).rw(FUNC(ns32202_device::lccvh_r), FUNC(ns32202_device::lccvh_w));
|
||||
map(0x1e, 0x1e).rw(FUNC(ns32202_device::hccvl_r), FUNC(ns32202_device::hccvl_w));
|
||||
map(0x1f, 0x1f).rw(FUNC(ns32202_device::hccvh_r), FUNC(ns32202_device::hccvh_w));
|
||||
}
|
||||
|
||||
template void ns32202_device::map<0>(address_map &map);
|
||||
template void ns32202_device::map<1>(address_map &map);
|
||||
|
||||
/*
|
||||
* Set (and clear, for level-triggered interrupts) interrupt pending state
|
||||
* based on edge/level/polarity configuration and previous/current line state,
|
||||
* regardless of mask.
|
||||
*/
|
||||
template <unsigned Number> void ns32202_device::ir_w(int state)
|
||||
{
|
||||
// ignore external interrupts assigned to counters
|
||||
if (((m_cictl & CICTL_CIEL) && (m_ciptr & 15) == Number) ||
|
||||
((m_cictl & CICTL_CIEH) && (m_ciptr >> 4) == Number))
|
||||
return;
|
||||
|
||||
u16 const mask = 1 << Number;
|
||||
|
||||
if (m_eltg & mask)
|
||||
{
|
||||
// level triggered
|
||||
if (state == BIT(m_tpl, Number))
|
||||
m_ipnd |= mask;
|
||||
else
|
||||
m_ipnd &= ~mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
// edge triggered
|
||||
if (bool(state) == BIT(m_tpl, Number) && bool(state) ^ BIT(m_line_state, Number))
|
||||
m_ipnd |= mask;
|
||||
}
|
||||
|
||||
// record input line state
|
||||
if (state)
|
||||
m_line_state |= mask;
|
||||
else
|
||||
m_line_state &= ~mask;
|
||||
|
||||
// datasheet states maximum 800ns
|
||||
m_interrupt->adjust(attotime::from_nsec(600));
|
||||
}
|
||||
|
||||
// instantiate all valid interrupt request templates
|
||||
template void ns32202_device::ir_w<0>(int state);
|
||||
template void ns32202_device::ir_w<1>(int state);
|
||||
template void ns32202_device::ir_w<2>(int state);
|
||||
template void ns32202_device::ir_w<3>(int state);
|
||||
template void ns32202_device::ir_w<4>(int state);
|
||||
template void ns32202_device::ir_w<5>(int state);
|
||||
template void ns32202_device::ir_w<6>(int state);
|
||||
template void ns32202_device::ir_w<7>(int state);
|
||||
template void ns32202_device::ir_w<8>(int state);
|
||||
template void ns32202_device::ir_w<9>(int state);
|
||||
template void ns32202_device::ir_w<10>(int state);
|
||||
template void ns32202_device::ir_w<11>(int state);
|
||||
template void ns32202_device::ir_w<12>(int state);
|
||||
template void ns32202_device::ir_w<13>(int state);
|
||||
template void ns32202_device::ir_w<14>(int state);
|
||||
template void ns32202_device::ir_w<15>(int state);
|
||||
|
||||
/*
|
||||
* Assert interrupt output if there are any unmasked pending interrupts; and
|
||||
* - in auto-rotate mode and no interrupts are in-service; or
|
||||
* - in fixed priority mode; and
|
||||
* - no interrupts are in-service; or
|
||||
* - unmasked pending interrupt has priority > in-service interrupt; or
|
||||
* - unmasked pending cascade interrupt has priorty >= in-service interrupt
|
||||
*/
|
||||
void ns32202_device::interrupt(void *ptr, s32 param)
|
||||
{
|
||||
// check for unmasked pending interrupts
|
||||
if (!(m_ipnd & m_imsk))
|
||||
return;
|
||||
|
||||
if (m_mctl & MCTL_NTAR)
|
||||
{
|
||||
// fixed priority mode
|
||||
bool accept = false;
|
||||
|
||||
// check any interrupts in-service
|
||||
if (m_isrv)
|
||||
{
|
||||
// check interrupts in descending priority order
|
||||
u16 mask = m_fprt;
|
||||
for (unsigned i = 0; i < 16; i++)
|
||||
{
|
||||
// check interrupt in-service
|
||||
if (m_isrv & mask)
|
||||
{
|
||||
// check equal priority unmasked pending cascade interrupt
|
||||
if ((m_csrc & mask) && (m_ipnd & mask) && !(m_imsk & mask))
|
||||
{
|
||||
LOGMASKED(LOG_STATE, "unmasked pending cascade in-service interrupt %d\n", 31 - count_leading_zeros(mask));
|
||||
accept = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// check unmasked pending interrupt
|
||||
if ((m_ipnd & mask) && !(m_imsk & mask))
|
||||
{
|
||||
LOGMASKED(LOG_STATE, "unmasked pending interrupt %d\n", 31 - count_leading_zeros(mask));
|
||||
accept = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// rotate priority mask
|
||||
mask = (mask << 1) | (mask >> 15);
|
||||
}
|
||||
}
|
||||
else
|
||||
accept = true;
|
||||
|
||||
if (!accept)
|
||||
return;
|
||||
}
|
||||
else if (m_isrv)
|
||||
return;
|
||||
|
||||
set_int(true);
|
||||
}
|
||||
|
||||
u8 ns32202_device::interrupt_acknowledge(bool side_effects)
|
||||
{
|
||||
side_effects &= !machine().side_effects_disabled();
|
||||
u8 vector = m_hvct | 0x0f;
|
||||
|
||||
if ((m_ipnd & m_imsk) && m_fprt)
|
||||
{
|
||||
// find highest priority unmasked pending interrupt
|
||||
u16 mask = m_fprt;
|
||||
for (unsigned i = 0; i < 16; i++)
|
||||
{
|
||||
if ((m_ipnd & mask) && !(m_imsk & mask))
|
||||
break;
|
||||
|
||||
// rotate priority mask
|
||||
mask = (mask << 1) | (mask >> 15);
|
||||
}
|
||||
|
||||
unsigned const number = 31 - count_leading_zeros(mask);
|
||||
if (side_effects)
|
||||
{
|
||||
LOGMASKED(LOG_STATE, "acknowledge highest priority unmasked interrupt %d\n", number);
|
||||
|
||||
if (m_mctl & MCTL_NTAR)
|
||||
{
|
||||
if (m_csrc & mask)
|
||||
m_isrv_count[number]++;
|
||||
}
|
||||
else
|
||||
m_fprt = mask;
|
||||
|
||||
// mark interrupt in-service
|
||||
m_isrv |= mask;
|
||||
|
||||
// clear interrupt pending
|
||||
m_ipnd &= ~(mask);
|
||||
|
||||
// clear l-counter interrupt pending
|
||||
if ((m_cictl & CICTL_CIEL) && (m_cictl & CICTL_CIRL) && BIT(mask, m_ciptr & 15))
|
||||
m_cictl &= ~CICTL_CIRL;
|
||||
|
||||
// clear h-counter interrupt pending
|
||||
if ((m_cictl & CICTL_CIEH) && (m_cictl & CICTL_CIRH) && BIT(mask, m_ciptr >> 4))
|
||||
m_cictl &= ~CICTL_CIRH;
|
||||
|
||||
// clear interrupt output
|
||||
set_int(false);
|
||||
}
|
||||
|
||||
// compute acknowledge vector
|
||||
if (m_csrc & mask)
|
||||
vector = 0xf0 | number;
|
||||
else
|
||||
vector = m_hvct | number;
|
||||
}
|
||||
else if (side_effects)
|
||||
{
|
||||
if (m_fprt)
|
||||
LOGMASKED(LOG_STATE, "acknowledge without unmasked interrupt pending\n");
|
||||
else
|
||||
LOGMASKED(LOG_STATE, "acknowledge with FPRT clear\n");
|
||||
|
||||
// clear pending edge for interrupt 15
|
||||
if (!BIT(m_eltg, 15))
|
||||
m_ipnd &= ~(1 << 15);
|
||||
|
||||
// clear first priority
|
||||
if (!(m_mctl & MCTL_NTAR))
|
||||
m_fprt = 0;
|
||||
}
|
||||
|
||||
if (side_effects)
|
||||
LOGMASKED(LOG_STATE, "acknowledge vector 0x%02x\n", vector);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
u8 ns32202_device::interrupt_return(bool side_effects)
|
||||
{
|
||||
side_effects &= !machine().side_effects_disabled();
|
||||
u8 vector = m_hvct | 0x0f;
|
||||
|
||||
// find highest priority in-service interrupt
|
||||
if (m_isrv && m_fprt)
|
||||
{
|
||||
u16 mask = m_fprt;
|
||||
for (unsigned i = 0; i < 16; i++)
|
||||
{
|
||||
if (m_isrv & mask)
|
||||
break;
|
||||
|
||||
// rotate priority mask
|
||||
mask = (mask << 1) | (mask >> 15);
|
||||
}
|
||||
unsigned const number = 31 - count_leading_zeros(mask);
|
||||
|
||||
if (side_effects)
|
||||
{
|
||||
LOGMASKED(LOG_STATE, "return highest priority in-service interrupt %d\n", number);
|
||||
|
||||
if (m_mctl & MCTL_NTAR)
|
||||
{
|
||||
if (m_csrc & mask)
|
||||
{
|
||||
m_isrv_count[number]--;
|
||||
|
||||
if (!m_isrv_count[number])
|
||||
m_isrv &= ~mask;
|
||||
}
|
||||
else
|
||||
// clear interrupt in-service
|
||||
m_isrv &= ~mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
// clear interrupt in-service
|
||||
m_isrv &= ~mask;
|
||||
|
||||
// rotate priority mask
|
||||
m_fprt = (m_fprt << 1) | (m_fprt >> 15);
|
||||
}
|
||||
}
|
||||
|
||||
// compute return vector
|
||||
if (m_csrc & mask)
|
||||
vector = 0xf0 | number;
|
||||
else
|
||||
vector = m_hvct | number;
|
||||
}
|
||||
else if (side_effects)
|
||||
{
|
||||
if (m_fprt)
|
||||
LOGMASKED(LOG_STATE, "return without in-service interrupt\n");
|
||||
else
|
||||
LOGMASKED(LOG_STATE, "return with FPRT clear\n");
|
||||
|
||||
if (!(m_mctl & MCTL_NTAR))
|
||||
// rotate priority mask
|
||||
m_fprt = (m_fprt << 1) | (m_fprt >> 15);
|
||||
}
|
||||
|
||||
if (side_effects)
|
||||
LOGMASKED(LOG_STATE, "return vector 0x%02x\n", vector);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for level-triggered interrupts which become pending due to change of
|
||||
* edge/level or polarity registers.
|
||||
*/
|
||||
void ns32202_device::interrupt_update()
|
||||
{
|
||||
// compute new pending state
|
||||
u16 const ipnd = m_ipnd | (m_eltg & ~(m_line_state ^ m_tpl));
|
||||
|
||||
// update and assert if state changed
|
||||
if (ipnd ^ m_ipnd)
|
||||
{
|
||||
m_ipnd = ipnd;
|
||||
m_interrupt->adjust(attotime::zero);
|
||||
}
|
||||
}
|
||||
|
||||
// N=0 -> l-counter
|
||||
template <unsigned N> void ns32202_device::counter(void *buf, s32 param)
|
||||
{
|
||||
u32 const scaled_clock = clock() / ((m_cctl & CCTL_CFNPS) ? 1 : 4);
|
||||
|
||||
// for now, assume this is the periodic timer triggered when we hit zero
|
||||
// reload on cycle after zero
|
||||
if (param)
|
||||
{
|
||||
u32 const ticks = (m_cctl & CCTL_CCON)
|
||||
? ((u32(m_csv[1]) << 16) | m_csv[0]) - ((u32(m_ccv[1]) << 16) | m_ccv[0])
|
||||
: m_csv[N] - m_ccv[N];
|
||||
|
||||
// reload current value
|
||||
if (m_cctl & CCTL_CCON)
|
||||
{
|
||||
m_ccv[0] = m_csv[0];
|
||||
m_ccv[1] = m_csv[1];
|
||||
}
|
||||
else
|
||||
m_ccv[N] = m_csv[N];
|
||||
|
||||
// reschedule counter
|
||||
m_counter[N]->adjust(attotime::from_ticks(ticks, scaled_clock), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// clear current value
|
||||
if (m_cctl & CCTL_CCON)
|
||||
{
|
||||
m_ccv[0] = 0;
|
||||
m_ccv[1] = 0;
|
||||
}
|
||||
else
|
||||
m_ccv[N] = 0;
|
||||
|
||||
// schedule reload cycle
|
||||
m_counter[N]->adjust(attotime::from_ticks(1, scaled_clock), 1);
|
||||
|
||||
// update cout
|
||||
if (!(m_mctl & MCTL_COUTD) && (m_cctl & (CCTL_COUT0 << N)))
|
||||
{
|
||||
if (m_mctl & MCTL_COUTM)
|
||||
{
|
||||
set_cout(true);
|
||||
set_cout(false);
|
||||
}
|
||||
else
|
||||
set_cout(!m_out_cout_state);
|
||||
}
|
||||
|
||||
// update port
|
||||
if ((N == 1) && !(m_mctl & MCTL_T16N8) && (m_ocasn & 15))
|
||||
{
|
||||
// TODO: trigger interrupts if IPS != 0
|
||||
|
||||
u8 const mask = (m_ocasn & ~m_pdir) & 15;
|
||||
if (m_mctl & MCTL_CLKM)
|
||||
{
|
||||
m_pdat &= ~mask;
|
||||
|
||||
m_out_port(0, m_ocasn & 15, mask);
|
||||
m_out_port(0, 0, mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pdat ^= mask;
|
||||
|
||||
m_out_port(0, m_pdat, mask);
|
||||
}
|
||||
}
|
||||
|
||||
// interrupts
|
||||
unsigned const shift = N ? 4 : 0;
|
||||
if (m_cictl & (CICTL_CIEL << shift))
|
||||
{
|
||||
// check counter interrupt error
|
||||
if (m_cictl & (CICTL_CIRL << shift))
|
||||
m_cictl |= (CICTL_CERL << shift);
|
||||
|
||||
// set counter interrupt request
|
||||
m_cictl |= (CICTL_CIRL << shift);
|
||||
|
||||
// raise interrupt
|
||||
m_ipnd |= 1 << ((m_ciptr >> shift) & 15);
|
||||
m_interrupt->adjust(attotime::zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <unsigned ST1, bool SideEffects> u8 ns32202_device::hvct_r()
|
||||
{
|
||||
if (!ST1)
|
||||
return interrupt_acknowledge(SideEffects);
|
||||
else
|
||||
return interrupt_return(SideEffects);
|
||||
}
|
||||
|
||||
void ns32202_device::eltgl_w(u8 data)
|
||||
{
|
||||
m_eltg = (m_eltg & 0xff00) | data;
|
||||
|
||||
interrupt_update();
|
||||
}
|
||||
|
||||
void ns32202_device::eltgh_w(u8 data)
|
||||
{
|
||||
m_eltg = (u16(data) << 8) | u8(m_eltg);
|
||||
|
||||
interrupt_update();
|
||||
}
|
||||
|
||||
void ns32202_device::tpll_w(u8 data)
|
||||
{
|
||||
m_tpl = (m_tpl & 0xff00) | data;
|
||||
|
||||
interrupt_update();
|
||||
}
|
||||
|
||||
void ns32202_device::tplh_w(u8 data)
|
||||
{
|
||||
m_tpl = (u16(data) << 8) | u8(m_tpl);
|
||||
|
||||
interrupt_update();
|
||||
}
|
||||
|
||||
void ns32202_device::csrcl_w(u8 data)
|
||||
{
|
||||
m_csrc = (m_csrc & 0xff00) | data;
|
||||
|
||||
// clear in-service counters
|
||||
for (unsigned i = 0; i < 8; i++)
|
||||
if (!BIT(m_csrc, i))
|
||||
m_isrv_count[i] = 0;
|
||||
}
|
||||
|
||||
void ns32202_device::csrch_w(u8 data)
|
||||
{
|
||||
m_csrc = (u16(data) << 8) | u8(m_csrc);
|
||||
|
||||
// clear in-service counters
|
||||
for (unsigned i = 8; i < 16; i++)
|
||||
if (!BIT(m_csrc, i))
|
||||
m_isrv_count[i] = 0;
|
||||
}
|
||||
|
||||
void ns32202_device::ipndl_w(u8 data)
|
||||
{
|
||||
if (BIT(data, 6))
|
||||
// clear all pending interrupts in register
|
||||
m_ipnd &= 0xff00;
|
||||
else if (BIT(data, 7))
|
||||
{
|
||||
// set interrupt
|
||||
m_ipnd |= 1 << (data & 7);
|
||||
|
||||
m_interrupt->adjust(attotime::zero);
|
||||
}
|
||||
else
|
||||
// clear interrupt
|
||||
m_ipnd &= ~(1 << (data & 7));
|
||||
}
|
||||
|
||||
void ns32202_device::ipndh_w(u8 data)
|
||||
{
|
||||
if (BIT(data, 6))
|
||||
// clear all pending interrupts in register
|
||||
m_ipnd &= 0x00ff;
|
||||
else if (BIT(data, 7))
|
||||
{
|
||||
// set interrupt
|
||||
m_ipnd |= 256 << (data & 7);
|
||||
|
||||
m_interrupt->adjust(attotime::zero);
|
||||
}
|
||||
else
|
||||
// clear interrupt
|
||||
m_ipnd &= ~(256 << (data & 7));
|
||||
}
|
||||
|
||||
void ns32202_device::fprtl_w(u8 data)
|
||||
{
|
||||
m_fprt = 1 << (data & 15);
|
||||
}
|
||||
|
||||
void ns32202_device::cctl_w(u8 data)
|
||||
{
|
||||
// disable l-counter in concatenated mode
|
||||
if ((data & CCTL_CCON) && m_counter[0]->enabled())
|
||||
m_counter[0]->enable(false);
|
||||
|
||||
// compute scaled clock
|
||||
u32 const scaled_clock = clock() / ((data & CCTL_CFNPS) ? 1 : 4);
|
||||
|
||||
// start/stop h-counter
|
||||
if (!(m_cctl & CCTL_CRUNH) && (data & CCTL_CRUNH))
|
||||
m_counter[1]->adjust(attotime::from_ticks(1, scaled_clock), 1);
|
||||
else if ((m_cctl & CCTL_CRUNH) && !(data & CCTL_CRUNH))
|
||||
m_counter[1]->enable(false);
|
||||
|
||||
if (!(data & CCTL_CRUNH) && (data & CCTL_CDCRH))
|
||||
; // TODO: decrement h-counter
|
||||
|
||||
// start/stop l-counter
|
||||
if (!(data & CCTL_CCON))
|
||||
{
|
||||
if (!(m_cctl & CCTL_CRUNH) && (data & CCTL_CRUNH))
|
||||
m_counter[0]->adjust(attotime::from_ticks(1, scaled_clock), 1);
|
||||
else if ((m_cctl & CCTL_CRUNH) && !(data & CCTL_CRUNH))
|
||||
m_counter[0]->enable(false);
|
||||
|
||||
if (!(data & CCTL_CRUNL) && (data & CCTL_CDCRL))
|
||||
; // TODO: decrement l-counter
|
||||
}
|
||||
|
||||
m_cctl = data & ~(CCTL_CRUNH | CCTL_CRUNL);
|
||||
}
|
||||
|
||||
void ns32202_device::cictl_w(u8 data)
|
||||
{
|
||||
u8 const mask =
|
||||
((data & CICTL_WENL) ? (CICTL_CERL | CICTL_CIRL | CICTL_CIEL) : 0) |
|
||||
((data & CICTL_WENH) ? (CICTL_CERH | CICTL_CIRH | CICTL_CIEH) : 0);
|
||||
|
||||
m_cictl = (m_cictl & ~mask) | (data & mask);
|
||||
}
|
137
src/devices/machine/ns32202.h
Normal file
137
src/devices/machine/ns32202.h
Normal file
@ -0,0 +1,137 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Patrick Mackinlay
|
||||
|
||||
#ifndef MAME_MACHINE_NS32202_H
|
||||
#define MAME_MACHINE_NS32202_H
|
||||
|
||||
#pragma once
|
||||
|
||||
class ns32202_device : public device_t
|
||||
{
|
||||
public:
|
||||
auto out_int() { return m_out_int.bind(); }
|
||||
auto out_cout() { return m_out_cout.bind(); }
|
||||
auto out_port() { return m_out_port.bind(); }
|
||||
|
||||
template <unsigned Number> void ir_w(int state);
|
||||
template <unsigned ST1> void map(address_map &map);
|
||||
|
||||
ns32202_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
|
||||
|
||||
protected:
|
||||
// device_t overrides
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
void set_int(bool int_state);
|
||||
void set_cout(bool cout_state);
|
||||
|
||||
void interrupt(void *buf, s32 param);
|
||||
u8 interrupt_acknowledge(bool side_effects);
|
||||
u8 interrupt_return(bool side_effects);
|
||||
|
||||
void interrupt_update();
|
||||
|
||||
template <unsigned N> void counter(void *buf, s32 param);
|
||||
|
||||
template <unsigned ST1, bool SideEffects> u8 hvct_r();
|
||||
|
||||
u8 eltgl_r() { return u8(m_eltg); }
|
||||
u8 eltgh_r() { return m_eltg >> 8; }
|
||||
u8 tpll_r() { return u8(m_tpl); }
|
||||
u8 tplh_r() { return m_tpl >> 8; }
|
||||
u8 ipndl_r() { return u8(m_ipnd); }
|
||||
u8 ipndh_r() { return m_ipnd >> 8; }
|
||||
u8 isrvl_r() { return u8(m_isrv); }
|
||||
u8 isrvh_r() { return m_isrv >> 8; }
|
||||
u8 imskl_r() { return u8(m_imsk); }
|
||||
u8 imskh_r() { return m_imsk >> 8; }
|
||||
u8 csrcl_r() { return u8(m_csrc); }
|
||||
u8 csrch_r() { return m_csrc >> 8; }
|
||||
u8 fprtl_r() { return u8(m_fprt); }
|
||||
u8 fprth_r() { return m_fprt >> 8; }
|
||||
u8 mctl_r() { return m_mctl; }
|
||||
u8 ocasn_r() { return m_ocasn; }
|
||||
u8 ciptr_r() { return m_ciptr; }
|
||||
u8 pdat_r() { return 0; }
|
||||
u8 ips_r() { return m_ips; }
|
||||
u8 pdir_r() { return m_pdir; }
|
||||
u8 cctl_r() { return m_cctl; }
|
||||
u8 cictl_r() { return m_cictl; }
|
||||
template <unsigned N> u8 csvl_r() { return u8(m_csv[N]); }
|
||||
template <unsigned N> u8 csvh_r() { return m_csv[N] >> 8; }
|
||||
u8 lccvl_r() { return 0; }
|
||||
u8 lccvh_r() { return 0; }
|
||||
u8 hccvl_r() { return 0; }
|
||||
u8 hccvh_r() { return 0; }
|
||||
|
||||
void svct_w(u8 data) { m_hvct = data & 0xf0; }
|
||||
|
||||
void eltgl_w(u8 data);
|
||||
void eltgh_w(u8 data);
|
||||
void tpll_w(u8 data);
|
||||
void tplh_w(u8 data);
|
||||
void ipndl_w(u8 data);
|
||||
void ipndh_w(u8 data);
|
||||
void isrvl_w(u8 data) { m_isrv = (m_isrv & 0xff00) | data; }
|
||||
void isrvh_w(u8 data) { m_isrv = (u16(data) << 8) | u8(m_isrv); }
|
||||
void imskl_w(u8 data) { m_imsk = (m_imsk & 0xff00) | data; m_interrupt->adjust(attotime::zero); }
|
||||
void imskh_w(u8 data) { m_imsk = (u16(data) << 8) | u8(m_imsk); m_interrupt->adjust(attotime::zero); }
|
||||
void csrcl_w(u8 data);
|
||||
void csrch_w(u8 data);
|
||||
void fprtl_w(u8 data);
|
||||
void fprth_w(u8 data) {}
|
||||
|
||||
void mctl_w(u8 data) { m_mctl = data; }
|
||||
void ocasn_w(u8 data) { m_ocasn = data; }
|
||||
void ciptr_w(u8 data) { m_ciptr = data; }
|
||||
void pdat_w(u8 data) {}
|
||||
void ips_w(u8 data) { m_ips = data; }
|
||||
void pdir_w(u8 data) { m_pdir = data; }
|
||||
void cctl_w(u8 data);
|
||||
void cictl_w(u8 data);
|
||||
|
||||
template <unsigned N> void csvl_w(u8 data) { m_csv[N] = (m_csv[N] & 0xff00) | data; }
|
||||
template <unsigned N> void csvh_w(u8 data) { m_csv[N] = (u16(data) << 8) | u8(m_csv[N]); }
|
||||
void lccvl_w(u8 data) {}
|
||||
void lccvh_w(u8 data) {}
|
||||
void hccvl_w(u8 data) {}
|
||||
void hccvh_w(u8 data) {}
|
||||
|
||||
private:
|
||||
devcb_write_line m_out_int;
|
||||
devcb_write_line m_out_cout;
|
||||
devcb_write8 m_out_port;
|
||||
|
||||
emu_timer *m_interrupt;
|
||||
emu_timer *m_counter[2];
|
||||
|
||||
u8 m_hvct; // hardware vector
|
||||
u16 m_eltg; // edge/level triggering
|
||||
u16 m_tpl; // triggering polarity
|
||||
u16 m_ipnd; // interrupts pending
|
||||
u16 m_isrv; // interrupts in-service
|
||||
u16 m_imsk; // interrupt mask
|
||||
u16 m_csrc; // cascaded source
|
||||
u16 m_fprt; // first priority
|
||||
u8 m_mctl; // mode control
|
||||
u8 m_ocasn; // output clock assignment
|
||||
u8 m_ciptr; // counter interrupt pointer
|
||||
u8 m_pdat; // port data
|
||||
u8 m_ips; // interrupt/port select
|
||||
u8 m_pdir; // port direction
|
||||
u8 m_cctl; // counter control
|
||||
u8 m_cictl; // counter interrupt control
|
||||
u16 m_csv[2]; // counter starting value
|
||||
u16 m_ccv[2]; // counter current value
|
||||
|
||||
unsigned m_isrv_count[16];
|
||||
|
||||
u16 m_line_state;
|
||||
bool m_out_int_state;
|
||||
bool m_out_cout_state;
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(NS32202, ns32202_device)
|
||||
|
||||
#endif // MAME_MACHINE_NS32202_H
|
Loading…
Reference in New Issue
Block a user