2 Skelton for retropc emulator
4 Author : Takeda.Toshiya
7 [ AY-3-8910 / YM2203 / YM2608 ]
11 #include "../fileio.h"
13 void YM2203::initialize()
22 #ifdef SUPPORT_MAME_FM_DLL
24 // fmdll = new CFMDLL(_T("mamefm.dll"));
25 fmdll = new CFMDLL(config.fmgen_dll_path);
28 register_vline_event(this);
30 clock_prev = clock_accum = clock_busy = 0;
33 void YM2203::release()
41 #ifdef SUPPORT_MAME_FM_DLL
43 fmdll->Release(dllchip);
57 #ifdef SUPPORT_MAME_FM_DLL
59 fmdll->Reset(dllchip);
61 memset(port_log, 0, sizeof(port_log));
63 this->SetReg(0x27, 0); // stop timer
65 #ifdef SUPPORT_YM2203_PORT
66 port[0].first = port[1].first = true;
68 irq_prev = busy = false;
72 #define amask (is_ym2608 ? 3 : 1)
77 void YM2203::write_io8(uint32 addr, uint32 data)
79 switch(addr & amask) {
83 // write dummy data for prescaler
84 if(0x2d <= ch && ch <= 0x2f) {
88 clock_busy = current_clock();
96 #ifdef SUPPORT_YM2203_PORT
98 #ifdef YM2203_PORT_MODE
99 mode = (data & 0x3f) | YM2203_PORT_MODE;
103 } else if(ch == 14) {
104 #ifdef SUPPORT_YM2203_PORT_A
105 if(port[0].wreg != data || port[0].first) {
106 write_signals(&port[0].outputs, data);
108 port[0].first = false;
111 } else if(ch == 15) {
112 #ifdef SUPPORT_YM2203_PORT_B
113 if(port[1].wreg != data || port[1].first) {
114 write_signals(&port[1].outputs, data);
116 port[1].first = false;
121 // don't write again for prescaler
122 if(!(0x2d <= ch && ch <= 0x2f)) {
124 this->SetReg(ch, data);
127 clock_busy = current_clock();
138 this->SetReg(0x100 | ch1, data);
146 uint32 YM2203::read_io8(uint32 addr)
148 switch(addr & amask) {
152 /* BUSY : x : x : x : x : x : FLAGB : FLAGA */
158 status = opna->ReadStatus() & ~0x80;
161 status = opn->ReadStatus() & ~0x80;
163 // FIXME: we need to investigate the correct busy period
164 if(passed_usec(clock_busy) < 8) {
173 #ifdef SUPPORT_YM2203_PORT
175 #ifdef SUPPORT_YM2203_PORT_A
176 return (mode & 0x40) ? port[0].wreg : port[0].rreg;
178 } else if(ch == 15) {
179 #ifdef SUPPORT_YM2203_PORT_B
180 return (mode & 0x80) ? port[1].wreg : port[1].rreg;
186 return opna->GetReg(ch);
189 return opn->GetReg(ch);
193 /* BUSY : x : PCMBUSY : ZERO : BRDY : EOS : FLAGB : FLAGA */
196 uint32 status = opna->ReadStatusEx() & ~0x80;
198 // FIXME: we need to investigate the correct busy period
199 if(passed_usec(clock_busy) < 8) {
208 return opna->GetReg(0x100 | ch1);
209 // } else if(ch1 == 0x0f) {
210 // return 0x80; // from mame fm.c
218 void YM2203::write_signal(int id, uint32 data, uint32 mask)
220 if(id == SIG_YM2203_MUTE) {
221 mute = ((data & mask) != 0);
222 #ifdef SUPPORT_YM2203_PORT_A
223 } else if(id == SIG_YM2203_PORT_A) {
224 port[0].rreg = (port[0].rreg & ~mask) | (data & mask);
226 #ifdef SUPPORT_YM2203_PORT_B
227 } else if(id == SIG_YM2203_PORT_B) {
228 port[1].rreg = (port[1].rreg & ~mask) | (data & mask);
233 void YM2203::event_vline(int v, int clock)
241 void YM2203::update_count()
243 clock_accum += clock_const * passed_clock(clock_prev);
244 uint32 count = clock_accum >> 20;
252 clock_accum -= count << 20;
254 clock_prev = current_clock();
258 void YM2203::update_interrupt()
263 irq = opna->ReadIRQ();
266 irq = opn->ReadIRQ();
267 if(!irq_prev && irq) {
268 write_signals(&outputs_irq, 0xffffffff);
269 } else if(irq_prev && !irq) {
270 write_signals(&outputs_irq, 0);
276 void YM2203::mix(int32* buffer, int cnt)
278 if(cnt > 0 && !mute) {
281 opna->Mix(buffer, cnt);
284 opn->Mix(buffer, cnt);
285 #ifdef SUPPORT_MAME_FM_DLL
287 fmdll->Mix(dllchip, buffer, cnt);
293 void YM2203::init(int rate, int clock, int samples, int volf, int volp)
297 opna->Init(clock, rate, false, emu->application_path());
298 opna->SetVolumeFM(volf);
299 opna->SetVolumePSG(volp);
302 opn->Init(clock, rate, false, NULL);
303 opn->SetVolumeFM(volf);
304 opn->SetVolumePSG(volp);
309 #ifdef SUPPORT_MAME_FM_DLL
312 fmdll->Create((LPVOID*)&dllchip, clock, rate);
315 fmdll->Create((LPVOID*)&dllchip, clock * 2, rate);
317 fmdll->SetVolumeFM(dllchip, volf);
318 fmdll->SetVolumePSG(dllchip, volp);
321 DWORD dwCaps = fmdll->GetCaps(dllchip);
322 if((dwCaps & SUPPORT_FM_A) == SUPPORT_FM_A) {
325 if((dwCaps & SUPPORT_FM_B) == SUPPORT_FM_B) {
328 if((dwCaps & SUPPORT_PSG) == SUPPORT_PSG) {
331 if((dwCaps & SUPPORT_ADPCM_B) == SUPPORT_ADPCM_B) {
334 if((dwCaps & SUPPORT_RHYTHM) == SUPPORT_RHYTHM) {
339 opna->SetChannelMask(mask);
342 opn->SetChannelMask(mask);
343 fmdll->SetChannelMask(dllchip, ~mask);
349 void YM2203::SetReg(uint addr, uint data)
353 opna->SetReg(addr, data);
356 opn->SetReg(addr, data);
357 #ifdef SUPPORT_MAME_FM_DLL
359 fmdll->SetReg(dllchip, addr, data);
361 if(0x2d <= addr && addr <= 0x2f) {
362 port_log[0x2d].written = port_log[0x2e].written = port_log[0x2f].written = false;
364 port_log[addr].written = true;
365 port_log[addr].data = data;
369 void YM2203::update_timing(int new_clocks, double new_frames_per_sec, int new_lines_per_frame)
373 clock_const = (uint32)((double)chip_clock * 1024.0 * 1024.0 / (double)new_clocks / 2.0 + 0.5);
376 clock_const = (uint32)((double)chip_clock * 1024.0 * 1024.0 / (double)new_clocks + 0.5);
379 #define STATE_VERSION 2
381 void YM2203::save_state(FILEIO* state_fio)
383 state_fio->FputUint32(STATE_VERSION);
384 state_fio->FputInt32(this_device_id);
388 opna->SaveState((void *)state_fio);;
391 opn->SaveState((void *)state_fio);
392 #ifdef SUPPORT_MAME_FM_DLL
393 state_fio->Fwrite(port_log, sizeof(port_log), 1);
395 state_fio->FputUint8(ch);
396 #ifdef SUPPORT_YM2203_PORT
397 state_fio->FputUint8(mode);
400 state_fio->FputUint8(ch1);
401 state_fio->FputUint8(data1);
403 #ifdef SUPPORT_YM2203_PORT
404 for(int i = 0; i < 2; i++) {
405 state_fio->FputUint8(port[i].wreg);
406 state_fio->FputUint8(port[i].rreg);
407 state_fio->FputBool(port[i].first);
410 state_fio->FputInt32(chip_clock);
411 state_fio->FputBool(irq_prev);
412 state_fio->FputBool(mute);
413 state_fio->FputUint32(clock_prev);
414 state_fio->FputUint32(clock_accum);
415 state_fio->FputUint32(clock_const);
416 state_fio->FputUint32(clock_busy);
417 state_fio->FputBool(busy);
420 bool YM2203::load_state(FILEIO* state_fio)
422 if(state_fio->FgetUint32() != STATE_VERSION) {
425 if(state_fio->FgetInt32() != this_device_id) {
430 if(!opna->LoadState((void *)state_fio)) {
435 if(!opn->LoadState((void *)state_fio)) {
441 #ifdef SUPPORT_MAME_FM_DLL
442 state_fio->Fread(port_log, sizeof(port_log), 1);
444 ch = state_fio->FgetUint8();
445 #ifdef SUPPORT_YM2203_PORT
446 mode = state_fio->FgetUint8();
449 ch1 = state_fio->FgetUint8();
450 data1 = state_fio->FgetUint8();
452 #ifdef SUPPORT_YM2203_PORT
453 for(int i = 0; i < 2; i++) {
454 port[i].wreg = state_fio->FgetUint8();
455 port[i].rreg = state_fio->FgetUint8();
456 port[i].first = state_fio->FgetBool();
459 chip_clock = state_fio->FgetInt32();
460 irq_prev = state_fio->FgetBool();
461 mute = state_fio->FgetBool();
462 clock_prev = state_fio->FgetUint32();
463 clock_accum = state_fio->FgetUint32();
464 clock_const = state_fio->FgetUint32();
465 clock_busy = state_fio->FgetUint32();
466 busy = state_fio->FgetBool();
468 #ifdef SUPPORT_MAME_FM_DLL
471 fmdll->Reset(dllchip);
472 for(int i = 0; i < 0x200; i++) {
473 if(port_log[i].written) {
474 fmdll->SetReg(dllchip, i, port_log[i].data);