1 /*****************************************************************************
2 ** $Source: /cygdrive/d/Private/_SVNROOT/bluemsx/blueMSX/Src/SoundChips/Moonsound.cpp,v $
3 **
4 ** $Revision: 1.22 $
5 **
6 ** $Date: 2008-03-30 18:38:45 $
7 **
8 ** More info: http://www.bluemsx.com
9 **
10 ** Copyright (C) 2003-2006 Daniel Vik
11 **
12 ** This program is free software; you can redistribute it and/or modify
13 ** it under the terms of the GNU General Public License as published by
14 ** the Free Software Foundation; either version 2 of the License, or
15 ** (at your option) any later version.
16 **
17 ** This program is distributed in the hope that it will be useful,
18 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ** GNU General Public License for more details.
21 **
22 ** You should have received a copy of the GNU General Public License
23 ** along with this program; if not, write to the Free Software
24 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 **
26 ******************************************************************************
27 */
28 #include "Moonsound.h"
29 #include <string.h>
30 #include "OpenMsxYMF262.h"
31 #include "OpenMsxYMF278.h"
32 extern "C" {
33 #include "Board.h"
34 #include "SaveState.h"
35 #include "Language.h"
36 }
37 
38 #define FREQUENCY        3579545
39 
40 struct Moonsound {
MoonsoundMoonsound41     Moonsound() : opl3latch(0), opl4latch(0),
42         timerValue1(0), timerValue2(0), timerRef1(0xff), timerRef2(0xff) {
43         memset(defaultBuffer, 0, sizeof(defaultBuffer));
44     }
45 
46     Mixer* mixer;
47     Int32 handle;
48 
49     YMF278* ymf278;
50     YMF262* ymf262;
51     Int32  buffer[AUDIO_STEREO_BUFFER_SIZE];
52     Int32  defaultBuffer[AUDIO_STEREO_BUFFER_SIZE];
53     BoardTimer* timer1;
54     BoardTimer* timer2;
55     UInt32 timeout1;
56     UInt32 timeout2;
57     UInt32 timerValue1;
58     UInt32 timerValue2;
59     UInt32 timerStarted1;
60     UInt32 timerStarted2;
61     UInt8  timerRef1;
62     UInt8  timerRef2;
63     int opl3latch;
64     UInt8 opl4latch;
65 };
66 
67 
68 void moonsoundTimerStart(void* ref, int timer, int start, UInt8 timerRef);
69 
onTimeout1(void * ref,UInt32 time)70 static void onTimeout1(void* ref, UInt32 time)
71 {
72     Moonsound* moonsound = (Moonsound*)ref;
73 
74     moonsoundTimerStart(moonsound, 1, 1, moonsound->timerRef1);
75     moonsound->ymf262->callback(moonsound->timerRef1);
76 }
77 
onTimeout2(void * ref,UInt32 time)78 static void onTimeout2(void* ref, UInt32 time)
79 {
80     Moonsound* moonsound = (Moonsound*)ref;
81 
82     moonsoundTimerStart(moonsound, 4, 1, moonsound->timerRef2);
83     moonsound->ymf262->callback(moonsound->timerRef2);
84 }
85 
moonsoundTimerSet(void * ref,int timer,int count)86 void moonsoundTimerSet(void* ref, int timer, int count)
87 {
88     Moonsound* moonsound = (Moonsound*)ref;
89 
90     if (timer == 1) {
91         moonsound->timerValue1 = count;
92         if (moonsound->timerStarted1) {
93             moonsoundTimerStart(moonsound, timer, 1, moonsound->timerRef1);
94         }
95     }
96     else {
97         moonsound->timerValue2 = count;
98         if (moonsound->timerStarted2) {
99             moonsoundTimerStart(moonsound, timer, 1, moonsound->timerRef2);
100         }
101     }
102 }
103 
moonsoundTimerStart(void * ref,int timer,int start,UInt8 timerRef)104 void moonsoundTimerStart(void* ref, int timer, int start, UInt8 timerRef)
105 {
106     Moonsound* moonsound = (Moonsound*)ref;
107 
108     if (timer == 1) {
109         moonsound->timerRef1 = timerRef;
110         moonsound->timerStarted1 = start;
111         if (start) {
112             moonsound->timeout1 = boardCalcRelativeTimeout(12380, moonsound->timerValue1);
113             boardTimerAdd(moonsound->timer1, moonsound->timeout1);
114         }
115         else {
116             boardTimerRemove(moonsound->timer1);
117         }
118     }
119     else {
120         moonsound->timerRef2 = timerRef;
121         moonsound->timerStarted2 = start;
122         if (start) {
123             moonsound->timeout2 = boardCalcRelativeTimeout(12380, moonsound->timerValue2);
124             boardTimerAdd(moonsound->timer2, moonsound->timeout2);
125         }
126         else {
127             boardTimerRemove(moonsound->timer2);
128         }
129     }
130 }
131 
132 extern "C" {
133 
moonsoundDestroy(Moonsound * moonsound)134 void moonsoundDestroy(Moonsound* moonsound)
135 {
136     mixerUnregisterChannel(moonsound->mixer, moonsound->handle);
137 
138     delete moonsound->ymf262;
139     delete moonsound->ymf278;
140 
141     boardTimerDestroy(moonsound->timer1);
142     boardTimerDestroy(moonsound->timer2);
143 }
144 
moonsoundSaveState(Moonsound * moonsound)145 void moonsoundSaveState(Moonsound* moonsound)
146 {
147     SaveState* state = saveStateOpenForWrite("moonsound");
148 
149     saveStateSet(state, "timerValue1",    moonsound->timerValue1);
150     saveStateSet(state, "timeout1",       moonsound->timeout1);
151     saveStateSet(state, "timerStarted1",  moonsound->timerStarted1);
152     saveStateSet(state, "timerRef1",      moonsound->timerRef1);
153     saveStateSet(state, "timerValue2",    moonsound->timerValue2);
154     saveStateSet(state, "timeout2",       moonsound->timeout2);
155     saveStateSet(state, "timerStarted2",  moonsound->timerStarted2);
156     saveStateSet(state, "timerRef2",      moonsound->timerRef2);
157     saveStateSet(state, "opl3latch", moonsound->opl3latch);
158     saveStateSet(state, "opl4latch", moonsound->opl4latch);
159 
160     saveStateClose(state);
161 
162     moonsound->ymf262->saveState();
163     moonsound->ymf278->saveState();
164 }
165 
moonsoundLoadState(Moonsound * moonsound)166 void moonsoundLoadState(Moonsound* moonsound)
167 {
168     SaveState* state = saveStateOpenForRead("moonsound");
169 
170     moonsound->timerValue1    =        saveStateGet(state, "timerValue1",    0);
171     moonsound->timeout1       =        saveStateGet(state, "timeout1",       0);
172     moonsound->timerStarted1  =        saveStateGet(state, "timerStarted1",  0);
173     moonsound->timerRef1      = (UInt8)saveStateGet(state, "timerRef1",      0);
174     moonsound->timerValue2    =        saveStateGet(state, "timerValue2",    0);
175     moonsound->timeout2       =        saveStateGet(state, "timeout2",       0);
176     moonsound->timerStarted2  =        saveStateGet(state, "timerStarted2",  0);
177     moonsound->timerRef2      = (UInt8)saveStateGet(state, "timerRef2",      0);
178     moonsound->opl3latch =        saveStateGet(state, "opl3latch", 0);
179     moonsound->opl4latch = (UInt8)saveStateGet(state, "opl4latch", 0);
180 
181     saveStateClose(state);
182 
183     moonsound->ymf262->loadState();
184     moonsound->ymf278->loadState();
185 
186     if (moonsound->timerStarted1) {
187         boardTimerAdd(moonsound->timer1, moonsound->timeout1);
188     }
189 
190     if (moonsound->timerStarted2) {
191         boardTimerAdd(moonsound->timer2, moonsound->timeout2);
192     }
193 }
194 
195 
regText(int d)196 static char* regText(int d)
197 {
198     static char text[5];
199     sprintf(text, "R%.2x", d);
200     return text;
201 }
202 
slotRegText(int s,int r)203 static char* slotRegText(int s, int r)
204 {
205     static char text[5];
206     sprintf(text, "S%d:%d", s, r);
207     return text;
208 }
209 
210 static char regsAvailYMF262[] = {
211     0,1,1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x00
212     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0, // 0x20
213     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0, // 0x40
214     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0, // 0x60
215     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0, // 0x80
216     1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,1,0,0, // 0xa0
217     1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0xc0
218     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0  // 0xe0
219 };
220 
moonsoundGetDebugInfo(Moonsound * moonsound,DbgDevice * dbgDevice)221 void moonsoundGetDebugInfo(Moonsound* moonsound, DbgDevice* dbgDevice)
222 {
223     UInt32 systemTime = boardSystemTime();
224     DbgRegisterBank* regBank;
225     int r;
226 
227     // Add YMF262 registers
228     int c = 1;
229     for (r = 0; r < sizeof(regsAvailYMF262); r++) {
230         c += regsAvailYMF262[r];
231     }
232 
233     regBank = dbgDeviceAddRegisterBank(dbgDevice, langDbgRegsYmf262(), c);
234 
235     c = 0;
236     dbgRegisterBankAddRegister(regBank, c++, "SR", 8, moonsound->ymf262->peekStatus());
237 
238     for (r = 0; r < sizeof(regsAvailYMF262); r++) {
239         if (regsAvailYMF262[r]) {
240             if (r <= 8) {
241                 dbgRegisterBankAddRegister(regBank, c++, regText(r), 8, moonsound->ymf262->peekReg(r|0x100));
242             }
243             else {
244                 dbgRegisterBankAddRegister(regBank, c++, regText(r), 8, moonsound->ymf262->peekReg(r));
245             }
246         }
247     }
248 
249     // Add YMF278 registers
250     c = 1 + 7 + 2 + 10 * 10;
251     regBank = dbgDeviceAddRegisterBank(dbgDevice, langDbgRegsYmf278(), c);
252 
253     c = 0;
254     dbgRegisterBankAddRegister(regBank, c++, "SR", 8, moonsound->ymf278->peekStatus(systemTime));
255 
256     r=0x00; dbgRegisterBankAddRegister(regBank, c++, regText(r), 8, moonsound->ymf278->peekRegOPL4(r, systemTime));
257     r=0x01; dbgRegisterBankAddRegister(regBank, c++, regText(r), 8, moonsound->ymf278->peekRegOPL4(r, systemTime));
258     r=0x02; dbgRegisterBankAddRegister(regBank, c++, regText(r), 8, moonsound->ymf278->peekRegOPL4(r, systemTime));
259     r=0x03; dbgRegisterBankAddRegister(regBank, c++, regText(r), 8, moonsound->ymf278->peekRegOPL4(r, systemTime));
260     r=0x04; dbgRegisterBankAddRegister(regBank, c++, regText(r), 8, moonsound->ymf278->peekRegOPL4(r, systemTime));
261     r=0x05; dbgRegisterBankAddRegister(regBank, c++, regText(r), 8, moonsound->ymf278->peekRegOPL4(r, systemTime));
262     r=0x06; dbgRegisterBankAddRegister(regBank, c++, regText(r), 8, moonsound->ymf278->peekRegOPL4(r, systemTime));
263     r=0xf8; dbgRegisterBankAddRegister(regBank, c++, regText(r), 8, moonsound->ymf278->peekRegOPL4(r, systemTime));
264     r=0xf9; dbgRegisterBankAddRegister(regBank, c++, regText(r), 8, moonsound->ymf278->peekRegOPL4(r, systemTime));
265 
266     for (int i = 0; i < 10; i++) {
267         for (int j = 0; j < 10; j++) {
268             int r = 8 + i * 24 + j;
269             dbgRegisterBankAddRegister(regBank, c++, slotRegText(i,j), 8, moonsound->ymf278->peekRegOPL4(r, systemTime));
270         }
271     }
272 
273     dbgDeviceAddMemoryBlock(dbgDevice, langDbgMemYmf278(), 0, 0,
274                             moonsound->ymf278->getRamSize(),
275                             (UInt8*)moonsound->ymf278->getRam());
276 }
277 
moonsoundReset(Moonsound * moonsound)278 void moonsoundReset(Moonsound* moonsound)
279 {
280     UInt32 systemTime = boardSystemTime();
281 
282     moonsound->timerStarted1 = (UInt32)-1;
283     moonsound->timerStarted2 = (UInt32)-1;
284     moonsound->ymf262->reset(systemTime);
285     moonsound->ymf278->reset(systemTime);
286 
287     moonsoundTimerStart(moonsound, 1, 0, moonsound->timerRef1);
288     moonsoundTimerStart(moonsound, 4, 0, moonsound->timerRef2);
289 }
290 
moonsoundSync(void * ref,UInt32 count)291 static Int32* moonsoundSync(void* ref, UInt32 count)
292 {
293     Moonsound* moonsound = (Moonsound*)ref;
294     int* genBuf1 = NULL;
295     int* genBuf2 = NULL;
296     UInt32 i;
297 
298     genBuf1 = moonsound->ymf262->updateBuffer(count);
299     if (genBuf1 == NULL) {
300         genBuf1 = (int*)moonsound->defaultBuffer;
301     }
302 
303     genBuf2 = moonsound->ymf278->updateBuffer(count);
304     if (genBuf2 == NULL) {
305         genBuf2 = (int*)moonsound->defaultBuffer;
306     }
307 
308     for (i = 0; i < 2 * count; i++) {
309         moonsound->buffer[i] = genBuf1[i] + genBuf2[i];
310     }
311 
312     return moonsound->buffer;
313 }
314 
moonsoundPeek(Moonsound * moonsound,UInt16 ioPort)315 UInt8 moonsoundPeek(Moonsound* moonsound, UInt16 ioPort)
316 {
317 	UInt8 result = 0xff;
318     UInt32 systemTime = boardSystemTime();
319 
320     if (moonsound == NULL) {
321         return 0xff;
322     }
323 
324 	if (ioPort < 0xC0) {
325 		switch (ioPort & 0x01) {
326 		case 1: // read wave register
327 			result = moonsound->ymf278->peekRegOPL4(moonsound->opl4latch, systemTime);
328 			break;
329 		}
330 	} else {
331 		switch (ioPort & 0x03) {
332 		case 0: // read status
333 		case 2:
334 			result = moonsound->ymf262->peekStatus() |
335                      moonsound->ymf278->peekStatus(systemTime);
336 			break;
337 		case 1:
338 		case 3: // read fm register
339 			result = moonsound->ymf262->peekReg(moonsound->opl3latch);
340 			break;
341 		}
342 	}
343 
344     return result;
345 }
346 
moonsoundRead(Moonsound * moonsound,UInt16 ioPort)347 UInt8 moonsoundRead(Moonsound* moonsound, UInt16 ioPort)
348 {
349 	UInt8 result = 0xff;
350     UInt32 systemTime = boardSystemTime();
351 
352 	if (ioPort < 0xC0) {
353 		switch (ioPort & 0x01) {
354 		case 1: // read wave register
355             mixerSync(moonsound->mixer);
356 			result = moonsound->ymf278->readRegOPL4(moonsound->opl4latch, systemTime);
357 			break;
358 		}
359 	} else {
360 		switch (ioPort & 0x03) {
361 		case 0: // read status
362 		case 2:
363             mixerSync(moonsound->mixer);
364 			result = moonsound->ymf262->readStatus() |
365                      moonsound->ymf278->readStatus(systemTime);
366 			break;
367 		case 1:
368 		case 3: // read fm register
369             mixerSync(moonsound->mixer);
370 			result = moonsound->ymf262->readReg(moonsound->opl3latch);
371 			break;
372 		}
373 	}
374 
375     return result;
376 }
377 
moonsoundWrite(Moonsound * moonsound,UInt16 ioPort,UInt8 value)378 void moonsoundWrite(Moonsound* moonsound, UInt16 ioPort, UInt8 value)
379 {
380     UInt32 systemTime = boardSystemTime();
381 	if (ioPort < 0xC0) {
382 		switch (ioPort & 0x01) {
383 		case 0: // select register
384 			moonsound->opl4latch = value;
385 			break;
386 		case 1:
387             mixerSync(moonsound->mixer);
388   			moonsound->ymf278->writeRegOPL4(moonsound->opl4latch, value, systemTime);
389 			break;
390 		}
391 	} else {
392 		switch (ioPort & 0x03) {
393 		case 0:
394 			moonsound->opl3latch = value;
395 			break;
396 		case 2: // select register bank 1
397 			moonsound->opl3latch = value | 0x100;
398 			break;
399 		case 1:
400 		case 3: // write fm register
401             mixerSync(moonsound->mixer);
402 			moonsound->ymf262->writeReg(moonsound->opl3latch, value, systemTime);
403 			break;
404 		}
405 	}
406 }
407 
moonsoundSetSampleRate(void * ref,UInt32 rate)408 void moonsoundSetSampleRate(void* ref, UInt32 rate)
409 {
410     Moonsound* moonsound = (Moonsound*)ref;
411     moonsound->ymf262->setSampleRate(rate, boardGetMoonsoundOversampling());
412     moonsound->ymf278->setSampleRate(rate, boardGetMoonsoundOversampling());
413 }
414 
moonsoundCreate(Mixer * mixer,void * romData,int romSize,int sramSize)415 Moonsound* moonsoundCreate(Mixer* mixer, void* romData, int romSize, int sramSize)
416 {
417     Moonsound* moonsound = new Moonsound;
418     UInt32 systemTime = boardSystemTime();
419 
420     moonsound->mixer = mixer;
421     moonsound->timerStarted1 = 0;
422     moonsound->timerStarted2 = 0;
423 
424     moonsound->timer1 = boardTimerCreate(onTimeout1, moonsound);
425     moonsound->timer2 = boardTimerCreate(onTimeout2, moonsound);
426 
427     moonsound->handle = mixerRegisterChannel(mixer, MIXER_CHANNEL_MOONSOUND, 1, moonsoundSync, moonsoundSetSampleRate, moonsound);
428 
429     moonsound->ymf262 = new YMF262(0, systemTime, moonsound);
430     moonsound->ymf262->setSampleRate(mixerGetSampleRate(mixer), boardGetMoonsoundOversampling());
431 	moonsound->ymf262->setVolume(32767 * 9 / 10);
432 
433     moonsound->ymf278 = new YMF278(0, sramSize, romData, romSize, systemTime);
434     moonsound->ymf278->setSampleRate(mixerGetSampleRate(mixer), boardGetMoonsoundOversampling());
435     moonsound->ymf278->setVolume(32767 * 9 / 10);
436 
437     return moonsound;
438 }
439 
440 }
441 
442