-hal2: Various changes. [Ryan Holtz]

* Added handling for different frequency rates.
 * Moved DAC devices into HAL2 from HPC3.
 * Added readback of DAC parameters.
 * Fixed stereo DAC playback.
This commit is contained in:
mooglyguy 2019-05-29 02:16:16 +02:00 committed by MooglyGuy
parent e72d1130fe
commit e15b2b50ad
4 changed files with 308 additions and 59 deletions

View File

@ -21,8 +21,8 @@ DEFINE_DEVICE_TYPE(SGI_HAL2, hal2_device, "hal2", "SGI HAL2")
hal2_device::hal2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, SGI_HAL2, tag, owner, clock)
, m_iar(0)
, m_idr{0, 0, 0, 0}
, m_ldac(*this, "ldac")
, m_rdac(*this, "rdac")
{
}
@ -31,6 +31,19 @@ void hal2_device::device_start()
save_item(NAME(m_isr));
save_item(NAME(m_iar));
save_item(NAME(m_idr));
save_item(NAME(m_codeca_ctrl));
save_item(NAME(m_codeca_channel));
save_item(NAME(m_codeca_clock));
save_item(NAME(m_codeca_channel_count));
save_item(NAME(m_codecb_ctrl));
save_item(NAME(m_codecb_channel));
save_item(NAME(m_codecb_clock));
save_item(NAME(m_codecb_channel_count));
save_item(NAME(m_bres_clock_sel));
save_item(NAME(m_bres_clock_inc));
save_item(NAME(m_bres_clock_modctrl));
save_item(NAME(m_bres_clock_freq));
save_item(NAME(m_curr_dac));
}
void hal2_device::device_reset()
@ -38,6 +51,23 @@ void hal2_device::device_reset()
m_isr = 0;
m_iar = 0;
memset(m_idr, 0, sizeof(uint32_t) * 4);
memset(m_codeca_ctrl, 0, sizeof(uint32_t) * 2);
m_codeca_channel = 0;
m_codeca_clock = 0;
m_codeca_channel_count = 0;
memset(m_codecb_ctrl, 0, sizeof(uint32_t) * 2);
m_codecb_channel = 0;
m_codecb_clock = 0;
m_codecb_channel_count = 0;
memset(m_bres_clock_sel, 0, sizeof(uint32_t) * 3);
memset(m_bres_clock_inc, 0, sizeof(uint32_t) * 3);
memset(m_bres_clock_modctrl, 0, sizeof(uint32_t) * 3);
memset(m_bres_clock_freq, 0, sizeof(uint32_t) * 3);
for (int i = 0; i < 3; i++)
{
m_bres_clock_rate[i] = attotime::zero;
}
m_curr_dac = 0;
}
READ32_MEMBER(hal2_device::read)
@ -50,6 +80,22 @@ READ32_MEMBER(hal2_device::read)
case REVISION_REG:
LOGMASKED(LOG_READS, "%s: HAL2 Revision Read: 0x4011\n", machine().describe_context());
return 0x4011;
case INDIRECT_DATA0_REG:
LOGMASKED(LOG_WRITES, "%s: HAL2 Indirect Data Register 0 Read: %08x & %08x\n", machine().describe_context(), m_idr[3], mem_mask);
return m_idr[0];
case INDIRECT_DATA1_REG:
LOGMASKED(LOG_WRITES, "%s: HAL2 Indirect Data Register 1 Read: %08x & %08x\n", machine().describe_context(), m_idr[3], mem_mask);
return m_idr[1];
case INDIRECT_DATA2_REG:
LOGMASKED(LOG_WRITES, "%s: HAL2 Indirect Data Register 2 Read: %08x & %08x\n", machine().describe_context(), m_idr[3], mem_mask);
return m_idr[2];
case INDIRECT_DATA3_REG:
LOGMASKED(LOG_WRITES, "%s: HAL2 Indirect Data Register 3 Read: %08x & %08x\n", machine().describe_context(), m_idr[3], mem_mask);
return m_idr[3];
}
LOGMASKED(LOG_READS | LOG_UNKNOWN, "%s: Unknown HAL2 read: %08x & %08x\n", machine().describe_context(), 0x1fbd8000 + offset*4, mem_mask);
return 0;
@ -85,31 +131,143 @@ WRITE32_MEMBER(hal2_device::write)
LOGMASKED(LOG_WRITES, " AES Out\n");
break;
case 0x0400:
LOGMASKED(LOG_WRITES, " DAC Out\n");
{
LOGMASKED(LOG_WRITES, " Codec A (DAC) Out\n");
const uint32_t param = (data & IAR_PARAM) >> IAR_PARAM_SHIFT;
switch (param)
{
case 1:
LOGMASKED(LOG_WRITES, " Control 1\n");
if (data & IAR_ACCESS_SEL)
{
m_idr[0] = m_codeca_ctrl[0];
}
else
{
m_codeca_ctrl[0] = m_idr[0];
m_codeca_channel = m_idr[0] & 3;
m_codeca_clock = (m_idr[0] >> 3) & 3;
m_codeca_channel_count = (m_idr[0] >> 8) & 3;
}
break;
case 2:
LOGMASKED(LOG_WRITES, " Control 2\n");
if (data & IAR_ACCESS_SEL)
{
m_idr[0] = m_codeca_ctrl[1];
}
else
{
m_codeca_ctrl[1] = m_idr[0];
}
break;
default:
LOGMASKED(LOG_WRITES, " Unknown Register\n");
break;
}
break;
}
case 0x0500:
LOGMASKED(LOG_WRITES, " ADC Out\n");
{
LOGMASKED(LOG_WRITES, " Codec B (ADC) Out\n");
const uint32_t param = (data & IAR_PARAM) >> IAR_PARAM_SHIFT;
switch (param)
{
case 1:
LOGMASKED(LOG_WRITES, " Control 1\n");
if (data & IAR_ACCESS_SEL)
{
m_idr[0] = m_codecb_ctrl[0];
}
else
{
m_codecb_ctrl[0] = m_idr[0];
m_codecb_channel = m_idr[0] & 3;
m_codecb_clock = (m_idr[0] >> 3) & 3;
m_codecb_channel_count = (m_idr[0] >> 8) & 3;
}
break;
case 2:
LOGMASKED(LOG_WRITES, " Control 2\n");
if (data & IAR_ACCESS_SEL)
{
m_idr[0] = m_codecb_ctrl[1];
}
else
{
m_codecb_ctrl[1] = m_idr[0];
}
break;
default:
LOGMASKED(LOG_WRITES, " Unknown Register\n");
break;
}
break;
}
case 0x0600:
LOGMASKED(LOG_WRITES, " Synth Control\n");
break;
default:
LOGMASKED(LOG_WRITES, " Unknown\n");
break;
}
break;
case 0x2000:
{
LOGMASKED(LOG_WRITES, " Bresenham\n");
switch (data & IAR_NUM)
uint32_t clock_gen = (data & IAR_NUM) >> IAR_NUM_SHIFT;
if (clock_gen >= 1 && clock_gen <= 3)
{
case 0x0100:
LOGMASKED(LOG_WRITES, " Bresenham Clock Gen 1\n");
break;
case 0x0200:
LOGMASKED(LOG_WRITES, " Bresenham Clock Gen 2\n");
break;
case 0x0300:
LOGMASKED(LOG_WRITES, " Bresenham Clock Gen 3\n");
break;
LOGMASKED(LOG_WRITES, " Bresenham Clock Gen %d\n", clock_gen);
clock_gen--;
const uint32_t param = (data & IAR_PARAM) >> IAR_PARAM_SHIFT;
if (param == 1)
{
LOGMASKED(LOG_WRITES, " Control 1 (Clock Select)\n");
if (data & IAR_ACCESS_SEL)
{
m_idr[0] = m_bres_clock_sel[clock_gen];
}
else
{
m_bres_clock_sel[clock_gen] = m_idr[0];
switch (m_idr[0])
{
case 0: LOGMASKED(LOG_WRITES, " 48kHz\n"); break;
case 1: LOGMASKED(LOG_WRITES, " 44.1kHz\n"); break;
case 2: LOGMASKED(LOG_WRITES, " Off\n"); break;
default: LOGMASKED(LOG_WRITES, " Unknown (%d)\n", m_idr[0]); break;
}
update_clock_freq(clock_gen);
}
}
else if (param == 2)
{
LOGMASKED(LOG_WRITES, " Control 2 (Inc/Mod Ctrl)\n");
if (data & IAR_ACCESS_SEL)
{
m_idr[0] = m_bres_clock_inc[clock_gen];
m_idr[1] = m_bres_clock_modctrl[clock_gen];
}
else
{
m_bres_clock_inc[clock_gen] = m_idr[0];
m_bres_clock_modctrl[clock_gen] = m_idr[1];
LOGMASKED(LOG_WRITES, " Inc:%04x, ModCtrl:%04x\n", (uint16_t)m_idr[0], (uint16_t)m_idr[1]);
update_clock_freq(clock_gen);
}
}
else
{
LOGMASKED(LOG_WRITES, " Unknown Param\n");
}
}
else
{
LOGMASKED(LOG_WRITES, " Unknown\n");
}
break;
}
case 0x3000:
LOGMASKED(LOG_WRITES, " Unix Timer\n");
@ -118,6 +276,9 @@ WRITE32_MEMBER(hal2_device::write)
case 0x0100:
LOGMASKED(LOG_WRITES, " Unix Timer\n");
break;
default:
LOGMASKED(LOG_WRITES, " Unknown\n");
break;
}
break;
@ -128,19 +289,18 @@ WRITE32_MEMBER(hal2_device::write)
case 0x0100:
LOGMASKED(LOG_WRITES, " DMA Control\n");
break;
default:
LOGMASKED(LOG_WRITES, " Unknown\n");
break;
}
break;
}
switch (data & IAR_ACCESS_SEL)
{
case 0x0000:
LOGMASKED(LOG_WRITES, " Write\n");
break;
case 0x0080:
if (data & IAR_ACCESS_SEL)
LOGMASKED(LOG_WRITES, " Read\n");
break;
}
else
LOGMASKED(LOG_WRITES, " Write\n");
LOGMASKED(LOG_WRITES, " Parameter: %01x\n", (data & IAR_PARAM) >> 2);
return;
@ -169,3 +329,68 @@ WRITE32_MEMBER(hal2_device::write)
break;
}
}
void hal2_device::update_clock_freq(int clock_gen)
{
switch (m_bres_clock_sel[clock_gen])
{
case 0: // 48kHz
m_bres_clock_freq[clock_gen] = 48000;
break;
case 1: // 44.1kHz
m_bres_clock_freq[clock_gen] = 44100;
break;
default:
m_bres_clock_freq[clock_gen] = 0;
m_bres_clock_rate[clock_gen] = attotime::zero;
return;
}
const uint32_t mod = 0x10000 - (((uint16_t)m_bres_clock_modctrl[clock_gen] + 1) - m_bres_clock_inc[clock_gen]);
if (mod == 0)
m_bres_clock_rate[clock_gen] = attotime::from_ticks(1, m_bres_clock_freq[clock_gen] * m_bres_clock_inc[clock_gen]);
else
m_bres_clock_rate[clock_gen] = attotime::from_ticks(mod, m_bres_clock_freq[clock_gen] * m_bres_clock_inc[clock_gen]);
}
attotime hal2_device::get_rate(const uint32_t channel)
{
if ((channel == m_codeca_channel || channel == (3 - m_codeca_channel)) && m_codeca_clock > 0 && m_codeca_channel_count > 0)
return m_bres_clock_rate[m_codeca_clock - 1] / m_codeca_channel_count;
if ((channel == m_codecb_channel || channel == (3 - m_codecb_channel)) && m_codecb_clock > 0 && m_codecb_channel_count > 0)
return m_bres_clock_rate[m_codecb_clock - 1] / m_codecb_channel_count;
return attotime::zero;
}
void hal2_device::dma_write(uint32_t channel, int16_t data)
{
if (channel >= 2)
return;
if (m_curr_dac)
m_rdac->write(data);
else
m_ldac->write(data);
m_curr_dac++;
if (m_curr_dac == m_codeca_channel_count)
m_curr_dac = 0;
}
void hal2_device::device_add_mconfig(machine_config &config)
{
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();
DAC_16BIT_R2R_TWOS_COMPLEMENT(config, m_ldac, 0);
m_ldac->add_route(ALL_OUTPUTS, "lspeaker", 0.25);
DAC_16BIT_R2R_TWOS_COMPLEMENT(config, m_rdac, 0);
m_rdac->add_route(ALL_OUTPUTS, "rspeaker", 0.25);
voltage_regulator_device &vreg = VOLTAGE_REGULATOR(config, "vref");
vreg.add_route(0, "ldac", 1.0, DAC_VREF_POS_INPUT);
vreg.add_route(0, "rdac", 1.0, DAC_VREF_POS_INPUT);
vreg.add_route(0, "ldac", -1.0, DAC_VREF_NEG_INPUT);
vreg.add_route(0, "rdac", -1.0, DAC_VREF_NEG_INPUT);
}

View File

@ -11,6 +11,10 @@
#pragma once
#include "sound/dac.h"
#include "sound/volt_reg.h"
#include "speaker.h"
class hal2_device : public device_t
{
public:
@ -24,17 +28,30 @@ public:
DECLARE_WRITE32_MEMBER(write);
DECLARE_READ32_MEMBER(read);
attotime get_rate(const uint32_t channel);
void set_right_volume(uint8_t vol) { m_rdac->set_output_gain(ALL_OUTPUTS, vol / 255.0f); }
void set_left_volume(uint8_t vol) { m_ldac->set_output_gain(ALL_OUTPUTS, vol / 255.0f); }
void dma_write(uint32_t channel, int16_t data);
protected:
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_add_mconfig(machine_config &config) override;
void update_clock_freq(int clock_gen);
enum
{
IAR_TYPE = 0xf000,
IAR_NUM = 0x0f00,
IAR_ACCESS_SEL = 0x0080,
IAR_PARAM = 0x000c,
IAR_RB_INDEX = 0x0003,
IAR_TYPE = 0xf000,
IAR_TYPE_SHIFT = 12,
IAR_NUM = 0x0f00,
IAR_NUM_SHIFT = 8,
IAR_ACCESS_SEL = 0x0080,
IAR_PARAM = 0x000c,
IAR_PARAM_SHIFT = 2,
IAR_RB_INDEX = 0x0003
};
enum
@ -57,9 +74,38 @@ protected:
INDIRECT_DATA3_REG = 0x0070/4,
};
enum
{
DAC_L,
DAC_R
};
required_device<dac_16bit_r2r_twos_complement_device> m_ldac;
required_device<dac_16bit_r2r_twos_complement_device> m_rdac;
uint32_t m_isr;
uint32_t m_iar;
uint32_t m_idr[4];
uint32_t m_codeca_ctrl[2];
uint32_t m_codeca_channel;
uint32_t m_codeca_clock;
uint32_t m_codeca_channel_count;
uint32_t m_codecb_ctrl[2];
uint32_t m_codecb_channel;
uint32_t m_codecb_clock;
uint32_t m_codecb_channel_count;
uint32_t m_bres_clock_sel[3];
uint32_t m_bres_clock_inc[3];
uint32_t m_bres_clock_modctrl[3];
uint32_t m_bres_clock_freq[3];
attotime m_bres_clock_rate[3];
uint32_t m_curr_dac;
static const uint32_t s_channel_pair[4];
};
DECLARE_DEVICE_TYPE(SGI_HAL2, hal2_device)

View File

@ -45,8 +45,6 @@ hpc3_base_device::hpc3_base_device(const machine_config &mconfig, device_type ty
, m_rtc(*this, "rtc")
, m_ioc2(*this, "ioc2")
, m_hal2(*this, "hal2")
, m_ldac(*this, "ldac")
, m_rdac(*this, "rdac")
{
}
@ -148,21 +146,6 @@ void hpc3_base_device::device_reset()
void hpc3_base_device::device_add_mconfig(machine_config &config)
{
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();
DAC_16BIT_R2R_TWOS_COMPLEMENT(config, m_ldac, 0);
m_ldac->add_route(ALL_OUTPUTS, "lspeaker", 0.25);
DAC_16BIT_R2R_TWOS_COMPLEMENT(config, m_rdac, 0);
m_rdac->add_route(ALL_OUTPUTS, "rspeaker", 0.25);
voltage_regulator_device &vreg = VOLTAGE_REGULATOR(config, "vref");
vreg.add_route(0, "ldac", 1.0, DAC_VREF_POS_INPUT);
vreg.add_route(0, "rdac", 1.0, DAC_VREF_POS_INPUT);
vreg.add_route(0, "ldac", -1.0, DAC_VREF_NEG_INPUT);
vreg.add_route(0, "rdac", -1.0, DAC_VREF_NEG_INPUT);
SGI_HAL2(config, m_hal2);
DS1386_8K(config, m_rtc, 32768);
@ -237,10 +220,7 @@ void hpc3_base_device::do_pbus_dma(uint32_t channel)
uint16_t temp16 = m_cpu_space->read_dword(dma.m_cur_ptr) >> 16;
int16_t stemp16 = (int16_t)((temp16 >> 8) | (temp16 << 8));
if (channel == 1)
m_ldac->write(stemp16);
else if (channel == 2)
m_rdac->write(stemp16);
m_hal2->dma_write(channel, stemp16);
dma.m_cur_ptr += 4;
dma.m_bytes_left -= 4;
@ -266,7 +246,7 @@ void hpc3_base_device::do_pbus_dma(uint32_t channel)
return;
}
}
dma.m_timer->adjust(attotime::from_hz(44100));
dma.m_timer->adjust(m_hal2->get_rate(channel));
}
else
{
@ -646,12 +626,12 @@ WRITE32_MEMBER(hpc3_base_device::volume_w)
if (offset == 0)
{
m_volume_r = (uint8_t)data;
m_rdac->set_output_gain(ALL_OUTPUTS, m_volume_r / 255.0f);
m_hal2->set_right_volume((uint8_t)data);
}
else
{
m_volume_l = (uint8_t)data;
m_ldac->set_output_gain(ALL_OUTPUTS, m_volume_l / 255.0f);
m_hal2->set_left_volume((uint8_t)data);
}
}
@ -765,7 +745,6 @@ WRITE32_MEMBER(hpc3_base_device::pbus4_w)
READ32_MEMBER(hpc3_base_device::pbusdma_r)
{
uint32_t channel = offset / (0x2000/4);
LOGMASKED(LOG_PBUS_DMA, "%s: PBUS DMA Channel %d Read: %08x & %08x\n", machine().describe_context(), channel, 0x1fb80000 + offset*4, mem_mask);
pbus_dma_t &dma = m_pbus_dma[channel];
uint32_t ret = 0;
@ -836,8 +815,12 @@ WRITE32_MEMBER(hpc3_base_device::pbusdma_w)
if (((data & PBUS_CTRL_DMASTART) && (data & PBUS_CTRL_LOAD_EN)) && channel < 4)
{
LOGMASKED(LOG_PBUS_DMA, " Starting DMA\n");
dma.m_timer->adjust(attotime::from_hz(44100));
dma.m_active = true;
attotime rate = m_hal2->get_rate(channel);
if (rate != attotime::zero)
{
dma.m_timer->adjust(rate);
dma.m_active = true;
}
}
break;
default:

View File

@ -16,9 +16,6 @@
#include "machine/hal2.h"
#include "machine/ioc2.h"
#include "machine/wd33c9x.h"
#include "sound/dac.h"
#include "sound/volt_reg.h"
#include "speaker.h"
class hpc3_base_device : public device_t
{
@ -149,8 +146,6 @@ protected:
required_device<ds1386_device> m_rtc;
required_device<ioc2_device> m_ioc2;
required_device<hal2_device> m_hal2;
required_device<dac_16bit_r2r_twos_complement_device> m_ldac;
required_device<dac_16bit_r2r_twos_complement_device> m_rdac;
uint32_t m_intstat;
uint32_t m_cpu_aux_ctrl;