mirror of
https://github.com/holub/mame
synced 2025-07-04 17:38:08 +03:00
Namco custom chip improvements (#9141)
* namco06: synchronize data writes * namco06: Improve NMI delay. * namco5x: use chip select lines, synchronize writes. * mb88xx: clarify interrupt line is 'logical', not voltage-based * mb88xx: clear the appropriate interrupt enable flag when taking the int * galaga: use correct callback for bosco 06xx rw. * galaga: re-order namco06 callbacks, for consistency. * galaga: use correct clock for the second 06xx in bosco.
This commit is contained in:
parent
25dce8aa6d
commit
a6addb11da
@ -368,8 +368,10 @@ int mb88_cpu_device::pla( int inA, int inB )
|
||||
|
||||
void mb88_cpu_device::execute_set_input(int inputnum, int state)
|
||||
{
|
||||
/* on rising edge trigger interrupt */
|
||||
if ( (m_pio & 0x04) && !m_nf && state != CLEAR_LINE )
|
||||
/* On rising edge trigger interrupt.
|
||||
* Note this is a logical level, the actual pin is high-to-low voltage
|
||||
* triggered. */
|
||||
if ( (m_pio & INT_CAUSE_EXTERNAL) && !m_nf && state != CLEAR_LINE )
|
||||
{
|
||||
m_pending_interrupt |= INT_CAUSE_EXTERNAL;
|
||||
}
|
||||
@ -437,6 +439,9 @@ void mb88_cpu_device::update_pio( int cycles )
|
||||
{
|
||||
/* if we have a live external source, call the irqcallback */
|
||||
standard_irq_callback( 0 );
|
||||
/* The datasheet doesn't mention if the interrupt flag
|
||||
* is cleared, but it seems to be only for this case. */
|
||||
m_pio &= ~INT_CAUSE_EXTERNAL;
|
||||
m_PC = 0x02;
|
||||
}
|
||||
else if (m_pending_interrupt & m_pio & INT_CAUSE_TIMER)
|
||||
|
@ -56,11 +56,6 @@ WRITE_LINE_MEMBER( namco_52xx_device::reset )
|
||||
m_cpu->set_input_line(INPUT_LINE_RESET, !state);
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER( namco_52xx_device::latch_callback )
|
||||
{
|
||||
m_latched_cmd = param;
|
||||
}
|
||||
|
||||
uint8_t namco_52xx_device::K_r()
|
||||
{
|
||||
return m_latched_cmd & 0x0f;
|
||||
@ -108,16 +103,17 @@ void namco_52xx_device::O_w(uint8_t data)
|
||||
|
||||
void namco_52xx_device::write(uint8_t data)
|
||||
{
|
||||
machine().scheduler().synchronize(timer_expired_delegate(FUNC(namco_52xx_device::latch_callback),this), data);
|
||||
machine().scheduler().synchronize(timer_expired_delegate(FUNC(namco_52xx_device::write_sync),this), data);
|
||||
}
|
||||
|
||||
// TODO: should use chip_select line for this
|
||||
m_cpu->pulse_input_line(0, m_irq_duration);
|
||||
TIMER_CALLBACK_MEMBER( namco_52xx_device::write_sync )
|
||||
{
|
||||
m_latched_cmd = param;
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER( namco_52xx_device::chip_select )
|
||||
{
|
||||
// TODO: broken sound when using this
|
||||
//m_cpu->set_input_line(0, state);
|
||||
m_cpu->set_input_line(0, state);
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER( namco_52xx_device::external_clock_pulse )
|
||||
@ -143,7 +139,6 @@ namco_52xx_device::namco_52xx_device(const machine_config &mconfig, const char *
|
||||
: device_t(mconfig, NAMCO_52XX, tag, owner, clock),
|
||||
m_cpu(*this, "mcu"),
|
||||
m_discrete(*this, finder_base::DUMMY_TAG),
|
||||
m_irq_duration(attotime::from_usec(100)),
|
||||
m_basenode(0),
|
||||
m_extclock(0),
|
||||
m_romread(*this),
|
||||
|
@ -16,7 +16,6 @@ public:
|
||||
void set_extclock(attoseconds_t clk) { m_extclock = clk; }
|
||||
auto romread_callback() { return m_romread.bind(); }
|
||||
auto si_callback() { return m_si.bind(); }
|
||||
namco_52xx_device &set_irq_duration(attotime t) { m_irq_duration = t; return *this; }
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER( reset );
|
||||
WRITE_LINE_MEMBER( chip_select );
|
||||
@ -28,7 +27,7 @@ protected:
|
||||
virtual const tiny_rom_entry *device_rom_region() const override;
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
|
||||
TIMER_CALLBACK_MEMBER( latch_callback );
|
||||
TIMER_CALLBACK_MEMBER( write_sync );
|
||||
TIMER_CALLBACK_MEMBER( external_clock_pulse );
|
||||
|
||||
private:
|
||||
@ -36,7 +35,6 @@ private:
|
||||
required_device<mb88_cpu_device> m_cpu;
|
||||
required_device<discrete_device> m_discrete;
|
||||
|
||||
attotime m_irq_duration;
|
||||
int m_basenode;
|
||||
attoseconds_t m_extclock;
|
||||
emu_timer *m_extclock_pulse_timer;
|
||||
|
@ -52,10 +52,6 @@
|
||||
#include "emu.h"
|
||||
#include "namco54.h"
|
||||
|
||||
TIMER_CALLBACK_MEMBER( namco_54xx_device::latch_callback )
|
||||
{
|
||||
m_latched_cmd = param;
|
||||
}
|
||||
|
||||
WRITE_LINE_MEMBER( namco_54xx_device::reset )
|
||||
{
|
||||
@ -92,16 +88,18 @@ void namco_54xx_device::R1_w(uint8_t data)
|
||||
|
||||
void namco_54xx_device::write(uint8_t data)
|
||||
{
|
||||
machine().scheduler().synchronize(timer_expired_delegate(FUNC(namco_54xx_device::latch_callback),this), data);
|
||||
|
||||
// TODO: should use chip_select line for this
|
||||
m_cpu->pulse_input_line(0, m_irq_duration);
|
||||
machine().scheduler().synchronize(timer_expired_delegate(FUNC(namco_54xx_device::write_sync),this), data);
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER( namco_54xx_device::write_sync )
|
||||
{
|
||||
m_latched_cmd = param;
|
||||
}
|
||||
|
||||
|
||||
WRITE_LINE_MEMBER( namco_54xx_device::chip_select )
|
||||
{
|
||||
// TODO: broken sound when using this
|
||||
//m_cpu->set_input_line(0, state);
|
||||
m_cpu->set_input_line(0, state);
|
||||
}
|
||||
|
||||
|
||||
@ -120,7 +118,6 @@ namco_54xx_device::namco_54xx_device(const machine_config &mconfig, const char *
|
||||
: device_t(mconfig, NAMCO_54XX, tag, owner, clock),
|
||||
m_cpu(*this, "mcu"),
|
||||
m_discrete(*this, finder_base::DUMMY_TAG),
|
||||
m_irq_duration(attotime::from_usec(100)),
|
||||
m_basenode(0),
|
||||
m_latched_cmd(0)
|
||||
{
|
||||
|
@ -14,7 +14,6 @@ public:
|
||||
|
||||
template <typename T> void set_discrete(T &&tag) { m_discrete.set_tag(std::forward<T>(tag)); }
|
||||
void set_basenote(int node) { m_basenode = node; }
|
||||
namco_54xx_device &set_irq_duration(attotime t) { m_irq_duration = t; return *this; }
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER( reset );
|
||||
WRITE_LINE_MEMBER( chip_select );
|
||||
@ -26,14 +25,11 @@ protected:
|
||||
virtual const tiny_rom_entry *device_rom_region() const override;
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
|
||||
TIMER_CALLBACK_MEMBER( latch_callback );
|
||||
|
||||
private:
|
||||
// internal state
|
||||
required_device<mb88_cpu_device> m_cpu;
|
||||
required_device<discrete_device> m_discrete;
|
||||
|
||||
attotime m_irq_duration;
|
||||
int m_basenode;
|
||||
uint8_t m_latched_cmd;
|
||||
|
||||
@ -41,6 +37,7 @@ private:
|
||||
uint8_t R0_r();
|
||||
void O_w(uint8_t data);
|
||||
void R1_w(uint8_t data);
|
||||
TIMER_CALLBACK_MEMBER( write_sync );
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(NAMCO_54XX, namco_54xx_device)
|
||||
|
@ -1607,7 +1607,6 @@ void bosco_state::bosco(machine_config &config)
|
||||
namco_54xx_device &n54xx(NAMCO_54XX(config, "54xx", MASTER_CLOCK/6/2)); /* 1.536 MHz */
|
||||
n54xx.set_discrete("discrete");
|
||||
n54xx.set_basenote(NODE_01);
|
||||
n54xx.set_irq_duration(attotime::from_usec(200));
|
||||
|
||||
namco_06xx_device &n06xx_0(NAMCO_06XX(config, "06xx_0", MASTER_CLOCK/6/64));
|
||||
n06xx_0.set_maincpu(m_maincpu);
|
||||
@ -1615,18 +1614,19 @@ void bosco_state::bosco(machine_config &config)
|
||||
n06xx_0.rw_callback<0>().set("51xx", FUNC(namco_51xx_device::rw));
|
||||
n06xx_0.read_callback<0>().set("51xx", FUNC(namco_51xx_device::read));
|
||||
n06xx_0.write_callback<0>().set("51xx", FUNC(namco_51xx_device::write));
|
||||
n06xx_0.read_callback<2>().set("50xx_1", FUNC(namco_50xx_device::read));
|
||||
n06xx_0.chip_select_callback<2>().set("50xx_1", FUNC(namco_50xx_device::chip_select));
|
||||
n06xx_0.rw_callback<2>().set("50xx_1", FUNC(namco_50xx_device::rw));
|
||||
n06xx_0.read_callback<2>().set("50xx_1", FUNC(namco_50xx_device::read));
|
||||
n06xx_0.write_callback<2>().set("50xx_1", FUNC(namco_50xx_device::write));
|
||||
n06xx_0.write_callback<3>().set("54xx", FUNC(namco_54xx_device::write));
|
||||
n06xx_0.chip_select_callback<3>().set("54xx", FUNC(namco_54xx_device::chip_select));
|
||||
n06xx_0.write_callback<3>().set("54xx", FUNC(namco_54xx_device::write));
|
||||
|
||||
namco_06xx_device &n06xx_1(NAMCO_06XX(config, "06xx_1", MASTER_CLOCK/6/64));
|
||||
// The clock should be hblank, but approx with 512.
|
||||
namco_06xx_device &n06xx_1(NAMCO_06XX(config, "06xx_1", MASTER_CLOCK/6/512));
|
||||
n06xx_1.set_maincpu(m_subcpu);
|
||||
n06xx_1.read_callback<0>().set("50xx_2", FUNC(namco_50xx_device::read));
|
||||
n06xx_1.chip_select_callback<0>().set("50xx_2", FUNC(namco_50xx_device::chip_select));
|
||||
n06xx_1.rw_callback<2>().set("50xx_2", FUNC(namco_50xx_device::rw));
|
||||
n06xx_1.rw_callback<0>().set("50xx_2", FUNC(namco_50xx_device::rw));
|
||||
n06xx_1.write_callback<0>().set("50xx_2", FUNC(namco_50xx_device::write));
|
||||
n06xx_1.write_callback<1>().set("52xx", FUNC(namco_52xx_device::write));
|
||||
n06xx_1.chip_select_callback<1>().set("52xx", FUNC(namco_52xx_device::chip_select));
|
||||
|
@ -106,23 +106,16 @@ TIMER_CALLBACK_MEMBER( namco_06xx_device::nmi_generate )
|
||||
//
|
||||
// During reads, the first NMI pulse is supressed to give the chip a
|
||||
// cycle to write.
|
||||
//
|
||||
// If the control register is written while CS is asserted, RW won't be
|
||||
// changed until the next rising edge.
|
||||
|
||||
if (m_rw_change && m_next_timer_state)
|
||||
if (m_next_timer_state)
|
||||
{
|
||||
if (!m_rw_stretch)
|
||||
{
|
||||
m_rw[0](0, BIT(m_control, 4));
|
||||
m_rw[1](0, BIT(m_control, 4));
|
||||
m_rw[2](0, BIT(m_control, 4));
|
||||
m_rw[3](0, BIT(m_control, 4));
|
||||
m_rw_change = false;
|
||||
}
|
||||
m_rw[0](0, BIT(m_control, 4));
|
||||
m_rw[1](0, BIT(m_control, 4));
|
||||
m_rw[2](0, BIT(m_control, 4));
|
||||
m_rw[3](0, BIT(m_control, 4));
|
||||
}
|
||||
|
||||
if (m_next_timer_state && !m_nmi_stretch )
|
||||
if (m_next_timer_state && !m_read_stretch)
|
||||
{
|
||||
set_nmi(ASSERT_LINE);
|
||||
}
|
||||
@ -130,6 +123,7 @@ TIMER_CALLBACK_MEMBER( namco_06xx_device::nmi_generate )
|
||||
{
|
||||
set_nmi(CLEAR_LINE);
|
||||
}
|
||||
m_read_stretch = false;
|
||||
|
||||
m_chipsel[0](0, BIT(m_control, 0) && m_next_timer_state);
|
||||
m_chipsel[1](0, BIT(m_control, 1) && m_next_timer_state);
|
||||
@ -137,8 +131,6 @@ TIMER_CALLBACK_MEMBER( namco_06xx_device::nmi_generate )
|
||||
m_chipsel[3](0, BIT(m_control, 3) && m_next_timer_state);
|
||||
|
||||
m_next_timer_state = !m_next_timer_state;
|
||||
m_nmi_stretch = false;
|
||||
m_rw_stretch = false;
|
||||
}
|
||||
|
||||
uint8_t namco_06xx_device::data_r(offs_t offset)
|
||||
@ -161,16 +153,21 @@ uint8_t namco_06xx_device::data_r(offs_t offset)
|
||||
|
||||
|
||||
void namco_06xx_device::data_w(offs_t offset, uint8_t data)
|
||||
{
|
||||
machine().scheduler().synchronize(timer_expired_delegate(FUNC(namco_06xx_device::write_sync),this), data);
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER( namco_06xx_device::write_sync )
|
||||
{
|
||||
if (BIT(m_control, 4))
|
||||
{
|
||||
logerror("%s: 06XX '%s' write in read mode %02x\n",machine().describe_context(),tag(),m_control);
|
||||
return;
|
||||
}
|
||||
if (BIT(m_control, 0)) m_write[0](0, data);
|
||||
if (BIT(m_control, 1)) m_write[1](0, data);
|
||||
if (BIT(m_control, 2)) m_write[2](0, data);
|
||||
if (BIT(m_control, 3)) m_write[3](0, data);
|
||||
if (BIT(m_control, 0)) m_write[0](0, param);
|
||||
if (BIT(m_control, 1)) m_write[1](0, param);
|
||||
if (BIT(m_control, 2)) m_write[2](0, param);
|
||||
if (BIT(m_control, 3)) m_write[3](0, param);
|
||||
}
|
||||
|
||||
|
||||
@ -181,34 +178,56 @@ uint8_t namco_06xx_device::ctrl_r()
|
||||
|
||||
void namco_06xx_device::ctrl_w(uint8_t data)
|
||||
{
|
||||
m_control = data;
|
||||
machine().scheduler().synchronize(timer_expired_delegate(FUNC(namco_06xx_device::ctrl_w_sync),this), data);
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER( namco_06xx_device::ctrl_w_sync )
|
||||
{
|
||||
m_control = param;
|
||||
|
||||
// The upper 3 control bits are the clock divider.
|
||||
if ((m_control & 0xe0) == 0)
|
||||
{
|
||||
m_nmi_timer->adjust(attotime::never);
|
||||
m_next_timer_state = true;
|
||||
set_nmi(CLEAR_LINE);
|
||||
m_chipsel[0](0, CLEAR_LINE);
|
||||
m_chipsel[1](0, CLEAR_LINE);
|
||||
m_chipsel[2](0, CLEAR_LINE);
|
||||
m_chipsel[3](0, CLEAR_LINE);
|
||||
// Setting this to true makes the next RW change not stretch.
|
||||
m_next_timer_state = true;
|
||||
// RW is left as-is
|
||||
}
|
||||
else
|
||||
{
|
||||
m_rw_stretch = !m_next_timer_state;
|
||||
m_rw_change = true;
|
||||
m_next_timer_state = true;
|
||||
m_nmi_stretch = BIT(m_control, 4);
|
||||
// NMI is cleared immediately if its to be stretched.
|
||||
if (m_nmi_stretch) set_nmi(CLEAR_LINE);
|
||||
// NMI is cleared immediately if this is a read
|
||||
// It will be supressed the next clock cycle.
|
||||
if (BIT(m_control, 4))
|
||||
{
|
||||
set_nmi(CLEAR_LINE);
|
||||
m_read_stretch = true;
|
||||
} else {
|
||||
m_read_stretch = false;
|
||||
}
|
||||
|
||||
|
||||
uint8_t num_shifts = (m_control & 0xe0) >> 5;
|
||||
uint8_t divisor = 1 << num_shifts;
|
||||
// The next change should happen on the next clock falling edge.
|
||||
// Xevious' race causes this to bootloopsif it isn't 0.
|
||||
m_nmi_timer->adjust(attotime::zero, 0, attotime::from_hz(clock() / divisor) / 2);
|
||||
attotime period = attotime::from_hz(clock() / divisor) / 2;
|
||||
// This delay should be the next falling clock.
|
||||
// That's complicated to get, as it's derived from the master
|
||||
// clock. The CPU uses this same clock, so writes will come at
|
||||
// a specific pace.
|
||||
// Instead, just approximate a quarter cycle.
|
||||
// Xevious is very sensitive to this. It will bootloop if it
|
||||
// isn't correct.
|
||||
attotime delay = attotime::from_hz(clock()) / 4; // average of one clock
|
||||
if (!m_next_timer_state)
|
||||
{
|
||||
// NMI is asserted, wait one additional clock to start
|
||||
m_nmi_timer->adjust(delay + attotime::from_hz(clock() / divisor), 0, period);
|
||||
} else {
|
||||
m_nmi_timer->adjust(delay, 0, period);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,9 +247,7 @@ namco_06xx_device::namco_06xx_device(const machine_config &mconfig, const char *
|
||||
: device_t(mconfig, NAMCO_06XX, tag, owner, clock)
|
||||
, m_control(0)
|
||||
, m_next_timer_state(false)
|
||||
, m_nmi_stretch(false)
|
||||
, m_rw_stretch(false)
|
||||
, m_rw_change(false)
|
||||
, m_read_stretch(false)
|
||||
, m_nmicpu(*this, finder_base::DUMMY_TAG)
|
||||
, m_chipsel(*this)
|
||||
, m_rw(*this)
|
||||
@ -255,9 +272,7 @@ void namco_06xx_device::device_start()
|
||||
|
||||
save_item(NAME(m_control));
|
||||
save_item(NAME(m_next_timer_state));
|
||||
save_item(NAME(m_nmi_stretch));
|
||||
save_item(NAME(m_rw_stretch));
|
||||
save_item(NAME(m_rw_change));
|
||||
save_item(NAME(m_read_stretch));
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
|
@ -33,14 +33,14 @@ private:
|
||||
void set_nmi(int state);
|
||||
|
||||
TIMER_CALLBACK_MEMBER( nmi_generate );
|
||||
TIMER_CALLBACK_MEMBER( write_sync );
|
||||
TIMER_CALLBACK_MEMBER( ctrl_w_sync );
|
||||
|
||||
// internal state
|
||||
emu_timer *m_nmi_timer;
|
||||
uint8_t m_control;
|
||||
bool m_next_timer_state;
|
||||
bool m_nmi_stretch;
|
||||
bool m_rw_stretch;
|
||||
bool m_rw_change;
|
||||
bool m_read_stretch;
|
||||
|
||||
required_device<cpu_device> m_nmicpu;
|
||||
|
||||
|
@ -159,8 +159,13 @@ uint8_t namco_50xx_device::R2_r()
|
||||
|
||||
void namco_50xx_device::O_w(uint8_t data)
|
||||
{
|
||||
uint8_t out = (data & 0x0f);
|
||||
if (data & 0x10)
|
||||
machine().scheduler().synchronize(timer_expired_delegate(FUNC(namco_50xx_device::O_w_sync),this), data);
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER( namco_50xx_device::O_w_sync )
|
||||
{
|
||||
uint8_t out = (param & 0x0f);
|
||||
if (param & 0x10)
|
||||
m_portO = (m_portO & 0x0f) | (out << 4);
|
||||
else
|
||||
m_portO = (m_portO & 0xf0) | (out);
|
||||
|
@ -32,6 +32,7 @@ private:
|
||||
uint8_t m_cmd;
|
||||
uint8_t m_portO;
|
||||
|
||||
TIMER_CALLBACK_MEMBER( O_w_sync );
|
||||
TIMER_CALLBACK_MEMBER( rw_sync );
|
||||
TIMER_CALLBACK_MEMBER( write_sync );
|
||||
|
||||
|
@ -130,8 +130,13 @@ uint8_t namco_51xx_device::R3_r()
|
||||
|
||||
void namco_51xx_device::O_w(uint8_t data)
|
||||
{
|
||||
uint8_t out = (data & 0x0f);
|
||||
if (data & 0x10)
|
||||
machine().scheduler().synchronize(timer_expired_delegate(FUNC(namco_51xx_device::O_w_sync),this), data);
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER( namco_51xx_device::O_w_sync )
|
||||
{
|
||||
uint8_t out = (param & 0x0f);
|
||||
if (param & 0x10)
|
||||
m_portO = (m_portO & 0x0f) | (out << 4);
|
||||
else
|
||||
m_portO = (m_portO & 0xf0) | (out);
|
||||
|
@ -49,6 +49,7 @@ private:
|
||||
|
||||
TIMER_CALLBACK_MEMBER( rw_sync );
|
||||
TIMER_CALLBACK_MEMBER( write_sync );
|
||||
TIMER_CALLBACK_MEMBER( O_w_sync );
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(NAMCO_51XX, namco_51xx_device)
|
||||
|
Loading…
Reference in New Issue
Block a user