@@ -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 ;
}
This comment has been minimized.
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.
This comment has been minimized.
@Tafoid Expected.