New generic ripple counter device

This commit is contained in:
AJR 2017-12-10 09:06:41 -05:00
parent c1a652b083
commit 141f2364cc
8 changed files with 350 additions and 60 deletions

View File

@ -2196,6 +2196,18 @@ if (MACHINES["RF5C296"]~=null) then
}
end
---------------------------------------------------
--
--@src/devices/machine/ripple_counter.h,MACHINES["RIPPLE_COUNTER"] = true
---------------------------------------------------
if (MACHINES["RIPPLE_COUNTER"]~=null) then
files {
MAME_DIR .. "src/devices/machine/ripple_counter.cpp",
MAME_DIR .. "src/devices/machine/ripple_counter.h",
}
end
---------------------------------------------------
--
--@src/devices/machine/roc10937.h,MACHINES["ROC10937"] = true

View File

@ -535,6 +535,7 @@ MACHINES["RA17XX"] = true
--MACHINES["R64H156"] = true
MACHINES["RF5C296"] = true
--MACHINES["RIOT6532"] = true
MACHINES["RIPPLE_COUNTER"] = true
MACHINES["ROC10937"] = true
MACHINES["RP5C01"] = true
MACHINES["RP5C15"] = true

View File

@ -524,6 +524,7 @@ MACHINES["PROM82S129"] = true
MACHINES["R64H156"] = true
MACHINES["RF5C296"] = true
MACHINES["RIOT6532"] = true
MACHINES["RIPPLE_COUNTER"] = true
MACHINES["ROC10937"] = true
MACHINES["RP5C01"] = true
MACHINES["RP5C15"] = true

View File

@ -13,6 +13,7 @@
#include "bus/rs232/rs232.h"
#include "machine/6821pia.h"
#include "machine/input_merger.h"
#include "machine/ripple_counter.h"
//**************************************************************************
// TYPE DEFINITIONS
@ -29,10 +30,8 @@ public:
ss50_card_interface(mconfig, *this),
m_pia(*this, "pia"),
m_loopback(*this, "loopback"),
m_counter(*this, "counter"),
m_baud_jumper(*this, "BAUD"),
m_cd4024ae_count(0),
m_cd4024ae_clock(false),
m_cd4024ae_reset(true),
m_count_select(false)
{
}
@ -53,17 +52,13 @@ private:
DECLARE_WRITE_LINE_MEMBER(serial_input_w);
DECLARE_WRITE_LINE_MEMBER(reader_control_w);
DECLARE_READ_LINE_MEMBER(count_r);
DECLARE_WRITE_LINE_MEMBER(count_reset_w);
DECLARE_WRITE_LINE_MEMBER(count_select_w);
DECLARE_WRITE_LINE_MEMBER(clock_input_w);
required_device<pia6821_device> m_pia;
required_device<input_merger_device> m_loopback;
required_device<ripple_counter_device> m_counter;
required_ioport m_baud_jumper;
u8 m_cd4024ae_count;
bool m_cd4024ae_clock;
bool m_cd4024ae_reset;
bool m_count_select;
};
@ -113,7 +108,7 @@ MACHINE_CONFIG_MEMBER(ss50_mpc_device::device_add_mconfig)
MCFG_PIA_READPB_HANDLER(IOPORT("STOP")) MCFG_DEVCB_BIT(6)
MCFG_DEVCB_CHAIN_INPUT(READLINE(ss50_mpc_device, count_r)) MCFG_DEVCB_BIT(7)
MCFG_PIA_WRITEPB_HANDLER(WRITELINE(ss50_mpc_device, count_select_w)) MCFG_DEVCB_BIT(2)
MCFG_DEVCB_CHAIN_OUTPUT(WRITELINE(ss50_mpc_device, count_reset_w)) MCFG_DEVCB_BIT(0)
MCFG_DEVCB_CHAIN_OUTPUT(DEVWRITELINE("counter", ripple_counter_device, reset_w)) MCFG_DEVCB_BIT(0)
//MCFG_PIA_IRQA_HANDLER(WRITELINE(ss50_mpc_device, pia_irq_w))
//MCFG_PIA_IRQB_HANDLER(WRITELINE(ss50_mpc_device, pia_irq_w))
@ -126,6 +121,9 @@ MACHINE_CONFIG_MEMBER(ss50_mpc_device::device_add_mconfig)
MCFG_INPUT_MERGER_ANY_HIGH("loopback")
MCFG_INPUT_MERGER_OUTPUT_HANDLER(DEVWRITELINE("outgate", input_merger_device, in_w<1>))
MCFG_DEVICE_ADD("counter", RIPPLE_COUNTER, 0) // CD4024AE (IC3)
MCFG_RIPPLE_COUNTER_STAGES(7) // only Q5 (÷32) and Q4 (÷16) are actually used
MACHINE_CONFIG_END
@ -135,9 +133,6 @@ MACHINE_CONFIG_END
void ss50_mpc_device::device_start()
{
save_item(NAME(m_cd4024ae_count));
save_item(NAME(m_cd4024ae_clock));
save_item(NAME(m_cd4024ae_reset));
save_item(NAME(m_count_select));
}
@ -155,14 +150,7 @@ WRITE_LINE_MEMBER(ss50_mpc_device::reader_control_w)
READ_LINE_MEMBER(ss50_mpc_device::count_r)
{
return BIT(m_cd4024ae_count, m_count_select ? 4 : 3);
}
WRITE_LINE_MEMBER(ss50_mpc_device::count_reset_w)
{
m_cd4024ae_reset = bool(state);
if (state)
m_cd4024ae_count = 0;
return BIT(m_counter->count(), m_count_select ? 4 : 3);
}
WRITE_LINE_MEMBER(ss50_mpc_device::count_select_w)
@ -170,16 +158,6 @@ WRITE_LINE_MEMBER(ss50_mpc_device::count_select_w)
m_count_select = bool(state);
}
WRITE_LINE_MEMBER(ss50_mpc_device::clock_input_w)
{
if (m_cd4024ae_clock != bool(state))
{
m_cd4024ae_clock = bool(state);
if (!state && !m_cd4024ae_reset)
m_cd4024ae_count++;
}
}
//-------------------------------------------------
// register_read - read from a port register
@ -202,13 +180,13 @@ WRITE8_MEMBER(ss50_mpc_device::register_write)
WRITE_LINE_MEMBER(ss50_mpc_device::f110_w)
{
if (m_baud_jumper->read())
clock_input_w(state);
m_counter->clock_w(state);
}
WRITE_LINE_MEMBER(ss50_mpc_device::f300_w)
{
if (!m_baud_jumper->read())
clock_input_w(state);
m_counter->clock_w(state);
}

View File

@ -0,0 +1,202 @@
// license:BSD-3-Clause
// copyright-holders:AJR
/**********************************************************************
Generic binary ripple counter emulation
This device emulates basic ripple counter logic ICs with falling-
edge clocks and a synchronous reset inputs such as CD4040 and
74LS393.
The optional 8-bit ROM interface is intended to help stream ROM
data to sound chips that lack memory interfaces of their own
(e.g. MSM5205, TMS5110).
**********************************************************************/
#include "emu.h"
#include "machine/ripple_counter.h"
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
// device type definition
DEFINE_DEVICE_TYPE(RIPPLE_COUNTER, ripple_counter_device, "ripple_counter", "Generic ripple counter")
//**************************************************************************
// RIPPLE COUNTER DEVICE
//**************************************************************************
//-------------------------------------------------
// ripple_counter_device - constructor
//-------------------------------------------------
ripple_counter_device::ripple_counter_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, RIPPLE_COUNTER, tag, owner, clock),
device_rom_interface(mconfig, *this, 0, ENDIANNESS_LITTLE, 8),
m_count_out_cb(*this),
m_rom_out_cb(*this),
m_count_timer(nullptr),
m_count_mask(0),
m_count(1),
m_clk(false),
m_reset(false)
{
}
//-------------------------------------------------
// static_set_stages - configure the number of
// stages used to count
//-------------------------------------------------
void ripple_counter_device::static_set_stages(device_t &device, u8 stages)
{
auto &dev = downcast<ripple_counter_device &>(device);
dev.m_count_mask = (1U << stages) - 1;
dev.set_rom_addr_width(stages);
}
//-------------------------------------------------
// memory_space_config - return a description of
// any address spaces owned by this device
//-------------------------------------------------
device_memory_interface::space_config_vector ripple_counter_device::memory_space_config() const
{
if (m_rom_out_cb.isnull())
return space_config_vector();
else
return device_rom_interface::memory_space_config();
}
//-------------------------------------------------
// device_validity_check - validate a device after
// the configuration has been constructed
//-------------------------------------------------
void ripple_counter_device::device_validity_check(validity_checker &valid) const
{
if (m_count_mask == 0)
osd_printf_error("No counting stages configured\n");
}
//-------------------------------------------------
// device_resolve_objects - resolve objects that
// may be needed for other devices to set
// initial conditions at start time
//-------------------------------------------------
void ripple_counter_device::device_resolve_objects()
{
// resolve callbacks
m_count_out_cb.resolve_safe();
m_rom_out_cb.resolve();
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void ripple_counter_device::device_start()
{
// initialize timers
m_count_timer = timer_alloc(TIMER_COUNT);
// register internal state
save_item(NAME(m_count));
save_item(NAME(m_clk));
save_item(NAME(m_reset));
}
//-------------------------------------------------
// device_clock_changed - called when the
// device clock is altered in any way
//-------------------------------------------------
void ripple_counter_device::device_clock_changed()
{
attotime freq = m_reset ? attotime::never : clocks_to_attotime(1);
m_count_timer->adjust(freq, 0, freq);
}
//-------------------------------------------------
// rom_bank_updated - called when the ROM bank
// is changed
//-------------------------------------------------
void ripple_counter_device::rom_bank_updated()
{
m_rom_out_cb(read_byte(m_count));
}
//-------------------------------------------------
// set_count - update the count and associated
// outputs
//-------------------------------------------------
void ripple_counter_device::set_count(u32 count)
{
m_count = count;
m_count_out_cb(count);
if (!m_rom_out_cb.isnull())
m_rom_out_cb(read_byte(count));
}
//-------------------------------------------------
// clock_w - handle falling-edge clock input
//-------------------------------------------------
WRITE_LINE_MEMBER(ripple_counter_device::clock_w)
{
if (m_clk != bool(state))
{
m_clk = bool(state);
if (!state && !m_reset)
set_count((m_count + 1) & m_count_mask);
}
}
//-------------------------------------------------
// reset_w - handle active-high reset input
//-------------------------------------------------
WRITE_LINE_MEMBER(ripple_counter_device::reset_w)
{
if (m_reset != bool(state))
{
m_reset = bool(state);
if (state && m_count != 0)
set_count(0);
// stop or start the count timer as required
notify_clock_changed();
}
}
//-------------------------------------------------
// device_timer - called whenever a device timer
// fires
//-------------------------------------------------
void ripple_counter_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
switch (id)
{
case TIMER_COUNT:
set_count((m_count + 1) & m_count_mask);
break;
}
}

View File

@ -0,0 +1,92 @@
// license:BSD-3-Clause
// copyright-holders:AJR
/**********************************************************************
Generic binary ripple counter emulation
**********************************************************************/
#ifndef MAME_MACHINE_RIPPLE_COUNTER_H
#define MAME_MACHINE_RIPPLE_COUNTER_H
#pragma once
//**************************************************************************
// CONFIGURATION MACROS
//**************************************************************************
#define MCFG_RIPPLE_COUNTER_STAGES(_stages) \
ripple_counter_device::static_set_stages(*device, _stages);
// output callbacks
#define MCFG_RIPPLE_COUNTER_COUNT_OUT_CB(_devcb) \
devcb = &ripple_counter_device::static_set_count_out_cb(*device, DEVCB_##_devcb);
#define MCFG_RIPPLE_COUNTER_ROM_OUT_CB(_devcb) \
devcb = &ripple_counter_device::static_set_rom_out_cb(*device, DEVCB_##_devcb);
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> ripple_counter_device
class ripple_counter_device : public device_t, public device_rom_interface
{
public:
// construction/destruction
ripple_counter_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
// static configuration
static void static_set_stages(device_t &device, u8 stages);
template<class Object> static devcb_base &static_set_count_out_cb(device_t &device, Object &&cb)
{ return downcast<ripple_counter_device &>(device).m_count_out_cb.set_callback(std::forward<Object>(cb)); }
template<class Object> static devcb_base &static_set_rom_out_cb(device_t &device, Object &&cb)
{ return downcast<ripple_counter_device &>(device).m_rom_out_cb.set_callback(std::forward<Object>(cb)); }
// control line handlers
DECLARE_WRITE_LINE_MEMBER(clock_w);
DECLARE_WRITE_LINE_MEMBER(reset_w);
// getters
u32 count() const { return m_count; }
protected:
// device-level overrides
virtual void device_validity_check(validity_checker &valid) const override;
virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_clock_changed() override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
// device_rom_interface overrides
virtual space_config_vector memory_space_config() const override;
virtual void rom_bank_updated() override;
private:
// internal helpers
void set_count(u32 count);
// device callbacks
devcb_write32 m_count_out_cb;
devcb_write8 m_rom_out_cb;
// device timers
enum
{
TIMER_COUNT
};
emu_timer *m_count_timer;
// configuration parameters
u32 m_count_mask;
// running state
u32 m_count;
bool m_clk;
bool m_reset;
};
// device type definition
DECLARE_DEVICE_TYPE(RIPPLE_COUNTER, ripple_counter_device)
#endif // MAME_MACHINE_RIPPLE_COUNTER_H

View File

@ -180,21 +180,22 @@ ADDRESS_MAP_END
WRITE_LINE_MEMBER(mermaid_state::rougien_sample_rom_lo_w)
{
m_adpcm_rom_sel = state | (m_adpcm_rom_sel & 2);
m_adpcm_counter->set_rom_bank(m_adpcm_rom_sel);
}
WRITE_LINE_MEMBER(mermaid_state::rougien_sample_rom_hi_w)
{
m_adpcm_rom_sel = (state <<1) | (m_adpcm_rom_sel & 1);
m_adpcm_counter->set_rom_bank(m_adpcm_rom_sel);
}
WRITE_LINE_MEMBER(mermaid_state::rougien_sample_playback_w)
{
if (state)
{
m_adpcm_pos = m_adpcm_rom_sel*0x1000;
m_adpcm_end = m_adpcm_pos+0x1000;
m_adpcm_idle = 0;
m_adpcm->reset_w(0);
m_adpcm_counter->reset_w(0);
}
}
@ -366,13 +367,10 @@ void mermaid_state::machine_start()
save_item(NAME(m_rougien_gfxbank2));
save_item(NAME(m_ay8910_enable));
save_item(NAME(m_adpcm_pos));
save_item(NAME(m_adpcm_end));
save_item(NAME(m_adpcm_idle));
save_item(NAME(m_adpcm_data));
save_item(NAME(m_adpcm_trigger));
save_item(NAME(m_adpcm_rom_sel));
save_item(NAME(m_adpcm_play_reg));
}
void mermaid_state::machine_reset()
@ -387,33 +385,32 @@ void mermaid_state::machine_reset()
m_adpcm_idle = 1;
m_adpcm_rom_sel = 0;
m_adpcm_play_reg = 0;
m_adpcm->reset_w(1);
m_adpcm_counter->reset_w(1);
m_adpcm_trigger = 0;
m_adpcm_data = 0;
}
/* Similar to Jantotsu, apparently the HW has three ports that controls what kind of sample should be played. Every sample size is 0x1000. */
WRITE8_MEMBER(mermaid_state::adpcm_data_w)
{
m_adpcm_data = data;
m_adpcm->data_w(m_adpcm_trigger ? (data & 0x0f) : (data & 0xf0) >> 4);
}
WRITE_LINE_MEMBER(mermaid_state::rougien_adpcm_int)
{
// popmessage("%08x",m_adpcm_pos);
if (!state)
return;
if (m_adpcm_pos >= m_adpcm_end || m_adpcm_idle)
m_adpcm_trigger ^= 1;
m_adpcm->data_w(m_adpcm_trigger ? (m_adpcm_data & 0x0f) : (m_adpcm_data & 0xf0) >> 4);
m_adpcm_counter->clock_w(m_adpcm_trigger);
if (m_adpcm_trigger == 0 && m_adpcm_counter->count() == 0)
{
//m_adpcm_idle = 1;
m_adpcm_idle = 1;
m_adpcm->reset_w(1);
m_adpcm_trigger = 0;
}
else
{
uint8_t *ROM = memregion("adpcm")->base();
m_adpcm_data = ((m_adpcm_trigger ? (ROM[m_adpcm_pos] & 0x0f) : (ROM[m_adpcm_pos] & 0xf0) >> 4));
m_adpcm->data_w(m_adpcm_data & 0xf);
m_adpcm_trigger ^= 1;
if (m_adpcm_trigger == 0)
{
m_adpcm_pos++;
//if ((ROM[m_adpcm_pos] & 0xff) == 0x70)
// m_adpcm_idle = 1;
}
m_adpcm_counter->reset_w(1);
}
}
@ -483,9 +480,14 @@ static MACHINE_CONFIG_DERIVED( rougien, mermaid )
MCFG_PALETTE_INIT_OWNER(mermaid_state,rougien)
MCFG_SOUND_ADD("adpcm", MSM5205, 384000)
MCFG_MSM5205_VCLK_CB(WRITELINE(mermaid_state, rougien_adpcm_int)) /* interrupt function */
MCFG_MSM5205_VCK_CALLBACK(WRITELINE(mermaid_state, rougien_adpcm_int))
MCFG_MSM5205_PRESCALER_SELECTOR(S96_4B)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00)
MCFG_DEVICE_ADD("adpcm_counter", RIPPLE_COUNTER, 0)
MCFG_DEVICE_ROM("adpcm")
MCFG_RIPPLE_COUNTER_STAGES(12)
MCFG_RIPPLE_COUNTER_ROM_OUT_CB(WRITE8(mermaid_state, adpcm_data_w))
MACHINE_CONFIG_END
/* ROMs */

View File

@ -5,6 +5,8 @@
Mermaid
*************************************************************************/
#include "machine/ripple_counter.h"
#include "sound/msm5205.h"
#include "sound/ay8910.h"
#include "screen.h"
@ -22,6 +24,7 @@ public:
m_colorram(*this, "colorram"),
m_maincpu(*this, "maincpu"),
m_adpcm(*this, "adpcm"),
m_adpcm_counter(*this, "adpcm_counter"),
m_ay8910(*this, "ay%u", 1),
m_gfxdecode(*this, "gfxdecode"),
m_screen(*this, "screen"),
@ -51,18 +54,16 @@ public:
int m_rougien_gfxbank2;
/* sound-related */
uint32_t m_adpcm_pos;
uint32_t m_adpcm_end;
uint8_t m_adpcm_idle;
int m_adpcm_data;
uint8_t m_adpcm_trigger;
uint8_t m_adpcm_rom_sel;
uint8_t m_adpcm_play_reg;
bool m_ay8910_enable[2];
/* devices */
required_device<cpu_device> m_maincpu;
optional_device<msm5205_device> m_adpcm;
optional_device<ripple_counter_device> m_adpcm_counter;
required_device_array<ay8910_device, 2> m_ay8910;
required_device<gfxdecode_device> m_gfxdecode;
required_device<screen_device> m_screen;
@ -77,6 +78,7 @@ public:
DECLARE_WRITE_LINE_MEMBER(rougien_sample_rom_lo_w);
DECLARE_WRITE_LINE_MEMBER(rougien_sample_rom_hi_w);
DECLARE_WRITE_LINE_MEMBER(rougien_sample_playback_w);
DECLARE_WRITE8_MEMBER(adpcm_data_w);
DECLARE_WRITE8_MEMBER(mermaid_videoram2_w);
DECLARE_WRITE8_MEMBER(mermaid_videoram_w);
DECLARE_WRITE8_MEMBER(mermaid_colorram_w);