1 // license:BSD-3-Clause
2 // copyright-holders:David Haywood
3 /* Inder / Dinamic Sound Board */
4 
5 
6 #include "emu.h"
7 #include "machine/inder_sb.h"
8 
9 #include "speaker.h"
10 
11 
12 DEFINE_DEVICE_TYPE(INDER_AUDIO, inder_sb_device, "indersb", "Inder 4xDAC Sound Board")
13 
14 
inder_sb_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)15 inder_sb_device::inder_sb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
16 	: device_t(mconfig, INDER_AUDIO, tag, owner, clock)
17 	, device_mixer_interface(mconfig, *this, 2)
18 	, m_audiocpu(*this, "audiocpu")
19 	, m_ctc(*this, "ctc")
20 	, m_audiocpu_rom(*this, "audiocpu")
21 	, m_sounddata_bank(*this, "snddata")
22 {
23 }
24 
25 
26 
27 // hacks for test purposes, these are installed over the program rom so we know when irqs are actually taken
vec_bankswitch_r(offs_t offset)28 uint8_t inder_sb_device::vec_bankswitch_r(offs_t offset)
29 {
30 	if (!machine().side_effects_disabled())
31 		m_sounddata_bank->set_entry(m_soundbank[(offset & 6) >> 1] & 7);
32 	return m_audiocpu_rom[offset + 0x0020];
33 }
34 
35 
36 
megaphx_0x050002_r(offs_t offset,uint16_t mem_mask)37 uint16_t inder_sb_device::megaphx_0x050002_r(offs_t offset, uint16_t mem_mask)
38 {
39 	//logerror("%s megaphx_0x050002_r (from z80?) %04x\n", machine().describe_context(), mem_mask);
40 	machine().scheduler().synchronize();
41 	int ret = m_soundback;
42 	//m_soundback = 0;
43 	return ret;
44 }
45 
megaphx_0x050000_w(offs_t offset,uint16_t data,uint16_t mem_mask)46 void inder_sb_device::megaphx_0x050000_w(offs_t offset, uint16_t data, uint16_t mem_mask)
47 {
48 	//logerror("%s megaphx_0x050000_w (to z80?) %04x %04x\n", machine().describe_context(), data, mem_mask);
49 	machine().scheduler().synchronize();
50 
51 	m_soundsent = 0xff;
52 	m_sounddata = data;
53 
54 }
55 
56 
57 
58 
59 static const z80_daisy_config daisy_chain[] =
60 {
61 	{ "ctc" },
62 	{ nullptr }
63 };
64 
65 
sound_map(address_map & map)66 void inder_sb_device::sound_map(address_map &map)
67 {
68 	map(0x0000, 0x1fff).rom();
69 	map(0x0020, 0x0020).select(0x0006).r(FUNC(inder_sb_device::vec_bankswitch_r));
70 	map(0x4000, 0x7fff).ram();
71 	map(0x8000, 0xffff).bankr("snddata");
72 }
73 
megaphx_sound_cmd_r()74 uint8_t inder_sb_device::megaphx_sound_cmd_r()
75 {
76 	machine().scheduler().synchronize();
77 	return m_sounddata;
78 }
79 
megaphx_sound_sent_r()80 uint8_t inder_sb_device::megaphx_sound_sent_r()
81 {
82 	machine().scheduler().synchronize();
83 	int ret = m_soundsent;
84 	m_soundsent = 0;
85 	return ret;
86 }
87 
megaphx_sound_to_68k_w(uint8_t data)88 void inder_sb_device::megaphx_sound_to_68k_w(uint8_t data)
89 {
90 	//logerror("%s megaphx_sound_to_68k_w (to 68k?) %02x\n", machine().describe_context(), data);
91 	machine().scheduler().synchronize();
92 
93 	m_soundback = data;
94 }
95 
dac0_rombank_write(uint8_t data)96 void inder_sb_device::dac0_rombank_write(uint8_t data)
97 {
98 	m_soundbank[0] = data;
99 
100 //  printf("dac0_rombank_write %02x", data);
101 }
102 
dac1_rombank_write(uint8_t data)103 void inder_sb_device::dac1_rombank_write(uint8_t data)
104 {
105 	m_soundbank[1] = data;
106 //  printf("dac1_rombank_write %02x", data);
107 
108 }
109 
dac2_rombank_write(uint8_t data)110 void inder_sb_device::dac2_rombank_write(uint8_t data)
111 {
112 	m_soundbank[2] = data;
113 //  printf("dac2_rombank_write %02x", data);
114 }
115 
dac3_rombank_write(uint8_t data)116 void inder_sb_device::dac3_rombank_write(uint8_t data)
117 {
118 	m_soundbank[3] = data;
119 //  printf("dac3_rombank_write %02x", data);
120 
121 }
122 
123 
sound_io(address_map & map)124 void inder_sb_device::sound_io(address_map &map)
125 {
126 	map.global_mask(0xff);
127 	map(0x00, 0x00).w("dac0", FUNC(dac_byte_interface::data_w));
128 	map(0x01, 0x01).w("dac0vol", FUNC(dac_byte_interface::data_w));
129 	map(0x02, 0x02).w("dac1", FUNC(dac_byte_interface::data_w));
130 	map(0x03, 0x03).w("dac1vol", FUNC(dac_byte_interface::data_w));
131 	map(0x04, 0x04).w("dac2", FUNC(dac_byte_interface::data_w));
132 	map(0x05, 0x05).w("dac2vol", FUNC(dac_byte_interface::data_w));
133 	map(0x06, 0x06).w("dac3", FUNC(dac_byte_interface::data_w));
134 	map(0x07, 0x07).w("dac3vol", FUNC(dac_byte_interface::data_w));
135 
136 	// not 100% sure how rom banking works.. but each channel can specify a different bank for the 0x8000 range.  Maybe the bank happens when the interrupt triggers so each channel reads the correct data? (so we'd need to put the actual functions in the CTC callbacks)
137 	map(0x10, 0x10).w(FUNC(inder_sb_device::dac0_rombank_write));
138 	map(0x11, 0x11).w(FUNC(inder_sb_device::dac1_rombank_write));
139 	map(0x12, 0x12).w(FUNC(inder_sb_device::dac2_rombank_write));
140 	map(0x13, 0x13).w(FUNC(inder_sb_device::dac3_rombank_write));
141 
142 
143 
144 
145 	map(0x20, 0x23).rw("ctc", FUNC(z80ctc_device::read), FUNC(z80ctc_device::write));
146 
147 	map(0x30, 0x30).rw(FUNC(inder_sb_device::megaphx_sound_cmd_r), FUNC(inder_sb_device::megaphx_sound_to_68k_w));
148 	map(0x31, 0x31).r(FUNC(inder_sb_device::megaphx_sound_sent_r));
149 }
150 
151 
device_add_mconfig(machine_config & config)152 void inder_sb_device::device_add_mconfig(machine_config &config)
153 {
154 	Z80(config, m_audiocpu, 8000000); // unk freq
155 	m_audiocpu->set_daisy_config(daisy_chain);
156 	m_audiocpu->set_addrmap(AS_PROGRAM, &inder_sb_device::sound_map);
157 	m_audiocpu->set_addrmap(AS_IO, &inder_sb_device::sound_io);
158 
159 	Z80CTC(config, m_ctc, 4000000); // unk freq
160 	// runs in IM2 , vector set to 0x20 , values there are 0xCC, 0x02, 0xE6, 0x02, 0x09, 0x03, 0x23, 0x03  (so 02cc, 02e6, 0309, 0323, all of which are valid irq handlers)
161 	m_ctc->intr_callback().set_inputline(m_audiocpu, 0);
162 
163 	SPEAKER(config, "speaker").front_center();
164 	DAC_8BIT_R2R_TWOS_COMPLEMENT(config, "dac0", 0).add_route(ALL_OUTPUTS, "speaker", 0.5); // unknown DAC
165 	DAC_8BIT_R2R_TWOS_COMPLEMENT(config, "dac1", 0).add_route(ALL_OUTPUTS, "speaker", 0.5); // unknown DAC
166 	DAC_8BIT_R2R_TWOS_COMPLEMENT(config, "dac2", 0).add_route(ALL_OUTPUTS, "speaker", 0.5); // unknown DAC
167 	DAC_8BIT_R2R_TWOS_COMPLEMENT(config, "dac3", 0).add_route(ALL_OUTPUTS, "speaker", 0.5); // unknown DAC
168 	DAC_8BIT_R2R(config, "dac0vol", 0).set_output_range(0, 1).add_route(0, "dac0", 1.0, DAC_INPUT_RANGE_HI).add_route(0, "dac0", -1.0, DAC_INPUT_RANGE_LO); // unknown DAC
169 	DAC_8BIT_R2R(config, "dac1vol", 0).set_output_range(0, 1).add_route(0, "dac1", 1.0, DAC_INPUT_RANGE_HI).add_route(0, "dac1", -1.0, DAC_INPUT_RANGE_LO); // unknown DAC
170 	DAC_8BIT_R2R(config, "dac2vol", 0).set_output_range(0, 1).add_route(0, "dac2", 1.0, DAC_INPUT_RANGE_HI).add_route(0, "dac2", -1.0, DAC_INPUT_RANGE_LO); // unknown DAC
171 	DAC_8BIT_R2R(config, "dac3vol", 0).set_output_range(0, 1).add_route(0, "dac3", 1.0, DAC_INPUT_RANGE_HI).add_route(0, "dac3", -1.0, DAC_INPUT_RANGE_LO); // unknown DAC
172 }
173 
174 
device_start()175 void inder_sb_device::device_start()
176 {
177 	m_sounddata_bank->configure_entries(0, 8, memregion("user2")->base(), 0x8000);
178 	m_sounddata_bank->set_entry(0);
179 
180 	save_item(NAME(m_soundbank));
181 	save_item(NAME(m_soundsent));
182 	save_item(NAME(m_sounddata));
183 	save_item(NAME(m_soundback));
184 }
185 
device_reset()186 void inder_sb_device::device_reset()
187 {
188 	m_soundsent = 0;
189 	m_soundback = 0;
190 }
191