]> Shamusworld >> Repos - thunder/blobdiff - src/thunder.cpp
Fixed IRQ/DAA problems. Emulator is now in a stable state. Woo hoo!
[thunder] / src / thunder.cpp
index ffbfed9574a7ec070ea679c79c0f2668ace9e130..17ea566f26774da6ad315789ed1df2f5584a855e 100755 (executable)
@@ -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