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