X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fthunder.cpp;h=17ea566f26774da6ad315789ed1df2f5584a855e;hb=7c0ff1ece391810183f1d37923a66bf30de480ee;hp=ffbfed9574a7ec070ea679c79c0f2668ace9e130;hpb=f76a576fe270d4bd78eb4070eb9604115a096c2d;p=thunder diff --git a/src/thunder.cpp b/src/thunder.cpp index ffbfed9..17ea566 100755 --- a/src/thunder.cpp +++ b/src/thunder.cpp @@ -290,6 +290,8 @@ uint8 RdMem(uint16 addr) { uint8 b; + // $4000-4300 is RAM shared with the microcontroller... + if (addr < 0x8000) { if (addr > 0x5FFF) @@ -308,6 +310,7 @@ uint8 RdMem(uint16 addr) // void WrMem(uint16 addr, uint8 b) { + extern bool disasm; extern bool charbase; // Needed for screen. Extern it in it?? //extern uint16 sr, ur, xr, yr; // Needed for tracelog //extern uint16 pcr; @@ -321,6 +324,12 @@ void WrMem(uint16 addr, uint8 b) //} tr << endl; }//*/ +#if 1 + if (addr == 0x4182) + { + WriteLog("\nWriteMem: CPU #1 writing $%02X to $4182!\n\n", b); + } +#endif if (addr == 0x6000) SpawnSound(GAMESOUND, gram1[0x6200], 0); // Do voice chan 1 @@ -349,8 +358,16 @@ void WrMem(uint16 addr, uint8 b) BlitChar(screen, chr_rom, gram1); refresh_ = (refresh2 ? 1 : 0); // 60/30 Hz... } +//Seems they're more regular than this... // irqGoA = true; // Will this work??? no... - cpu1.cpuFlags |= V6809_ASSERT_LINE_IRQ;//wil wok??? +// cpu1.cpuFlags |= V6809_ASSERT_LINE_IRQ;//wil wok??? + // IRQ Ack (may also be frame go... +// cpu1.cpuFlags &= ~V6809_ASSERT_LINE_IRQ; +#if 1 + if (disasm) + WriteLog("WriteMem: CPU #1 Acknowledging IRQ...\n", b); +#endif + ClearLineOfCurrentV6809(V6809_ASSERT_LINE_IRQ); } } @@ -389,6 +406,7 @@ uint8 RdMemB(uint16 addr) // void WrMemB(uint16 addr, uint8 b) { + extern bool disasm; extern bool charbase; //extern uint16 sr, ur, xr, yr; // Needed for tracelog //extern uint16 pcr; @@ -402,10 +420,17 @@ void WrMemB(uint16 addr, uint8 b) //} tr << endl; }//*/ +#if 1 + if (addr == 0x0182) + { + WriteLog("\nWriteMem: CPU #2 writing $%02X to $0182 ($4182)!\n\n", b); + } +#endif - if (addr == 0x8800) +// Bah. Dunno if this is accurate or not! +// if (addr == 0x8800) // irqGoB = true; // Will it work??? no... - cpu2.cpuFlags |= V6809_ASSERT_LINE_IRQ;//wil wok??? +// cpu2.cpuFlags |= V6809_ASSERT_LINE_IRQ;//wil wok??? if (addr == 0x6000) SpawnSound(GAMESOUND, gram1[0x6200], 0); // Do voice chan 1 if (addr == 0x6400) @@ -429,6 +454,16 @@ void WrMemB(uint16 addr, uint8 b) if (addr > 0x5FFF) gram1[addr] = b; } + if (addr == 0x8800) + { + // IRQ Ack (may also be frame go...) +// cpu2.cpuFlags &= ~V6809_ASSERT_LINE_IRQ; +#if 1 + if (disasm) + WriteLog("WriteMem: CPU #2 Acknowledging IRQ...\n", b); +#endif + ClearLineOfCurrentV6809(V6809_ASSERT_LINE_IRQ); + } } // @@ -870,7 +905,8 @@ void LoadPSGs(void) } psg_lens[i] = len; - cout << "Found sample file: " << file << " [Length: " << dec << len << "]" << endl; +// cout << "Found sample file: " << file << "\t[Length: " << dec << len << "]" << endl; + printf("Found sample file: %s\t[Length: %u]\n", file, len); } fp.close(); @@ -911,8 +947,8 @@ void LoadFMs(void) } fm_lens[i] = len; - cout << "Found sample file: " << file << " [Length: " << dec << len - << "]" << endl; +// cout << "Found sample file: " << file << " [Length: " << dec << len << "]" << endl; + printf("Found sample file: %s\t[Length: %u]\n", file, len); } fp.close(); @@ -927,6 +963,7 @@ int main(int argc, char * argv[]) { InitLog("thunder.log"); +extern bool disasm; // From 'V6809.CPP' extern bool charbase; // From 'SCREEN.CPP' charbase = false; @@ -967,41 +1004,6 @@ int main(int argc, char * argv[]) keys = SDL_GetKeyState(NULL); // Get the SDL keyboard matrix -#if 0 - cout << "Allocating memory..." << endl; -//Does this anyway... set_new_handler(0); // Make 'new' return NULL on failure... - gram1 = new uint8[0x10000]; - if (gram1 == NULL) { cout << "Could not allocate RAM space #1!" << endl - << "Aborting!" << endl; return -1; } - grom1 = new uint8[0x10000]; - if (grom1 == NULL) { cout << "Could not allocate ROM space #1!" << endl - << "Aborting!" << endl; return -1; } - gram2 = new uint8[0x10000]; - if (gram2 == NULL) { cout << "Could not allocate RAM space #2!" << endl - << "Aborting!" << endl; return -1; } - grom2 = new uint8[0x10000]; - if (grom2 == NULL) { cout << "Could not allocate ROM space #2!" << endl - << "Aborting!" << endl; return -1; } - chr_rom = new uint8[0x60000]; - if (chr_rom == NULL) { cout << "Could not allocate character RAM!" << endl - << "Aborting!" << endl; return -1; } - grom3 = new uint8[0x8000]; - if (grom3 == NULL) { cout << "Could not allocate ROM space #4!" << endl - << "Aborting!" << endl; return -1; } - grom4 = new uint8[0x8000]; - if (grom4 == NULL) { cout << "Could not allocate ROM space #5!" << endl - << "Aborting!" << endl; return -1; } - data_rom = new uint8[0x40000]; - if (data_rom == NULL) { cout << "Could not allocate ROM level data!" << endl - << "Aborting!" << endl; return -1; } - spr_rom = new uint8[0x80000]; - if (spr_rom == NULL) { cout << "Could not allocate ROM sprite data!" << endl - << "Aborting!" << endl; return -1; } - voice_rom = new uint8[0x20000]; - if (voice_rom == NULL) { cout << "Could not allocate ROM voice data!" << endl - << "Aborting!" << endl; return -1; } -#endif - gram = gram1; grom = grom1; // Needed only for debugger for(long i=0; i<0x10000; i++) @@ -1208,10 +1210,13 @@ WriteLog("Executing 'run' command...\n"); if (lbuff[0] == 'r') // If run, then reset CPUs { WriteLog("Executing secondary 'run' command...\n"); +#if 1 + // 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; gram1[0x4183] = 0x00; // More of the same gram1[0x4185] = 0x00; +#endif banksw1 = 0; // Will this work? banksw2 = 0; // iclock = 0; // Reset instr clock #1... @@ -1309,6 +1314,8 @@ WriteLog("About to enter main loop...\n"); if (game_over_switch == 0) gram1[0x4380] = 0; // Kill music! } +//testing... (works) +//gram1[0x423D] = 1; //gram1[0x423D] = self_test; // Reset DSW1-1 gram1[0x4268] = 0; // Reset Video test gram1[0x427A] = 0; gram1[0x427C] = 0; @@ -1495,37 +1502,47 @@ WriteLog("About to enter main loop...\n"); cpu1.cpuFlags |= V6809_ASSERT_LINE_RESET; cpu2.cpuFlags |= V6809_ASSERT_LINE_RESET; } - -// if (enable_cpu) - if (true) - { + if (keys[SDLK_d]) // (D) start disassembly + disasm = true; #if 0 -// if (irqGoA) - cpu1.cpuFlags |= V6809_ASSERT_LINE_IRQ; - - Execute6809(&cpu1, 25000); - cpu1.clock -= 25000; // Remove 25K ticks from clock (in case it overflowed) + if (keys[SDLK_k]) + gram1[0x5606] = 0x00; + if (keys[SDLK_l]) + { + gram1[0x5607] = 0x01; // Hangs here... (CPU #1 waiting...) + WriteLog("\nMAIN: Stuffed $01 in $5607!!!\n\n"); + } + if (keys[SDLK_o]) + { + gram1[0x5FF3] = 0x02; + WriteLog("\nMAIN: Stuffed $02 in $5FF3!!!\n\n"); + } +#endif -// if (irqGoB) - cpu2.cpuFlags |= V6809_ASSERT_LINE_IRQ; - Execute6809(&cpu2, 25000); - cpu2.clock -= 25000; // Remove 25K ticks from clock (in case it overflowed)//*/ -#else + if (enable_cpu) +// if (true) + { + // 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; // while (cpu1.clock < 25000) - for(uint32 i=0; i<250; i++) +// 1.538 MHz = 25633.333... cycles per frame (1/60 s) +// 25600 cycles/frame +// Setting interleave to 25 and below causes the V6809 core to hang... +// 32 gets to the title screen before hanging... +// 40 works, until it doesn't... :-P +// 640 * 40 +// 800 * 32 +// Interesting, putting IRQs at 30 Hz makes it run at the correct speed. Still hangs in the demo, though. + for(uint32 i=0; i<640; i++) +// for(uint32 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, 100); - Execute6809(&cpu2, 100); + Execute6809(&cpu1, 40); + Execute6809(&cpu2, 40); } - -// cpu1.clock -= 25000; // Remove 25K ticks from clock (in case it overflowed) -// cpu2.clock -= 25000; // Remove 25K ticks from clock (in case it overflowed)//*/ -#endif } // END: enable_cpu // if (refresh_++ == 1) // 30 Hz... @@ -1537,11 +1554,13 @@ WriteLog("About to enter main loop...\n"); // refresh_ = (refresh2 ? 1 : 0); // 60/30 Hz... // } +#if 1 //temp, for testing... BlitChar(screen, chr_rom, gram1); - +#endif // Speed throttling happens here... while (SDL_GetTicks() - oldTicks < 16) // Actually, it's 16.66... Need to account for that somehow +// while (SDL_GetTicks() - oldTicks < 32) // Actually, it's 16.66... Need to account for that somehow SDL_Delay(1); // Release our timeslice... oldTicks = SDL_GetTicks(); @@ -1654,19 +1673,6 @@ BlitChar(screen, chr_rom, gram1); SDL_Quit(); // Shut down SDL -#if 0 - delete[] gram1; // Deallocate RAM & ROM spaces - delete[] grom1; - delete[] gram2; - delete[] grom2; - delete[] chr_rom; - delete[] grom3; - delete[] grom4; - delete[] data_rom; - delete[] spr_rom; - delete[] voice_rom; -#endif - for(int i=0; i<16; i++) if (psg_adrs[i]) delete[] psg_adrs[i]; // Deallocate if loaded @@ -1679,3 +1685,126 @@ BlitChar(screen, chr_rom, gram1); return 1; } + +#if 0 +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: +----- +- we are using an unusually high CPU interleave factor (800) to avoid hangs + in rthunder. The two 6809 in this game synchronize using a semaphore at + 5606/5607 (CPU1) 1606/1607 (CPU2). CPU1 clears 5606, does some quick things, + and then increments 5606. While it does its quick things (which require + about 40 clock cycles) it expects CPU2 to clear 5607. + Raising the interleave factor to 1000 makes wndrmomo crash during attract + mode. I haven't investigated on the cause. + +- 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