From: Shamus Hammons Date: Fri, 13 Jan 2023 17:35:16 +0000 (-0600) Subject: Oops, forgot to pull first before the changes. :-P X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=637d07e46cc5104e76a428be3e8f27f85c8e1d63;hp=-c;p=thunder Oops, forgot to pull first before the changes. :-P Merge branch 'master' of http://shamusworld.gotdns.org/git/thunder --- 637d07e46cc5104e76a428be3e8f27f85c8e1d63 diff --combined makefile index 5f2d1b6,11b7da9..722d983 --- a/makefile +++ b/makefile @@@ -6,14 -6,15 +6,15 @@@ # This software is licensed under the GPL v3 or later # -ifeq "$(OSTYPE)" "msys" # Win32 +ifeq "$(OSTYPE)" "msys" # Win32 SYSTYPE = __GCCWIN32__ EXESUFFIX = .exe GLLIB = -lopengl32 ICON = obj/icon.o - SDLLIBTYPE = --libs + SDLLIBTYPE = --static-libs MSG = Win32 on MinGW + EXTRA = -static else #ifeq "$(OSTYPE)" "darwin" @@@ -51,7 -52,7 +52,7 @@@ CPPFLAGS = -MMD -Wall -Wno-switch -Wno- LDFLAGS = # Ugh, let's get rid of the ref to -lcurses [DONE] - LIBS = `sdl2-config $(SDLLIBTYPE)` -lstdc++ -lz -lm $(GLLIB) + LIBS = `sdl2-config $(SDLLIBTYPE)` -lstdc++ -lz -lm $(GLLIB) $(EXTRA) INCS = -I. -Isrc @@@ -81,7 -82,7 +82,7 @@@ all: checkenv message obj $(TARGET)$(EX checkenv: @echo @echo -en "\033[01;33m***\033[00;32m Checking compilation environment... \033[00m" - ifeq "" "$(shell which sdl-config)" + ifeq "" "$(shell which sdl2-config)" @echo @echo @echo -e "\033[01;33mIt seems that you don't have the SDL development libraries installed. diff --combined src/gui.h index 6dfb03f,bc3ed2e..4a472c9 --- a/src/gui.h +++ b/src/gui.h @@@ -4,11 -4,12 +4,11 @@@ // by James Hammmons // (C) 1998, 2014 Underground Software // - #ifndef __GUI_H__ #define __GUI_H__ #include - #include + #include // Message macros diff --combined src/sound.cpp index f2af13a,8d87ad9..27d7a39 --- a/src/sound.cpp +++ b/src/sound.cpp @@@ -12,13 -12,13 +12,13 @@@ // #include "sound.h" - #include + #include #include "psg.h" #include "resource.h" #include "ym2151.h" - -#define SAMPLE_RATE 48000 +#define SAMPLE_RATE 48000 +#define BUFFER_SIZE 512 // Function prototypes void SoundFunc(void *, Uint8 *, int); @@@ -27,28 -27,37 +27,28 @@@ extern uint8_t voice_rom[]; // PCM data pointer static bool soundInitialized = false; -const float sampleBase = (float)SAMPLE_RATE/6000.0; // Voice is between 5512.5 and 6000 Hz -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; +const float sampleBase = (float)SAMPLE_RATE / 6000.0; // Voice is between 5512.5 and 6000 Hz +bool chan1_go = false, chan2_go = false; +bool chan6_go = false; +uint8_t * sndp1, * sndp2, * sndp6; 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; -int16_t prevSamp1; -//int8_t delta_x1; -float sample2; -int16_t prevSamp2; -//int8_t delta_x2; +float sample1, sample2; +int16_t prevSamp1, prevSamp2; uint16_t snd_num; -uint8_t * snd_array[3] = { sunknown, scya, scamera }; // From RESOURCE.H +// From RESOURCE.H +uint8_t * snd_array[3] = { sunknown, scya, scamera }; uint32_t snd_lens[3] = { sunknownlen, scyalen, scameralen }; - void InitSound(void) { // params 1, 4 & 5 are useless -// if (YMInit(1, 3579580, 22050, 16, 512))//, (SAMPLE **)sbp)) - if (YMInit(1, 3579580, SAMPLE_RATE, 16, 512)) +// if (YMInit(1, 3579580, SAMPLE_RATE, 16, 512)) + if (YMInit(3579580, SAMPLE_RATE)) { printf("SOUND: Could not init YM2151 emulator!\n"); - return;// -1; + return; } InitPSG(SAMPLE_RATE); @@@ -57,11 -66,11 +57,11 @@@ desired.freq = SAMPLE_RATE; desired.format = AUDIO_S16; desired.channels = 1; - desired.samples = 1024; + desired.samples = BUFFER_SIZE * 2; // Size is in BYTES, so x2 desired.callback = SoundFunc; desired.userdata = NULL; - // Also, should check to see if it got the hardware it needed, correct sample size, etc. + // Also, should check to see if it got the hardware it needed, correct sample size, etc. (actually, SDL guarantees we get what we asked for--I think) if (SDL_OpenAudio(&desired, &obtained) < 0) { soundInitialized = false; @@@ -74,12 -83,21 +74,12 @@@ 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); // Voice type sounds... if (type == GAMESOUND) @@@ -121,6 -139,43 +121,6 @@@ chan2_go = true; } } -#if 0 - 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! - } - } -#endif -#if 0 - 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! - } -#endif else if (type == USERSOUND) { spos6 = 0; @@@ -130,18 -185,23 +130,18 @@@ } } - void SoundFunc(void * userdata, Uint8 * buffer, int num) { - static bool psg1go = false, psg2go = false; - // Length / 2 is because it's set up for 16-bit samples -// YM2151UpdateOne(buffer, length / 2); - // Have to go into ym2151.cpp and change this manually back to 8 bit + // We do num / 2 because num is in BYTES, and the buffer uses signed WORDs. YM2151UpdateOne(buffer, num / 2); -// return; UpdatePSG(buffer, num / 2); // 0-22 different sounds... - uint16_t cnt = 0;//, sample; + uint16_t cnt = 0; uint8_t start_samp1, end_samp1, start_samp2, end_samp2; int16_t samp1 = 0, samp2 = 0, samp6 = 0; // Zero samples... - if (!(chan1_go || chan2_go /*|| chan3_go || chan4_go || chan5_go*/ || chan6_go)) + if (!(chan1_go || chan2_go || chan6_go)) return; while (cnt != (num / 2)) @@@ -185,6 -245,7 +185,6 @@@ { uint8_t voiceSample = voice_rom[spos2++]; samp2 = ((int16_t)voiceSample - 128) * 160; -// samp2 = voice_rom[spos2++]; if (voiceSample == 0xFF) { @@@ -206,6 -267,42 +206,6 @@@ sample2 -= 1.0; } -#if 0 - if (chan3_go) - { - samp3 = ((psg1go ? sndp3[spos3++] : sndp3[spos3]) - 128) * 160; - psg1go = !psg1go; - - if (spos3 == end_pos3) - { - chan3_go = false; - samp3 = 0; // Kill channel 3 if done... - } - } - - if (chan4_go) - { - samp4 = ((psg2go ? sndp4[spos4++] : sndp4[spos4]) - 128) * 160; - psg2go = !psg2go; - - if (spos4 == end_pos4) - { - chan4_go = false; - samp4 = 0; // 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... - } - } -#endif if (chan6_go) { samp6 = sndp6[spos6++]; @@@ -218,10 -315,14 +218,10 @@@ } // Mix 'em... -// sample = samp1 + samp2 + samp3 + samp4 + samp5 + samp6 - 640; int32_t sample = samp1 + samp2 + samp6; sample += ((int16_t *)buffer)[cnt]; // If it overflowed, clip it -// if (sample & 0xFFFF0000) -// sample = (sample & 0x8000 ? 0x00 : 0xFF); -// sample = (sample & 0x80000000 ? 0x0000 : 0xFFFF); if (sample > 32767) sample = 32767; else if (sample < -32767) @@@ -230,3 -331,4 +230,3 @@@ ((int16_t *)buffer)[cnt++] = (int16_t)sample; } } - diff --combined src/thunder.cpp index 2914a96,f53dd68..9a06f3f --- a/src/thunder.cpp +++ b/src/thunder.cpp @@@ -2,7 -2,7 +2,7 @@@ // Thunder: A Rolling Thunder Emulator // // by James Hammons -// (C) 2004, 2014 Underground Software +// (C) 2004, 2023 Underground Software // // JLH = James Hammons // @@@ -12,12 -12,11 +12,12 @@@ // JLH 08/12/2009 Stabilized emulation so that it works // JLH 04/04/2014 Converted to SDL 2 // JLH 04/17/2014 Removed a metric fuck-tonne of cruft, added YM2151 & MCU +// JLH 01/13/2023 Finally fixed the sprite lag problem :-D // -#define THUNDER_VERSION "1.2.0" +#define THUNDER_VERSION "1.2.1" - #include + #include #include #include #include @@@ -33,6 -32,7 +33,6 @@@ #include "video.h" #include "ym2151.h" - #define ROM1 "rt3-1b.9c" #define ROM2 "rt3-2b.12c" #define ROM3 "rt3-3.12d" @@@ -62,6 -62,7 +62,6 @@@ #define PROM5 "mb7112e.6u" #define MCUROM "rt1-mcu.bin" - // Global defines uint8_t gram1[0x10000], grom1[0x10000], grom2[0x10000]; @@@ -79,13 -80,11 +79,13 @@@ uint32_t banksw1, banksw2 // MCU inputs Byte input1, input2, input3, input4, input5; +// Copy sprites flag +bool copySprites = false; + // Function prototypes uint8_t MCUReadMemory(uint16_t address); void MCUWriteMemory(uint16_t address, uint8_t data); - // // Read a byte from memory // @@@ -108,11 -107,14 +108,11 @@@ uint8_t MainReadMemory(uint16_t addr return grom1[addr]; } - // // Write a byte to memory // void MainWriteMemory(uint16_t address, uint8_t data) { - extern bool disasm; - if (address == 0x6000) SpawnSound(GAMESOUND, gram1[0x6200], 0); // Do voice chan 1 if (address == 0x6400) @@@ -127,15 -129,25 +127,15 @@@ gram1[address] = data; if (address == 0x5FF2) - CopySprites(); + copySprites = true; if (address == 0x8800) charBankSwitch = false; // Char banksw1 if (address == 0x8C00) charBankSwitch = true; // Char banksw2 - if (address == 0x8400) // Frame go strobe? VBlank acknowledge? - { -// BlitChar(charROM, gram1); - - // IRQ Ack (may also be frame go...) - ClearLineOfCurrentV6809(V6809_ASSERT_LINE_IRQ); -#if 1 - if (disasm) - WriteLog("WriteMem: CPU #1 Acknowledging IRQ...\n", data); -#endif - } + if (address == 0x8400) // Frame go strobe? VBlank acknowledge? + ClearLineOfCurrentV6809(V6809_LINE_IRQ); // IRQ Ack } - // // Read a byte from memory (2nd processor) // @@@ -154,11 -166,14 +154,11 @@@ uint8_t SubReadMemory(uint16_t address return grom2[address]; } - // // Write a byte to memory (2nd processor) // void SubWriteMemory(uint16_t address, uint8_t data) { - extern bool disasm; - // Set sprite data bank switch if (address == 0xD803) banksw2 = (uint32_t)(data & 0x03) << 13; @@@ -170,12 -185,20 +170,12 @@@ gram1[address - 0x2000] = data; if (address == 0x1FF2) - CopySprites(); + copySprites = true; if (address == 0x8800) - { - // IRQ Ack (may also be frame go...) - ClearLineOfCurrentV6809(V6809_ASSERT_LINE_IRQ); -#if 1 - if (disasm) - WriteLog("WriteMem: CPU #2 Acknowledging IRQ...\n", data); -#endif - } + ClearLineOfCurrentV6809(V6809_LINE_IRQ); // IRQ Ack } - uint8_t MCUReadMemory(uint16_t address) { if (address < 0x20) @@@ -198,6 -221,7 +198,6 @@@ return mcuMem[address]; } - void MCUWriteMemory(uint16_t address, uint8_t data) { static uint8_t ymRegister; @@@ -230,27 -254,32 +230,27 @@@ mcuMem[address] = data; } - uint8_t V63701ReadPort1(void) { // printf("V63701ReadPort1: Read $%02X...\n", input3.byte); return input3.byte; } - uint8_t V63701ReadPort2(void) { return 0xFF; } - void V63701WritePort1(uint8_t data) { // printf("V63701WritePort1: Wrote $%02X...\n", data); } - void V63701WritePort2(uint8_t data) { // printf("V63701WritePort2: Wrote $%02X...\n", data); } - // // Generic Load file into image space // (No error checking performed! Responsibility of caller!) @@@ -269,18 -298,19 +269,18 @@@ bool LoadImg(const char * filename, uin return false; } - fread(&mem[address], 1, length, file); + size_t ignored = fread(&mem[address], 1, length, file); fclose(file); return true; } - // // Read color PROMs // bool ReadColorPROMs(void) { - FILE * file1 = fopen("./ROMs/"PROM3, "rb"); + FILE * file1 = fopen("./ROMs/" PROM3, "rb"); if (file1) { @@@ -291,7 -321,7 +291,7 @@@ fclose(file1); } - file1 = fopen("./ROMs/"PROM4, "rb"); + file1 = fopen("./ROMs/" PROM4, "rb"); if (file1) { @@@ -302,8 -332,8 +302,8 @@@ fclose(file1); } - file1 = fopen("./ROMs/"PROM1, "rb"); - FILE * file2 = fopen("./ROMs/"PROM2, "rb"); + file1 = fopen("./ROMs/" PROM1, "rb"); + FILE * file2 = fopen("./ROMs/" PROM2, "rb"); // If open was successful... if (file1 && file2) @@@ -325,7 -355,7 +325,7 @@@ // 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 + // 10: 88 A8 C8 E8 8A AA CA EA 8C AC CC EC 8E AE CE EE if (!file1) { @@@ -336,18 -366,19 +336,18 @@@ return true; } - // // Unpack font data // bool UnpackFonts(void) { // 0x4000 $800 chars - FILE * file1 = fopen("./ROMs/"ROM7, "rb"); - FILE * file2 = fopen("./ROMs/"ROM8, "rb"); + FILE * file1 = fopen("./ROMs/" ROM7, "rb"); + FILE * file2 = fopen("./ROMs/" ROM8, "rb"); if (!file1 || !file2) { - printf("Could not open either "ROM7" or "ROM8"!\n"); + printf("Could not open either " ROM7 " or " ROM8 "!\n"); return false; } @@@ -372,12 -403,12 +372,12 @@@ fclose(file1); fclose(file2); - file1 = fopen("./ROMs/"ROM5, "rb"); - file2 = fopen("./ROMs/"ROM6, "rb"); + file1 = fopen("./ROMs/" ROM5, "rb"); + file2 = fopen("./ROMs/" ROM6, "rb"); if (!file1 || !file2) { - printf("Could not open either "ROM5" or "ROM6"!\n"); + printf("Could not open either " ROM5 " or " ROM6 "!\n"); return false; } @@@ -405,6 -436,7 +405,6 @@@ return true; } - // // Main loop // @@@ -412,14 -444,16 +412,14 @@@ int main(int argc, char * argv[] { InitLog("thunder.log"); - extern bool disasm; // From 'V6809.CPP' - bool running; // CPU running state flag... SDL_Event event; // SDL "event" uint32_t ticks, oldTicks; uint8_t frameTickCount = 0; - printf("THUNDER v"THUNDER_VERSION" by James Hammons\n"); - printf("Serial #20149417 / Prerelease\n"); - printf("© 2003, 2014 Underground Software\n\n"); + printf("THUNDER v" THUNDER_VERSION " by James Hammons\n"); + printf("Serial #20230113 / Prerelease\n"); + printf("© 2003, 2023 Underground Software\n\n"); printf("This emulator is free software. If you paid for it you were RIPPED OFF\n\n"); // SDL_WM_SetCaption("Thunder v"THUNDER_VERSION" ", "Thunder"); @@@ -498,17 -532,17 +498,17 @@@ memset(&cpu1, 0, sizeof(V6809REGS)); cpu1.RdMem = MainReadMemory; cpu1.WrMem = MainWriteMemory; - cpu1.cpuFlags |= V6809_ASSERT_LINE_RESET; + cpu1.cpuFlags |= V6809_LINE_RESET; memset(&cpu2, 0, sizeof(V6809REGS)); cpu2.RdMem = SubReadMemory; cpu2.WrMem = SubWriteMemory; - cpu2.cpuFlags |= V6809_ASSERT_LINE_RESET; + cpu2.cpuFlags |= V6809_LINE_RESET; memset(&mcu, 0, sizeof(V63701REGS)); mcu.RdMem = MCUReadMemory; mcu.WrMem = MCUWriteMemory; - mcu.cpuFlags |= V63701_ASSERT_LINE_RESET; + mcu.cpuFlags |= V63701_LINE_RESET; running = true; @@@ -519,7 -553,7 +519,7 @@@ InitGUI(); // Reset # of coins // Set up DIP switches... - input4.bit.b0 = 1; // DSW B-0: Contiues (1 = 6, 0 = 3) + input4.bit.b0 = 1; // DSW B-0: Continues (1 = 6, 0 = 3) input4.bit.b1 = 1; // DSW B-2: ??? input4.bit.b2 = 1; // DSW B-4: Difficulty (1 = normal, 0 = easy) input4.bit.b3 = 1; // DSW B-6: Bonus lives (70K/200K = 1, 100K/300K = 0) @@@ -545,6 -579,9 +545,6 @@@ WriteLog("About to set up screen...\n") WriteLog("About to set up audio...\n"); InitSound(); -//memset(scrBuffer, 0xFF, VIRTUAL_SCREEN_WIDTH*VIRTUAL_SCREEN_HEIGHT*sizeof(uint32_t)); -//RenderScreenBuffer(); - WriteLog("About to enter main loop...\n"); while (running) { @@@ -553,6 -590,11 +553,6 @@@ // 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 - // SDL key handling... SDL_Event event; @@@ -906,9 -948,9 +906,9 @@@ #endif // We can do this here because we're not executing the cores yet. - cpu1.cpuFlags |= V6809_ASSERT_LINE_IRQ; - cpu2.cpuFlags |= V6809_ASSERT_LINE_IRQ; - mcu.cpuFlags |= V63701_ASSERT_LINE_IRQ; + cpu1.cpuFlags |= V6809_LINE_IRQ; + cpu2.cpuFlags |= V6809_LINE_IRQ; + mcu.cpuFlags |= V63701_LINE_IRQ; // while (cpu1.clock < 25000) // 1.538 MHz = 25633.333... cycles per frame (1/60 s) // 25600 cycles/frame @@@ -917,33 -959,21 +917,33 @@@ // 40 works, until it doesn't... :-P // 640 * 40 // 800 * 32 +// 20 seems to work... :-) // Interesting, putting IRQs at 30 Hz makes it run at the correct speed. Still hangs in the demo, though. - for(int i=0; i<640; i++) +// for(int i=0; i<640; i++) + for(int i=0; i<1280; i++) { // Gay, but what are ya gonna do? // There's better ways, such as keeping track of when slave writes to master, etc... - Execute6809(&cpu1, 40); - Execute6809(&cpu2, 40); +// Execute6809(&cpu1, 40); +// Execute6809(&cpu2, 40); + Execute6809(&cpu1, 20); + Execute6809(&cpu2, 20); // MCU runs at 1,536,000 Hz // 1536000 / 60 / 640 == 40 - Execute63701(&mcu, 40); +// Execute63701(&mcu, 40); + Execute63701(&mcu, 20); } BlitChar(charROM, gram1); + // Make sure that the sprite RAM lags by one frame... :-) + if (copySprites) + { + CopySprites(); + copySprites = false; + } + frameTickCount++; if (frameTickCount == 3) @@@ -962,3 -992,126 +962,3 @@@ return 1; } - -#if 0 -/* -Hitachi uC runs at 6.144 MHz -YM2151 runs at 3.579580 MHz - - -Rolling Thunder Memory map --------------------------- -Most of the decoding is done by custom chips (CUS47 and CUS41), so the memory -map is inferred by program behaviour. The customs also handle internally irq -and watchdog. - -The main CPU memory map is the same in all games because CUS47 is used by all -games. The sub CPU and sound CPU, on the other hand, change because CUS41 is -replaced by other chips. - -All RAM is shared between main and sub CPU, except for sound RAM which is -shared between main and sound CPU; the portion of object RAM that is overlapped -by sound RAM is used exclusively by the sub CPU. - -MAIN CPU: - -Address Dir Data Name Description -------------------- --- -------- --------- ----------------------- -000x xxxx xxxx xxxx R/W xxxxxxxx SCROLL0 tilemap 0/1 RAM (shared with sub CPU) -001x xxxx xxxx xxxx R/W xxxxxxxx SCROLL1 tilemap 2/3 RAM (shared with sub CPU) -0100 00xx xxxx xxxx R/W xxxxxxxx SOUND sound RAM (through CUS30, shared with MCU) -0100 0000 xxxx xxxx R/W xxxxxxxx portion holding the sound wave data -0100 0001 00xx xxxx R/W xxxxxxxx portion holding the sound registers -010x xxxx xxxx xxxx R/W xxxxxxxx OBJECT work RAM (shared with sub CPU) [1] -0101 1xxx xxxx xxxx R/W xxxxxxxx portion holding sprite registers -011x xxxx xxxx xxxx R xxxxxxxx ROM 9D program ROM (banked) [2] -1xxx xxxx xxxx xxxx R xxxxxxxx ROM 9C program ROM -1000 00-- ---- ---- W -------- watchdog reset (RES generated by CUS47) -1000 01-- ---- ---- W -------- main CPU irq acknowledge (IRQ generated by CUS47) -1000 1x-- ---- ---- W -------- BANK tile gfx bank select (data is in A10) (latch in CUS47) -1001 00-- ---- -x0x W xxxxxxxx LATCH0 tilemap 0/1 X scroll + priority -1001 00-- ---- -x10 W xxxxxxxx LATCH0 tilemap 0/1 Y scroll -1001 00-- ---- --11 W ------xx BAMNKM ROM 9D bank select -1001 01-- ---- -x0x W xxxxxxxx LATCH1 tilemap 2/3 X scroll + priority -1001 01-- ---- -x10 W xxxxxxxx LATCH1 tilemap 2/3 Y scroll -1001 01-- ---- --11 W ------xx BAMNKS ROM 12D bank select -1100 00-- ---- ---- W xxxxxxxx BACKCOLOR background color - -[1] Note that this is partially overlapped by sound RAM -[2] In Rolling Thunder and others, replaced by the ROM/voice expansion board - - -SUB CPU: - -Address Dir Data Name Description -------------------- --- -------- --------- ----------------------- -000x xxxx xxxx xxxx R/W xxxxxxxx SUBOBJ work RAM (shared with main CPU) -0001 1xxx xxxx xxxx R/W xxxxxxxx portion holding sprite registers -001x xxxx xxxx xxxx R/W xxxxxxxx SUBSCR0 tilemap 0/1 RAM (shared with main CPU) -010x xxxx xxxx xxxx R/W xxxxxxxx SUBSCR1 tilemap 2/3 RAM (shared with main CPU) -011x xxxx xxxx xxxx R xxxxxxxx ROM 12D program ROM (banked) [1] -1xxx xxxx xxxx xxxx R xxxxxxxx ROM 12C program ROM -1000 0--- ---- ---- W -------- watchdog reset (MRESET generated by CUS41) -1000 1--- ---- ---- W -------- main CPU irq acknowledge (generated by CUS41) -1101 0--- ---- -x0x W xxxxxxxx LATCH0 tilemap 0/1 X scroll + priority -1101 0--- ---- -x10 W xxxxxxxx LATCH0 tilemap 0/1 Y scroll -1101 0--- ---- --11 W ------xx BAMNKM ROM 9D bank select -1101 1--- ---- -x0x W xxxxxxxx LATCH1 tilemap 2/3 X scroll + priority -1101 1--- ---- -x10 W xxxxxxxx LATCH1 tilemap 2/3 Y scroll -1101 1--- ---- --11 W ------xx BAMNKS ROM 12D bank select - -[1] Only used by Rolling Thunder - - -MCU: - -Address Dir Data Name Description -------------------- --- -------- --------- ----------------------- -0000 0000 xxxx xxxx MCU internal registers, timers, ports and RAM -0001 xxxx xxxx xxxx R/W xxxxxxxx RAM 3F sound RAM (through CUS30, partially shared with main CPU) -0001 0000 xxxx xxxx R/W xxxxxxxx portion holding the sound wave data -0001 0001 00xx xxxx R/W xxxxxxxx portion holding the sound registers -0010 0--- --00 ---x R/W xxxxxxxx YMCS YM2151 -0010 0--- --01 ---- n.c. -0010 0--- --10 ---- R xxxxxxxx PORTA switch inputs -0010 0--- --11 ---- R xxxxxxxx PORTB dip switches -01xx xxxx xxxx xxxx R xxxxxxxx ROM 6B program ROM (lower half) -10xx xxxx xxxx xxxx R xxxxxxxx ROM 6B program ROM (upper half) -1011 0--- ---- ---- W unknown (CUS41) -1011 1--- ---- ---- W unknown (CUS41) -1111 xxxx xxxx xxxx R xxxxxxxx MCU internal ROM - - -Notes: ------ -- There are two watchdogs, one per CPU (or maybe three). Handling them - separately is necessary to allow entering service mode without manually - resetting in rthunder and genpeitd: only one of the CPUs stops writing to - the watchdog. - -- The sprite hardware buffers spriteram: the program writes the sprite list to - offsets 4-9 of every 16-byte block, then at the end writes to offset 0x1ff2 - of sprite RAM to signal the chip that the list is complete. The chip will - copy the list from 4-9 to 10-15 and use it from there. This has not been - verified on the real hardware, but it is the most logical way of doing it. - Emulating this behaviour and not using an external buffer is important in - rthunder: when you insert a coin, the whole sprite RAM is cleared, but 0x1ff2 - is not written to. If we buffered spriteram to an external buffer, this would - cause dangling sprites because the buffer would not be updated. - -- spriteram buffering fixes sprite lag, but causes a glitch in rthunder when - entering a door. The *closed* door is made of tiles, but the *moving* door is - made of sprites. Since sprites are delayed by 1 frame, when you enter a door - there is one frame where neither the tile-based closed door nor the - sprite-based moving door is shown, so it flickers. This behavior has been - confirmed on a real PCB. - -TODO: ----- -- The two unknown writes for the MCU are probably watchdog reset and irq acknowledge, - but they don't seem to work as expected. During the first few frames they are - written out of order and hooking them up in the usual way causes the MCU to - stop receiving interrupts. -*/ -#endif - diff --combined src/video.h index acacc76,b3afeaf..8d1847e --- a/src/video.h +++ b/src/video.h @@@ -1,10 -1,11 +1,10 @@@ // // VIDEO.H: Header file // - #ifndef __VIDEO_H__ #define __VIDEO_H__ - #include + #include #include // For uint32_t #define VIRTUAL_SCREEN_WIDTH 288 @@@ -24,3 -25,4 +24,3 @@@ extern uint32_t scrBuffer[] //extern uint32_t mainScrBuffer[]; #endif // __VIDEO_H__ -