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_opn_psg(int ch_num)
25 if((ch_num < 0) || (ch_num > 3)) return;
27 opn_cmdreg[ch_num] = 0;
28 opn_address[ch_num] = 0;
30 opn_prescaler_type[ch_num] = 1;
31 memset(opn_regs[ch_num], 0x00, 0x100 * sizeof(uint8_t));
33 #if !defined(_FM77AV_VARIANTS)
36 write_opn_reg(3, 0x2e, 0);
37 write_opn_reg(3, 0x27, 0);
38 write_opn_reg(3, 0, 0);
43 if(opn[ch_num] != NULL) {
45 write_opn_reg(ch_num, 0x2e, 0);
46 write_opn_reg(ch_num, 0x27, 0);
51 void FM7_MAINIO::reset_sound(void)
55 for(i = 0; i < 4; i++) {
59 #if defined(_FM77AV_VARIANTS)
64 connect_opn = connect_whg = connect_thg = false;
65 if(opn_psg_77av) connect_opn = true;
69 #if defined(_FM77AV_VARIANTS)
74 switch(config.sound_type) {
104 pcm1bit->write_signal(SIG_PCM1BIT_MUTE, 0x01, 0x01);
105 pcm1bit->write_signal(SIG_PCM1BIT_ON, 0x00, 0x01);
107 opn[0]->write_signal(SIG_YM2203_MUTE, !connect_opn ? 0xffffffff : 0x00000000, 0xffffffff);
108 opn[1]->write_signal(SIG_YM2203_MUTE, !connect_whg ? 0xffffffff : 0x00000000, 0xffffffff);
109 opn[2]->write_signal(SIG_YM2203_MUTE, !connect_thg ? 0xffffffff : 0x00000000, 0xffffffff);
110 # if !defined(_FM77AV_VARIANTS)
111 # if defined(USE_AY_3_8910_AS_PSG)
112 psg->write_signal(SIG_AY_3_891X_MUTE, 0x00000000, 0xffffffff);
114 psg->write_signal(SIG_YM2203_MUTE, 0x00000000, 0xffffffff);
120 void FM7_MAINIO::set_psg(uint8_t val)
122 if(opn_psg_77av) return set_opn(0, val); // 77AV ETC
126 uint8_t FM7_MAINIO::get_psg(void)
135 * $fd0d : After 77AV, this is OPN.
137 void FM7_MAINIO::set_psg_cmd(uint8_t cmd)
149 // Write to FD16, same as
150 void FM7_MAINIO::write_opn_reg(int index, uint32_t addr, uint32_t data)
152 //out_debug_log("OPN_WRITE: #%d REG=%02x VAL=%02x\n", index, addr, data);
153 static const uint32_t mask[16] = { // Parameter is related by XM7. Thanks Ryu.
154 0xff, 0x0f, 0xff, 0x0f,
155 0xff, 0x0f, 0x1f, 0xff,
156 0x1f, 0x1f, 0x1f, 0xff,
157 0xff, 0x0f, 0xff, 0xff
160 # if !defined(_FM77AV_VARIANTS)
161 if(index == 3) { // PSG
162 data = data & mask[addr & 0x0f];
163 psg->write_io8(0, addr & 0x0f);
164 psg->write_io8(1, data);
165 opn_regs[index][addr & 0x0f] = data;
169 if(addr < 0x10) { // PSG part
170 data = data & mask[addr]; // Right?
171 } else if((addr >= 0x2d) && (addr < 0x30)) { // Prescaler
174 if(opn_prescaler_type[index] != 1) {
175 opn_prescaler_type[index] = 0;
176 opn[index]->write_io8(0, addr);
177 for(int ii = 0x2d; ii <= 0x2f; ii++) opn_regs[index][ii] = 0;
178 opn_regs[index][addr] = 0xff;
181 default: // 0x2e, 0x2f
182 opn_prescaler_type[index] = addr - 0x2d;
183 opn[index]->write_io8(0, addr);
184 for(int ii = 0x2d; ii <= 0x2f; ii++) opn_regs[index][ii] = 0;
185 opn_regs[index][addr] = 0xff;
189 }/* else if(addr == 0xff) { // Check : from XM7.
190 if((opn_regs[index][0x27] & 0xc0) != 0x80) {
191 opn_regs[index][addr] = data;
196 opn[index]->write_io8(0, addr);
197 opn[index]->write_io8(1, data);
198 opn_regs[index][addr] = data;
200 # if !defined(_FM77AV_VARIANTS)
202 if(psg != NULL) psg->set_reg(addr & 0x0f, data);
206 if(opn[index] != NULL) opn[index]->set_reg(addr, data);
208 opn_regs[index][addr] = data;
213 void FM7_MAINIO::set_opn(int index, uint8_t val)
215 if((index > 3) || (index < 0)) return;
216 if((index == 0) && (!connect_opn)) return;
217 if((index == 1) && (!connect_whg)) return;
218 if((index == 2) && (!connect_thg)) return;
219 if((index == 3) && (opn_psg_77av)) return;
220 # if !defined(_FM77AV_VARIANTS)
222 if(psg == NULL) return;
225 if(opn[index] == NULL) {
228 opn_data[index] = val;
229 switch(opn_cmdreg[index]) {
230 case 2: // Write data
231 write_opn_reg(index, opn_address[index], opn_data[index]);
233 case 3: // Register address
234 # if !defined(_FM77AV_VARIANTS)
236 opn_address[index] = val & 0x0f;
237 if(psg != NULL) psg->write_io8(0, opn_address[index]);
241 opn_address[index] = val;
242 if(opn[index] != NULL) opn[index]->write_io8(0, opn_address[index]);
250 uint8_t FM7_MAINIO::get_opn(int index)
253 if((index > 3) || (index < 0)) return val;
254 if((index == 0) && (!connect_opn)) return val;
255 if((index == 1) && (!connect_whg)) return val;
256 if((index == 2) && (!connect_thg)) return val;
257 if((index == 3) && (opn_psg_77av)) return val;
258 # if !defined(_FM77AV_VARIANTS)
260 if(psg == NULL) return val;
263 if(opn[index] == NULL) {
266 // 20190922 from XM7 3477a.
267 static const uint8_t opn_bitmask[16] = {
268 0xff, 0x0f, 0xff, 0x0f,
269 0xff, 0x0f, 0x1f, 0xff,
270 0x1f, 0x1f, 0x1f, 0xff,
271 0xff, 0x0f, 0xff, 0xff,
274 if(index == 3) opn_cmdreg[index] = opn_cmdreg[index] & 0x03;
276 switch(opn_cmdreg[index]) {
277 case 0: // Unavailable
281 // val = opn_data[index];
282 if((opn_address[index] == 14) || (opn_address[index] == 15)) {
284 val = opn_data[index]; // OK?
287 # if !defined(_FM77AV_VARIANTS)
289 // if(opn_address[index] < 0x10) {
290 val = psg->read_io8(1) & opn_bitmask[opn_address[index] & 15];
295 val = opn[index]->read_io8(1);
299 case 2: // Write address
300 val = opn_data[index];
302 case 3: // Write to reg
303 val = opn_data[index];
308 //opn_stat[index] = opn[index]->read_io8(0) & 0x03;
309 opn_stat[index] = opn[index]->read_io8(0);
310 val = opn_stat[index];
313 case 0x09: // Joystick
314 if(index != 0) return 0xff;
315 if(opn_address[0] == 0x0e) {
316 //return opn[0]->read_signal(SIG_YM2203_PORT_A);
317 return joystick->read_data8(0);
331 void FM7_MAINIO::set_opn_cmd(int index, uint8_t cmd)
333 if((index >= 4) || (index < 0)) return;
334 if((index == 0) && (!connect_opn)) return;
335 if((index == 1) && (!connect_whg)) return;
336 if((index == 2) && (!connect_thg)) return;
337 if((index == 3) && (opn_psg_77av)) return ;
338 # if !defined(_FM77AV_VARIANTS)
340 if(psg == NULL) return;
343 opn_cmdreg[index] = cmd & 0x0f;
344 if(index == 3) opn_cmdreg[index] = opn_cmdreg[index] & 0x03;
346 uint8_t val = opn_data[index];
347 switch(opn_cmdreg[index]) {
351 case 2: // Write data
352 write_opn_reg(index, opn_address[index], opn_data[index]);
354 case 3: // Register address
355 # if !defined(_FM77AV_VARIANTS)
357 opn_address[index] = val & 0x0f;
358 if(psg != NULL) psg->write_io8(0, opn_address[index]);
362 opn_address[index] = val;
363 if(opn[index] != NULL) opn[index]->write_io8(0, opn_address[index]);
373 uint8_t FM7_MAINIO::get_extirq_whg(void)
376 if(intstat_whg && connect_whg) val &= ~0x08;
380 uint8_t FM7_MAINIO::get_extirq_thg(void)
383 if(intstat_thg && connect_thg) val &= ~0x08;
388 void FM7_MAINIO::set_beep(uint32_t data) // fd03
390 bool flag = ((data & 0xc0) != 0);
391 pcm1bit->write_signal(SIG_PCM1BIT_MUTE, ~data, 0x01);
393 if(flag != beep_flag) {
396 pcm1bit->write_signal(SIG_PCM1BIT_SIGNAL, 1, 1);
397 pcm1bit->write_signal(SIG_PCM1BIT_ON, 1, 1);
400 pcm1bit->write_signal(SIG_PCM1BIT_SIGNAL, 0, 1);
401 pcm1bit->write_signal(SIG_PCM1BIT_ON, 0, 1);
406 if(flag != beep_flag) {
409 pcm1bit->write_signal(SIG_PCM1BIT_SIGNAL, data, 0xc0);
410 pcm1bit->write_signal(SIG_PCM1BIT_ON, data, 0xc0);
413 if((data & 0x40) != 0) {
414 // BEEP ON, after 205ms, BEEP OFF.
419 // SIGNAL / FM7_MAINIO_BEEP
420 void FM7_MAINIO::set_beep_oneshot(void) // SUB:D4xx
424 pcm1bit->write_signal(SIG_PCM1BIT_ON, 1, 1);
425 if(event_beep_oneshot >= 0) cancel_event(this, event_beep_oneshot);
426 register_event(this, EVENT_BEEP_OFF, 205.0 * 1000.0, false, &event_beep_oneshot); // NEXT CYCLE
427 //if(event_beep <= -1) {
428 // register_event(this, EVENT_BEEP_CYCLE, (1000.0 * 1000.0) / (1200.0 * 2.0), true, &event_beep);
433 void FM7_MAINIO::event_beep_off(void)
437 pcm1bit->write_signal(SIG_PCM1BIT_ON, 0, 1);
438 event_beep_oneshot = -1;
442 void FM7_MAINIO::event_beep_cycle(void)
444 beep_snd = !beep_snd;
446 pcm1bit->write_signal(SIG_PCM1BIT_SIGNAL, beep_snd ? 1 : 0, 1);
450 bool FM7_MAINIO::load_state_opn(FILEIO *state_fio, bool loading)
452 state_fio->StateValue(connect_opn);
453 state_fio->StateValue(connect_whg);
454 state_fio->StateValue(connect_thg);
456 state_fio->StateValue(opn_psg_77av);
457 state_fio->StateArray(opn_address, sizeof(opn_address), 1);
458 state_fio->StateArray(opn_data, sizeof(opn_data), 1);
459 state_fio->StateArray(opn_stat, sizeof(opn_stat), 1);
460 state_fio->StateArray(opn_cmdreg, sizeof(opn_cmdreg), 1);
461 state_fio->StateArray(opn_prescaler_type, sizeof(opn_prescaler_type), 1);
462 state_fio->StateArray(&opn_regs[0][0], sizeof(opn_regs), 1);