2 * FM-7 Main I/O [sound.cpp]
3 * - PSG, OPN, and Buzzer.
5 * Author: K.Ohta <whatisthis.sowhat _at_ gmail.com>
8 * Mar 19, 2015 : Initial, split from fm7_mainio.cpp.
12 #include "../pcm1bit.h"
13 #include "../datarec.h"
14 #include "../ym2203.h"
15 #include "fm7_mainio.h"
16 #include "../ay_3_891x.h"
17 #include "../../config.h"
18 #include "./joystick.h"
23 void FM7_MAINIO::reset_sound(void)
28 for(i = 0; i < 3; i++) {
33 opn_prescaler_type[i] = 1;
34 memset(opn_regs[i], 0x00, 0x100 * sizeof(uint8_t));
37 write_opn_reg(i, 0x2e, 0);
38 write_opn_reg(i, 0x27, 0);
42 #if !defined(_FM77AV_VARIANTS)
45 write_opn_reg(3, 0x2e, 0);
46 write_opn_reg(3, 0x27, 0);
49 #if defined(_FM77AV_VARIANTS)
54 connect_opn = connect_whg = connect_thg = false;
55 if(opn_psg_77av) connect_opn = true;
59 #if defined(_FM77AV_VARIANTS)
64 switch(config.sound_type) {
94 pcm1bit->write_signal(SIG_PCM1BIT_MUTE, 0x01, 0x01);
95 pcm1bit->write_signal(SIG_PCM1BIT_ON, 0x00, 0x01);
97 opn[0]->write_signal(SIG_YM2203_MUTE, !connect_opn ? 0xffffffff : 0x00000000, 0xffffffff);
98 opn[1]->write_signal(SIG_YM2203_MUTE, !connect_whg ? 0xffffffff : 0x00000000, 0xffffffff);
99 opn[2]->write_signal(SIG_YM2203_MUTE, !connect_thg ? 0xffffffff : 0x00000000, 0xffffffff);
100 # if !defined(_FM77AV_VARIANTS)
101 # if defined(USE_AY_3_8910_AS_PSG)
102 psg->write_signal(SIG_AY_3_891X_MUTE, 0x00000000, 0xffffffff);
104 psg->write_signal(SIG_YM2203_MUTE, 0x00000000, 0xffffffff);
110 void FM7_MAINIO::set_psg(uint8_t val)
112 if(opn_psg_77av) return set_opn(0, val); // 77AV ETC
116 uint8_t FM7_MAINIO::get_psg(void)
125 * $fd0d : After 77AV, this is OPN.
127 void FM7_MAINIO::set_psg_cmd(uint8_t cmd)
139 // Write to FD16, same as
140 void FM7_MAINIO::write_opn_reg(int index, uint32_t addr, uint32_t data)
142 //out_debug_log("OPN_WRITE: #%d REG=%02x VAL=%02x\n", index, addr, data);
143 static const uint32_t mask[16] = { // Parameter is related by XM7. Thanks Ryu.
144 0xff, 0x0f, 0xff, 0x0f,
145 0xff, 0x0f, 0x1f, 0xff,
146 0x1f, 0x1f, 0x1f, 0xff,
147 0xff, 0x0f, 0xff, 0xff
150 # if !defined(_FM77AV_VARIANTS)
151 if(index == 3) { // PSG
152 data = data & mask[addr & 0x0f];
153 psg->write_io8(0, addr & 0x0f);
154 psg->write_io8(1, data);
155 opn_regs[index][addr & 0x0f] = data;
159 if(addr < 0x10) { // PSG part
160 data = data & mask[addr]; // Right?
161 } else if((addr >= 0x2d) && (addr < 0x30)) { // Prescaler
164 if(opn_prescaler_type[index] != 1) {
165 opn_prescaler_type[index] = 0;
166 opn[index]->write_io8(0, addr);
167 for(int ii = 0x2d; ii <= 0x2f; ii++) opn_regs[index][ii] = 0;
168 opn_regs[index][addr] = 0xff;
171 default: // 0x2e, 0x2f
172 opn_prescaler_type[index] = addr - 0x2d;
173 opn[index]->write_io8(0, addr);
174 for(int ii = 0x2d; ii <= 0x2f; ii++) opn_regs[index][ii] = 0;
175 opn_regs[index][addr] = 0xff;
179 }/* else if(addr == 0xff) { // Check : from XM7.
180 if((opn_regs[index][0x27] & 0xc0) != 0x80) {
181 opn_regs[index][addr] = data;
186 opn[index]->write_io8(0, addr);
187 opn[index]->write_io8(1, data);
188 opn_regs[index][addr] = data;
190 # if !defined(_FM77AV_VARIANTS)
192 if(psg != NULL) psg->set_reg(addr & 0x0f, data);
196 if(opn[index] != NULL) opn[index]->set_reg(addr, data);
198 opn_regs[index][addr] = data;
203 void FM7_MAINIO::set_opn(int index, uint8_t val)
205 if((index > 3) || (index < 0)) return;
206 if((index == 0) && (!connect_opn)) return;
207 if((index == 1) && (!connect_whg)) return;
208 if((index == 2) && (!connect_thg)) return;
209 if((index == 3) && (opn_psg_77av)) return;
210 # if !defined(_FM77AV_VARIANTS)
212 if(psg == NULL) return;
215 if(opn[index] == NULL) {
218 opn_data[index] = val;
219 switch(opn_cmdreg[index]) {
220 case 2: // Write data
221 write_opn_reg(index, opn_address[index], opn_data[index]);
223 case 3: // Register address
224 # if !defined(_FM77AV_VARIANTS)
226 opn_address[index] = val & 0x0f;
227 if(psg != NULL) psg->write_io8(0, opn_address[index]);
231 opn_address[index] = val;
232 if(opn[index] != NULL) opn[index]->write_io8(0, opn_address[index]);
240 uint8_t FM7_MAINIO::get_opn(int index)
243 if((index > 2) || (index < 0)) return val;
244 if((index == 0) && (!connect_opn)) return val;
245 if((index == 1) && (!connect_whg)) return val;
246 if((index == 2) && (!connect_thg)) return val;
247 if((index == 3) && (opn_psg_77av)) return val;
248 # if !defined(_FM77AV_VARIANTS)
250 if(psg == NULL) return val;
253 if(opn[index] == NULL) {
256 if(index == 3) opn_cmdreg[index] = opn_cmdreg[index] & 0x03;
257 switch(opn_cmdreg[index]) {
258 case 0: // Unavailable
262 // val = opn_data[index];
263 if((opn_address[index] == 14) || (opn_address[index] == 15)) {
265 val = opn_data[index]; // OK?
268 # if !defined(_FM77AV_VARIANTS)
270 val = psg->read_io8(1);
274 val = opn[index]->read_io8(1);
278 case 2: // Write address
279 val = opn_data[index];
281 case 3: // Write to reg
282 val = opn_data[index];
287 //opn_stat[index] = opn[index]->read_io8(0) & 0x03;
288 opn_stat[index] = opn[index]->read_io8(0);
289 val = opn_stat[index];
292 case 0x09: // Joystick
293 if(index != 0) return 0xff;
294 if(opn_address[0] == 0x0e) {
295 //return opn[0]->read_signal(SIG_YM2203_PORT_A);
296 return joystick->read_data8(0);
310 void FM7_MAINIO::set_opn_cmd(int index, uint8_t cmd)
312 if((index >= 4) || (index < 0)) return;
313 if((index == 0) && (!connect_opn)) return;
314 if((index == 1) && (!connect_whg)) return;
315 if((index == 2) && (!connect_thg)) return;
316 if((index == 3) && (opn_psg_77av)) return ;
317 # if !defined(_FM77AV_VARIANTS)
319 if(psg == NULL) return;
322 opn_cmdreg[index] = cmd & 0x0f;
323 if(index == 3) opn_cmdreg[index] = opn_cmdreg[index] & 0x03;
325 uint8_t val = opn_data[index];
326 switch(opn_cmdreg[index]) {
330 case 2: // Write data
331 write_opn_reg(index, opn_address[index], opn_data[index]);
333 case 3: // Register address
334 # if !defined(_FM77AV_VARIANTS)
336 opn_address[index] = val & 0x0f;
337 if(psg != NULL) psg->write_io8(0, opn_address[index]);
341 opn_address[index] = val;
342 if(opn[index] != NULL) opn[index]->write_io8(0, opn_address[index]);
352 uint8_t FM7_MAINIO::get_extirq_whg(void)
355 if(intstat_whg && connect_whg) val &= ~0x08;
359 uint8_t FM7_MAINIO::get_extirq_thg(void)
362 if(intstat_thg && connect_thg) val &= ~0x08;
367 void FM7_MAINIO::set_beep(uint32_t data) // fd03
369 bool flag = ((data & 0xc0) != 0);
370 pcm1bit->write_signal(SIG_PCM1BIT_MUTE, ~data, 0x01);
372 if(flag != beep_flag) {
375 pcm1bit->write_signal(SIG_PCM1BIT_SIGNAL, 1, 1);
376 pcm1bit->write_signal(SIG_PCM1BIT_ON, 1, 1);
379 pcm1bit->write_signal(SIG_PCM1BIT_SIGNAL, 0, 1);
380 pcm1bit->write_signal(SIG_PCM1BIT_ON, 0, 1);
385 if(flag != beep_flag) {
388 pcm1bit->write_signal(SIG_PCM1BIT_SIGNAL, data, 0xc0);
389 pcm1bit->write_signal(SIG_PCM1BIT_ON, data, 0xc0);
392 if((data & 0x40) != 0) {
393 // BEEP ON, after 205ms, BEEP OFF.
398 // SIGNAL / FM7_MAINIO_BEEP
399 void FM7_MAINIO::set_beep_oneshot(void) // SUB:D4xx
403 pcm1bit->write_signal(SIG_PCM1BIT_ON, 1, 1);
404 if(event_beep_oneshot >= 0) cancel_event(this, event_beep_oneshot);
405 register_event(this, EVENT_BEEP_OFF, 205.0 * 1000.0, false, &event_beep_oneshot); // NEXT CYCLE
406 //if(event_beep <= -1) {
407 // register_event(this, EVENT_BEEP_CYCLE, (1000.0 * 1000.0) / (1200.0 * 2.0), true, &event_beep);
412 void FM7_MAINIO::event_beep_off(void)
416 pcm1bit->write_signal(SIG_PCM1BIT_ON, 0, 1);
417 event_beep_oneshot = -1;
421 void FM7_MAINIO::event_beep_cycle(void)
423 beep_snd = !beep_snd;
425 pcm1bit->write_signal(SIG_PCM1BIT_SIGNAL, beep_snd ? 1 : 0, 1);
429 bool FM7_MAINIO::decl_state_opn(FILEIO *state_fio, bool loading)
431 state_fio->StateBool(connect_opn);
432 state_fio->StateBool(connect_whg);
433 state_fio->StateBool(connect_thg);
435 state_fio->StateBool(opn_psg_77av);
436 state_fio->StateBuffer(opn_address, sizeof(opn_address), 1);
437 state_fio->StateBuffer(opn_data, sizeof(opn_data), 1);
438 state_fio->StateBuffer(opn_stat, sizeof(opn_stat), 1);
439 state_fio->StateBuffer(opn_cmdreg, sizeof(opn_cmdreg), 1);
440 state_fio->StateBuffer(opn_prescaler_type, sizeof(opn_prescaler_type), 1);
441 state_fio->StateBuffer(opn_regs, sizeof(opn_regs), 1);