]> Shamusworld >> Repos - thunder/blobdiff - test/mcu-sound.cpp
Added V63701, YM2151 emulation, more SDL 2 fixes.
[thunder] / test / mcu-sound.cpp
diff --git a/test/mcu-sound.cpp b/test/mcu-sound.cpp
new file mode 100644 (file)
index 0000000..6c8f230
--- /dev/null
@@ -0,0 +1,557 @@
+//
+// Rolling Thunder HD63701/YM2151 sound test
+//
+// by James Hammons
+// (C) 2014 Underground Software
+//
+
+#include <stdio.h>
+#include <SDL2/SDL.h>
+#include "v63701.h"
+#include "ym2151.h"
+#include "dis63701.h"
+
+
+// HD63701's memory (RAM & ROM)
+uint8_t memory[0x10000];
+
+// Sound vars
+static SDL_AudioSpec desired, obtained;
+static SDL_AudioDeviceID device;
+static bool soundInitialized = false;
+static int16_t sample;
+static uint8_t soundBuffer[1024];
+
+// Other vars
+static uint32_t frameCount = 0;
+static uint32_t startTicks;
+static int ymRegister;
+
+// Do this, for now
+#define WriteLog printf
+#define SAMPLE_RATE    48000
+
+// Private function prototypes
+static void SDLSoundCallback(void * userdata, Uint8 * buffer, int length);
+
+
+// Bogus M.A.M.E. shite
+int cpu_scalebyfcount(int f) { return f; }
+void timer_remove(void *) { printf("STUB: timer_remove()\n"); }
+void * timer_set(int, int, void (*)(int)) { printf("STUB: timer_set()\n"); return 0; }
+
+
+uint8_t ReadMemory(uint16_t address)
+{
+#if 1
+       if (address < 0x20)
+       {
+//             printf("V63701 read $%02X from $%02X...\n", memory[address], address);
+               return InternalRegisterRead(address);
+       }
+#endif
+
+       if ((address >= 0x2000) && (address <= 0x2001))
+       {
+               return YMReadReg(0);
+       }
+//     else if (address == 0x2020)
+//             return input_port_0_r(0);
+//     else if (address == 0x2021)
+//             return input_port_1_r(0);
+
+#if 0
+       // This is a cheap hack to fool the MCU into thinking something's
+       // attached to it...
+       if (address == 0x1181)
+               return 0xA6;
+#endif
+
+       return memory[address];
+}
+
+
+void WriteMemory(uint16_t address, uint8_t data)
+{
+#if 1
+       if (address < 0x20)
+       {
+//             printf("V63701 wrote $%02X to $%02X...\n", data, address);
+               InternalRegisterWrite(address, data);
+               return;
+       }
+#endif
+
+       if (((address >= 0x4000) && (address <= 0xBFFF))
+               || (address >= 0xF000))
+               return;
+       else if (address == 0x2000)
+       {
+               ymRegister = data;
+               return;
+       }
+       else if (address == 0x2001)
+       {
+//printf("Writing $%02X to YM2151 register $%02X...\n", data, ymRegister);
+               YMWriteReg(0, ymRegister, data);
+               return;
+       }
+
+       // RAM is from $0 - $3FFF, $C000 - $EFFF
+       memory[address] = data;
+}
+
+
+bool LoadMemory(void)
+{
+       FILE * file1 = fopen("../ROMs/rt1-mcu.bin", "rb");
+       FILE * file2 = fopen("../ROMs/rt1-4.6b", "rb");
+
+       if (!file1)
+       {
+               printf("Could not open file \"rt1-mcu.bin\"!\n");
+               return false;
+       }
+
+       if (!file2)
+       {
+               printf("Could not open file \"rt1-4.6b\"!\n");
+               return false;
+       }
+
+       fread(&memory[0xF000], 1, 0x1000, file1);
+       fread(&memory[0x4000], 1, 0x8000, file2);
+       fclose(file1);
+       fclose(file2);
+
+       return true;
+}
+
+
+void InitSound(void)
+{
+       SDL_zero(desired);
+       desired.freq = SAMPLE_RATE;             // SDL will do conversion on the fly, if it can't get the exact rate. Nice!
+       desired.format = AUDIO_S16SYS;  // This uses the native endian (for portability)...
+       desired.channels = 1;
+       desired.samples = 512;                  // Let's try a 1/2K buffer (can always go lower)
+       desired.callback = SDLSoundCallback;
+
+       device = SDL_OpenAudioDevice(NULL, 0, &desired, &obtained, 0);
+
+       if (device == 0)
+       {
+               WriteLog("Sound: Failed to initialize SDL sound.\n");
+               return;
+       }
+
+//     conditional = SDL_CreateCond();
+//     mutex = SDL_CreateMutex();
+//     mutex2 = SDL_CreateMutex();// Let's try real signalling...
+//     soundBufferPos = 0;
+//     lastToggleCycles = 0;
+       sample = desired.silence;       // ? wilwok ? yes
+
+       SDL_PauseAudioDevice(device, 0);                        // Start playback!
+       soundInitialized = true;
+       WriteLog("Sound: Successfully initialized.\n");
+}
+
+
+static void SDLSoundCallback(void * userdata, Uint8 * buffer, int length)
+{
+#if 0
+//printf("Callback: buffer size is %i bytes.\n", length);
+       do
+       {
+               YM2151Update();
+
+               if (length >= 1024)
+               {
+                       memcpy(buffer, soundBuffer, 1024);
+                       buffer += 1024;
+                       length -= 1024;
+               }
+               else
+               {
+                       memcpy(buffer, soundBuffer, length);
+                       length = 0;
+               }
+       }
+       while (length > 0);
+#else
+       // Length / 2 is because it's set up for 16-bit samples
+       YM2151UpdateOne(buffer, length / 2);
+#endif
+}
+
+
+void ShutdownSound(void)
+{
+       if (soundInitialized)
+       {
+               SDL_PauseAudioDevice(device, 1);
+               SDL_CloseAudioDevice(device);
+//             SDL_DestroyCond(conditional);
+//             SDL_DestroyMutex(mutex);
+//             SDL_DestroyMutex(mutex2);
+               WriteLog("Sound: Done.\n");
+       }
+}
+
+
+#if 0
+/*
+YM2151 registers:
+
+WRITE
+-----
+01: Test
+08: (SM)^KON   1(CH #)  (Key on, SN=4 bits, CH #=3 (SN = C2,M2,C1,M1))
+0F: [NE] [XX] [NFRQ][][][][] (Noise enable, noise frequency)
+10: CLKA1
+11: [XXXXXX][CLKA2][]
+12: CLKB
+14: [CSM][X][FLAG RESET B][A][[IRQEN B][A][LOAD B][A]
+18: LFRQ (LFO frequency)
+19: PMD/AMD (7 bits, bit 8 => 1=PMD, 0=AMD)
+1B: [CT][][XXXX][W][] (Ctrl Output,Wave => 0=saw, 1=square, 2=triangle, 3=noise)
+
+20-3F: 
+    [RL][][FB][][][CONECT][][] (Right/Left, Feedback, Connection)
+    [X][KC][][][][][][] (Key code, 7 bits: 3=octave, 4=note)
+    [KF][][][][][][XX] (Key fractionb, 6-bits)
+    [X][PMS][][][XX][AMS][] 
+40-5F:
+    [X][DT1][][][MUL][][][] (Detune 1, Phase multiply)
+60-7F:
+    [X][TL][][][][][][] (Total level, 7 bits)
+80-9F:
+    [KS][][X][AR][][][][] (Key scaling, Attack rate)
+A0-BF:
+    [AMS-EN][XX][D1R][][][][] (1st decay rate)
+C0-DF:
+    [DT2][][X][D2R][][][][] (Detune 2, 2nd decay rate)
+E0-FF:
+    [D1L][][][][RR][][][] (1st decay level, Release rate)
+
+READ
+----
+XX: [B][XXXXX][ist][] (Busy flag, 0=ready, 1=busy; IRQ status)
+
+
+FUNCTION | Modulator 1     | Modulator 2            | Carrier 1       2  |
+---------+-----------------+------------------------+------------ ... ---|
+Slot #   | 1 2 3 4 5 6 7 8 | 9 10 11 12 13 14 15 16 | 17 18 19 20 ... 32 |
+Channel #| 1 2 3 4 5 6 7 8 | 1  2  3  4  5  6  7 8  |  1  2  3  4 ...  8 |
+
+KEY CODE:
+NOTE: C# D  D# E  F  F# G  G# A A# B  C
+       0 1  2  4  5  6  8  9 10 12 13 14
+*/
+#endif
+
+
+int main(int, char * [])
+{
+       V63701REGS mcu;
+       memset(&mcu, 0, sizeof(V63701REGS));
+       mcu.RdMem = ReadMemory;
+       mcu.WrMem = WriteMemory;
+
+       mcu.cpuFlags |= V63701_ASSERT_LINE_RESET;
+
+       uint8_t * sbp[1] = { soundBuffer };
+//     soundBuffer[0] = new uint8_t[1024];
+//     ptrToBuffer = (SAMPLE **)sbp;
+
+       if (YMInit(1, 3579580, 48000, 16, 512, (SAMPLE **)sbp))
+       {
+               WriteLog("YM: Could not init YM2151 emulator!\n");
+               return -1;
+       }
+
+       if (!LoadMemory())
+               return -1;
+
+       if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER | SDL_INIT_NOPARACHUTE) != 0)
+       {
+               WriteLog("Video: Could not initialize the SDL library: %s\n", SDL_GetError());
+               return -1;
+       }
+
+       SDL_Window * sdlWindow = NULL;
+       SDL_Renderer * sdlRenderer = NULL;
+       int retVal = SDL_CreateWindowAndRenderer(500, 400, SDL_WINDOW_OPENGL, &sdlWindow, &sdlRenderer);
+
+       if (retVal != 0)
+       {
+               WriteLog("Video: Could not window and/or renderer: %s\n", SDL_GetError());
+               return false;
+       }
+
+       InitSound();
+
+       bool done = false;
+       SDL_Event event;
+       startTicks = SDL_GetTicks();
+
+//try to get some noise outta this sucka
+//YMWriteReg(0, 0x20, 0xC0);  // Enable R+L channel
+//YMWriteReg(0, 0x21, 0xC0);  // Enable R+L channel
+YMWriteReg(0, 0x28, 0x4A);     // KC = A 440
+YMWriteReg(0, 0x29, 0x50);     // KC = C# 440+
+YMWriteReg(0, 0x2A, 0x34);     // KC = E 440-
+YMWriteReg(0, 0x40, 0x01);  // Write phase multiply of 1
+YMWriteReg(0, 0x41, 0x01);  // Write phase multiply of 1
+YMWriteReg(0, 0x42, 0x01);  // Write phase multiply of 1
+YMWriteReg(0, 0x60, 0x7F);  // Total level = 127
+YMWriteReg(0, 0x61, 0x7F);  // Total level = 127
+YMWriteReg(0, 0x62, 0x7F);  // Total level = 127
+YMWriteReg(0, 0xE0, 0x7F);  // 1st decay = 7, release = 15
+YMWriteReg(0, 0xE1, 0x7F);  // 1st decay = 7, release = 15
+YMWriteReg(0, 0xE2, 0x7F);  // 1st decay = 7, release = 15
+YMWriteReg(0, 0x08, 0x78);     // Key on channel #1, M1+C1+M2+C2
+YMWriteReg(0, 0x08, 0x79);     // Key on channel #2, M1+C1+M2+C2
+YMWriteReg(0, 0x08, 0x7A);     // Key on channel #3, M1+C1+M2+C2
+
+       do
+       {
+               while (SDL_PollEvent(&event))
+               {
+                       switch (event.type)
+                       {
+                       case SDL_KEYDOWN:
+                               if (event.key.keysym.sym == SDLK_ESCAPE)
+                                       done = true;
+                               else if (event.key.keysym.sym == SDLK_SPACE)
+                               {
+                                       YMWriteReg(0, 0x08, 0x40);
+                                       YMWriteReg(0, 0x08, 0x41);
+                                       YMWriteReg(0, 0x08, 0x42);
+                               }
+                               else if (event.key.keysym.sym == SDLK_1)
+                               {
+                                       memory[0x1380] = 1;
+                               }
+                               else if (event.key.keysym.sym == SDLK_2)
+                               {
+                                       memory[0x1380] = 2;
+                               }
+                               else if (event.key.keysym.sym == SDLK_3)
+                               {
+                                       memory[0x1380] = 3;
+                               }
+                               else if (event.key.keysym.sym == SDLK_4)
+                               {
+                                       memory[0x1380] = 4;
+                               }
+                               else if (event.key.keysym.sym == SDLK_5)
+                               {
+                                       memory[0x1380] = 5;
+                               }
+                               else if (event.key.keysym.sym == SDLK_6)
+                               {
+                                       memory[0x1380] = 6;
+                               }
+                               else if (event.key.keysym.sym == SDLK_7)
+                               {
+                                       memory[0x1380] = 7;
+                               }
+                               else if (event.key.keysym.sym == SDLK_8)
+                               {
+                                       memory[0x1380] = 8;
+                               }
+                               else if (event.key.keysym.sym == SDLK_9)
+                               {
+                                       memory[0x1380] = 9;
+                               }
+                               else if (event.key.keysym.sym == SDLK_0)
+                               {
+                                       memory[0x1380] = 10;
+                               }
+                               else if (event.key.keysym.sym == SDLK_q)
+                               {
+                                       memory[0x1380] = 11;
+                               }
+                               else if (event.key.keysym.sym == SDLK_w)
+                               {
+                                       memory[0x1380] = 12;
+                               }
+                               else if (event.key.keysym.sym == SDLK_e)
+                               {
+                                       memory[0x1380] = 13;
+                               }
+                       }
+               }
+
+               // 49152000/32 = 1536000 Hz, /60 = 25600
+               Execute63701(&mcu, 25600);
+
+               frameCount = (frameCount + 1) % 3;
+               uint32_t waitFrameTime = 17 - (frameCount == 0 ? 1 : 0);
+
+               // Wait for next frame...
+               while (SDL_GetTicks() - startTicks < waitFrameTime)
+                       SDL_Delay(1);
+
+               startTicks = SDL_GetTicks();
+       }
+       while (!done);
+
+       ShutdownSound();
+       SDL_Quit();
+//     delete[] soundBuffer[0];
+
+#if 0
+FILE * f = fopen("mcu-dis-$4000.txt", "w");
+uint32_t address = 0x4000;
+//for(uint32_t i=0xF000, i<0x10000; i++)
+do
+{
+       char line[8192];
+       address += Decode63701(memory, address, line);
+       fprintf(f, "%s\n", line);
+}
+while (address < 0xC000);
+
+fclose(f);
+#endif
+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);
+
+       return 0;
+}
+
+
+#if 0
+#define MCU_MEMORY(NAME,ADDR_LOWROM,ADDR_INPUT,ADDR_UNK1,ADDR_UNK2)                    \
+static MEMORY_READ_START( NAME##_mcu_readmem )                                                         \
+       { 0x0000, 0x001f, hd63701_internal_registers_r },                                               \
+       { 0x0080, 0x00ff, MRA_RAM },                                                                                    \
+       { 0x1000, 0x10ff, namcos1_wavedata_r }, /* PSG device, shared RAM */    \
+       { 0x1100, 0x113f, namcos1_sound_r }, /* PSG device, shared RAM */               \
+       { 0x1000, 0x13ff, shared1_r },                                                                                  \
+       { 0x1400, 0x1fff, MRA_RAM },                                                                                    \
+       { ADDR_INPUT+0x00, ADDR_INPUT+0x01, YM2151_status_port_0_r },                   \
+       { ADDR_INPUT+0x20, ADDR_INPUT+0x20, input_port_0_r },                                   \
+       { ADDR_INPUT+0x21, ADDR_INPUT+0x21, input_port_1_r },                                   \
+       { ADDR_INPUT+0x30, ADDR_INPUT+0x30, dsw0_r },                                                   \
+       { ADDR_INPUT+0x31, ADDR_INPUT+0x31, dsw1_r },                                                   \
+       { ADDR_LOWROM, ADDR_LOWROM+0x3fff, MRA_ROM },                                                   \
+       { 0x8000, 0xbfff, MRA_ROM },                                                                                    \
+       { 0xf000, 0xffff, MRA_ROM },                                                                                    \
+MEMORY_END                                                                                                                                     \
+                                                                                                                                                       \
+static MEMORY_WRITE_START( NAME##_mcu_writemem )                                                       \
+       { 0x0000, 0x001f, hd63701_internal_registers_w },                                               \
+       { 0x0080, 0x00ff, MWA_RAM },                                                                                    \
+       { 0x1000, 0x10ff, namcos1_wavedata_w }, /* PSG device, shared RAM */    \
+       { 0x1100, 0x113f, namcos1_sound_w }, /* PSG device, shared RAM */               \
+       { 0x1000, 0x13ff, shared1_w },                                                                                  \
+       { 0x1400, 0x1fff, MWA_RAM },                                                                                    \
+       { ADDR_INPUT+0x00, ADDR_INPUT+0x00, YM2151_register_port_0_w },                 \
+       { ADDR_INPUT+0x01, ADDR_INPUT+0x01, YM2151_data_port_0_w },                             \
+       { ADDR_UNK1, ADDR_UNK1, MWA_NOP }, /* ??? written (not always) at end of interrupt */   \
+       { ADDR_UNK2, ADDR_UNK2, MWA_NOP }, /* ??? written (not always) at end of interrupt */   \
+       { ADDR_LOWROM, ADDR_LOWROM+0x3fff, MWA_ROM },                                                   \
+       { 0x8000, 0xbfff, MWA_ROM },                                                                                    \
+       { 0xf000, 0xffff, MWA_ROM },                                                                                    \
+MEMORY_END
+
+#define UNUSED 0x4000
+/*                    LOWROM   INPUT    UNK1    UNK2 */
+MCU_MEMORY( rthunder, 0x4000, 0x2000, 0xb000, 0xb800 )
+#undef UNUSED
+
+/*
+0123456789ABCDEF
+----------------
+@ABCDEFGHIJKLMNO
+PQRSTUVWXYZ
+
+
+Sound: Successfully initialized.
+V63701 read $00 from $00...
+V63701 read $00 from $14...
+
+V63701 wrote $40 to $14...
+V63701 wrote $FF to $05...
+
+V63701 read $40 from $14...
+
+V63701 wrote $40 to $14...
+V63701 wrote $00 to $02...
+V63701 wrote $00 to $00...
+
+V63701 read $40 from $14...
+V63701 read $00 from $08...
+
+V63701 wrote $00 to $09...
+V63701 wrote $00 to $0A...
+V63701 wrote $01 to $0B...
+V63701 wrote $00 to $0C...
+
+V63701 read $00 from $08...
+
+V63701 wrote $08 to $08...
+
+V63701 read $00 from $02...
+V63701 read $00 from $02...
+V63701 read $00 from $02...
+
+V63701 wrote $00 to $03...
+V63701 wrote $18 to $01...
+V63701 wrote $C0 to $14...
+Sound: Done.
+MCU state:
+PC=814F, S=1FFD, X=8065, D=A600, CC=C4
+
+
+Problem:
+
+8110: 86 C0           LDAA  #$C0   
+ [PC=8112 S=1FFF X=1100 A=C0 B=00 CC=..N... TN=2C00 CT=2BBA OC=2C00 TO=3F00]
+8112: 97 14           STAA  $14    
+ [PC=8114 S=1FFF X=1100 A=C0 B=00 CC=..N... TN=2C00 CT=2BBC OC=2C00 TO=3F00]
+8114: DE AE           LDX   $AE    
+ [PC=8116 S=1FFF X=14F0 A=C0 B=00 CC=...... TN=2C00 CT=2BBF OC=2C00 TO=3F00]
+
+; Fetches 3 bytes here instead of 2!!
+8116: 6D 7A           TST   $7A,X  
+ [PC=8119 S=1FFF X=14F0 A=C0 B=00 CC=...... TN=2C00 CT=2BC3 OC=2C00 TO=3F00]
+
+; Execution is wrong at this point!!
+8119: 06              TAP          
+ [PC=811A S=1FFF X=14F0 A=C0 B=00 CC=...... TN=2C00 CT=2BC7 OC=2C00 TO=3F00]
+811A: 96 82           LDAA  $82    
+ [PC=811C S=1FFF X=14F0 A=00 B=00 CC=...Z.. TN=2C00 CT=2BC8 OC=2C00 TO=3F00]
+811C: 9B 80           ADDA  $80    
+ [PC=811E S=1FFF X=14F0 A=00 B=00 CC=...Z.. TN=2C00 CT=2BCB OC=2C00 TO=3F00]
+811E: 97 80           STAA  $80    
+ [PC=8120 S=1FFF X=14F0 A=00 B=00 CC=...Z.. TN=2C00 CT=2BCE OC=2C00 TO=3F00]
+8120: 7F 00 82        CLR   $0082  
+ [PC=8123 S=1FFF X=14F0 A=00 B=00 CC=...Z.. TN=2C00 CT=2BD1 OC=2C00 TO=3F00]
+8123: DE AA           LDX   $AA    
+ [PC=8125 S=1FFF X=8068 A=00 B=00 CC=..N... TN=2C00 CT=2BD6 OC=2C00 TO=3F00]
+8125: AD 00           JSR   $00,X  
+ [PC=8068 S=1FFD X=8068 A=00 B=00 CC=..N... TN=2C00 CT=2BDA OC=2C00 TO=3F00]
+8068: 39              RTS          
+ [PC=8127 S=1FFF X=8068 A=00 B=00 CC=..N... TN=2C00 CT=2BDF OC=2C00 TO=3F00]
+8127: 86 A6           LDAA  #$A6   
+ [PC=8129 S=1FFF X=8068 A=A6 B=00 CC=..N... TN=2C00 CT=2BE4 OC=2C00 TO=3F00]
+8129: B7 11 82        STAA  $1182  
+ [PC=812C S=1FFF X=8068 A=A6 B=00 CC=..N... TN=2C00 CT=2BE6 OC=2C00 TO=3F00]
+812C: DE AE           LDX   $AE    
+ [PC=812E S=1FFF X=14F0 A=A6 B=00 CC=...... TN=2C00 CT=2BEA OC=2C00 TO=3F00]
+812E: EE 2C           LDX   $2C,X  
+ [PC=8130 S=1FFF X=8065 A=A6 B=00 CC=..N... TN=2C00 CT=2BEE OC=2C00 TO=3F00]
+8130: AD 00           JSR   $00,X  
+ [PC=8065 S=1FFD X=8065 A=A6 B=00 CC=..N... TN=2C00 CT=2BF3 OC=2C00 TO=3F00]
+8065: B7 B0 00        STAA  $B000  
+ [PC=8068 S=1FFD X=8065 A=A6 B=00 CC=..N... TN=2C00 CT=2BF8 OC=2C00 TO=3F00]
+8068: 39              RTS          
+ [PC=8132 S=1FFF X=8065 A=A6 B=00 CC=..N... TN=2C00 CT=2BFC OC=2C00 TO=3F00]
+
+*/
+#endif
+