cmi.cpp: Separate source file for CMI-01A device (nw)

This commit is contained in:
AJR 2018-04-27 16:50:50 -04:00
parent ac7b891ec8
commit ed8bb86e08
4 changed files with 543 additions and 546 deletions

View File

@ -2042,6 +2042,8 @@ files {
createMESSProjects(_target, _subtarget, "fairlight") createMESSProjects(_target, _subtarget, "fairlight")
files { files {
MAME_DIR .. "src/mame/drivers/cmi.cpp", MAME_DIR .. "src/mame/drivers/cmi.cpp",
MAME_DIR .. "src/mame/audio/cmi01a.cpp",
MAME_DIR .. "src/mame/audio/cmi01a.h",
} }
createMESSProjects(_target, _subtarget, "fidelity") createMESSProjects(_target, _subtarget, "fidelity")

422
src/mame/audio/cmi01a.cpp Normal file
View File

@ -0,0 +1,422 @@
// license:BSD-3-Clause
// copyright-holders:Phil Bennett
/***************************************************************************
Fairlight CMI-01A Channel Controller Card
***************************************************************************/
#include "emu.h"
#include "audio/cmi01a.h"
#include "machine/input_merger.h"
#define MASTER_OSCILLATOR XTAL(34'291'712)
DEFINE_DEVICE_TYPE(CMI01A_CHANNEL_CARD, cmi01a_device, "cmi_01a", "Fairlight CMI-01A Channel Card")
cmi01a_device::cmi01a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, CMI01A_CHANNEL_CARD, tag, owner, clock)
, device_sound_interface(mconfig, *this)
, m_pia(*this, "cmi01a_pia_%u", 0U)
, m_ptm(*this, "cmi01a_ptm")
, m_cmi02_pia(*this, "^cmi02_pia_%u", 1U)
, m_stream(nullptr)
, m_irq_cb(*this)
{
}
MACHINE_CONFIG_START(cmi01a_device::device_add_mconfig)
MCFG_DEVICE_ADD("cmi01a_pia_0", PIA6821, 0) // pia_cmi01a_1_config
MCFG_PIA_READCB1_HANDLER(READLINE(cmi01a_device, tri_r))
MCFG_PIA_WRITEPA_HANDLER(WRITE8(cmi01a_device, ws_dir_w))
MCFG_PIA_WRITEPB_HANDLER(WRITE8(cmi01a_device, rp_w))
MCFG_PIA_CA2_HANDLER(WRITELINE(cmi01a_device, pia_0_ca2_w))
MCFG_PIA_CB2_HANDLER(WRITELINE(cmi01a_device, pia_0_cb2_w))
MCFG_PIA_IRQA_HANDLER(DEVWRITELINE("cmi01a_irq", input_merger_device, in_w<0>))
MCFG_PIA_IRQB_HANDLER(DEVWRITELINE("cmi01a_irq", input_merger_device, in_w<1>))
MCFG_DEVICE_ADD("cmi01a_pia_1", PIA6821, 0) // pia_cmi01a_2_config
MCFG_PIA_READCA1_HANDLER(READLINE(cmi01a_device, zx_r))
MCFG_PIA_READCA2_HANDLER(READLINE(cmi01a_device, eosi_r))
MCFG_PIA_WRITEPA_HANDLER(WRITE8(cmi01a_device, pia_1_a_w))
MCFG_PIA_WRITEPB_HANDLER(WRITE8(cmi01a_device, pia_1_b_w))
MCFG_PIA_IRQA_HANDLER(DEVWRITELINE("cmi01a_irq", input_merger_device, in_w<2>))
MCFG_PIA_IRQB_HANDLER(DEVWRITELINE("cmi01a_irq", input_merger_device, in_w<3>))
MCFG_DEVICE_ADD("cmi01a_ptm", PTM6840, 2000000) // ptm_cmi01a_config
MCFG_PTM6840_EXTERNAL_CLOCKS(250000, 500000, 500000)
MCFG_PTM6840_O1_CB(WRITELINE(cmi01a_device, ptm_o1))
MCFG_PTM6840_IRQ_CB(DEVWRITELINE("cmi01a_irq", input_merger_device, in_w<4>))
MCFG_INPUT_MERGER_ANY_HIGH("cmi01a_irq")
MCFG_INPUT_MERGER_OUTPUT_HANDLER(WRITELINE(cmi01a_device, cmi01a_irq))
MACHINE_CONFIG_END
void cmi01a_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
{
if (m_active && m_vol_latch)
{
int length = samples;
int seg_addr = m_segment_cnt & 0x7f;
uint8_t *wave_ptr = &m_wave_ram[m_segment_cnt & 0x3fff];
stream_sample_t *buf = outputs[0];
while (length--)
{
*buf++ = wave_ptr[seg_addr];
seg_addr = (seg_addr + 1) & 0x7f;
}
m_segment_cnt = (m_segment_cnt & ~0x7f) | seg_addr;
}
else
{
memset(outputs[0], 0, samples);
}
}
void cmi01a_device::device_resolve_objects()
{
m_irq_cb.resolve_safe();
}
void cmi01a_device::device_start()
{
m_wave_ram = std::make_unique<uint8_t[]>(0x4000);
m_zx_timer = timer_alloc(TIMER_ZX);
m_zx_timer->adjust(attotime::never);
m_stream = stream_alloc(0, 1, 44100);
}
void cmi01a_device::device_reset()
{
m_ptm->set_g1(1);
m_ptm->set_g2(1);
m_ptm->set_g3(1);
m_segment_cnt = 0;
m_new_addr = 0;
m_env_dir_ctrl = 0;
m_vol_latch = 0;
m_flt_latch = 0;
m_rp = 0;
m_ws = 0;
m_dir = 0;
m_freq = 0.0;
m_active = false;
m_ptm_o1 = 0;
}
WRITE_LINE_MEMBER( cmi01a_device::pia_0_ca2_w )
{
// upate_stream()
if (!state)
{
m_segment_cnt = 0x4000 | ((m_pia[0]->a_output() & 0x7f) << 7);
m_new_addr = 1;
m_pia[1]->cb1_w(1);
}
}
WRITE8_MEMBER( cmi01a_device::pia_1_a_w )
{
// top two
}
WRITE8_MEMBER( cmi01a_device::pia_1_b_w )
{
}
WRITE8_MEMBER( cmi01a_device::rp_w )
{
m_rp = data;
}
WRITE8_MEMBER( cmi01a_device::ws_dir_w )
{
m_ws = data & 0x7f;
m_dir = (data >> 7) & 1;
}
READ_LINE_MEMBER( cmi01a_device::tri_r )
{
bool top_terminal_count = (m_dir == ENV_DIR_UP && m_rp == 0);
bool bottom_terminal_count = (m_dir == ENV_DIR_DOWN && m_rp == 0xff);
return (top_terminal_count || bottom_terminal_count) ? 1 : 0;
}
WRITE_LINE_MEMBER( cmi01a_device::cmi01a_irq )
{
m_irq_cb(state ? ASSERT_LINE : CLEAR_LINE);
}
void cmi01a_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
switch(id)
{
case TIMER_ZX:
zx_timer_cb();
break;
}
}
void cmi01a_device::zx_timer_cb()
{
/* Set ZX */
if (m_zx_flag == 0)
m_pia[1]->ca1_w(1);
else
m_pia[1]->ca1_w(0);
m_zx_flag ^= 1;
if (m_zx_flag == 0)
{
/* Low to high transition - clock flip flop */
int op = m_ptm_o1;
/* Set /ZCINT */
if (op != m_zx_ff)
m_pia[0]->ca1_w(0);
m_zx_ff = op;
m_pia[0]->ca1_w(1);
}
}
void cmi01a_device::run_voice()
{
int val_a = m_pia[1]->a_output();
int pitch = ((val_a & 3) << 8) | m_pia[1]->b_output();
int o_val = (val_a >> 2) & 0xf;
int m_tune = m_cmi02_pia[0]->b_output();
double mfreq = (double)(0xf00 | m_tune) * (MASTER_OSCILLATOR / 2.0 / 4096.0).dvalue();
double cfreq = ((double)(0x800 | (pitch << 1))* mfreq) / 4096.0;
// if (cfreq > 0.0)
{
/* Octave register enabled? */
if (!(o_val & 0x8))
cfreq /= 2 << ((7 ^ o_val) & 7);
cfreq /= 16.0f;
m_freq = cfreq;
m_stream->set_sample_rate(cfreq);
// Set timers and things?
attotime zx_period = attotime::from_ticks(64, cfreq);
m_zx_timer->adjust(zx_period, 0, zx_period);
m_active = true;
}
}
WRITE_LINE_MEMBER( cmi01a_device::pia_0_cb2_w )
{
//streams_update();
/* RUN */
if (state)
{
m_segment_cnt = 0x4000 | ((m_pia[0]->a_output() & 0x7f) << 7);
m_new_addr = 1;
/* Clear /EOSI */
// pia6821_cb1_w(card->pia[1], 0, 1);
/* Clear ZX */
m_pia[1]->ca1_w(0);
/* Clear /ZCINT */
m_pia[0]->ca1_w(1);
m_ptm->set_g1(0);
m_ptm->set_g2(0);
m_ptm->set_g3(0);
run_voice();
}
else
{
/* Clear /EOSI */
m_pia[1]->cb1_w(1);
m_ptm->set_g1(1);
m_ptm->set_g2(1);
m_ptm->set_g3(1);
//printf("Stop %d\n", m_channel);
m_zx_timer->adjust(attotime::never);
m_active = false;
m_zx_flag = 0; // TEST
m_zx_ff = 0;
}
}
void cmi01a_device::update_wave_addr(int inc)
{
int old_cnt = m_segment_cnt;
if (inc)
++m_segment_cnt;
/* Update end of sound interrupt flag */
m_pia[1]->cb1_w((m_segment_cnt & 0x4000) >> 14);
/* TODO Update zero crossing flag */
m_pia[1]->ca1_w((m_segment_cnt & 0x40) >> 6);
/* Clock a latch on a transition */
if ((old_cnt & 0x40) && !(m_segment_cnt & 0x40))
{
// TODO: ECLK
m_pia[1]->ca2_w(1);
m_pia[1]->ca2_w(0);
}
/* Zero crossing interrupt is a pulse */
}
WRITE_LINE_MEMBER( cmi01a_device::ptm_o1 )
{
m_ptm_o1 = state;
}
READ_LINE_MEMBER( cmi01a_device::eosi_r )
{
return (m_segment_cnt & 0x4000) >> 14;
}
READ_LINE_MEMBER( cmi01a_device::zx_r )
{
return m_segment_cnt & 0x40;
}
WRITE8_MEMBER( cmi01a_device::write )
{
//printf("C%d W: %02x = %02x\n", m_channel, offset, data);
switch (offset)
{
case 0x0:
if (m_new_addr)
m_new_addr = 0;
m_wave_ram[m_segment_cnt & 0x3fff] = data;
update_wave_addr(1);
break;
case 0x3:
m_env_dir_ctrl = ENV_DIR_DOWN;
break;
case 0x4:
m_env_dir_ctrl = ENV_DIR_UP;
break;
case 0x5:
m_vol_latch = data;
break;
case 0x6:
m_flt_latch = data;
break;
case 0x8: case 0x9: case 0xa: case 0xb:
m_pia[0]->write(space, offset & 3, data);
break;
case 0xc: case 0xd: case 0xe: case 0xf:
m_pia[1]->write(space, (BIT(offset, 0) << 1) | BIT(offset, 1), data);
break;
case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
{
/* PTM addressing is a little funky */
int a0 = offset & 1;
int a1 = (m_ptm_o1 && BIT(offset, 3)) || (!BIT(offset, 3) && BIT(offset, 2));
int a2 = BIT(offset, 1);
//printf("CH%d PTM W: [%x] = %02x\n", m_channel, (a2 << 2) | (a1 << 1) | a0, data);
m_ptm->write(space, (a2 << 2) | (a1 << 1) | a0, data);
break;
}
default:
logerror("Unknown channel card write to E0%02X = %02X\n", offset, data);
break;
}
}
READ8_MEMBER( cmi01a_device::read )
{
if (machine().side_effects_disabled())
return 0;
uint8_t data = 0;
switch (offset)
{
case 0x0:
if (m_new_addr)
{
m_new_addr = 0;
break;
}
data = m_wave_ram[m_segment_cnt & 0x3fff];
update_wave_addr(1);
break;
case 0x3:
m_env_dir_ctrl = ENV_DIR_DOWN;
break;
case 0x4:
m_env_dir_ctrl = ENV_DIR_UP;
break;
case 0x5:
data = 0xff;
break;
case 0x8: case 0x9: case 0xa: case 0xb:
data = m_pia[0]->read(space, offset & 3);
break;
case 0xc: case 0xd: case 0xe: case 0xf:
data = m_pia[1]->read(space, (BIT(offset, 0) << 1) | BIT(offset, 1));
break;
case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
{
int a0 = offset & 1;
int a1 = (m_ptm_o1 && BIT(offset, 3)) || (!BIT(offset, 3) && BIT(offset, 2));
int a2 = BIT(offset, 1);
data = m_ptm->read(space, (a2 << 2) | (a1 << 1) | a0);
//printf("CH%d PTM R: [%x] %02x\n", m_channel, (a2 << 2) | (a1 << 1) | a0, data);
break;
}
default:
logerror("Unknown channel card read from E0%02X\n", offset);
break;
}
//printf("C%d R: %02x = %02x\n", m_channel, offset, data);
return data;
}

93
src/mame/audio/cmi01a.h Normal file
View File

@ -0,0 +1,93 @@
// license:BSD-3-Clause
// copyright-holders:Phil Bennett
/***************************************************************************
Fairlight CMI-01A Channel Controller Card
***************************************************************************/
#ifndef MAME_AUDIO_CMI01A_H
#define MAME_AUDIO_CMI01A_H
#include "machine/6821pia.h"
#include "machine/6840ptm.h"
#define ENV_DIR_DOWN 0
#define ENV_DIR_UP 1
#define MCFG_CMI01A_IRQ_CALLBACK(_devcb) \
devcb = &downcast<cmi01a_device &>(*device).set_irq_callback(DEVCB_##_devcb);
class cmi01a_device : public device_t, public device_sound_interface {
public:
cmi01a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
template<class Object> devcb_base &set_irq_callback(Object &&cb) { return m_irq_cb.set_callback(std::forward<Object>(cb)); }
DECLARE_WRITE8_MEMBER( write );
DECLARE_READ8_MEMBER( read );
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
protected:
virtual void device_resolve_objects() override;
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_add_mconfig(machine_config &config) override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
static const device_timer_id TIMER_ZX = 0;
required_device_array<pia6821_device, 2> m_pia;
required_device<ptm6840_device> m_ptm;
required_device_array<pia6821_device, 2> m_cmi02_pia;
sound_stream* m_stream;
private:
DECLARE_WRITE_LINE_MEMBER(cmi01a_irq);
void zx_timer_cb();
void run_voice();
void update_wave_addr(int inc);
emu_timer * m_zx_timer;
uint8_t m_zx_flag;
uint8_t m_zx_ff;
std::unique_ptr<uint8_t[]> m_wave_ram;
uint16_t m_segment_cnt;
uint8_t m_new_addr; // Flag
uint8_t m_env_dir_ctrl;
uint8_t m_vol_latch;
uint8_t m_flt_latch;
uint8_t m_rp;
uint8_t m_ws;
int m_dir;
double m_freq;
bool m_active;
int m_ptm_o1;
devcb_write_line m_irq_cb;
DECLARE_WRITE8_MEMBER( rp_w );
DECLARE_WRITE8_MEMBER( ws_dir_w );
DECLARE_READ_LINE_MEMBER( tri_r );
DECLARE_WRITE_LINE_MEMBER( pia_0_ca2_w );
DECLARE_WRITE_LINE_MEMBER( pia_0_cb2_w );
DECLARE_READ_LINE_MEMBER( eosi_r );
DECLARE_READ_LINE_MEMBER( zx_r );
DECLARE_WRITE8_MEMBER( pia_1_a_w );
DECLARE_WRITE8_MEMBER( pia_1_b_w );
DECLARE_WRITE_LINE_MEMBER( ptm_o1 );
};
// device type definition
DECLARE_DEVICE_TYPE(CMI01A_CHANNEL_CARD, cmi01a_device)
#endif // MAME_AUDIO_CMI01A_H

View File

@ -99,7 +99,8 @@
****************************************************************************/ ****************************************************************************/
#include "emu.h" #include "emu.h"
#include "emu.h"
#include "audio/cmi01a.h"
#include "cpu/m6800/m6800.h" #include "cpu/m6800/m6800.h"
#include "cpu/m6809/m6809.h" #include "cpu/m6809/m6809.h"
@ -206,196 +207,6 @@ static const int ch_int_levels[8] =
#define FDC_STATUS_DRIVER_LOAD (1 << 7) #define FDC_STATUS_DRIVER_LOAD (1 << 7)
#define ENV_DIR_DOWN 0
#define ENV_DIR_UP 1
#define MCFG_CMI01A_ADD(_tag, _channel) \
MCFG_DEVICE_ADD(_tag, CMI01A_CHANNEL_CARD, 0) \
cmi01a_device::set_channel_number(*device, _channel);
#define MCFG_CMI01A_CHANNEL_NUMBER(_channel) \
cmi01a_device::set_channel_number(*device, _channel);
class cmi01a_device : public device_t, public device_sound_interface {
public:
cmi01a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
static void set_channel_number(device_t &device, int channel) { dynamic_cast<cmi01a_device&>(device).m_channel = channel; }
DECLARE_WRITE8_MEMBER( write );
DECLARE_READ8_MEMBER( read );
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
protected:
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_add_mconfig(machine_config &config) override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
static const device_timer_id TIMER_ZX = 0;
required_device<pia6821_device> m_pia_0;
required_device<pia6821_device> m_pia_1;
required_device<ptm6840_device> m_ptm;
required_device<pia6821_device> m_cmi02_pia_0;
required_device<pia6821_device> m_cmi02_pia_1;
sound_stream* m_stream;
private:
void zx_timer_cb();
void run_voice();
void update_wave_addr(int inc);
void update_interrupts();
emu_timer * m_zx_timer;
uint8_t m_zx_flag;
uint8_t m_zx_ff;
int m_channel;
std::unique_ptr<uint8_t[]> m_wave_ram;
uint16_t m_segment_cnt;
uint8_t m_new_addr; // Flag
uint8_t m_env_dir_ctrl;
uint8_t m_vol_latch;
uint8_t m_flt_latch;
uint8_t m_rp;
uint8_t m_ws;
int m_dir;
double m_freq;
bool m_active;
int m_ptm_o1;
int m_pia_0_irqa;
int m_pia_0_irqb;
int m_pia_1_irqa;
int m_pia_1_irqb;
int m_ptm_irq;
int m_irq_state;
DECLARE_WRITE8_MEMBER( rp_w );
DECLARE_WRITE8_MEMBER( ws_dir_w );
DECLARE_READ_LINE_MEMBER( tri_r );
DECLARE_WRITE_LINE_MEMBER( pia_0_ca2_w );
DECLARE_WRITE_LINE_MEMBER( pia_0_cb2_w );
DECLARE_WRITE_LINE_MEMBER( pia_0_irqa );
DECLARE_WRITE_LINE_MEMBER( pia_0_irqb );
DECLARE_READ_LINE_MEMBER( eosi_r );
DECLARE_READ_LINE_MEMBER( zx_r );
DECLARE_WRITE8_MEMBER( pia_1_a_w );
DECLARE_WRITE8_MEMBER( pia_1_b_w );
DECLARE_WRITE_LINE_MEMBER( pia_1_irqa );
DECLARE_WRITE_LINE_MEMBER( pia_1_irqb );
DECLARE_WRITE_LINE_MEMBER( ptm_irq );
DECLARE_WRITE_LINE_MEMBER( ptm_o1 );
};
DEFINE_DEVICE_TYPE(CMI01A_CHANNEL_CARD, cmi01a_device, "cmi_01a", "Fairlight CMI-01A Channel Card")
cmi01a_device::cmi01a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, CMI01A_CHANNEL_CARD, tag, owner, clock)
, device_sound_interface(mconfig, *this)
, m_pia_0(*this, "cmi01a_pia_0")
, m_pia_1(*this, "cmi01a_pia_1")
, m_ptm(*this, "cmi01a_ptm")
, m_cmi02_pia_0(*this, "^cmi02_pia_1")
, m_cmi02_pia_1(*this, "^cmi02_pia_2")
, m_stream(nullptr)
{
}
MACHINE_CONFIG_START(cmi01a_device::device_add_mconfig)
MCFG_DEVICE_ADD("cmi01a_pia_0", PIA6821, 0) // pia_cmi01a_1_config
MCFG_PIA_READCB1_HANDLER(READLINE(cmi01a_device, tri_r))
MCFG_PIA_WRITEPA_HANDLER(WRITE8(cmi01a_device, ws_dir_w))
MCFG_PIA_WRITEPB_HANDLER(WRITE8(cmi01a_device, rp_w))
MCFG_PIA_CA2_HANDLER(WRITELINE(cmi01a_device, pia_0_ca2_w))
MCFG_PIA_CB2_HANDLER(WRITELINE(cmi01a_device, pia_0_cb2_w))
MCFG_PIA_IRQA_HANDLER(WRITELINE(cmi01a_device, pia_0_irqa))
MCFG_PIA_IRQB_HANDLER(WRITELINE(cmi01a_device, pia_0_irqb))
MCFG_DEVICE_ADD("cmi01a_pia_1", PIA6821, 0) // pia_cmi01a_2_config
MCFG_PIA_READCA1_HANDLER(READLINE(cmi01a_device, zx_r))
MCFG_PIA_READCA2_HANDLER(READLINE(cmi01a_device, eosi_r))
MCFG_PIA_WRITEPA_HANDLER(WRITE8(cmi01a_device, pia_1_a_w))
MCFG_PIA_WRITEPB_HANDLER(WRITE8(cmi01a_device, pia_1_b_w))
MCFG_PIA_IRQA_HANDLER(WRITELINE(cmi01a_device, pia_1_irqa))
MCFG_PIA_IRQB_HANDLER(WRITELINE(cmi01a_device, pia_1_irqb))
MCFG_DEVICE_ADD("cmi01a_ptm", PTM6840, 2000000) // ptm_cmi01a_config
MCFG_PTM6840_EXTERNAL_CLOCKS(250000, 500000, 500000)
MCFG_PTM6840_O1_CB(WRITELINE(cmi01a_device, ptm_o1))
MCFG_PTM6840_IRQ_CB(WRITELINE(cmi01a_device, ptm_irq))
MACHINE_CONFIG_END
void cmi01a_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
{
if (m_active && m_vol_latch)
{
int length = samples;
int seg_addr = m_segment_cnt & 0x7f;
uint8_t *wave_ptr = &m_wave_ram[m_segment_cnt & 0x3fff];
stream_sample_t *buf = outputs[0];
while (length--)
{
*buf++ = wave_ptr[seg_addr];
seg_addr = (seg_addr + 1) & 0x7f;
}
m_segment_cnt = (m_segment_cnt & ~0x7f) | seg_addr;
}
else
{
memset(outputs[0], 0, samples);
}
}
void cmi01a_device::device_start()
{
m_wave_ram = std::make_unique<uint8_t[]>(0x4000);
m_zx_timer = timer_alloc(TIMER_ZX);
m_zx_timer->adjust(attotime::never);
m_stream = stream_alloc(0, 1, 44100);
}
void cmi01a_device::device_reset()
{
m_ptm->set_g1(1);
m_ptm->set_g2(1);
m_ptm->set_g3(1);
m_pia_0_irqa = 0;
m_pia_0_irqb = 0;
m_pia_1_irqa = 0;
m_pia_1_irqb = 0;
m_ptm_irq = 0;
m_irq_state = 0;
m_segment_cnt = 0;
m_new_addr = 0;
m_env_dir_ctrl = 0;
m_vol_latch = 0;
m_flt_latch = 0;
m_rp = 0;
m_ws = 0;
m_dir = 0;
m_freq = 0.0;
m_active = false;
m_ptm_o1 = 0;
}
class cmi_state : public driver_device class cmi_state : public driver_device
{ {
public: public:
@ -551,6 +362,8 @@ public:
DECLARE_WRITE_LINE_MEMBER( cmi07_irq ); DECLARE_WRITE_LINE_MEMBER( cmi07_irq );
DECLARE_WRITE_LINE_MEMBER( mkbd_acia_clock ); DECLARE_WRITE_LINE_MEMBER( mkbd_acia_clock );
template<int Channel> DECLARE_WRITE_LINE_MEMBER( channel_irq );
void cmi2x(machine_config &config); void cmi2x(machine_config &config);
void alphakeys_map(address_map &map); void alphakeys_map(address_map &map);
void cmi07cpu_map(address_map &map); void cmi07cpu_map(address_map &map);
@ -1692,353 +1505,6 @@ WRITE8_MEMBER( cmi_state::master_tune_w )
// double mfreq = (double)data * ((double)MASTER_OSCILLATOR / 2.0) / 256.0; // double mfreq = (double)data * ((double)MASTER_OSCILLATOR / 2.0) / 256.0;
} }
WRITE_LINE_MEMBER( cmi01a_device::pia_0_ca2_w )
{
// upate_stream()
if (!state)
{
m_segment_cnt = 0x4000 | ((m_pia_0->a_output() & 0x7f) << 7);
m_new_addr = 1;
m_pia_1->cb1_w(1);
}
}
WRITE_LINE_MEMBER( cmi01a_device::pia_0_irqa )
{
m_pia_0_irqa = state;
//printf("CH%d pia0 irqa int: %x\n", m_channel, state);
update_interrupts();
}
WRITE_LINE_MEMBER( cmi01a_device::pia_0_irqb )
{
m_pia_0_irqb = state;
//printf("CH%d pia0 irqb int: %x\n", m_channel, state);
update_interrupts();
}
WRITE8_MEMBER( cmi01a_device::pia_1_a_w )
{
// top two
}
WRITE8_MEMBER( cmi01a_device::pia_1_b_w )
{
}
WRITE8_MEMBER( cmi01a_device::rp_w )
{
m_rp = data;
}
WRITE8_MEMBER( cmi01a_device::ws_dir_w )
{
m_ws = data & 0x7f;
m_dir = (data >> 7) & 1;
}
READ_LINE_MEMBER( cmi01a_device::tri_r )
{
bool top_terminal_count = (m_dir == ENV_DIR_UP && m_rp == 0);
bool bottom_terminal_count = (m_dir == ENV_DIR_DOWN && m_rp == 0xff);
return (top_terminal_count || bottom_terminal_count) ? 1 : 0;
}
WRITE_LINE_MEMBER( cmi01a_device::pia_1_irqa )
{
m_pia_1_irqa = state;
//printf("CH%d pia1 irqa int: %x\n", m_channel, state);
update_interrupts();
}
WRITE_LINE_MEMBER( cmi01a_device::pia_1_irqb )
{
m_pia_1_irqb = state;
//printf("CH%d pia1 irqb int: %x\n", m_channel, state);
update_interrupts();
}
void cmi01a_device::update_interrupts()
{
int old_state = m_irq_state;
m_irq_state = m_pia_0_irqa || m_pia_0_irqb || m_pia_1_irqa || m_pia_1_irqb || m_ptm_irq;
if (m_irq_state != old_state)
dynamic_cast<cmi_state*>(owner())->set_interrupt(CPU_1, ch_int_levels[m_channel], m_irq_state ? ASSERT_LINE : CLEAR_LINE);
}
WRITE_LINE_MEMBER( cmi01a_device::ptm_irq )
{
m_ptm_irq = state;
//printf("CH%d ptm irq int: %x\n", m_channel, state);
update_interrupts();
}
void cmi01a_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
switch(id)
{
case TIMER_ZX:
zx_timer_cb();
break;
}
}
void cmi01a_device::zx_timer_cb()
{
/* Set ZX */
if (m_zx_flag == 0)
m_pia_1->ca1_w(1);
else
m_pia_1->ca1_w(0);
m_zx_flag ^= 1;
if (m_zx_flag == 0)
{
/* Low to high transition - clock flip flop */
int op = m_ptm_o1;
/* Set /ZCINT */
if (op != m_zx_ff)
m_pia_0->ca1_w(0);
m_zx_ff = op;
m_pia_0->ca1_w(1);
}
}
void cmi01a_device::run_voice()
{
int val_a = m_pia_1->a_output();
int pitch = ((val_a & 3) << 8) | m_pia_1->b_output();
int o_val = (val_a >> 2) & 0xf;
int m_tune = m_cmi02_pia_0->b_output();
double mfreq = (double)(0xf00 | m_tune) * (MASTER_OSCILLATOR / 2.0 / 4096.0).dvalue();
double cfreq = ((double)(0x800 | (pitch << 1))* mfreq) / 4096.0;
// if (cfreq > 0.0)
{
/* Octave register enabled? */
if (!(o_val & 0x8))
cfreq /= 2 << ((7 ^ o_val) & 7);
cfreq /= 16.0f;
m_freq = cfreq;
m_stream->set_sample_rate(cfreq);
// Set timers and things?
attotime zx_period = attotime::from_ticks(64, cfreq);
m_zx_timer->adjust(zx_period, 0, zx_period);
m_active = true;
}
}
WRITE_LINE_MEMBER( cmi01a_device::pia_0_cb2_w )
{
//streams_update();
/* RUN */
if (state)
{
m_segment_cnt = 0x4000 | ((m_pia_0->a_output() & 0x7f) << 7);
m_new_addr = 1;
/* Clear /EOSI */
// pia6821_cb1_w(card->pia[1], 0, 1);
/* Clear ZX */
m_pia_1->ca1_w(0);
/* Clear /ZCINT */
m_pia_0->ca1_w(1);
m_ptm->set_g1(0);
m_ptm->set_g2(0);
m_ptm->set_g3(0);
run_voice();
}
else
{
/* Clear /EOSI */
m_pia_1->cb1_w(1);
m_ptm->set_g1(1);
m_ptm->set_g2(1);
m_ptm->set_g3(1);
//printf("Stop %d\n", m_channel);
m_zx_timer->adjust(attotime::never);
m_active = false;
m_zx_flag = 0; // TEST
m_zx_ff = 0;
}
}
void cmi01a_device::update_wave_addr(int inc)
{
int old_cnt = m_segment_cnt;
if (inc)
++m_segment_cnt;
/* Update end of sound interrupt flag */
m_pia_1->cb1_w((m_segment_cnt & 0x4000) >> 14);
/* TODO Update zero crossing flag */
m_pia_1->ca1_w((m_segment_cnt & 0x40) >> 6);
/* Clock a latch on a transition */
if ((old_cnt & 0x40) && !(m_segment_cnt & 0x40))
{
// TODO: ECLK
m_pia_1->ca2_w(1);
m_pia_1->ca2_w(0);
}
/* Zero crossing interrupt is a pulse */
}
WRITE_LINE_MEMBER( cmi01a_device::ptm_o1 )
{
m_ptm_o1 = state;
}
READ_LINE_MEMBER( cmi01a_device::eosi_r )
{
return (m_segment_cnt & 0x4000) >> 14;
}
READ_LINE_MEMBER( cmi01a_device::zx_r )
{
return m_segment_cnt & 0x40;
}
WRITE8_MEMBER( cmi01a_device::write )
{
//printf("C%d W: %02x = %02x\n", m_channel, offset, data);
switch (offset)
{
case 0x0:
if (m_new_addr)
m_new_addr = 0;
m_wave_ram[m_segment_cnt & 0x3fff] = data;
update_wave_addr(1);
break;
case 0x3:
m_env_dir_ctrl = ENV_DIR_DOWN;
break;
case 0x4:
m_env_dir_ctrl = ENV_DIR_UP;
break;
case 0x5:
m_vol_latch = data;
break;
case 0x6:
m_flt_latch = data;
break;
case 0x8: case 0x9: case 0xa: case 0xb:
m_pia_0->write(space, offset & 3, data);
break;
case 0xc: case 0xd: case 0xe: case 0xf:
m_pia_1->write(space, (BIT(offset, 0) << 1) | BIT(offset, 1), data);
break;
case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
{
/* PTM addressing is a little funky */
int a0 = offset & 1;
int a1 = (m_ptm_o1 && BIT(offset, 3)) || (!BIT(offset, 3) && BIT(offset, 2));
int a2 = BIT(offset, 1);
//printf("CH%d PTM W: [%x] = %02x\n", m_channel, (a2 << 2) | (a1 << 1) | a0, data);
m_ptm->write(space, (a2 << 2) | (a1 << 1) | a0, data);
break;
}
default:
printf("Unknown channel card %d write to E0%02X = %02X\n", m_channel, offset, data);
break;
}
}
READ8_MEMBER( cmi01a_device::read )
{
if (machine().side_effects_disabled())
return 0;
uint8_t data = 0;
switch (offset)
{
case 0x0:
if (m_new_addr)
{
m_new_addr = 0;
break;
}
data = m_wave_ram[m_segment_cnt & 0x3fff];
update_wave_addr(1);
break;
case 0x3:
m_env_dir_ctrl = ENV_DIR_DOWN;
break;
case 0x4:
m_env_dir_ctrl = ENV_DIR_UP;
break;
case 0x5:
data = 0xff;
break;
case 0x8: case 0x9: case 0xa: case 0xb:
data = m_pia_0->read(space, offset & 3);
break;
case 0xc: case 0xd: case 0xe: case 0xf:
data = m_pia_1->read(space, (BIT(offset, 0) << 1) | BIT(offset, 1));
break;
case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
{
int a0 = offset & 1;
int a1 = (m_ptm_o1 && BIT(offset, 3)) || (!BIT(offset, 3) && BIT(offset, 2));
int a2 = BIT(offset, 1);
data = m_ptm->read(space, (a2 << 2) | (a1 << 1) | a0);
//printf("CH%d PTM R: [%x] %02x\n", m_channel, (a2 << 2) | (a1 << 1) | a0, data);
break;
}
default:
printf("Unknown channel card %d read from E0%02X\n", m_channel, offset);
break;
}
//printf("C%d R: %02x = %02x\n", m_channel, offset, data);
return data;
}
WRITE_LINE_MEMBER( cmi_state::cmi02_ptm_irq ) WRITE_LINE_MEMBER( cmi_state::cmi02_ptm_irq )
{ {
//printf("cmi02_ptm_irq: %d\n", state); //printf("cmi02_ptm_irq: %d\n", state);
@ -2150,6 +1616,12 @@ WRITE8_MEMBER( cmi_state::cmi02_w )
} }
} }
template<int Channel>
WRITE_LINE_MEMBER(cmi_state::channel_irq)
{
set_interrupt(CPU_1, ch_int_levels[Channel], state);
}
void cmi_state::install_video_ram(int cpunum) void cmi_state::install_video_ram(int cpunum)
{ {
address_space *space = (cpunum == CPU_1 ? m_cpu1space : m_cpu2space); address_space *space = (cpunum == CPU_1 ? m_cpu1space : m_cpu2space);
@ -2855,22 +2327,30 @@ MACHINE_CONFIG_START(cmi_state::cmi2x)
MCFG_SPEAKER_STANDARD_MONO("mono") MCFG_SPEAKER_STANDARD_MONO("mono")
// Channel cards // Channel cards
MCFG_CMI01A_ADD("cmi01a_0", 0) MCFG_DEVICE_ADD("cmi01a_0", CMI01A_CHANNEL_CARD, 0)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
MCFG_CMI01A_ADD("cmi01a_1", 1) MCFG_CMI01A_IRQ_CALLBACK(WRITELINE(cmi_state, channel_irq<0>))
MCFG_DEVICE_ADD("cmi01a_1", CMI01A_CHANNEL_CARD, 0)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
MCFG_CMI01A_ADD("cmi01a_2", 2) MCFG_CMI01A_IRQ_CALLBACK(WRITELINE(cmi_state, channel_irq<1>))
MCFG_DEVICE_ADD("cmi01a_2", CMI01A_CHANNEL_CARD, 0)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
MCFG_CMI01A_ADD("cmi01a_3", 3) MCFG_CMI01A_IRQ_CALLBACK(WRITELINE(cmi_state, channel_irq<2>))
MCFG_DEVICE_ADD("cmi01a_3", CMI01A_CHANNEL_CARD, 0)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
MCFG_CMI01A_ADD("cmi01a_4", 4) MCFG_CMI01A_IRQ_CALLBACK(WRITELINE(cmi_state, channel_irq<3>))
MCFG_DEVICE_ADD("cmi01a_4", CMI01A_CHANNEL_CARD, 0)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
MCFG_CMI01A_ADD("cmi01a_5", 5) MCFG_CMI01A_IRQ_CALLBACK(WRITELINE(cmi_state, channel_irq<4>))
MCFG_DEVICE_ADD("cmi01a_5", CMI01A_CHANNEL_CARD, 0)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
MCFG_CMI01A_ADD("cmi01a_6", 6) MCFG_CMI01A_IRQ_CALLBACK(WRITELINE(cmi_state, channel_irq<5>))
MCFG_DEVICE_ADD("cmi01a_6", CMI01A_CHANNEL_CARD, 0)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
MCFG_CMI01A_ADD("cmi01a_7", 7) MCFG_CMI01A_IRQ_CALLBACK(WRITELINE(cmi_state, channel_irq<6>))
MCFG_DEVICE_ADD("cmi01a_7", CMI01A_CHANNEL_CARD, 0)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
MCFG_CMI01A_IRQ_CALLBACK(WRITELINE(cmi_state, channel_irq<7>))
MACHINE_CONFIG_END MACHINE_CONFIG_END
ROM_START( cmi2x ) ROM_START( cmi2x )