From: Shamus Hammons Date: Fri, 18 Apr 2014 17:36:58 +0000 (-0500) Subject: Added MCU to execution loop and it works. X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?p=thunder;a=commitdiff_plain;h=44a4bdffcaf520bc1681fcc0fd330460cd49129f Added MCU to execution loop and it works. --- diff --git a/makefile b/makefile index e19b93a..a382000 100644 --- a/makefile +++ b/makefile @@ -50,7 +50,7 @@ CPPFLAGS = -MMD -Wall -Wno-switch -Wno-non-virtual-dtor -Wno-uninitialized -Wno- LDFLAGS = -# Ugh, let's get rid of the ref to -lcurses +# Ugh, let's get rid of the ref to -lcurses [DONE] LIBS = `sdl2-config $(SDLLIBTYPE)` -lstdc++ -lz -lm $(GLLIB) INCS = -I. -Isrc @@ -63,6 +63,7 @@ OBJS = \ obj/log.o \ obj/resource.o \ obj/screen.o \ + obj/sound.o \ obj/v63701.o \ obj/v6809.o \ obj/video.o \ diff --git a/src/gui.cpp b/src/gui.cpp index e53b238..9eae58b 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -16,6 +16,7 @@ #include #include // Needed for tracelog #include "screen.h" +#include "sound.h" #include "resource.h" // Thunder graphics & sounds using namespace std; @@ -29,7 +30,6 @@ extern uint8_t gram1[]; // Game RAM (do here??) extern uint8_t hScrollOffset; // Horizontal scroll offset extern uint8_t vScrollOffset; // Vertical scroll offset extern uint32_t voffsets[8]; -extern uint8_t voice_rom[]; // PCM data pointer extern fstream tr; // Tracelog // Global shit @@ -39,7 +39,6 @@ bool show_text; // Whether or not to show text uint16_t show_which_msg; // Which message to show bool show_gui; // Whether or not to show GUI uint16_t selection; // Which GUI item currently selected -uint16_t snd_num; uint16_t gui_debounce; // GUI key debounce value uint16_t num_coins; // Number of coins dropped uint16_t blink = 0; // Used to blink player 1 & 2 start buttons @@ -53,30 +52,6 @@ bool do_decrement; // Flag to handle decrement... bool user_selected_something; // Flag for well, you know... uint16_t dswitch; // Which dipswitch is selected... -// The following are global for the sound routines... - -const float sampleBase = 22050.0/6000.0; // Btwn 5512.5 and 6000 -bool snd_go = false; -bool chan1_go = false, chan2_go = false, chan3_go = false; -bool chan4_go = false, chan5_go = false, chan6_go = false; -uint8_t * sndp1, * sndp2, * sndp3, * sndp4, * sndp5, * sndp6; -uint32_t rom_pos, end_pos; -uint32_t spos1, end_pos1; -uint32_t spos2, end_pos2; -uint32_t spos3, end_pos3; -uint32_t spos4, end_pos4; -uint32_t spos5, end_pos5; -uint32_t spos6, end_pos6; -float sample1; -uint8_t prevSamp1; -int8_t delta_x1; -float sample2; -uint8_t prevSamp2; -int8_t delta_x2; - -uint8_t * snd_array[3] = { sunknown, scya, scamera }; // From RESOURCE.H -uint32_t snd_lens[3] = { sunknownlen, scyalen, scameralen }; - // Bitmaps uint8_t bmp1[] = { @@ -868,7 +843,7 @@ uint8_t UserSelectedSomething(void) if (selection == SNAPSHOT) // Snapshot { SpawnSound(USERSOUND, SCAMERA); - SnapPCX(screen); + SavePCXSnapshot(); } if (selection == RESET) // Reset machine @@ -1020,232 +995,3 @@ void DrawText(void) ShowNumbers(snd_num); } - -// -// Sound stuff (Will go elsewhere??? Perhaps in sound.cpp?) -// -void SpawnSound(int type, int snd, int channel/* = 0*/) -{ - extern uint32_t psg_lens[16]; - extern uint8_t * psg_adrs[16]; - extern uint32_t voc_lens[32]; - extern uint8_t * voc_adrs[32]; - extern uint32_t fm_lens[14]; - extern uint8_t * fm_adrs[14]; - - snd_num = snd; - SpawnMsg(MSHOWNUMS); - - if (type == GAMESOUND) - { - snd--; // Will that do it??? Yes!!! - - if (channel == 0) - { - // 00 nn ss (nn # of repeats of sample ss) - uint32_t st = 0; - - if (snd & 0x40) - { - st = 0x10000; - snd &= 0x0F; - } - - spos1 = (voice_rom[st + (snd << 1)] << 8) | voice_rom[st + (snd << 1) + 1]; - spos1 += st; // Need to add start somewhere... - prevSamp1 = 128; - sample1 = 0; - chan1_go = true; - } - else - { - uint32_t st = 0; - - if (snd & 0x40) - { - st = 0x10000; - snd &= 0x0F; - } - - spos2 = (voice_rom[st + (snd << 1)] << 8) | voice_rom[st + (snd << 1) + 1]; - spos2 += st; // Need to add start somewhere... - prevSamp2 = 128; - sample2 = 0; - chan2_go = true; - } - } - else if (type == PSGSOUND) - { - if (snd_num & 0x10) // Second channel? - { - spos3 = 0; - end_pos3 = psg_lens[snd_num & 0x0F]; - sndp3 = psg_adrs[snd_num & 0x0F]; - chan3_go = true; - - if (spos3 == end_pos3) - chan3_go = false; // No sound loaded, so don't do it! - } - else // First channel - { - spos4 = 0; - end_pos4 = psg_lens[snd_num & 0x0F]; - sndp4 = psg_adrs[snd_num & 0x0F]; - chan4_go = true; - - if (spos4 == end_pos4) - chan4_go = false; // No sound loaded, so don't do it! - } - } - else if (type == FMSOUND) - { - spos5 = 0; - end_pos5 = fm_lens[snd_num]; - sndp5 = fm_adrs[snd_num]; - chan5_go = true; - - if (spos5 == end_pos5) - chan5_go = false; // No sound loaded, so don't do it! - } - else if (type == USERSOUND) - { - spos6 = 0; - end_pos6 = snd_lens[snd_num]; // User sound - sndp6 = snd_array[snd_num]; // Load pointer - chan6_go = true; - } -} - - -// -// Sound card IRQ handler -// -void SoundFunc(void * userdata, Uint8 * buff, int num) -{ - // 0-22 different sounds... - uint16_t cnt = 0, sample; - uint8_t start_samp1, end_samp1, start_samp2, end_samp2; - uint8_t samp1 = 128, samp2 = 128, samp3 = 128, - samp4 = 128, samp5 = 128, samp6 = 128; // Zero samples... - - // Kill sound... - memset(buff, 128, num); - - if (chan1_go || chan2_go || chan3_go || chan4_go || chan5_go || chan6_go) - { - while (cnt != num) - { - if (chan1_go) - { - if (sample1 < 1) - { - samp1 = voice_rom[spos1++]; - - // Kill channel 1 if done... - if (samp1 == 0xFF) - { - chan1_go = false; - samp1 = 128; - } - // RLE compression... - else if (samp1 == 0x00) - { - // # of repeats - sample1 += (float)voice_rom[spos1++] * sampleBase; - // Get last good sample - samp1 = prevSamp1; - } - else - // Keep fractional part intact - sample1 += sampleBase; - } - - prevSamp1 = samp1; // Save last sample value - sample1 -= 1.0; // Decrement repeat counter - } - -// Stretching 5KHz samples to 22KHz: -// numRepeats = 4; -// 6KHz -> 22KHz: 22/6 repeats... - if (chan2_go) - { - if (sample2 < 1) - { - samp2 = voice_rom[spos2++]; - - if (samp2 == 0xFF) - { - chan2_go = false; - samp2 = 128; // Kill channel 2 if done... - } - else if (samp2 == 0x00) // RLE compression... - { - sample2 += (float)voice_rom[spos2++] * sampleBase; // # of repeats - samp2 = prevSamp2; - } - else - sample2 += sampleBase; - } - -// Delta-X values were making the samples sound like crap... -// start_samp2 += delta_x2; - prevSamp2 = samp2; - sample2 -= 1.0; - } - - if (chan3_go) - { - samp3 = sndp3[spos3++]; - - if (spos3 == end_pos3) - { - chan3_go = false; - samp3 = 128; // Kill channel 3 if done... - } - } - - if (chan4_go) - { - samp4 = sndp4[spos4++]; - - if (spos4 == end_pos4) - { - chan4_go = false; - samp4 = 128; // Kill channel 4 if done... - } - } - - if (chan5_go) - { - samp5 = sndp5[spos5++]; - - if (spos5 == end_pos5) - { - chan5_go = false; - samp5 = 128; // Kill channel 5 if done... - } - } - - if (chan6_go) - { - samp6 = sndp6[spos6++]; - - if (spos6 == end_pos6) - { - chan6_go = false; - samp6 = 128; // Kill channel 6... - } - } - - // Mix 'em... - sample = samp1 + samp2 + samp3 + samp4 + samp5 + samp6 - 640; - - // If it overflowed, clip it - if (sample & 0xFF00) - sample = (sample & 0x8000 ? 0x00 : 0xFF); - - buff[cnt++] = sample; - } - } -} - diff --git a/src/gui.h b/src/gui.h index 9a17174..a5d4c6f 100644 --- a/src/gui.h +++ b/src/gui.h @@ -18,18 +18,6 @@ #define MSNAPSHOT 2 #define MSHOWNUMS 3 -// Sound routine macros - -#define GAMESOUND 0 -#define USERSOUND 1 -#define PSGSOUND 2 -#define VOCSOUND 3 -#define FMSOUND 4 - -#define SUNKNOWN 0 -#define SCYA 1 -#define SCAMERA 2 - // UserSelectedSomething icon value macros #define NOGUI 0 @@ -58,8 +46,5 @@ void SetRefreshRate(bool); void ActivateGUI(void); void DeactivateGUI(void); void HandleGUIDebounce(void); -void SpawnSound(int, int, int channel = 0); -//void SoundFunc(uint8 *, uint16); -void SoundFunc(void *, Uint8 *, int); #endif // __GUI_H__ diff --git a/src/screen.cpp b/src/screen.cpp index 660281f..dda0f6e 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -87,11 +87,7 @@ void BlitChar(SDL_Surface * scr, uint8_t * chr, uint8_t * ram) for(uint8_t sy=0; sy<29; sy++) { for(uint8_t sx=0; sx<37; sx++) -#if 0 - DrawChar(chr, ram, sx, sy, scp0, (charbase ? 0x20000 : 0x00000), 0, false); -#else DrawChar(chr, ram, sx, sy, scp0, (charbase ? 0x20000 : 0x00000), hScrollOffset, vScrollOffset, false); -#endif scp0 += 0x80; scp0 = 0x0000 | (scp0 & 0x0FFF); @@ -104,11 +100,7 @@ void BlitChar(SDL_Surface * scr, uint8_t * chr, uint8_t * ram) for(uint8_t sy=0; sy<29; sy++) { for(uint8_t sx=0; sx<37; sx++) -#if 0 - DrawChar(chr, ram, sx, sy, scp1, (charbase ? 0x30000 : 0x10000), 0); -#else DrawChar(chr, ram, sx, sy, scp1, (charbase ? 0x30000 : 0x10000), hScrollOffset, vScrollOffset); -#endif scp1 += 0x80; scp1 = 0x1000 | (scp1 & 0x0FFF); @@ -121,11 +113,7 @@ void BlitChar(SDL_Surface * scr, uint8_t * chr, uint8_t * ram) for(uint8_t sy=0; sy<29; sy++) { for(uint8_t sx=0; sx<37; sx++) -#if 0 - DrawChar(chr, ram, sx, sy, scp2, 0x40000, 0); -#else DrawChar(chr, ram, sx, sy, scp2, 0x40000, hScrollOffset, vScrollOffset); -#endif scp2 += 0x80; scp2 = 0x2000 | (scp2 & 0x0FFF); @@ -138,11 +126,7 @@ void BlitChar(SDL_Surface * scr, uint8_t * chr, uint8_t * ram) for(uint8_t sy=0; sy<28; sy++) { for(uint8_t sx=0; sx<36; sx++) -#if 0 - DrawChar(chr, ram, sx, sy, scp3, 0x50000, hScrollOffset + voffsets[vScrollOffset]); -#else DrawChar(chr, ram, sx, sy, scp3, 0x50000); -#endif scp3 += 0x80; } @@ -156,7 +140,9 @@ void BlitChar(SDL_Surface * scr, uint8_t * chr, uint8_t * ram) if (ShowGUI()) DrawGUI(); - // Rolling Thunder screen size is 288 x 224. Virtual is this, real may not be... + // Rolling Thunder screen size is 288 x 224. Virtual is this, real may not + // be... (and we don't have to care about that, the OpenGL backend takes + // care of it.) uint32_t src = 0; @@ -185,13 +171,8 @@ static inline void DrawChar(uint8_t * chr, uint8_t * ram, uint8_t sx, uint8_t sy uint8_t index = ram[sp2] & 0x03; uint8_t color = ram[sp2]; uint32_t chind = baseAddr + (((index << 8) + tile) * 64); -// uint32_t sc_addr = (sx * 8) + (sy * 2560) + scrollOffset; // Start addr in my_scr[] -// uint32_t sc_addr = (sx * 8) + (sy * 288 * 8);// + scrollOffset; - int xStart = (int)(sx * 8) - xScroll; int yStart = (int)(sy * 8) - yScroll; - -// int32_t sc_addr = ((sx * 8) - xScroll) + ((sy * 8 * 288) - (yScroll * 288)); int32_t sc_addr = xStart + (yStart * 288); for(int y=0; y<8; y++) @@ -339,11 +320,11 @@ void Sprite(uint32_t sprnum, uint16_t x, uint16_t y, uint8_t flip, if (horiz_bl) DrawSpriteBlock(sprnum, x, y, 16, 32, 2); else - sprnum += 128; // Advance to next... + sprnum += 128; // Advance to next... if (vert_bl) { - y += 16; // Do next row... + y += 16; // Do next row... DrawSpriteBlock(sprnum, x, y, 0, 16, 2); @@ -359,11 +340,11 @@ void Sprite(uint32_t sprnum, uint16_t x, uint16_t y, uint8_t flip, DrawSpriteBlock2(sprnum, x, y, 14, 0xFFFE, -2); if (!horiz_bl) - sprnum += 128; // If single, skip sprite... + sprnum += 128; // If single, skip sprite... if (vert_bl) { - y += 16; // Adjust Y coord... + y += 16; // Adjust Y coord... if (horiz_bl) DrawSpriteBlock2(sprnum, x, y, 30, 14, -2); @@ -397,88 +378,82 @@ int FindPCXName(void) } -void SnapPCX(SDL_Surface * scr) +void SavePCXSnapshot(void) { char filename[30]; - int i, line; - FILE * fw; - int XMax = 319; // Need to adjust this to handle 288 bytes per line - int YMax = 223; - int bytesPerLine = 320; - - // Return if failed... - if ((i = FindPCXName()) < 0) + int xMax = 287; + int yMax = 223; + int bytesPerLine = 288; + int i = FindPCXName(); + + if (i < 0) return; sprintf(filename, "thnd%04i.pcx", i); + FILE * fw = fopen(filename, "wb"); - if ((fw = fopen(filename, "wb")) == NULL) - return; // failed... + if (fw == NULL) + return; // Write the header - fputc(0xA, fw); // pcx signature - fputc(0x5, fw); // version 5 - fputc(0x1, fw); // RLE encoding - fputc(0x8, fw); // bits per pixel + fputc(0x0A, fw); // PCX signature + fputc(0x05, fw); // Version 5 + fputc(0x01, fw); // RLE encoding + fputc(0x08, fw); // Bits per pixel fputc(0, fw); fputc(0, fw); fputc(0, fw); - fputc(0, fw); // XMin=0,YMin=0 - fputc(XMax & 0xFF, fw); - fputc(XMax >> 8, fw); - fputc(YMax & 0xFF, fw); - fputc(YMax >> 8, fw); + fputc(0, fw); // XMin=0,YMin=0 + fputc(xMax & 0xFF, fw); + fputc(xMax >> 8, fw); + fputc(yMax & 0xFF, fw); + fputc(yMax >> 8, fw); fputc(0, fw); fputc(0, fw); fputc(0, fw); - fputc(0,fw); // unknown DPI + fputc(0, fw); // Unknown DPI - for (i=0; i<48; i++) - fputc(0, fw); // EGA color palette + // EGA color palette + for(i=0; i<48; i++) + fputc(0, fw); - fputc(0, fw); // reserved - fputc(1, fw); // number of bit planes + fputc(0, fw); // Reserved + fputc(1, fw); // Number of bit planes fputc(bytesPerLine & 0xFF, fw); fputc(bytesPerLine >> 8, fw); fputc(1, fw); - fputc(0, fw); // palette info - unused - fputc((XMax + 1) & 0xFF, fw); - fputc((XMax + 1) >> 8, fw); - fputc((YMax + 1) & 0xFF, fw); - fputc((YMax + 1) >> 8, fw); // screen resolution + fputc(0, fw); // Palette info - unused + fputc((xMax + 1) & 0xFF, fw); + fputc((xMax + 1) >> 8, fw); + fputc((yMax + 1) & 0xFF, fw); + fputc((yMax + 1) >> 8, fw); // Screen resolution + // Unused for (i=0; i<54; i++) - fputc(0, fw); // unused - - // Instead of using the screen, we should use our internal buffer... - SDL_LockSurface(scr); + fputc(0, fw); - uint32_t mem = scr->pitch * 8; // Skip first line... WAS:320*8; + uint8_t * mem = my_scr; - for (line=0; line<=YMax; line++) + for(int line=0; line<=yMax; line++) { - int count; - int last; - int xpos; - uint8_t * pMem = (uint8_t *)scr->pixels; - - xpos = 0; + int xpos = 0; while (xpos < bytesPerLine) { - last = pMem[mem++]; + uint8_t count = 1; + uint8_t last = *mem; + mem++; xpos++; - count = 1; - while (pMem[mem] == last && xpos < bytesPerLine && count < 63) + while ((*mem == last) && (xpos < bytesPerLine) && (count < 63)) { mem++; count++; xpos++; } - if (count > 1 || (last & 0xC0) == 0xC0) + if ((count > 1) || ((last & 0xC0) == 0xC0)) { fputc(0xC0 | (count & 0x3F), fw); fputc(last & 0xFF, fw); @@ -486,18 +461,19 @@ void SnapPCX(SDL_Surface * scr) else fputc(last & 0xFF, fw); } - - mem += (scr->pitch - 320); // Handle non-standard line lengths... } - SDL_UnlockSurface(scr); - - // Write the palette + // Write out the palette fputc(0x0C, fw); - for (i=0; i<768; i++) - fputc(palette[i], fw); + for(int i=0; i<256; i++) + { + fputc(palette[i] & 0xFF, fw); + fputc((palette[i] >> 8) & 0xFF, fw); + fputc((palette[i] >> 16) & 0xFF, fw); + } - fclose(fw); // success! + // Success! + fclose(fw); } diff --git a/src/screen.h b/src/screen.h index 48b4b29..6ea06f4 100644 --- a/src/screen.h +++ b/src/screen.h @@ -11,11 +11,8 @@ #include #include -//#define VIRTUAL_SCREEN_WIDTH 288 -//#define VIRTUAL_SCREEN_HEIGHT 224 - -void SnapPCX(SDL_Surface *); // Take a PCX snapshot -void BlitChar(SDL_Surface *, uint8_t *, uint8_t *); // Show NAMCO screen +void BlitChar(SDL_Surface *, uint8_t *, uint8_t *); +void SavePCXSnapshot(void); #endif // __SCREEN_H__ diff --git a/src/sound.cpp b/src/sound.cpp new file mode 100644 index 0000000..930de35 --- /dev/null +++ b/src/sound.cpp @@ -0,0 +1,296 @@ +// +// Sound Handler +// +// by James Hammons +// (C) 2014 Underground Software +// +// JLH = James Hammons +// +// Who When What +// --- ---------- ----------------------------------------------------------- +// JLH 04/18/2014 Created this file +// + +#include "sound.h" +#include +#include "resource.h" + +// Function prototypes +void SoundFunc(void *, Uint8 *, int); + +// Vars +extern uint8_t voice_rom[]; // PCM data pointer + +static bool soundInitialized = false; +const float sampleBase = 22050.0/6000.0; // Btwn 5512.5 and 6000 +bool snd_go = false; +bool chan1_go = false, chan2_go = false, chan3_go = false; +bool chan4_go = false, chan5_go = false, chan6_go = false; +uint8_t * sndp1, * sndp2, * sndp3, * sndp4, * sndp5, * sndp6; +uint32_t rom_pos, end_pos; +uint32_t spos1, end_pos1; +uint32_t spos2, end_pos2; +uint32_t spos3, end_pos3; +uint32_t spos4, end_pos4; +uint32_t spos5, end_pos5; +uint32_t spos6, end_pos6; +float sample1; +uint8_t prevSamp1; +int8_t delta_x1; +float sample2; +uint8_t prevSamp2; +int8_t delta_x2; +uint16_t snd_num; +uint8_t * snd_array[3] = { sunknown, scya, scamera }; // From RESOURCE.H +uint32_t snd_lens[3] = { sunknownlen, scyalen, scameralen }; + + +void InitSound(void) +{ + SDL_AudioSpec desired, obtained; + desired.freq = 22050; + desired.format = AUDIO_U8; + desired.channels = 1; + desired.samples = 1024; + desired.callback = SoundFunc; + desired.userdata = NULL; + // Also, should check to see if it got the hardware it needed, correct sample size, etc. + if (SDL_OpenAudio(&desired, &obtained) < 0) + { + soundInitialized = false; + printf("Couldn't open audio: %s\n", SDL_GetError()); + return; + } + + // Get that audio going! + SDL_PauseAudio(0); + soundInitialized = true; +} + + +void SpawnSound(int type, int snd, int channel/* = 0*/) +{ + extern uint32_t psg_lens[16]; + extern uint8_t * psg_adrs[16]; + extern uint32_t voc_lens[32]; + extern uint8_t * voc_adrs[32]; + extern uint32_t fm_lens[14]; + extern uint8_t * fm_adrs[14]; + + if (!soundInitialized) + return; + + snd_num = snd; +// SpawnMsg(MSHOWNUMS); + + if (type == GAMESOUND) + { + // Will that do it??? Yes!!! + snd--; + + if (channel == 0) + { + // 00 nn ss (nn # of repeats of sample ss) + uint32_t st = 0; + + if (snd & 0x40) + { + st = 0x10000; + snd &= 0x0F; + } + + spos1 = (voice_rom[st + (snd << 1)] << 8) | voice_rom[st + (snd << 1) + 1]; + spos1 += st; // Need to add start somewhere... + prevSamp1 = 128; + sample1 = 0; + chan1_go = true; + } + else + { + uint32_t st = 0; + + if (snd & 0x40) + { + st = 0x10000; + snd &= 0x0F; + } + + spos2 = (voice_rom[st + (snd << 1)] << 8) | voice_rom[st + (snd << 1) + 1]; + spos2 += st; // Need to add start somewhere... + prevSamp2 = 128; + sample2 = 0; + chan2_go = true; + } + } + else if (type == PSGSOUND) + { + if (snd_num & 0x10) // Second channel? + { + spos3 = 0; + end_pos3 = psg_lens[snd_num & 0x0F]; + sndp3 = psg_adrs[snd_num & 0x0F]; + chan3_go = true; + + if (spos3 == end_pos3) + chan3_go = false; // No sound loaded, so don't do it! + } + else // First channel + { + spos4 = 0; + end_pos4 = psg_lens[snd_num & 0x0F]; + sndp4 = psg_adrs[snd_num & 0x0F]; + chan4_go = true; + + if (spos4 == end_pos4) + chan4_go = false; // No sound loaded, so don't do it! + } + } + else if (type == FMSOUND) + { + spos5 = 0; + end_pos5 = fm_lens[snd_num]; + sndp5 = fm_adrs[snd_num]; + chan5_go = true; + + if (spos5 == end_pos5) + chan5_go = false; // No sound loaded, so don't do it! + } + else if (type == USERSOUND) + { + spos6 = 0; + end_pos6 = snd_lens[snd_num]; // User sound + sndp6 = snd_array[snd_num]; // Load pointer + chan6_go = true; + } +} + + +void SoundFunc(void * userdata, Uint8 * buff, int num) +{ + // 0-22 different sounds... + uint16_t cnt = 0, sample; + uint8_t start_samp1, end_samp1, start_samp2, end_samp2; + uint8_t samp1 = 128, samp2 = 128, samp3 = 128, + samp4 = 128, samp5 = 128, samp6 = 128; // Zero samples... + + // Kill sound... + memset(buff, 128, num); + + if (chan1_go || chan2_go || chan3_go || chan4_go || chan5_go || chan6_go) + { + while (cnt != num) + { + if (chan1_go) + { + if (sample1 < 1) + { + samp1 = voice_rom[spos1++]; + + // Kill channel 1 if done... + if (samp1 == 0xFF) + { + chan1_go = false; + samp1 = 128; + } + // RLE compression... + else if (samp1 == 0x00) + { + // # of repeats + sample1 += (float)voice_rom[spos1++] * sampleBase; + // Get last good sample + samp1 = prevSamp1; + } + else + // Keep fractional part intact + sample1 += sampleBase; + } + + prevSamp1 = samp1; // Save last sample value + sample1 -= 1.0; // Decrement repeat counter + } + +// Stretching 5KHz samples to 22KHz: +// numRepeats = 4; +// 6KHz -> 22KHz: 22/6 repeats... + if (chan2_go) + { + if (sample2 < 1) + { + samp2 = voice_rom[spos2++]; + + if (samp2 == 0xFF) + { + chan2_go = false; + samp2 = 128; // Kill channel 2 if done... + } + else if (samp2 == 0x00) // RLE compression... + { + sample2 += (float)voice_rom[spos2++] * sampleBase; // # of repeats + samp2 = prevSamp2; + } + else + sample2 += sampleBase; + } + +// Delta-X values were making the samples sound like crap... +// start_samp2 += delta_x2; + prevSamp2 = samp2; + sample2 -= 1.0; + } + + if (chan3_go) + { + samp3 = sndp3[spos3++]; + + if (spos3 == end_pos3) + { + chan3_go = false; + samp3 = 128; // Kill channel 3 if done... + } + } + + if (chan4_go) + { + samp4 = sndp4[spos4++]; + + if (spos4 == end_pos4) + { + chan4_go = false; + samp4 = 128; // Kill channel 4 if done... + } + } + + if (chan5_go) + { + samp5 = sndp5[spos5++]; + + if (spos5 == end_pos5) + { + chan5_go = false; + samp5 = 128; // Kill channel 5 if done... + } + } + + if (chan6_go) + { + samp6 = sndp6[spos6++]; + + if (spos6 == end_pos6) + { + chan6_go = false; + samp6 = 128; // Kill channel 6... + } + } + + // Mix 'em... + sample = samp1 + samp2 + samp3 + samp4 + samp5 + samp6 - 640; + + // If it overflowed, clip it + if (sample & 0xFF00) + sample = (sample & 0x8000 ? 0x00 : 0xFF); + + buff[cnt++] = sample; + } + } +} + diff --git a/src/sound.h b/src/sound.h new file mode 100644 index 0000000..39ee96f --- /dev/null +++ b/src/sound.h @@ -0,0 +1,27 @@ +#ifndef __SOUND_H__ +#define __SOUND_H__ + +#include + +// Sound routine macros +#define GAMESOUND 0 +#define USERSOUND 1 +#define PSGSOUND 2 +#define VOCSOUND 3 +#define FMSOUND 4 + +#define SUNKNOWN 0 +#define SCYA 1 +#define SCAMERA 2 + + +// Functions +void InitSound(void); +void SpawnSound(int, int, int channel = 0); + + +// Exported vars +extern uint16_t snd_num; + +#endif // __SOUND_H__ + diff --git a/src/thunder.cpp b/src/thunder.cpp index 09cc40f..5219805 100644 --- a/src/thunder.cpp +++ b/src/thunder.cpp @@ -1,5 +1,5 @@ // -// Thunder: A Rolling Thunder Emulator w/6809 debugger +// Thunder: A Rolling Thunder Emulator // // by James Hammons // (C) 2004, 2014 Underground Software @@ -16,6 +16,7 @@ #define THUNDER_VERSION "1.1.0" +#include #include #include #include @@ -24,13 +25,13 @@ #include #include #include -//#include // For getch() #include -#include -#include "v6809.h" -#include "screen.h" #include "gui.h" #include "log.h" +#include "screen.h" +#include "sound.h" +#include "v63701.h" +#include "v6809.h" #include "video.h" using namespace std; @@ -74,8 +75,10 @@ uint8_t * gram, * grom; // Allocate RAM & ROM pointers uint8_t gram1[0x10000], gram2[0x10000], grom1[0x10000], grom2[0x10000]; // Actual memory uint8_t grom3[0x8000], grom4[0x8000], data_rom[0x40000], spr_rom[0x80000], voice_rom[0x20000]; uint8_t chr_rom[0x60000]; // Character ROM pointer +uint8_t mcuMem[0x10000]; // 64K for MCU V6809REGS cpu1, cpu2; +V63701REGS mcu; bool trace1 = false; // ditto... bool looking_at_rom = true; // true = R1, false = R2 @@ -92,9 +95,9 @@ bool refresh2 = true; uint32_t psg_lens[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; uint8_t * psg_adrs[16]; -uint32_t voc_lens[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -uint8_t * voc_adrs[32]; +//uint32_t voc_lens[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +//uint8_t * voc_adrs[32]; uint32_t fm_lens[14] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; uint8_t * fm_adrs[14]; @@ -113,6 +116,10 @@ uint8_t RdMem(uint16_t addr) if (addr < 0x8000) { + // Memory shared with MCU (CPU #1 only! CPU #2 does not) + if ((addr >= 0x4000) && (addr <= 0x43FF)) + return mcuMem[addr - 0x3000]; + if (addr > 0x5FFF) b = data_rom[banksw1 + (addr - 0x6000)]; // Get char data else @@ -151,14 +158,22 @@ if (((addr >= 0x4180) && (addr <= 0x4191)) || (addr == 0x4380)) banksw1 = (uint32_t)b << 13; // Set char data bankswitch base address if (addr > 0x4284 && addr < 0x42A5 && b) SpawnSound(PSGSOUND, addr - 0x4285); // Do PSG sound on chans 2, 3 +#if 0 if (addr == 0x4380) { SpawnSound(FMSOUND, b); // Do FM sound on channel 4 if (b == 12) game_over_switch = 240; // Set game over delay... } - if (addr < 0x423D || addr > 0x425C) // Protect writes to DSWs +#endif +// if (addr < 0x423D || addr > 0x425C) // Protect writes to DSWs + + // Memory shared with MCU (CPU #1 only! CPU #2 does not) + if ((addr >= 0x4000) && (addr <= 0x43FF)) + mcuMem[addr - 0x3000] = b; + else gram1[addr] = b; + if (addr == 0x8800) charbase = false; // Char banksw1 if (addr == 0x8C00) @@ -195,7 +210,7 @@ uint8_t RdMemB(uint16_t addr) if (addr > 0x1FFF && addr < 0x6000) b = gram1[addr - 0x2000]; if (addr > 0x5FFF) - b = grom3[banksw2 + (addr - 0x6000)]; // Correct? + b = grom3[banksw2 + (addr - 0x6000)]; } else b = grom2[addr]; @@ -223,28 +238,32 @@ if (((addr >= 0x0180) && (addr <= 0x0191)) || (addr == 0x0380)) printf("WriteMem: CPU #2 writing $%02X to $%04X...\n", b, addr); #endif +#if 0 if (addr == 0x6000) SpawnSound(GAMESOUND, gram1[0x6200], 0); // Do voice chan 1 if (addr == 0x6400) SpawnSound(GAMESOUND, gram1[0x6600], 1); // Do voice chan 2 if (addr > 0x0284 && addr < 0x02A5 && b) SpawnSound(PSGSOUND, addr - 0x0285); // Do PSG sound on chans 2, 3 +#endif if (addr == 0xD803) banksw2 = (uint32_t)(b & 0x03) << 13; // Set sprite data bank switch +#if 0 if (addr == 0x0380) { SpawnSound(FMSOUND, b); // Do FM sound on chan 4 if (b == 12) game_over_switch = 240; // Set game over delay... } - if (addr < 0x023D || addr > 0x025C) // Protect writes against DSWs +#endif +// if (addr < 0x023D || addr > 0x025C) // Protect writes against DSWs { if (addr < 0x2000) gram1[addr + 0x4000] = b; if (addr > 0x1FFF && addr < 0x6000) gram1[addr - 0x2000] = b; - if (addr > 0x5FFF) - gram1[addr] = b; +// if (addr > 0x5FFF) +// gram1[addr] = b; } if (addr == 0x8800) { @@ -258,6 +277,83 @@ if (((addr >= 0x0180) && (addr <= 0x0191)) || (addr == 0x0380)) } +uint8_t MCUReadMemory(uint16_t address) +{ +#if 1 + if (address < 0x20) + { +// printf("V63701 read $%02X from $%02X...\n", memory[address], address); + return InternalRegisterRead(address); + } +#endif + +#if 0 + // Translate local reads @ $1000-$13FF to $4000-$43FF in shared RAM + if ((address >= 0x1000) && (address <= 0x13FF)) + return gram1[0x3000 + address]; + else +#endif + if ((address >= 0x2000) && (address <= 0x2001)) + { + return 0; //for now +// return YMReadReg(0); + } +// else if (address == 0x2020) +// return input_port_0_r(0); +// else if (address == 0x2021) +// return input_port_1_r(0); + // This is DSW1 & 2. All switch settings are active low. + else if (address == 0x2030) + return 0xFF; + else if (address == 0x2031) + return 0xFF; + + return mcuMem[address]; +} + + +void MCUWriteMemory(uint16_t address, uint8_t data) +{ + static uint8_t ymRegister; + +#if 1 + if (address < 0x20) + { +// printf("V63701 wrote $%02X to $%02X...\n", data, address); + InternalRegisterWrite(address, data); + return; + } +#endif + +#if 0 + // Translate local reads @ $1000-$13FF to $4000-$43FF in shared RAM + if ((address >= 0x1000) && (address <= 0x13FF)) + { + gram1[0x3000 + 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 + mcuMem[address] = data; +} + + // // Generic Load file into image space // (No error checking performed! Responsibility of caller!) @@ -334,12 +430,11 @@ bool ReadColorPROMs(void) for(int i=0; i<256; i++) { char c1, c2; - uint8_t r, g, b; ff1.get(c1); ff2.get(c2); - r = (uint8_t)c1 & 0x0F; - g = (uint8_t)c1 >> 4; - b = (uint8_t)c2; + uint8_t r = (uint8_t)c1 & 0x0F; + uint8_t g = (uint8_t)c1 >> 4; + uint8_t b = (uint8_t)c2; palette[i] = 0xFF000000 | (b << 20) | (b << 16) | (g << 12) | (g << 8) | (r << 4) | r; } @@ -348,8 +443,8 @@ bool ReadColorPROMs(void) } // PROM5 has the following in it (tile address decoder): - // 00: 00 20 40 60 02 22 42 62 04 24 44 64 06 26 46 66 - // 10: 88 A8 C8 E8 8A AA CA EA 8C AC CC EC 8E AE CE EE + // 00: 00 20 40 60 02 22 42 62 04 24 44 64 06 26 46 66 + // 10: 88 A8 C8 E8 8A AA CA EA 8C AC CC EC 8E AE CE EE return ff1; } @@ -434,10 +529,12 @@ uint32_t GetWAVLength(fstream & file) file.get(ch); len |= (int)(uint8_t)ch << 16; file.get(ch); len |= (int)(uint8_t)ch << 24; - file.ignore(len + 4); // Skip intermediate data + // Skip intermediate data + file.ignore(len + 4); } - file.get(ch); len = (int)(uint8_t)ch; // & finally get length of data + // & finally get length of data + file.get(ch); len = (int)(uint8_t)ch; file.get(ch); len |= (int)(uint8_t)ch << 8; file.get(ch); len |= (int)(uint8_t)ch << 16; file.get(ch); len |= (int)(uint8_t)ch << 24; @@ -586,8 +683,8 @@ extern bool disasm; // From 'V6809.CPP' if (!LoadImg(ROM3, grom3, 0, 0x8000)) // Load 3rd ROM into its own space { cout << "Could not open file '" << ROM3 << "'!" << endl; return -1; } - if (!LoadImg(ROM4, grom4, 0, 0x8000)) // Load 4rd ROM into its own space - { cout << "Could not open file '" << ROM4 << "'!" << endl; return -1; } +// if (!LoadImg(ROM4, grom4, 0, 0x8000)) // Load 4rd ROM into its own space +// { cout << "Could not open file '" << ROM4 << "'!" << endl; return -1; } if (!LoadImg(ROM17, data_rom, 0, 0x10000)) // Load 17th ROM { cout << "Could not open file '" << ROM17 << "'!" << endl; return -1; } @@ -637,6 +734,13 @@ extern bool disasm; // From 'V6809.CPP' return -1; } + // Load MCU program + data + if (!LoadImg(MCUROM, mcuMem, 0xF000, 0x1000)) // Load MCU ROM + { cout << "Could not open file '" << MCUROM << "'!" << endl; return -1; } + + if (!LoadImg(ROM4, mcuMem, 0x4000, 0x8000)) // Load 4th ROM + { cout << "Could not open file '" << ROM4 << "'!" << endl; return -1; } + // Load samples if they're there... LoadPSGs(); LoadFMs(); @@ -653,12 +757,17 @@ extern bool disasm; // From 'V6809.CPP' cpu2.WrMem = WrMemB; cpu2.cpuFlags |= V6809_ASSERT_LINE_RESET; + memset(&mcu, 0, sizeof(V63701REGS)); + mcu.RdMem = MCUReadMemory; + mcu.WrMem = MCUWriteMemory; + mcu.cpuFlags |= V63701_ASSERT_LINE_RESET; + uint32_t my_clock = 0; running = true; // Set running status... trace1 = false; SetRefreshRate(refresh2); // Tell GUI our refresh rate -#if 1 +#if 0 // This is data that is supposed to come from the MCU... So that's why it hangs gram1[0x4182] = 0xA6; // Temp kludge gram1[0x4184] = 0xA6; @@ -676,7 +785,7 @@ WriteLog("About to set up screen...\n"); oldTicks = SDL_GetTicks(); WriteLog("About to set up audio...\n"); -#if 1 +#if 0 // This crap SHOULD be in sound.cpp (not yet created)... SDL_AudioSpec desired, obtained; desired.freq = 22050; @@ -693,6 +802,8 @@ WriteLog("About to set up audio...\n"); } SDL_PauseAudio(0); // Get that audio going! +#else + InitSound(); #endif memset(scrBuffer, 0xFF, VIRTUAL_SCREEN_WIDTH*VIRTUAL_SCREEN_HEIGHT*sizeof(uint32_t)); @@ -703,6 +814,7 @@ WriteLog("About to enter main loop...\n"); { HandleGUIDebounce(); // Debounce GUI keys +#if 0 if (game_over_switch) { game_over_switch--; // Countdown... @@ -710,20 +822,24 @@ WriteLog("About to enter main loop...\n"); if (game_over_switch == 0) gram1[0x4380] = 0; // Kill music! } +#endif + +// Dipswitches are presented to the main CPUs as 0 or 1 at locations +// $423D - $425B by the MCU //testing... (works) //gram1[0x423D] = 1; //gram1[0x423D] = self_test; // Reset DSW1-1 - gram1[0x4268] = 0; // Reset Video test - gram1[0x427A] = 0; gram1[0x427C] = 0; +// gram1[0x4268] = 0; // Reset Video test +// gram1[0x427A] = 0; gram1[0x427C] = 0; //gram1[0x427B] = 0; gram1[0x427D] = 0; - gram1[0x427E] = 0;// gram1[0x427F] = 0; - gram1[0x4280] = 0;// gram1[0x4281] = 0; +// gram1[0x427E] = 0;// gram1[0x427F] = 0; +// gram1[0x4280] = 0;// gram1[0x4281] = 0; //gram1[0x4276] = 0; - gram1[0x426A] = 0; +// gram1[0x426A] = 0; //gram1[0x4278] = 0; - gram1[0x426C] = 0; - gram1[0x4262] = 0; gram1[0x4260] = 0; +// gram1[0x426C] = 0; +// gram1[0x4262] = 0; gram1[0x4260] = 0; //gram1[0x4247] = 0; // SDL key handling... @@ -737,6 +853,13 @@ WriteLog("About to enter main loop...\n"); case SDL_KEYDOWN: if (event.key.keysym.sym == SDLK_ESCAPE) running = false; + // Do PCX snapshot (F4) + else if (event.key.keysym.sym == SDLK_F4) + { +// SpawnSound(USERSOUND, SCAMERA); + SavePCXSnapshot(); +// debounce = 10; + } else if (event.key.keysym.sym == SDLK_F10) gram1[0x41A5]++; // Coin? (F10) else if (event.key.keysym.sym == SDLK_c) @@ -1024,6 +1147,10 @@ WriteLog("About to enter main loop...\n"); // There's better ways, such as keeping track of when slave writes to master, etc... Execute6809(&cpu1, 40); Execute6809(&cpu2, 40); + + // MCU runs at 1,536,000 Hz + // 1536000 / 60 / 640 == 40 + Execute63701(&mcu, 40); } } // END: enable_cpu diff --git a/src/ym2151.c b/src/ym2151.c index 2074a4c..a69a281 100644 --- a/src/ym2151.c +++ b/src/ym2151.c @@ -834,7 +834,7 @@ void write_YM_D1L_RR_BASE(uint8_t n, uint8_t r, uint8_t v) ** 'rate' is sampling rate and 'bufsiz' is the size of the ** buffer that should be updated at each interval */ -int YMInit(int num, int clock, int rate, int sample_bits, int bufsiz, SAMPLE ** buffer) +int YMInit(int num, int clock, int rate, int sample_bits, int bufsiz)//, SAMPLE ** buffer) { int i; @@ -922,7 +922,7 @@ int YMInit(int num, int clock, int rate, int sample_bits, int bufsiz, SAMPLE ** for(i=0; i