summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/k054321.cpp
blob: 21e02e9042f042259934bddf8f740f6916df579e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert

/***************************************************************************/
/*                                                                         */
/*    054321 / 054544 / 054986A                                            */
/*                                                                         */
/*    Konami sound control chip                                            */
/*                                                                         */
/***************************************************************************/

/*
  The 054321 is a sound communication latch/volume manager chip, that
  is integrated into the 054544 and 05489A hybrid chips.  The hybrid
  chips also include the DACs, capacitors, etc needed for the audio
  output.

  The 054321 manages three latches (maybe four) to allow communication
  between the main cpu and the sound cpu, and provides two independent
  busses to ensure decoupling.  It also manages one global volume and
  a per-channel mute for two channels.

  Volume setting is a little strange, with one address to reset it to
  zero and another to increment it by one.  Accepted volume range
  seems to be 1-60, with 40 for "normal".

  The chip seems to be an intermediate step between the 053260
  (full-on sound chip with dual busses and internal latches for
  communication) and the 056800 (MIRAC, similar to the 054321 but
  4-channel).
*/

#include "emu.h"
#include "k054321.h"

#include <math.h>

DEFINE_DEVICE_TYPE(K054321, k054321_device, "k054321", "K054321 Maincpu-Soundcpu interface")

void k054321_device::main_map(address_map &map)
{
	map(0x0, 0x0).w(FUNC(k054321_device::active_w));
	map(0x2, 0x2).w(FUNC(k054321_device::volume_reset_w));
	map(0x3, 0x3).w(FUNC(k054321_device::volume_up_w));
	map(0x4, 0x4).w(FUNC(k054321_device::dummy_w));
	map(0x6, 0x6).w(FUNC(k054321_device::main1_w));
	map(0x7, 0x7).w(FUNC(k054321_device::main2_w));
	map(0x8, 0x8).r(FUNC(k054321_device::busy_r));
	map(0xa, 0xa).r(FUNC(k054321_device::sound1_r));
}

void k054321_device::sound_map(address_map &map)
{
	map(0x0, 0x0).w(FUNC(k054321_device::sound1_w));
	map(0x2, 0x2).r(FUNC(k054321_device::main1_r));
	map(0x3, 0x3).r(FUNC(k054321_device::main2_r));
}

k054321_device::k054321_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	device_t(mconfig, K054321, tag, owner, clock),
	m_left(*this, finder_base::DUMMY_TAG),
	m_right(*this, finder_base::DUMMY_TAG)
{
}

void k054321_device::device_start()
{
	// make sure that device_sound_interface is configured
	if (!m_left->inputs() && !m_right->inputs())
		throw device_missing_dependencies();

	// remember initial input gains
	m_left_gains = std::make_unique<float[]>(m_left->inputs());
	m_right_gains = std::make_unique<float[]>(m_right->inputs());

	for (int i = 0; i < m_left->inputs(); i++)
		m_left_gains[i] = m_left->input_gain(i);
	for (int i = 0; i < m_right->inputs(); i++)
		m_right_gains[i] = m_right->input_gain(i);

	// register for savestates
	save_item(NAME(m_main1));
	save_item(NAME(m_main2));
	save_item(NAME(m_sound1));
	save_item(NAME(m_volume));
	save_item(NAME(m_active));
}

READ8_MEMBER( k054321_device::main1_r)
{
	return m_main1;
}

WRITE8_MEMBER(k054321_device::main1_w)
{
	m_main1 = data;
}

READ8_MEMBER( k054321_device::main2_r)
{
	return m_main2;
}

WRITE8_MEMBER(k054321_device::main2_w)
{
	m_main2 = data;
}

READ8_MEMBER( k054321_device::sound1_r)
{
	return m_sound1;
}

WRITE8_MEMBER(k054321_device::sound1_w)
{
	m_sound1 = data;
}

WRITE8_MEMBER(k054321_device::volume_reset_w)
{
	m_volume = 0;
	propagate_volume();
}

WRITE8_MEMBER(k054321_device::volume_up_w)
{
	// assume that max volume is 64
	if (data && m_volume < 64)
	{
		m_volume++;
		propagate_volume();
	}
}

READ8_MEMBER(k054321_device::busy_r)
{
	return 0; // bit0 = 1 means busy
}

WRITE8_MEMBER(k054321_device::active_w)
{
	m_active = data;
	propagate_volume();
}

WRITE8_MEMBER(k054321_device::dummy_w)
{
	if(data != 0x4a)
		logerror("unexpected dummy_w %02x\n", data);
}

void k054321_device::propagate_volume()
{
	double vol = pow(2, (m_volume - 40)/10.0);

	for (int i = 0; i < m_left->inputs(); i++)
		m_left->set_input_gain(i, m_active & 2 ? vol * m_left_gains[i] : 0.0);
	for (int i = 0; i < m_right->inputs(); i++)
		m_right->set_input_gain(i, m_active & 1 ? vol * m_right_gains[i] : 0.0);
}