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
obj/log.o \
obj/resource.o \
obj/screen.o \
+ obj/sound.o \
obj/v63701.o \
obj/v6809.o \
obj/video.o \
#include <string>
#include <fstream> // Needed for tracelog
#include "screen.h"
+#include "sound.h"
#include "resource.h" // Thunder graphics & sounds
using namespace std;
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
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
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[] = {
if (selection == SNAPSHOT) // Snapshot
{
SpawnSound(USERSOUND, SCAMERA);
- SnapPCX(screen);
+ SavePCXSnapshot();
}
if (selection == RESET) // Reset machine
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;
- }
- }
-}
-
#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
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__
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);
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);
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);
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;
}
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;
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++)
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);
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);
}
-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);
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);
}
#include <SDL2/SDL.h>
#include <stdint.h>
-//#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__
--- /dev/null
+//
+// Sound Handler
+//
+// by James Hammons
+// (C) 2014 Underground Software
+//
+// JLH = James Hammons <jlhamm@acm.org>
+//
+// Who When What
+// --- ---------- -----------------------------------------------------------
+// JLH 04/18/2014 Created this file
+//
+
+#include "sound.h"
+#include <SDL2/SDL.h>
+#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;
+ }
+ }
+}
+
--- /dev/null
+#ifndef __SOUND_H__
+#define __SOUND_H__
+
+#include <stdint.h>
+
+// 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__
+
//
-// Thunder: A Rolling Thunder Emulator w/6809 debugger
+// Thunder: A Rolling Thunder Emulator
//
// by James Hammons
// (C) 2004, 2014 Underground Software
#define THUNDER_VERSION "1.1.0"
+#include <SDL2/SDL.h>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
-//#include <curses.h> // For getch()
#include <time.h>
-#include <SDL2/SDL.h>
-#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;
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
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];
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
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)
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];
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)
{
}
+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!)
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;
}
}
// 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;
}
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;
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; }
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();
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;
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;
}
SDL_PauseAudio(0); // Get that audio going!
+#else
+ InitSound();
#endif
memset(scrBuffer, 0xFF, VIRTUAL_SCREEN_WIDTH*VIRTUAL_SCREEN_HEIGHT*sizeof(uint32_t));
{
HandleGUIDebounce(); // Debounce GUI keys
+#if 0
if (game_over_switch)
{
game_over_switch--; // Countdown...
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...
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)
// 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
** '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;
for(i=0; i<YMNumChips; i++)
{
- YMPSG[i].Buf = buffer[i];
+ YMPSG[i].Buf = 0;//buffer[i];
YMPSG[i].bufp = 0;
YMResetChip(i);
}
** '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);
/*
** shutdown the YM2151 emulators ...