]> Shamusworld >> Repos - thunder/blob - test/mcu-sound.cpp
Added V63701, YM2151 emulation, more SDL 2 fixes.
[thunder] / test / mcu-sound.cpp
1 //
2 // Rolling Thunder HD63701/YM2151 sound test
3 //
4 // by James Hammons
5 // (C) 2014 Underground Software
6 //
7
8 #include <stdio.h>
9 #include <SDL2/SDL.h>
10 #include "v63701.h"
11 #include "ym2151.h"
12 #include "dis63701.h"
13
14
15 // HD63701's memory (RAM & ROM)
16 uint8_t memory[0x10000];
17
18 // Sound vars
19 static SDL_AudioSpec desired, obtained;
20 static SDL_AudioDeviceID device;
21 static bool soundInitialized = false;
22 static int16_t sample;
23 static uint8_t soundBuffer[1024];
24
25 // Other vars
26 static uint32_t frameCount = 0;
27 static uint32_t startTicks;
28 static int ymRegister;
29
30 // Do this, for now
31 #define WriteLog printf
32 #define SAMPLE_RATE     48000
33
34 // Private function prototypes
35 static void SDLSoundCallback(void * userdata, Uint8 * buffer, int length);
36
37
38 // Bogus M.A.M.E. shite
39 int cpu_scalebyfcount(int f) { return f; }
40 void timer_remove(void *) { printf("STUB: timer_remove()\n"); }
41 void * timer_set(int, int, void (*)(int)) { printf("STUB: timer_set()\n"); return 0; }
42
43
44 uint8_t ReadMemory(uint16_t address)
45 {
46 #if 1
47         if (address < 0x20)
48         {
49 //              printf("V63701 read $%02X from $%02X...\n", memory[address], address);
50                 return InternalRegisterRead(address);
51         }
52 #endif
53
54         if ((address >= 0x2000) && (address <= 0x2001))
55         {
56                 return YMReadReg(0);
57         }
58 //      else if (address == 0x2020)
59 //              return input_port_0_r(0);
60 //      else if (address == 0x2021)
61 //              return input_port_1_r(0);
62
63 #if 0
64         // This is a cheap hack to fool the MCU into thinking something's
65         // attached to it...
66         if (address == 0x1181)
67                 return 0xA6;
68 #endif
69
70         return memory[address];
71 }
72
73
74 void WriteMemory(uint16_t address, uint8_t data)
75 {
76 #if 1
77         if (address < 0x20)
78         {
79 //              printf("V63701 wrote $%02X to $%02X...\n", data, address);
80                 InternalRegisterWrite(address, data);
81                 return;
82         }
83 #endif
84
85         if (((address >= 0x4000) && (address <= 0xBFFF))
86                 || (address >= 0xF000))
87                 return;
88         else if (address == 0x2000)
89         {
90                 ymRegister = data;
91                 return;
92         }
93         else if (address == 0x2001)
94         {
95 //printf("Writing $%02X to YM2151 register $%02X...\n", data, ymRegister);
96                 YMWriteReg(0, ymRegister, data);
97                 return;
98         }
99
100         // RAM is from $0 - $3FFF, $C000 - $EFFF
101         memory[address] = data;
102 }
103
104
105 bool LoadMemory(void)
106 {
107         FILE * file1 = fopen("../ROMs/rt1-mcu.bin", "rb");
108         FILE * file2 = fopen("../ROMs/rt1-4.6b", "rb");
109
110         if (!file1)
111         {
112                 printf("Could not open file \"rt1-mcu.bin\"!\n");
113                 return false;
114         }
115
116         if (!file2)
117         {
118                 printf("Could not open file \"rt1-4.6b\"!\n");
119                 return false;
120         }
121
122         fread(&memory[0xF000], 1, 0x1000, file1);
123         fread(&memory[0x4000], 1, 0x8000, file2);
124         fclose(file1);
125         fclose(file2);
126
127         return true;
128 }
129
130
131 void InitSound(void)
132 {
133         SDL_zero(desired);
134         desired.freq = SAMPLE_RATE;             // SDL will do conversion on the fly, if it can't get the exact rate. Nice!
135         desired.format = AUDIO_S16SYS;  // This uses the native endian (for portability)...
136         desired.channels = 1;
137         desired.samples = 512;                  // Let's try a 1/2K buffer (can always go lower)
138         desired.callback = SDLSoundCallback;
139
140         device = SDL_OpenAudioDevice(NULL, 0, &desired, &obtained, 0);
141
142         if (device == 0)
143         {
144                 WriteLog("Sound: Failed to initialize SDL sound.\n");
145                 return;
146         }
147
148 //      conditional = SDL_CreateCond();
149 //      mutex = SDL_CreateMutex();
150 //      mutex2 = SDL_CreateMutex();// Let's try real signalling...
151 //      soundBufferPos = 0;
152 //      lastToggleCycles = 0;
153         sample = desired.silence;       // ? wilwok ? yes
154
155         SDL_PauseAudioDevice(device, 0);                        // Start playback!
156         soundInitialized = true;
157         WriteLog("Sound: Successfully initialized.\n");
158 }
159
160
161 static void SDLSoundCallback(void * userdata, Uint8 * buffer, int length)
162 {
163 #if 0
164 //printf("Callback: buffer size is %i bytes.\n", length);
165         do
166         {
167                 YM2151Update();
168
169                 if (length >= 1024)
170                 {
171                         memcpy(buffer, soundBuffer, 1024);
172                         buffer += 1024;
173                         length -= 1024;
174                 }
175                 else
176                 {
177                         memcpy(buffer, soundBuffer, length);
178                         length = 0;
179                 }
180         }
181         while (length > 0);
182 #else
183         // Length / 2 is because it's set up for 16-bit samples
184         YM2151UpdateOne(buffer, length / 2);
185 #endif
186 }
187
188
189 void ShutdownSound(void)
190 {
191         if (soundInitialized)
192         {
193                 SDL_PauseAudioDevice(device, 1);
194                 SDL_CloseAudioDevice(device);
195 //              SDL_DestroyCond(conditional);
196 //              SDL_DestroyMutex(mutex);
197 //              SDL_DestroyMutex(mutex2);
198                 WriteLog("Sound: Done.\n");
199         }
200 }
201
202
203 #if 0
204 /*
205 YM2151 registers:
206
207 WRITE
208 -----
209 01: Test
210 08: (SM)^KON   1(CH #)  (Key on, SN=4 bits, CH #=3 (SN = C2,M2,C1,M1))
211 0F: [NE] [XX] [NFRQ][][][][] (Noise enable, noise frequency)
212 10: CLKA1
213 11: [XXXXXX][CLKA2][]
214 12: CLKB
215 14: [CSM][X][FLAG RESET B][A][[IRQEN B][A][LOAD B][A]
216 18: LFRQ (LFO frequency)
217 19: PMD/AMD (7 bits, bit 8 => 1=PMD, 0=AMD)
218 1B: [CT][][XXXX][W][] (Ctrl Output,Wave => 0=saw, 1=square, 2=triangle, 3=noise)
219
220 20-3F: 
221     [RL][][FB][][][CONECT][][] (Right/Left, Feedback, Connection)
222     [X][KC][][][][][][] (Key code, 7 bits: 3=octave, 4=note)
223     [KF][][][][][][XX] (Key fractionb, 6-bits)
224     [X][PMS][][][XX][AMS][] 
225 40-5F:
226     [X][DT1][][][MUL][][][] (Detune 1, Phase multiply)
227 60-7F:
228     [X][TL][][][][][][] (Total level, 7 bits)
229 80-9F:
230     [KS][][X][AR][][][][] (Key scaling, Attack rate)
231 A0-BF:
232     [AMS-EN][XX][D1R][][][][] (1st decay rate)
233 C0-DF:
234     [DT2][][X][D2R][][][][] (Detune 2, 2nd decay rate)
235 E0-FF:
236     [D1L][][][][RR][][][] (1st decay level, Release rate)
237
238 READ
239 ----
240 XX: [B][XXXXX][ist][] (Busy flag, 0=ready, 1=busy; IRQ status)
241
242
243 FUNCTION | Modulator 1     | Modulator 2            | Carrier 1       2  |
244 ---------+-----------------+------------------------+------------ ... ---|
245 Slot #   | 1 2 3 4 5 6 7 8 | 9 10 11 12 13 14 15 16 | 17 18 19 20 ... 32 |
246 Channel #| 1 2 3 4 5 6 7 8 | 1  2  3  4  5  6  7 8  |  1  2  3  4 ...  8 |
247
248 KEY CODE:
249 NOTE: C# D  D# E  F  F# G  G# A A# B  C
250        0 1  2  4  5  6  8  9 10 12 13 14
251 */
252 #endif
253
254
255 int main(int, char * [])
256 {
257         V63701REGS mcu;
258         memset(&mcu, 0, sizeof(V63701REGS));
259         mcu.RdMem = ReadMemory;
260         mcu.WrMem = WriteMemory;
261
262         mcu.cpuFlags |= V63701_ASSERT_LINE_RESET;
263
264         uint8_t * sbp[1] = { soundBuffer };
265 //      soundBuffer[0] = new uint8_t[1024];
266 //      ptrToBuffer = (SAMPLE **)sbp;
267
268         if (YMInit(1, 3579580, 48000, 16, 512, (SAMPLE **)sbp))
269         {
270                 WriteLog("YM: Could not init YM2151 emulator!\n");
271                 return -1;
272         }
273
274         if (!LoadMemory())
275                 return -1;
276
277         if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER | SDL_INIT_NOPARACHUTE) != 0)
278         {
279                 WriteLog("Video: Could not initialize the SDL library: %s\n", SDL_GetError());
280                 return -1;
281         }
282
283         SDL_Window * sdlWindow = NULL;
284         SDL_Renderer * sdlRenderer = NULL;
285         int retVal = SDL_CreateWindowAndRenderer(500, 400, SDL_WINDOW_OPENGL, &sdlWindow, &sdlRenderer);
286
287         if (retVal != 0)
288         {
289                 WriteLog("Video: Could not window and/or renderer: %s\n", SDL_GetError());
290                 return false;
291         }
292
293         InitSound();
294
295         bool done = false;
296         SDL_Event event;
297         startTicks = SDL_GetTicks();
298
299 //try to get some noise outta this sucka
300 //YMWriteReg(0, 0x20, 0xC0);  // Enable R+L channel
301 //YMWriteReg(0, 0x21, 0xC0);  // Enable R+L channel
302 YMWriteReg(0, 0x28, 0x4A);      // KC = A 440
303 YMWriteReg(0, 0x29, 0x50);      // KC = C# 440+
304 YMWriteReg(0, 0x2A, 0x34);      // KC = E 440-
305 YMWriteReg(0, 0x40, 0x01);  // Write phase multiply of 1
306 YMWriteReg(0, 0x41, 0x01);  // Write phase multiply of 1
307 YMWriteReg(0, 0x42, 0x01);  // Write phase multiply of 1
308 YMWriteReg(0, 0x60, 0x7F);  // Total level = 127
309 YMWriteReg(0, 0x61, 0x7F);  // Total level = 127
310 YMWriteReg(0, 0x62, 0x7F);  // Total level = 127
311 YMWriteReg(0, 0xE0, 0x7F);  // 1st decay = 7, release = 15
312 YMWriteReg(0, 0xE1, 0x7F);  // 1st decay = 7, release = 15
313 YMWriteReg(0, 0xE2, 0x7F);  // 1st decay = 7, release = 15
314 YMWriteReg(0, 0x08, 0x78);      // Key on channel #1, M1+C1+M2+C2
315 YMWriteReg(0, 0x08, 0x79);      // Key on channel #2, M1+C1+M2+C2
316 YMWriteReg(0, 0x08, 0x7A);      // Key on channel #3, M1+C1+M2+C2
317
318         do
319         {
320                 while (SDL_PollEvent(&event))
321                 {
322                         switch (event.type)
323                         {
324                         case SDL_KEYDOWN:
325                                 if (event.key.keysym.sym == SDLK_ESCAPE)
326                                         done = true;
327                                 else if (event.key.keysym.sym == SDLK_SPACE)
328                                 {
329                                         YMWriteReg(0, 0x08, 0x40);
330                                         YMWriteReg(0, 0x08, 0x41);
331                                         YMWriteReg(0, 0x08, 0x42);
332                                 }
333                                 else if (event.key.keysym.sym == SDLK_1)
334                                 {
335                                         memory[0x1380] = 1;
336                                 }
337                                 else if (event.key.keysym.sym == SDLK_2)
338                                 {
339                                         memory[0x1380] = 2;
340                                 }
341                                 else if (event.key.keysym.sym == SDLK_3)
342                                 {
343                                         memory[0x1380] = 3;
344                                 }
345                                 else if (event.key.keysym.sym == SDLK_4)
346                                 {
347                                         memory[0x1380] = 4;
348                                 }
349                                 else if (event.key.keysym.sym == SDLK_5)
350                                 {
351                                         memory[0x1380] = 5;
352                                 }
353                                 else if (event.key.keysym.sym == SDLK_6)
354                                 {
355                                         memory[0x1380] = 6;
356                                 }
357                                 else if (event.key.keysym.sym == SDLK_7)
358                                 {
359                                         memory[0x1380] = 7;
360                                 }
361                                 else if (event.key.keysym.sym == SDLK_8)
362                                 {
363                                         memory[0x1380] = 8;
364                                 }
365                                 else if (event.key.keysym.sym == SDLK_9)
366                                 {
367                                         memory[0x1380] = 9;
368                                 }
369                                 else if (event.key.keysym.sym == SDLK_0)
370                                 {
371                                         memory[0x1380] = 10;
372                                 }
373                                 else if (event.key.keysym.sym == SDLK_q)
374                                 {
375                                         memory[0x1380] = 11;
376                                 }
377                                 else if (event.key.keysym.sym == SDLK_w)
378                                 {
379                                         memory[0x1380] = 12;
380                                 }
381                                 else if (event.key.keysym.sym == SDLK_e)
382                                 {
383                                         memory[0x1380] = 13;
384                                 }
385                         }
386                 }
387
388                 // 49152000/32 = 1536000 Hz, /60 = 25600
389                 Execute63701(&mcu, 25600);
390
391                 frameCount = (frameCount + 1) % 3;
392                 uint32_t waitFrameTime = 17 - (frameCount == 0 ? 1 : 0);
393
394                 // Wait for next frame...
395                 while (SDL_GetTicks() - startTicks < waitFrameTime)
396                         SDL_Delay(1);
397
398                 startTicks = SDL_GetTicks();
399         }
400         while (!done);
401
402         ShutdownSound();
403         SDL_Quit();
404 //      delete[] soundBuffer[0];
405
406 #if 0
407 FILE * f = fopen("mcu-dis-$4000.txt", "w");
408 uint32_t address = 0x4000;
409 //for(uint32_t i=0xF000, i<0x10000; i++)
410 do
411 {
412         char line[8192];
413         address += Decode63701(memory, address, line);
414         fprintf(f, "%s\n", line);
415 }
416 while (address < 0xC000);
417
418 fclose(f);
419 #endif
420 printf("MCU state:\nPC=%04X, S=%04X, X=%04X, D=%04X, CC=%02X\n", mcu.pc, mcu.s, mcu.x, mcu.d.word, mcu.cc);
421
422         return 0;
423 }
424
425
426 #if 0
427 #define MCU_MEMORY(NAME,ADDR_LOWROM,ADDR_INPUT,ADDR_UNK1,ADDR_UNK2)                     \
428 static MEMORY_READ_START( NAME##_mcu_readmem )                                                          \
429         { 0x0000, 0x001f, hd63701_internal_registers_r },                                               \
430         { 0x0080, 0x00ff, MRA_RAM },                                                                                    \
431         { 0x1000, 0x10ff, namcos1_wavedata_r }, /* PSG device, shared RAM */    \
432         { 0x1100, 0x113f, namcos1_sound_r }, /* PSG device, shared RAM */               \
433         { 0x1000, 0x13ff, shared1_r },                                                                                  \
434         { 0x1400, 0x1fff, MRA_RAM },                                                                                    \
435         { ADDR_INPUT+0x00, ADDR_INPUT+0x01, YM2151_status_port_0_r },                   \
436         { ADDR_INPUT+0x20, ADDR_INPUT+0x20, input_port_0_r },                                   \
437         { ADDR_INPUT+0x21, ADDR_INPUT+0x21, input_port_1_r },                                   \
438         { ADDR_INPUT+0x30, ADDR_INPUT+0x30, dsw0_r },                                                   \
439         { ADDR_INPUT+0x31, ADDR_INPUT+0x31, dsw1_r },                                                   \
440         { ADDR_LOWROM, ADDR_LOWROM+0x3fff, MRA_ROM },                                                   \
441         { 0x8000, 0xbfff, MRA_ROM },                                                                                    \
442         { 0xf000, 0xffff, MRA_ROM },                                                                                    \
443 MEMORY_END                                                                                                                                      \
444                                                                                                                                                         \
445 static MEMORY_WRITE_START( NAME##_mcu_writemem )                                                        \
446         { 0x0000, 0x001f, hd63701_internal_registers_w },                                               \
447         { 0x0080, 0x00ff, MWA_RAM },                                                                                    \
448         { 0x1000, 0x10ff, namcos1_wavedata_w }, /* PSG device, shared RAM */    \
449         { 0x1100, 0x113f, namcos1_sound_w }, /* PSG device, shared RAM */               \
450         { 0x1000, 0x13ff, shared1_w },                                                                                  \
451         { 0x1400, 0x1fff, MWA_RAM },                                                                                    \
452         { ADDR_INPUT+0x00, ADDR_INPUT+0x00, YM2151_register_port_0_w },                 \
453         { ADDR_INPUT+0x01, ADDR_INPUT+0x01, YM2151_data_port_0_w },                             \
454         { ADDR_UNK1, ADDR_UNK1, MWA_NOP }, /* ??? written (not always) at end of interrupt */   \
455         { ADDR_UNK2, ADDR_UNK2, MWA_NOP }, /* ??? written (not always) at end of interrupt */   \
456         { ADDR_LOWROM, ADDR_LOWROM+0x3fff, MWA_ROM },                                                   \
457         { 0x8000, 0xbfff, MWA_ROM },                                                                                    \
458         { 0xf000, 0xffff, MWA_ROM },                                                                                    \
459 MEMORY_END
460
461 #define UNUSED 0x4000
462 /*                    LOWROM   INPUT    UNK1    UNK2 */
463 MCU_MEMORY( rthunder, 0x4000, 0x2000, 0xb000, 0xb800 )
464 #undef UNUSED
465
466 /*
467 0123456789ABCDEF
468 ----------------
469 @ABCDEFGHIJKLMNO
470 PQRSTUVWXYZ
471
472
473 Sound: Successfully initialized.
474 V63701 read $00 from $00...
475 V63701 read $00 from $14...
476
477 V63701 wrote $40 to $14...
478 V63701 wrote $FF to $05...
479
480 V63701 read $40 from $14...
481
482 V63701 wrote $40 to $14...
483 V63701 wrote $00 to $02...
484 V63701 wrote $00 to $00...
485
486 V63701 read $40 from $14...
487 V63701 read $00 from $08...
488
489 V63701 wrote $00 to $09...
490 V63701 wrote $00 to $0A...
491 V63701 wrote $01 to $0B...
492 V63701 wrote $00 to $0C...
493
494 V63701 read $00 from $08...
495
496 V63701 wrote $08 to $08...
497
498 V63701 read $00 from $02...
499 V63701 read $00 from $02...
500 V63701 read $00 from $02...
501
502 V63701 wrote $00 to $03...
503 V63701 wrote $18 to $01...
504 V63701 wrote $C0 to $14...
505 Sound: Done.
506 MCU state:
507 PC=814F, S=1FFD, X=8065, D=A600, CC=C4
508
509
510 Problem:
511
512 8110: 86 C0           LDAA  #$C0   
513  [PC=8112 S=1FFF X=1100 A=C0 B=00 CC=..N... TN=2C00 CT=2BBA OC=2C00 TO=3F00]
514 8112: 97 14           STAA  $14    
515  [PC=8114 S=1FFF X=1100 A=C0 B=00 CC=..N... TN=2C00 CT=2BBC OC=2C00 TO=3F00]
516 8114: DE AE           LDX   $AE    
517  [PC=8116 S=1FFF X=14F0 A=C0 B=00 CC=...... TN=2C00 CT=2BBF OC=2C00 TO=3F00]
518
519 ; Fetches 3 bytes here instead of 2!!
520 8116: 6D 7A           TST   $7A,X  
521  [PC=8119 S=1FFF X=14F0 A=C0 B=00 CC=...... TN=2C00 CT=2BC3 OC=2C00 TO=3F00]
522
523 ; Execution is wrong at this point!!
524 8119: 06              TAP          
525  [PC=811A S=1FFF X=14F0 A=C0 B=00 CC=...... TN=2C00 CT=2BC7 OC=2C00 TO=3F00]
526 811A: 96 82           LDAA  $82    
527  [PC=811C S=1FFF X=14F0 A=00 B=00 CC=...Z.. TN=2C00 CT=2BC8 OC=2C00 TO=3F00]
528 811C: 9B 80           ADDA  $80    
529  [PC=811E S=1FFF X=14F0 A=00 B=00 CC=...Z.. TN=2C00 CT=2BCB OC=2C00 TO=3F00]
530 811E: 97 80           STAA  $80    
531  [PC=8120 S=1FFF X=14F0 A=00 B=00 CC=...Z.. TN=2C00 CT=2BCE OC=2C00 TO=3F00]
532 8120: 7F 00 82        CLR   $0082  
533  [PC=8123 S=1FFF X=14F0 A=00 B=00 CC=...Z.. TN=2C00 CT=2BD1 OC=2C00 TO=3F00]
534 8123: DE AA           LDX   $AA    
535  [PC=8125 S=1FFF X=8068 A=00 B=00 CC=..N... TN=2C00 CT=2BD6 OC=2C00 TO=3F00]
536 8125: AD 00           JSR   $00,X  
537  [PC=8068 S=1FFD X=8068 A=00 B=00 CC=..N... TN=2C00 CT=2BDA OC=2C00 TO=3F00]
538 8068: 39              RTS          
539  [PC=8127 S=1FFF X=8068 A=00 B=00 CC=..N... TN=2C00 CT=2BDF OC=2C00 TO=3F00]
540 8127: 86 A6           LDAA  #$A6   
541  [PC=8129 S=1FFF X=8068 A=A6 B=00 CC=..N... TN=2C00 CT=2BE4 OC=2C00 TO=3F00]
542 8129: B7 11 82        STAA  $1182  
543  [PC=812C S=1FFF X=8068 A=A6 B=00 CC=..N... TN=2C00 CT=2BE6 OC=2C00 TO=3F00]
544 812C: DE AE           LDX   $AE    
545  [PC=812E S=1FFF X=14F0 A=A6 B=00 CC=...... TN=2C00 CT=2BEA OC=2C00 TO=3F00]
546 812E: EE 2C           LDX   $2C,X  
547  [PC=8130 S=1FFF X=8065 A=A6 B=00 CC=..N... TN=2C00 CT=2BEE OC=2C00 TO=3F00]
548 8130: AD 00           JSR   $00,X  
549  [PC=8065 S=1FFD X=8065 A=A6 B=00 CC=..N... TN=2C00 CT=2BF3 OC=2C00 TO=3F00]
550 8065: B7 B0 00        STAA  $B000  
551  [PC=8068 S=1FFD X=8065 A=A6 B=00 CC=..N... TN=2C00 CT=2BF8 OC=2C00 TO=3F00]
552 8068: 39              RTS          
553  [PC=8132 S=1FFF X=8065 A=A6 B=00 CC=..N... TN=2C00 CT=2BFC OC=2C00 TO=3F00]
554
555 */
556 #endif
557