From bb29b68685bde915f16113f5400dbbdb7be6c097 Mon Sep 17 00:00:00 2001 From: Shamus Hammons Date: Tue, 4 Aug 2009 16:48:47 +0000 Subject: [PATCH] Added old email from Lee Saito to notes, various attempts at fixes --- doc/notes.txt | 42 ++++++++- src/screen.cpp | 2 +- src/thunder.cpp | 246 ++++++++++++++++++++++++++++++++++++------------ src/v6809.cpp | 30 ++++-- src/v6809.h | 4 +- 5 files changed, 249 insertions(+), 75 deletions(-) diff --git a/doc/notes.txt b/doc/notes.txt index 4829af2..04b808a 100755 --- a/doc/notes.txt +++ b/doc/notes.txt @@ -28,7 +28,7 @@ Char matrix is 36x28 (Text mode) -> CMOS seems to be mapped to $5400 in RAM1... - TOP 5 + TOP 5 SCORE AREA INI'T 1ST 30000 5 ALB 2ND 20000 4 LIR @@ -57,7 +57,7 @@ $D803 is bank switch for CPU #2 (4 8K banks) $6000, 6200, 6400, 6600 are voice. 6200 & 6600 are sample # to play, 6000 & 6400 are the strobe lines. -PSG: +PSG: CPU #1's stack is mapped to $5FFF, #2 to $43FF @@ -86,3 +86,41 @@ DIPSWITCH SETTINGS: 10 undefined 11 Type C(cocktail, flip) 2-8: Continuation-off 6 games max, on 3 games max + + +Date: Thu, 30 Jul 1998 18:45:51 -0500 +From: Lee Saito +To: Jimmy Hamm +Subject: Re: Rolling Thunder clock freqs + +Jimmy Hamm wrote: + +> >> I need to know the clock frequency and IRQ frequency of both processors, +> so +> >> if you could look at the E and Q lines (pins 34 and 35 of the 6809s) and +> the +> >> IRQ lines (pin 3 of the 6809s) that would be great! +> > + +OK. I'm looking at the signals now... + +First, processor at 11A: + +pin 3 (IRQ line): Pulses vary in duration, making it somewhat difficult to +determine frequency, but it's about 60 Hz (around 16 -17ms per pulse, 60Hz +would be 16.6ms, I think) This seems to be tied to the sound processor? +(pulses get real short when no sounds are playing) + +pin 35: approx 650 ns/cycle = 1.538 MHz + +pin 34: same as 35 (1.538 Mhz) + +Processor at 9A: + +Pin 3: Same as 11A (looks like 60Hz to me) + +Pin 35: Same as other processor (1.538 MHz) + +pin 34: Same as other processor (1.538 MHz) + +Hope this helps! ;) diff --git a/src/screen.cpp b/src/screen.cpp index 654c277..b958582 100755 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -13,7 +13,7 @@ // // Who When What // --- ---------- ------------------------------------------------------------ -// JLH 03/12/2003 Ported this crud to Simple Directmedia Layer +// JLH 03/12/2003 Ported this steaming pile of crap from VESA to SDL // #include "screen.h" diff --git a/src/thunder.cpp b/src/thunder.cpp index ffbfed9..5fdd7a8 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) @@ -321,6 +323,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 +357,12 @@ 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; + ClearLineOfCurrentV6809(V6809_ASSERT_LINE_IRQ); } } @@ -402,10 +414,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 +448,12 @@ 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; + ClearLineOfCurrentV6809(V6809_ASSERT_LINE_IRQ); + } } // @@ -870,7 +895,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 +937,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 +953,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 +994,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 +1200,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 +1304,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,6 +1492,23 @@ WriteLog("About to enter main loop...\n"); cpu1.cpuFlags |= V6809_ASSERT_LINE_RESET; cpu2.cpuFlags |= V6809_ASSERT_LINE_RESET; } + if (keys[SDLK_d]) // (D) start disassembly + disasm = true; +#if 1 + 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 (enable_cpu) if (true) @@ -1512,19 +1526,21 @@ WriteLog("About to enter main loop...\n"); Execute6809(&cpu2, 25000); cpu2.clock -= 25000; // Remove 25K ticks from clock (in case it overflowed)//*/ #else + // 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... +// 40 works, until it doesn't... :-P + for(uint32 i=0; i<640; 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 @@ -1654,19 +1670,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 +1682,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 diff --git a/src/v6809.cpp b/src/v6809.cpp index 9c2160f..c8e081a 100755 --- a/src/v6809.cpp +++ b/src/v6809.cpp @@ -19,7 +19,7 @@ #include "v6809.h" -//#define __DEBUG__ +#define __DEBUG__ #ifdef __DEBUG__ #include "dis6809.h" // Temporary... #include "log.h" // Temporary... @@ -3058,6 +3058,11 @@ uint8 backTrace[256]; V6809REGS btRegs[256]; bool tripped = false; #endif +#ifdef __DEBUG__ +//Here so this can be externally linked +bool disasm = false; +//bool disasm = true; +#endif void Execute6809(V6809REGS * context, uint32 cycles) { // If this is not in place, the clockOverrun calculations can cause the V6809 to get @@ -3105,8 +3110,6 @@ if (!tripped) #endif #ifdef __DEBUG__ //Decode6809(regs.pc); -//static bool disasm = false; -static bool disasm = true; if (disasm) Decode6809(regs); /*//if (regs.pc == 0x15BA) disasm = true; //if (regs.pc == 0xFE76) disasm = true; @@ -3215,22 +3218,29 @@ if (disasm) WriteLog(" IRQ taken...\n"); regs.clock += 19; // Apparently, not done here! // Need to put IRQ handling in somewhere... It shouldn't be cleared here! - context->cpuFlags &= ~V6809_ASSERT_LINE_IRQ; // Reset the asserted line (IRQ)... - regs.cpuFlags &= ~V6809_ASSERT_LINE_IRQ; // Reset the asserted line (IRQ)... +// context->cpuFlags &= ~V6809_ASSERT_LINE_IRQ; // Reset the asserted line (IRQ)... +// regs.cpuFlags &= ~V6809_ASSERT_LINE_IRQ; // Reset the asserted line (IRQ)... } } #ifdef __DEBUG__ -if (disasm) WriteLog("\tA=%02X B=%02X CC=%02X DP=%02X X=%04X Y=%04X S=%04X U=%04X PC=%04X\n", - regs.a, regs.b, regs.cc, regs.dp, regs.x, regs.y, regs.s, regs.u, regs.pc);//*/ +if (disasm) WriteLog("\tCC=%s%s%s%s%s%s%s%s A=%02X B=%02X DP=%02X X=%04X Y=%04X S=%04X U=%04X PC=%04X\n", + (regs.cc & FLAG_E ? "E" : "-"), (regs.cc & FLAG_F ? "F" : "-"), (regs.cc & FLAG_H ? "H" : "-"), + (regs.cc & FLAG_I ? "I" : "-"), (regs.cc & FLAG_N ? "N" : "-"), (regs.cc & FLAG_Z ? "Z" : "-"), + (regs.cc & FLAG_V ? "V" : "-"), (regs.cc & FLAG_C ? "C" : "-"), + regs.a, regs.b, regs.dp, regs.x, regs.y, regs.s, regs.u, regs.pc);//*/ /*WriteLog("\tA=%02X B=%02X CC=%02X DP=%02X X=%04X Y=%04X S=%04X U=%04X PC=%04X\n", regs.a, regs.b, regs.cc, regs.dp, regs.x, regs.y, regs.s, regs.u, regs.pc);//*/ #endif } - // Keep track of how much we overran so we can adjust on the next run... regs.clockOverrun = (uint32)(regs.clock - endCycles); myMemcpy(context, ®s, sizeof(V6809REGS)); + +#ifdef __DEBUG__ + if (disasm) + WriteLog("\n*** CONTEXT SWITCH ***\n\n"); +#endif } // @@ -3250,13 +3260,13 @@ uint16 GetCurrentV6809PC(void) } // Set a line of the currently executing CPU -void SetLine(uint32 line) +void SetLineOfCurrentV6809(uint32 line) { regs.cpuFlags |= line; } // Clear a line of the currently executing CPU -void ClearLine(uint32 line) +void ClearLineOfCurrentV6809(uint32 line) { regs.cpuFlags &= ~line; } diff --git a/src/v6809.h b/src/v6809.h index 9511654..39fc3f8 100755 --- a/src/v6809.h +++ b/src/v6809.h @@ -57,7 +57,7 @@ struct V6809REGS void Execute6809(V6809REGS *, uint32); // Function to execute 6809 instructions uint64 GetCurrentV6809Clock(void); // Get the clock of the currently executing CPU uint16 GetCurrentV6809PC(void); // Get the PC of the currently executing CPU -void SetLine(uint32 line); // Set a line of the currently executing CPU -void ClearLine(uint32 line); // Clear a line of the currently executing CPU +void SetLineOfCurrentV6809(uint32 line); // Set a line of the currently executing CPU +void ClearLineOfCurrentV6809(uint32 line); // Clear a line of the currently executing CPU #endif // __V6809_H__ -- 2.37.2