summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound/mb87077.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/sound/mb87077.cpp')
-rw-r--r--src/devices/sound/mb87077.cpp181
1 files changed, 181 insertions, 0 deletions
diff --git a/src/devices/sound/mb87077.cpp b/src/devices/sound/mb87077.cpp
new file mode 100644
index 00000000000..495e0072e90
--- /dev/null
+++ b/src/devices/sound/mb87077.cpp
@@ -0,0 +1,181 @@
+// license:BSD-3-Clause
+// copyright-holders:Fabio Priuli, Philip Bennett, hap
+/*****************************************************************************
+
+ Fujitsu MB87078 6-bit, 4-channel electronic volume controller emulator
+
+ An excerpt from the datasheet about the chip functionality:
+ "A digital signal input controls gain every 0.5 dB step from 0dB to -32dB.
+ - Gain variable range: 0 dB to -32 dB by 0.5dB or -infinity
+ - Gain variable range is expanded to connect two channels serially (0 dB to -64 dB)
+ - Each channel gain can be set respectively
+ - Test function is provided (to confirm internal data)
+ - Data is initialized by reset signal (all channels are set to 0dB)
+ - Logic I/O is TTL comatible"
+
+ There are 6 digital data input/output pins and DSEL pin that selects
+ the group (there are two) of internal registers to be read/written.
+
+ Group 0 is 6-bit gain latch
+ Group 1 is 5-bit control latch (2-bits are channel select and 3-bits are volume control)
+
+ Digital I/O Setting:
+ /TC DSEL D0 D1 D2 D3 D4 D5 I/O MODES (when /TC==H ->write)
+ H H DSC1 DSC2 EN C0 C32 X Input mode
+ H L GD0 GD1 GD2 GD3 GD4 GD5 (set)
+ L H DSC1 DSC2 EN C0 C32 L Output mode
+ L L GD0 GD1 GD2 GD3 GD4 GD5 (check)
+
+ Channel Setting:
+ DSC2 DSC1 CHANNEL
+ L L 0
+ L H 1
+ H L 2
+ H H 3
+
+ Electrical Volume Setting:
+ DATA* GAIN
+ GD5 GD4 GD3 GD2 GD1 GD0 EN C0 C32 (dB)
+ 1 1 1 1 1 1 1 0 0 0
+ 1 1 1 1 1 0 1 0 0 -0.5
+ 1 1 1 1 0 1 1 0 0 -1
+ 1 1 1 1 0 0 1 0 0 -1.5
+ 1 1 1 0 1 1 1 0 0 -2
+ [..........................................]
+ 0 0 0 0 0 1 1 0 0 -31
+ 0 0 0 0 0 0 1 0 0 -31.5
+ X X X X X X 1 X 1 -32
+ X X X X X X 1 1 0 0
+ X X X X X X 0 X X -infinity
+
+ X=don't care
+ * When reset, DATA is set to 0 dB (code 111111 100)
+
+
+ MB87078 pins and assigned interface variables/functions:
+
+ /[ 1] D0 /TC [24]
+ | [ 2] D1 /WR [23]
+ data_w()| [ 3] D2 /CE [22]
+ data_r()| [ 4] D3 DSEL [21]-data_w()/data_r() (offset)
+ (data) | [ 5] D4 /RESET [20]
+ \[ 6] D5 /PD [19]
+ [ 7] DGND VDD [18]
+ [ 8] AGND 1/2 VDD [17]
+ [ 9] AIN0 AOUT3 [16]
+ [10] AOUT0 AIN3 [15]
+ [11] AIN1 AOUT2 [14]
+ [12] AOUT1 AIN2 [13]
+
+ MB87077 pin 8 is VSS, pin 17 is AGND, the rest is same as MB87078.
+
+*****************************************************************************/
+
+#include "emu.h"
+#include "mb87077.h"
+
+
+/*****************************************************************************
+ DEVICE INTERFACE
+*****************************************************************************/
+
+DEFINE_DEVICE_TYPE(MB87078, mb87078_device, "mb87078", "MB87078 Volume Controller")
+
+mb87078_device::mb87078_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, MB87078, tag, owner, clock),
+ m_gain_changed_cb(*this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mb87078_device::device_start()
+{
+ m_data = 0;
+ m_control = 0;
+
+ // invalidate gain index
+ for (int i = 0; i < 4; i++)
+ m_gain_index[i] = 66;
+
+ // output volume table, 0dB to -32dB in steps of -0.5dB
+ for (int i = 0; i < (64+1); i++)
+ m_lut_gains[i] = pow(10.0, (-0.5 * i) / 20.0);
+ m_lut_gains[65] = 0.0; // -infinity
+ m_lut_gains[66] = m_lut_gains[0];
+
+ // register for savestates
+ save_item(NAME(m_gain_index));
+ save_item(NAME(m_channel_latch));
+ save_item(NAME(m_data));
+ save_item(NAME(m_control));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void mb87078_device::device_reset()
+{
+ // all channels enabled, and set at 0dB
+ for (int i = 0; i < 4; i++)
+ m_channel_latch[i] = 0x7f;
+
+ gain_recalc();
+}
+
+
+/*****************************************************************************
+ IMPLEMENTATION
+*****************************************************************************/
+
+void mb87078_device::gain_recalc()
+{
+ for (int i = 0; i < 4; i++)
+ {
+ int gain_index;
+
+ // EN = 0: -infinity dB
+ if (~m_channel_latch[i] & 0x40)
+ gain_index = 65;
+
+ // C32 = 1: -32dB
+ else if (m_channel_latch[i] & 0x100)
+ gain_index = 64;
+
+ // C0 = 1: 0dB
+ else if (m_channel_latch[i] & 0x80)
+ gain_index = 0;
+
+ else
+ gain_index = ~m_channel_latch[i] & 0x3f;
+
+ // callback on change
+ if (gain_index != m_gain_index[i])
+ {
+ m_gain_index[i] = gain_index;
+ m_gain_changed_cb((offs_t)i, gain_percent_r(i));
+ }
+ }
+}
+
+void mb87078_device::data_w(offs_t offset, u8 data)
+{
+ if (offset & 1)
+ m_control = data & 0x1f;
+ else
+ {
+ m_data = data & 0x3f;
+
+ // set channel volume gain
+ m_channel_latch[m_control & 3] = (m_control << 4 & 0x1c0) | m_data;
+ gain_recalc();
+ }
+}
+
+u8 mb87078_device::data_r(offs_t offset)
+{
+ return (offset & 1) ? m_control : m_data;
+}