Skip to content
Permalink
Browse files
-cmi2x: Numerous fixes, now boots into System Software V19, and plays…
… audio badly.
  • Loading branch information
Ryan Holtz committed Jun 28, 2020
1 parent 9c19602 commit bc0b2c7b093ed57b8081c960c7e140f1a4c5192d
Showing with 305 additions and 148 deletions.
  1. +101 −41 src/mame/audio/cmi01a.cpp
  2. +13 −3 src/mame/audio/cmi01a.h
  3. +151 −83 src/mame/drivers/cmi.cpp
  4. +39 −21 src/mame/machine/cmi_mkbd.cpp
  5. +1 −0 src/mame/machine/cmi_mkbd.h
@@ -8,7 +8,6 @@

#include "emu.h"
#include "audio/cmi01a.h"
#include "machine/input_merger.h"

#define VERBOSE (0)
#include "logmacro.h"
@@ -21,6 +20,7 @@ DEFINE_DEVICE_TYPE(CMI01A_CHANNEL_CARD, cmi01a_device, "cmi_01a", "Fairlight CMI
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_irq_merger(*this, "cmi01a_irq")
, m_pia(*this, "cmi01a_pia_%u", 0U)
, m_ptm(*this, "cmi01a_ptm")
, m_cmi02_pia(*this, "^cmi02_pia_%u", 1U)
@@ -37,41 +37,42 @@ void cmi01a_device::device_add_mconfig(machine_config &config)
m_pia[0]->writepb_handler().set(FUNC(cmi01a_device::rp_w));
m_pia[0]->ca2_handler().set(FUNC(cmi01a_device::pia_0_ca2_w));
m_pia[0]->cb2_handler().set(FUNC(cmi01a_device::pia_0_cb2_w));
m_pia[0]->irqa_handler().set("cmi01a_irq", FUNC(input_merger_device::in_w<0>));
m_pia[0]->irqb_handler().set("cmi01a_irq", FUNC(input_merger_device::in_w<1>));
m_pia[0]->irqa_handler().set(m_irq_merger, FUNC(input_merger_device::in_w<0>));
m_pia[0]->irqb_handler().set(m_irq_merger, FUNC(input_merger_device::in_w<1>));

PIA6821(config, m_pia[1], 0); // pia_cmi01a_2_config
m_pia[1]->readca1_handler().set(FUNC(cmi01a_device::zx_r));
m_pia[1]->readca2_handler().set(FUNC(cmi01a_device::eosi_r));
m_pia[1]->writepa_handler().set(FUNC(cmi01a_device::pia_1_a_w));
m_pia[1]->writepb_handler().set(FUNC(cmi01a_device::pia_1_b_w));
m_pia[1]->irqa_handler().set("cmi01a_irq", FUNC(input_merger_device::in_w<2>));
m_pia[1]->irqb_handler().set("cmi01a_irq", FUNC(input_merger_device::in_w<3>));
m_pia[1]->irqa_handler().set(m_irq_merger, FUNC(input_merger_device::in_w<2>));
m_pia[1]->irqb_handler().set(m_irq_merger, FUNC(input_merger_device::in_w<3>));

PTM6840(config, m_ptm, DERIVED_CLOCK(1, 1)); // ptm_cmi01a_config
m_ptm->o1_callback().set(FUNC(cmi01a_device::ptm_o1));
m_ptm->irq_callback().set("cmi01a_irq", FUNC(input_merger_device::in_w<4>));
m_ptm->irq_callback().set(FUNC(cmi01a_device::ptm_irq));

INPUT_MERGER_ANY_HIGH(config, "cmi01a_irq").output_handler().set(FUNC(cmi01a_device::cmi01a_irq));
INPUT_MERGER_ANY_HIGH(config, m_irq_merger).output_handler().set(FUNC(cmi01a_device::cmi01a_irq));
}


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)
if ((m_status & CHANNEL_STATUS_RUN) && m_vol_latch)
{
int length = samples;
int seg_addr = m_segment_cnt & 0x7f;
int mask = (m_status & CHANNEL_STATUS_LOAD) ? 0x7fff : 0x7f;
int addr = m_segment_cnt;

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;
*buf++ = wave_ptr[addr++ & 0x3fff] << 7;
}

m_segment_cnt = (m_segment_cnt & ~0x7f) | seg_addr;
m_segment_cnt = (m_segment_cnt & ~mask) | addr;
}
else
{
@@ -89,7 +90,10 @@ void cmi01a_device::device_start()
m_wave_ram = std::make_unique<uint8_t[]>(0x4000);

m_zx_timer = timer_alloc(TIMER_ZX);
m_eosi_timer = timer_alloc(TIMER_EOSI);

m_zx_timer->adjust(attotime::never);
m_eosi_timer->adjust(attotime::never);

m_stream = stream_alloc(0, 1, 44100);

@@ -110,18 +114,25 @@ void cmi01a_device::device_reset()
m_rp = 0;
m_ws = 0;
m_dir = 0;
m_pia0_cb2_state = 1;

m_freq = 0.0;
m_active = false;
m_status = 0;

m_ptm_o1 = 0;

m_zx_timer->adjust(attotime::never);
m_eosi_timer->adjust(attotime::never);
}

WRITE_LINE_MEMBER( cmi01a_device::pia_0_ca2_w )
{
// update_stream()
m_status &= ~CHANNEL_STATUS_LOAD;

if (!state)
{
m_status |= CHANNEL_STATUS_LOAD;

m_segment_cnt = 0x4000 | ((m_pia[0]->a_output() & 0x7f) << 7);
m_new_addr = 1;
m_pia[1]->cb1_w(1);
@@ -152,7 +163,7 @@ 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;
return (top_terminal_count || bottom_terminal_count) ? 0 : 1;
}

WRITE_LINE_MEMBER( cmi01a_device::cmi01a_irq )
@@ -167,9 +178,19 @@ void cmi01a_device::device_timer(emu_timer &timer, device_timer_id id, int param
case TIMER_ZX:
zx_timer_cb();
break;
case TIMER_EOSI:
eosi_timer_cb();
break;
}
}

void cmi01a_device::eosi_timer_cb()
{
m_pia[1]->cb1_w(0);

// printf("End of sound\n");
}

void cmi01a_device::zx_timer_cb()
{
/* Set ZX */
@@ -197,46 +218,71 @@ void cmi01a_device::zx_timer_cb()
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 pitch = ((val_a & 3) << 8)
| m_pia[1]->b_output();
int o_val = (val_a >> 2) & 0xf;

LOG("CH%d running voice: PIA1 A output = %02x\n", m_channel, (uint8_t)val_a);
LOG("CH%d running voice: Pitch = %04x\n", m_channel, (uint16_t)pitch);
LOG("CH%d running voice: o_val = %x\n", m_channel, o_val);

int m_tune = m_cmi02_pia[0]->b_output();
double mfreq = (double)(0xf00 | m_tune) * (MASTER_OSCILLATOR / 2.0 / 4096.0).dvalue();
LOG("CH%d running voice: Tuning = %02x\n", m_channel, (uint8_t)m_tune);
double mfreq = (double)(0xf00 | m_tune) * (MASTER_OSCILLATOR.dvalue() / 2.0) / 4096.0;
LOG("CH%d running voice: mfreq = %f (%03x * %f)\n", m_channel, mfreq, 0xf00 | m_tune, (MASTER_OSCILLATOR / 2.0 / 4096.0).dvalue());

double cfreq = ((double)(0x800 | (pitch << 1))* mfreq) / 4096.0;
double cfreq = ((double)(0x800 | (pitch << 1)) * mfreq) / 4096.0;
LOG("CH%d running voice: cfreq = %f (%04x * %f) / 4096.0\n", m_channel, mfreq, 0x800 | (pitch << 1), mfreq, cfreq);

// if (cfreq > 0.0)
if (cfreq > MASTER_OSCILLATOR.dvalue())
{
/* Octave register enabled? */
if (!(o_val & 0x8))
cfreq /= 2 << ((7 ^ o_val) & 7);
LOG("CH%d Ignoring voice run due to excessive frequency\n");
return;
}

LOG("CH%d Running voice\n", m_channel);
/* Octave register enabled? */
if (!(o_val & 0x8))
cfreq /= 2 << ((7 ^ o_val) & 7);

cfreq /= 16.0f;

cfreq /= 16.0f;
m_freq = cfreq;

m_freq = cfreq;
LOG("CH%d running voice: Final freq: %f\n", m_channel, m_freq);

m_stream->set_sample_rate(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);
// Set timers and things?
attotime zx_period = attotime::from_ticks(64, cfreq);
m_zx_timer->adjust(zx_period, 0, zx_period);

m_active = true;
if (m_status & CHANNEL_STATUS_LOAD)
{
int samples = 0x4000 - (m_segment_cnt & 0x3fff);
m_eosi_timer->adjust(attotime::from_ticks(samples, cfreq));
}
}

WRITE_LINE_MEMBER( cmi01a_device::pia_0_cb2_w )
{
int old_state = m_pia0_cb2_state;
m_pia0_cb2_state = state;
LOG("CH%d PIA0 CB2: %d\n", m_channel, state);

//streams_update();

/* RUN */
if (state)
if (!old_state && m_pia0_cb2_state)
{
m_segment_cnt = 0x4000 | ((m_pia[0]->a_output() & 0x7f) << 7);
m_new_addr = 1;
m_status |= CHANNEL_STATUS_RUN;

/* Clear /EOSI */
// pia6821_cb1_w(card->pia[1], 0, 1);
/* Only reset address counter if /LOAD not asserted */
if ((m_status & CHANNEL_STATUS_LOAD) == 0)
{
m_segment_cnt = 0x4000 | ((m_pia[0]->a_output() & 0x7f) << 7);
m_new_addr = 1;
}

/* Clear ZX */
m_pia[1]->ca1_w(0);
@@ -250,8 +296,11 @@ WRITE_LINE_MEMBER( cmi01a_device::pia_0_cb2_w )

run_voice();
}
else

if (old_state && !m_pia0_cb2_state)
{
m_status &= ~CHANNEL_STATUS_RUN;

/* Clear /EOSI */
m_pia[1]->cb1_w(1);

@@ -260,8 +309,7 @@ WRITE_LINE_MEMBER( cmi01a_device::pia_0_cb2_w )
m_ptm->set_g3(1);

m_zx_timer->adjust(attotime::never);
m_active = false;
m_zx_flag = 0; // TEST
m_eosi_timer->adjust(attotime::never);
m_zx_ff = 0;
}

@@ -291,6 +339,11 @@ void cmi01a_device::update_wave_addr(int inc)
/* Zero crossing interrupt is a pulse */
}

WRITE_LINE_MEMBER( cmi01a_device::ptm_irq )
{
m_irq_merger->in_w<4>(state);
}

WRITE_LINE_MEMBER( cmi01a_device::ptm_o1 )
{
m_ptm_o1 = state;
@@ -303,7 +356,7 @@ READ_LINE_MEMBER( cmi01a_device::eosi_r )

READ_LINE_MEMBER( cmi01a_device::zx_r )
{
return m_segment_cnt & 0x40;
return (m_segment_cnt & 0x40) >> 6;
}

void cmi01a_device::write(offs_t offset, uint8_t data)
@@ -337,10 +390,12 @@ void cmi01a_device::write(offs_t offset, uint8_t data)
break;

case 0x8: case 0x9: case 0xa: case 0xb:
LOG("CH%d PIA0 Write: %d = %02x\n", m_channel, offset & 3, data);
m_pia[0]->write(offset & 3, data);
break;

case 0xc: case 0xd: case 0xe: case 0xf:
LOG("CH%d PIA1 Write: %d = %02x\n", m_channel, (BIT(offset, 0) << 1) | BIT(offset, 1), data);
m_pia[1]->write((BIT(offset, 0) << 1) | BIT(offset, 1), data);
break;

@@ -351,7 +406,10 @@ void cmi01a_device::write(offs_t offset, uint8_t data)
int a1 = (m_ptm_o1 && BIT(offset, 3)) || (!BIT(offset, 3) && BIT(offset, 2));
int a2 = BIT(offset, 1);

//osd_printf_debug("CH%d PTM W: [%x] = %02x\n", m_channel, (a2 << 2) | (a1 << 1) | a0, data);
if ((offset == 5 || offset == 7) && (data < 0x30))
data = 0xff;

LOG("CH%d PTM Write: %d = %02x\n", m_channel, (a2 << 2) | (a1 << 1) | a0, data);
m_ptm->write((a2 << 2) | (a1 << 1) | a0, data);
break;
}
@@ -395,21 +453,23 @@ uint8_t cmi01a_device::read(offs_t offset)

case 0x8: case 0x9: case 0xa: case 0xb:
data = m_pia[0]->read(offset & 3);
LOG("CH%d PIA0 Read: %d = %02x\n", m_channel, offset & 3, data);
break;

case 0xc: case 0xd: case 0xe: case 0xf:
data = m_pia[1]->read((BIT(offset, 0) << 1) | BIT(offset, 1));
LOG("CH%d PIA1 Read: %d = %02x\n", m_channel, (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:
{
int a0 = offset & 1;
int a1 = ((m_ptm_o1 && BIT(offset, 3)) || (!BIT(offset, 3) && BIT(offset, 2))) ? 1 : 0;
int a1 = (m_ptm_o1 && BIT(offset, 3)) || (!BIT(offset, 3) && BIT(offset, 2));
int a2 = BIT(offset, 1);

data = m_ptm->read((a2 << 2) | (a1 << 1) | a0);

//osd_printf_debug("CH%d PTM R: [%x] %02x\n", m_channel, (a2 << 2) | (a1 << 1) | a0, data);
LOG("CH%d PTM Read: %d = %02x\n", m_channel, (a2 << 2) | (a1 << 1) | a0, data);
break;
}

@@ -11,10 +11,13 @@

#include "machine/6821pia.h"
#include "machine/6840ptm.h"
#include "machine/input_merger.h"

#define ENV_DIR_DOWN 0
#define ENV_DIR_UP 1

#define CHANNEL_STATUS_LOAD 1
#define CHANNEL_STATUS_RUN 2

class cmi01a_device : public device_t, public device_sound_interface {
public:
@@ -41,7 +44,9 @@ class cmi01a_device : public device_t, public device_sound_interface {
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;

static const device_timer_id TIMER_ZX = 0;
static const device_timer_id TIMER_EOSI = 1;

required_device<input_merger_device> m_irq_merger;
required_device_array<pia6821_device, 2> m_pia;
required_device<ptm6840_device> m_ptm;

@@ -53,6 +58,7 @@ class cmi01a_device : public device_t, public device_sound_interface {
DECLARE_WRITE_LINE_MEMBER(cmi01a_irq);

void zx_timer_cb();
void eosi_timer_cb();
void run_voice();
void update_wave_addr(int inc);

@@ -61,18 +67,21 @@ class cmi01a_device : public device_t, public device_sound_interface {
uint8_t m_zx_flag;
uint8_t m_zx_ff;

emu_timer * m_eosi_timer;

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;
uint8_t m_rp;
uint8_t m_ws;
int m_dir;
int m_pia0_cb2_state;

double m_freq;
bool m_active;
uint8_t m_status;

int m_ptm_o1;

@@ -90,6 +99,7 @@ class cmi01a_device : public device_t, public device_sound_interface {
void pia_1_b_w(uint8_t data);

DECLARE_WRITE_LINE_MEMBER( ptm_o1 );
DECLARE_WRITE_LINE_MEMBER( ptm_irq );
};

// device type definition

2 comments on commit bc0b2c7

@Tafoid

This comment has been minimized.

Copy link
Contributor

@Tafoid Tafoid replied Jun 29, 2020

cmi2x - cmi.cpp
Odd observation, there is a green dot in the center of the screen right in the middle of where the lightgun cursor is. Could be nothing, but wanted to make sure I didn't miss anything.
cmi2x-diff

@MooglyGuy

This comment has been minimized.

Copy link
Contributor

@MooglyGuy MooglyGuy replied Jun 29, 2020

@Tafoid Expected.

Please sign in to comment.