Merge pull request #1864 from ajrhacker/cedar_magnet_40105

Preliminary work towards improving emulation of Cedar Magnet sound bo…
This commit is contained in:
Jonathan Gevaryahu 2016-12-23 15:08:50 -05:00 committed by GitHub
commit 0768d0b4fd
6 changed files with 192 additions and 90 deletions

View File

@ -389,7 +389,7 @@ MACHINES["AY31015"] = true
MACHINES["BANKDEV"] = true
MACHINES["CDP1852"] = true
MACHINES["CDP1871"] = true
--MACHINES["CMOS40105"] = true
MACHINES["CMOS40105"] = true
MACHINES["CDU76S"] = true
MACHINES["COM8116"] = true
MACHINES["CR589"] = true

View File

@ -49,7 +49,7 @@ http://www.stefan-uhlmann.de/cbm/MVM/index.html
#define T6721A_TAG "u5"
#define MOS6525_TAG "u2"
#define CMOS40105_TAG "u1"
#define CD40105_TAG "u1"
#define A12 BIT(offset, 12)
#define A13 BIT(offset, 13)
@ -226,7 +226,9 @@ static MACHINE_CONFIG_FRAGMENT( c64_magic_voice )
MCFG_TPI6525_OUT_PB_CB(WRITE8(c64_magic_voice_cartridge_device, tpi_pb_w))
MCFG_TPI6525_OUT_CA_CB(WRITELINE(c64_magic_voice_cartridge_device, tpi_ca_w))
MCFG_TPI6525_OUT_CA_CB(WRITELINE(c64_magic_voice_cartridge_device, tpi_cb_w))
MCFG_40105_ADD(CMOS40105_TAG, DEVWRITELINE(MOS6525_TAG, tpi6525_device, i3_w), NOOP)
MCFG_DEVICE_ADD(CD40105_TAG, CD40105, 0)
MCFG_40105_DATA_IN_READY_CB(DEVWRITELINE(MOS6525_TAG, tpi6525_device, i3_w))
MCFG_SPEAKER_STANDARD_MONO("mono")
MCFG_SOUND_ADD(T6721A_TAG, T6721A, XTAL_640kHz)
@ -265,7 +267,7 @@ c64_magic_voice_cartridge_device::c64_magic_voice_cartridge_device(const machine
device_c64_expansion_card_interface(mconfig, *this),
m_vslsi(*this, T6721A_TAG),
m_tpi(*this, MOS6525_TAG),
m_fifo(*this, CMOS40105_TAG),
m_fifo(*this, CD40105_TAG),
m_exp(*this, C64_EXPANSION_SLOT_TAG), m_ca(0),
m_tpi_pb(0x60),
m_tpi_pc6(1),

View File

@ -2,7 +2,16 @@
// copyright-holders:Curt Coder
/**********************************************************************
CMOS 40105 FIFO Register emulation
CD40105/HC40105 4-bit x 16-word FIFO Register
Part of the 4000B series of CMOS TTL devices, the 40105 includes
an asynchronous master reset pin intended to be connected to the
system bus.
Word size can be expanded from 4 bits to 8 bits by connecting two
40105s in parallel, with external AND gates to combine the DIR and
DOR outputs. They can also be connected in series to extend the
FIFO capacity, with DOR -> SI and /SO <- DIR.
**********************************************************************/
@ -22,8 +31,8 @@
// DEVICE DEFINITIONS
//**************************************************************************
const device_type CMOS_40105 = &device_creator<cmos_40105_device>;
const device_type CD40105 = &device_creator<cmos_40105_device>;
const device_type HC40105 = &device_creator<cmos_40105_device>;
//**************************************************************************
@ -34,10 +43,17 @@ const device_type CMOS_40105 = &device_creator<cmos_40105_device>;
// cmos_40105_device - constructor
//-------------------------------------------------
cmos_40105_device::cmos_40105_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, CMOS_40105, "40105", tag, owner, clock, "40105", __FILE__),
cmos_40105_device::cmos_40105_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, CD40105, "40105 FIFO", tag, owner, clock, "cd40105", __FILE__),
m_write_dir(*this),
m_write_dor(*this), m_d(0), m_q(0), m_dir(0), m_dor(0), m_si(0), m_so(0)
m_write_dor(*this),
m_write_q(*this),
m_d(0),
m_q(0),
m_dir(false),
m_dor(false),
m_si(false),
m_so(false)
{
}
@ -51,6 +67,7 @@ void cmos_40105_device::device_start()
// resolve callbacks
m_write_dir.resolve_safe();
m_write_dor.resolve_safe();
m_write_q.resolve_safe();
// state saving
save_item(NAME(m_d));
@ -68,36 +85,84 @@ void cmos_40105_device::device_start()
void cmos_40105_device::device_reset()
{
m_fifo = std::queue<uint8_t>();
// invalidate data in queue
m_fifo = std::queue<u8>();
m_dir = 1;
m_dor = 0;
m_si = 0;
m_write_dir(m_dir);
m_write_dor(m_dor);
// reset control flip-flops
m_dir = true;
m_dor = false;
m_write_dir(1);
m_write_dor(0);
}
//-------------------------------------------------
// read - read Q
// read - read output buffer (Q0 to Q3)
//-------------------------------------------------
uint8_t cmos_40105_device::read()
u8 cmos_40105_device::read()
{
return m_q;
}
//-------------------------------------------------
// write - write D
// write - write input buffer (D0 to D3)
//-------------------------------------------------
void cmos_40105_device::write(uint8_t data)
void cmos_40105_device::write(u8 data)
{
m_d = data & 0x0f;
}
WRITE8_MEMBER(cmos_40105_device::write)
{
write(data);
}
//-------------------------------------------------
// load_input - load new data into FIFO
//-------------------------------------------------
void cmos_40105_device::load_input()
{
if (m_fifo.size() == 16)
{
logerror("Attempt to load data into full FIFO\n");
return;
}
m_fifo.push(m_d);
// DIR remains low if FIFO is full, or else briefly pulses low
m_write_dir(0);
if (m_fifo.size() == 16)
m_dir = false;
else
m_write_dir(1);
}
//-------------------------------------------------
// output_ready - place new data at output
//-------------------------------------------------
void cmos_40105_device::output_ready()
{
if (m_fifo.size() == 0)
{
logerror("Attempt to output data from empty FIFO\n");
return;
}
m_q = m_fifo.front();
m_write_q(m_q);
m_dor = true;
m_write_dor(1);
}
//-------------------------------------------------
// si_w - shift in write
@ -105,22 +170,16 @@ void cmos_40105_device::write(uint8_t data)
WRITE_LINE_MEMBER( cmos_40105_device::si_w )
{
// load input on rising edge when ready
if (m_dir && !m_si && state)
{
m_fifo.push(m_d);
if (m_fifo.size() == 16)
{
m_dir = 0;
m_write_dir(m_dir);
}
load_input();
}
else if (m_si && !state && m_fifo.size() > 0)
{
// data propagates through FIFO when SI goes low
if (!m_dor)
{
m_dor = 1;
m_write_dor(m_dor);
}
output_ready();
}
m_si = state;
@ -133,18 +192,26 @@ WRITE_LINE_MEMBER( cmos_40105_device::si_w )
WRITE_LINE_MEMBER( cmos_40105_device::so_w )
{
if (m_dor && m_so && !m_so)
// shift out on falling edge when ready
if (m_dor && m_so && !state)
{
m_dor = 0;
m_write_dor(m_dor);
m_q = m_fifo.front();
m_fifo.pop();
m_dor = false;
m_write_dor(0);
// DOR remains low if FIFO is now empty, or else briefly pulses low
if (m_fifo.size() > 0)
output_ready();
if (!m_dir)
{
m_dor = 1;
m_write_dor(m_dor);
// raise DIR since FIFO is no longer full
m_dir = true;
m_write_dir(1);
// load new input immediately if SI is held high
if (m_si)
load_input();
}
}

View File

@ -2,7 +2,18 @@
// copyright-holders:Curt Coder
/**********************************************************************
CMOS 40105 FIFO Register emulation
CD40105/HC40105 4-bit x 16-word FIFO Register
***********************************************************************
____ ____
/OE 1 |* \_/ | 16 Vcc
DIR 2 | | 15 /SO
SI 3 | | 14 DOR
D0 4 | | 13 Q0
D1 5 | 40105 | 12 Q1
D2 6 | | 11 Q2
D3 7 | | 10 Q3
GND 8 |___________| 9 MR
**********************************************************************/
@ -20,11 +31,15 @@
// INTERFACE CONFIGURATION MACROS
///*************************************************************************
#define MCFG_40105_ADD(_tag, _dir, _dor) \
MCFG_DEVICE_ADD(_tag, CMOS_40105, 0) \
downcast<cmos_40105_device *>(device)->set_dir_callback(DEVCB_##_dir); \
#define MCFG_40105_DATA_IN_READY_CB(_dir) \
downcast<cmos_40105_device *>(device)->set_dir_callback(DEVCB_##_dir);
#define MCFG_40105_DATA_OUT_READY_CB(_dor) \
downcast<cmos_40105_device *>(device)->set_dor_callback(DEVCB_##_dor);
#define MCFG_40105_DATA_OUT_CB(_out) \
downcast<cmos_40105_device *>(device)->set_data_out_callback(DEVCB_##_out);
///*************************************************************************
@ -37,13 +52,15 @@ class cmos_40105_device : public device_t
{
public:
// construction/destruction
cmos_40105_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
cmos_40105_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
template<class _dir> void set_dir_callback(_dir dir) { m_write_dir.set_callback(dir); }
template<class _dor> void set_dor_callback(_dor dor) { m_write_dor.set_callback(dor); }
template<class _out> void set_data_out_callback(_out out) { m_write_q.set_callback(out); }
uint8_t read();
void write(uint8_t data);
u8 read();
void write(u8 data);
DECLARE_WRITE8_MEMBER(write);
DECLARE_WRITE_LINE_MEMBER( si_w );
DECLARE_WRITE_LINE_MEMBER( so_w );
@ -57,24 +74,30 @@ protected:
virtual void device_reset() override;
private:
// private helpers
void load_input();
void output_ready();
// callbacks
devcb_write_line m_write_dir;
devcb_write_line m_write_dor;
devcb_write8 m_write_q;
std::queue<uint8_t> m_fifo;
std::queue<u8> m_fifo;
uint8_t m_d;
uint8_t m_q;
u8 m_d;
u8 m_q;
int m_dir;
int m_dor;
int m_si;
int m_so;
bool m_dir;
bool m_dor;
bool m_si;
bool m_so;
};
// device type definition
extern const device_type CMOS_40105;
extern const device_type CD40105;
extern const device_type HC40105;
#endif

View File

@ -2,12 +2,14 @@
// copyright-holders:David Haywood
/*
how should the ctcs hook up properly?
This is very similar to the ZSU1 Sound Control Unit, also manufactured by
EFO SA and used in the Playmatic pinballs Skill Flight and Phantom Ship;
the emulation here is influenced by available schematics for that board.
irq vectors
0xe6 - from ctc0? (would need vector of e0?) probably used to drive MSM5205
0xee - from ctc0? (would need vector of e8?) ^^
0xe6 - from ctc0 channel 3 (vector = E0) used to drive MSM5205 through FIFO
0xee - from ctc0 channel 3 (vector = E8) ^^
0xf6 - drive AY (once per frame?) triggered by ctc1 channel 3? (sets vector to f0, f6 = channel3?)
0xff - read sound latch (triggered by write from master board)
@ -29,7 +31,9 @@ extern const device_type CEDAR_MAGNET_SOUND = &device_creator<cedar_magnet_sound
cedar_magnet_sound_device::cedar_magnet_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: cedar_magnet_board_device(mconfig, CEDAR_MAGNET_SOUND, "Cedar Sound", tag, owner, clock, "cedmag_sound", __FILE__),
m_ctc0(*this, "ctc0"),
m_ctc1(*this, "ctc1")
m_ctc1(*this, "ctc1"),
m_fifo(*this, "fifo"),
m_adpcm(*this, "adpcm")
{
}
@ -58,7 +62,7 @@ static ADDRESS_MAP_START( cedar_magnet_sound_io, AS_IO, 8, cedar_magnet_sound_de
AM_RANGE(0x00, 0x03) AM_DEVREADWRITE("ctc0", z80ctc_device, read, write)
AM_RANGE(0x04, 0x07) AM_DEVREADWRITE("ctc1", z80ctc_device, read, write)
AM_RANGE(0x08, 0x08) AM_WRITE(adpcm_latch_w)
AM_RANGE(0x08, 0x08) AM_WRITE(adpcm_fifo_w)
AM_RANGE(0x0c, 0x0c) AM_DEVWRITE("aysnd0", ay8910_device, address_w)
AM_RANGE(0x0d, 0x0d) AM_DEVWRITE("aysnd0", ay8910_device, data_w)
@ -70,16 +74,28 @@ static ADDRESS_MAP_START( cedar_magnet_sound_io, AS_IO, 8, cedar_magnet_sound_de
ADDRESS_MAP_END
WRITE8_MEMBER(cedar_magnet_sound_device::adpcm_latch_w)
WRITE8_MEMBER(cedar_magnet_sound_device::adpcm_fifo_w)
{
// it writes 8-bits of sample data here, to be fed to the msm 4-bits at a time
// probably via other triggers
m_adpcm_data = data;
// Z80 code first unpacks 8 bytes of ADPCM sample data into nibbles
// and, upon receiving interrupt vector E6, fills FIFO at once using OTIR
// 4-bit data is shifted out of the FIFO to the MSM5205 by another timer
m_fifo->write(data & 0x0f); // only low nibble is used here
m_fifo->si_w(1);
m_fifo->si_w(0);
}
WRITE8_MEMBER(cedar_magnet_sound_device::ay0_porta_w)
{
// unknown; 0x80 written on reset
}
WRITE8_MEMBER(cedar_magnet_sound_device::ay1_porta_w)
{
// unknown but used
m_adpcm->reset_w(data & 1);
if (data & 1)
m_fifo->reset();
// D4-D6 likely used to select clock for ctc0 channel 2
// other bits probably used to modulate analog sound output
}
WRITE_LINE_MEMBER(cedar_magnet_sound_device::ctc0_z0_w)
@ -92,9 +108,6 @@ WRITE_LINE_MEMBER(cedar_magnet_sound_device::ctc0_z1_w)
// printf("USED ctc0_z1_w %d\n", state);
}
// I don't think any of the below are used
WRITE_LINE_MEMBER(cedar_magnet_sound_device::ctc1_z0_w)
{
printf("ctc1_z0_w %d\n", state);
@ -115,14 +128,9 @@ WRITE_LINE_MEMBER(cedar_magnet_sound_device::ctc0_z2_w)
printf("ctc0_z2_w %d\n", state);
}
WRITE_LINE_MEMBER(cedar_magnet_sound_device::ctc0_int_w)
WRITE_LINE_MEMBER(cedar_magnet_sound_device::fifo_dor_w)
{
//printf("ctc0_int_w %d\n", state);
}
WRITE_LINE_MEMBER(cedar_magnet_sound_device::ctc1_int_w)
{
// combined with a clock signal and used to drive ctc0 channel 3
}
#if 0
@ -158,23 +166,20 @@ INTERRUPT_GEN_MEMBER(cedar_magnet_sound_device::fake_irq)
}
static MACHINE_CONFIG_FRAGMENT( cedar_magnet_sound )
MCFG_CPU_ADD("topcpu", Z80,4000000)
MCFG_CPU_ADD("topcpu", Z80, 4000000)
MCFG_CPU_PROGRAM_MAP(cedar_magnet_sound_map)
MCFG_CPU_IO_MAP(cedar_magnet_sound_io)
// MCFG_Z80_DAISY_CHAIN(daisy_chain)
MCFG_CPU_PERIODIC_INT_DRIVER(cedar_magnet_sound_device, fake_irq, 4*60)
MCFG_DEVICE_ADD("ctc0", Z80CTC, 4000000/8 )
MCFG_DEVICE_ADD("ctc0", Z80CTC, 4000000)
// MCFG_Z80CTC_INTR_CB(INPUTLINE("topcpu", INPUT_LINE_IRQ0))
MCFG_Z80CTC_INTR_CB(WRITELINE(cedar_magnet_sound_device, ctc0_int_w))
MCFG_Z80CTC_ZC0_CB(WRITELINE(cedar_magnet_sound_device, ctc0_z0_w))
MCFG_Z80CTC_ZC1_CB(WRITELINE(cedar_magnet_sound_device, ctc0_z1_w))
MCFG_Z80CTC_ZC2_CB(WRITELINE(cedar_magnet_sound_device, ctc0_z2_w))
MCFG_DEVICE_ADD("ctc1", Z80CTC, 4000000/8 )
MCFG_DEVICE_ADD("ctc1", Z80CTC, 4000000)
// MCFG_Z80CTC_INTR_CB(INPUTLINE("topcpu", INPUT_LINE_IRQ0))
// MCFG_Z80CTC_INTR_CB(DEVWRITELINE("ctc0", z80ctc_device, trg0))
MCFG_Z80CTC_INTR_CB(WRITELINE(cedar_magnet_sound_device, ctc1_int_w))
MCFG_Z80CTC_ZC0_CB(WRITELINE(cedar_magnet_sound_device, ctc1_z0_w))
MCFG_Z80CTC_ZC1_CB(WRITELINE(cedar_magnet_sound_device, ctc1_z1_w))
MCFG_Z80CTC_ZC2_CB(WRITELINE(cedar_magnet_sound_device, ctc1_z2_w))
@ -182,15 +187,19 @@ static MACHINE_CONFIG_FRAGMENT( cedar_magnet_sound )
MCFG_SPEAKER_STANDARD_MONO("mono")
MCFG_SOUND_ADD("aysnd0", AY8910, 4000000/2)
MCFG_AY8910_PORT_A_WRITE_CB(WRITE8(cedar_magnet_sound_device, ay0_porta_w))
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.5)
MCFG_SOUND_ADD("aysnd1", AY8910, 4000000/2)
MCFG_AY8910_PORT_A_WRITE_CB(WRITE8(cedar_magnet_sound_device, ay1_porta_w))
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.5)
MCFG_SOUND_ADD("adpcm", MSM5205, 4000000/16)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
MCFG_DEVICE_ADD("fifo", HC40105, 0) // HCF40105BE at IC13
MCFG_40105_DATA_OUT_READY_CB(WRITELINE(cedar_magnet_sound_device, fifo_dor_w))
MCFG_40105_DATA_OUT_CB(DEVWRITELINE("adpcm", msm5205_device, data_w))
MCFG_SOUND_ADD("adpcm", MSM5205, 4000000/8)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
MACHINE_CONFIG_END
machine_config_constructor cedar_magnet_sound_device::device_mconfig_additions() const

View File

@ -9,6 +9,7 @@
#include "cpu/z80/z80.h"
#include "cpu/z80/z80daisy.h"
#include "machine/z80ctc.h"
#include "machine/40105.h"
#include "sound/ay8910.h"
#include "sound/msm5205.h"
#include "machine/cedar_magnet_board.h"
@ -27,13 +28,14 @@ public:
required_device<z80ctc_device> m_ctc0;
required_device<z80ctc_device> m_ctc1;
required_device<cmos_40105_device> m_fifo;
required_device<msm5205_device> m_adpcm;
DECLARE_READ8_MEMBER(soundlatch_r);
DECLARE_WRITE8_MEMBER(adpcm_latch_w);
DECLARE_WRITE8_MEMBER(adpcm_fifo_w);
DECLARE_WRITE8_MEMBER(ay0_porta_w);
DECLARE_WRITE8_MEMBER(ay1_porta_w);
uint8_t m_adpcm_data;
void write_command(uint8_t data);
uint8_t m_command;
@ -43,8 +45,7 @@ public:
DECLARE_WRITE_LINE_MEMBER(ctc0_z0_w);
DECLARE_WRITE_LINE_MEMBER(ctc0_z1_w);
DECLARE_WRITE_LINE_MEMBER(ctc0_z2_w);
DECLARE_WRITE_LINE_MEMBER(ctc0_int_w);
DECLARE_WRITE_LINE_MEMBER(ctc1_int_w);
DECLARE_WRITE_LINE_MEMBER(fifo_dor_w);
TIMER_CALLBACK_MEMBER(reset_assert_callback) override;