2 // Stargate Emulator (StarGem2) v2.0 SDL
5 // (C) 2006 Underground Software
7 // JLH = James L. Hammons <jlhamm@acm.org>
10 // --- ---------- ------------------------------------------------------------
11 // JLH 06/15/2006 Added changelog ;-)
12 // JLH 06/15/2006 Switched over to timeslice execution code
38 #define SOUNDROM "ROMs/sg.snd"
39 #define CMOS "cmos.ram"
40 #define SAVESTATE "sg2.state"
44 uint8 gram[0x10000], grom[0x10000], sram[0x10000], srom[0x10000]; // RAM & ROM spaces
52 static bool running = true; // Machine running state flag...
53 static uint32 startTicks;
54 static uint8 * keys; // SDL raw keyboard matrix
56 // Local timer callback functions
58 static void FrameCallback(void);
59 static void ScanlineCallback(void);
63 // 6809 memory functions
66 uint8 RdMem6809(uint16 addr)
70 if (addr >= 0x9000 && addr <= 0xCFFF) // No ROM between $9000 - $CFFF...
74 if (!gram[0xC900] && addr <= 0x8FFF) // Check RAM $C900 bank switch
80 //Is $C80E COUNT240? Hmm... No.
84 //if (addr >= 0xC000 && addr <= 0xCBFF)
86 WriteLog("RdMem: Reading address %04X [=%02X, PC=%04X]\n", addr, b, pcr);//*/
87 /*if (addr >= 0xC80D && addr <= 0xC80F)
88 WriteLog("V6809 RdMem: Reading address %04X [=%02X, PC=%04X]\n", addr, b, mainCPU.pc);//*/
93 void WrMem6809(uint16 addr, uint8 b)
96 //extern V6809REGS regs;
97 //if (addr >= 0xC800 && addr <= 0xCBFE)
98 //if (addr == 0xC80F || addr == 0xC80D)
99 // WriteLog("WrMem: Writing address %04X with %02X [PC=%04X, $CB00=%02X]\n", addr, b, regs.pc, gram[0xCB00]);//*/
100 //if (addr == 0xC80E)
101 /*if (addr >= 0xC800 && addr <= 0xC80F)
102 WriteLog("V6809 WrMem: Writing address %04X with %02X [PC=%04X, $CB00=%02X]\n", addr, b, mainCPU.pc, gram[0xCB00]);//*/
106 if (addr > 0x0006 && addr < 0x97F7) // 304 pixels 152-128=24-16=8
108 // NOTE: Screen was 304 x 256, but we truncate the vertical dimension here...
109 uint16 sx = (addr >> 7) & 0x01FE, sy = addr & 0x00FF;
111 if (sy > 5 && sy < 246)
113 uint32 saddr = 8 + sx + ((sy - 6) * 320); // Calc screen address
114 //Hmm. This approach won't work with palette color cycling...
116 scrBuffer[saddr + 0] = b >> 4;
117 scrBuffer[saddr + 1] = b & 0x0F;
119 scrBuffer[saddr + 0] = palette[color[b >> 4]];
120 scrBuffer[saddr + 1] = palette[color[b & 0x0F]];
124 else if (addr >= 0xC000 && addr <= 0xC00F)
125 //Let's see if we can fix the color cycling here... [DONE]
127 color[addr - 0xC000] = b; // color[] from VIDEO.CPP (not any more!)
130 // A better strategy here would probably be to set a flag when the color register changes,
131 // then change it before doing the render.
132 // ALSO: This approach doesn't take the color to the edges of the screen
133 color[addr - 0xC000] = b;
135 for(uint32 addr=0x0007; addr<0x97F7; addr++)
137 uint16 sx = (addr >> 7) & 0x01FE, sy = addr & 0x00FF;
139 if (sy > 5 && sy < 246)
141 uint32 saddr = 8 + sx + ((sy - 6) * 320); // Calc screen address
142 uint8 sb = gram[addr];
144 scrBuffer[saddr + 0] = palette[color[sb >> 4]];
145 scrBuffer[saddr + 1] = palette[color[sb & 0x0F]];
150 else if (addr == 0xC80E)
152 sram[0x0402] = b; // Connect PIAs in 6809 & 6808
153 soundCPU.cpuFlags |= V6808_ASSERT_LINE_IRQ; // Start sound IRQ
158 // 6808 memory functions
161 uint8 RdMem6808(uint16 addr)
163 return (addr < 0xF000 ? sram[addr] : srom[addr]);
166 void WrMem6808(uint16 addr, uint8 b)
170 // A total guess, but let's try it...
171 //It probably depends on how the PIA is configured, so this is most likely wrong.
172 // if (addr == 0x0401)
173 // soundCPU.cpuFlags &= ~V6808_ASSERT_LINE_IRQ;
177 // Load a file into RAM/ROM image space
179 bool LoadImg(char * filename, uint8 * ram, int size)
181 FILE * fp = fopen(filename, "rb");
186 fread(ram, 1, size, fp);
197 FILE * fp = fopen(CMOS, "wb");
201 fwrite(gram + 0xCC00, 1, 1024, fp);
205 WriteLog("CMOS RAM not saved!\n");
209 // Load state save file
211 bool LoadMachineState(void)
213 FILE * fp = fopen(SAVESTATE, "rb");
218 // This is kinda crappy--we don't do any sanity checking here!!!
219 fread(gram, 1, 0x10000, fp);
220 fread(sram, 1, 0x10000, fp);
221 fread(&mainCPU, 1, sizeof(V6809REGS), fp);
222 fread(&soundCPU, 1, sizeof(V6808REGS), fp);
225 for(int i=0x0006; i<0x97F8; i++) // Set up backbuffer... ;-)
226 WrMem6809(i, gram[i]);
228 mainCPU.RdMem = RdMem6809; // Make sure our function pointers are
229 mainCPU.WrMem = WrMem6809; // pointing to the right places!
230 soundCPU.RdMem = RdMem6808;
231 soundCPU.WrMem = WrMem6808;
237 // Save state save file
239 void SaveMachineState(void)
241 FILE * fp = fopen(SAVESTATE, "wb");
245 fwrite(gram, 1, 0x10000, fp);
246 fwrite(sram, 1, 0x10000, fp);
247 fwrite(&mainCPU, 1, sizeof(V6809REGS), fp);
248 fwrite(&soundCPU, 1, sizeof(V6808REGS), fp);
252 WriteLog("Machine state not saved!\n");
258 int main(int /*argc*/, char * /*argv*/[])
260 InitLog("stargem2.log");
261 WriteLog("StarGem2 - A portable Stargate emulator by James L. Hammons\n");
265 // Initialize Williams' palette (RGB coded as: 3 bits red, 3 bits green, 2 bits blue)
266 for(uint32 i=0; i<256; i++)
268 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
269 (((i & 0x01) * 33 + ((i & 0x02) >> 1) * 71 + ((i & 0x04) >> 2) * 151) << 24)
270 | ((((i & 0x08) >> 3) * 33 + ((i & 0x10) >> 4) * 71 + ((i & 0x20) >> 5) * 151) << 16)
271 | ((((i & 0x40) >> 6) * 71 + ((i & 0x80) >> 7) * 151) << 8) | 0xFF;
273 ((i & 0x01) * 33 + ((i & 0x02) >> 1) * 71 + ((i & 0x04) >> 2) * 151)
274 | ((((i & 0x08) >> 3) * 33 + ((i & 0x10) >> 4) * 71 + ((i & 0x20) >> 5) * 151) << 8)
275 | ((((i & 0x40) >> 6) * 71 + ((i & 0x80) >> 7) * 151) << 16) | 0xFF000000;
279 for(long i=0; i<0x10000; i++)
280 gram[i] = grom[i] = sram[i] = srom[i] = 0;
282 // Set up V6809 & V6808 execution contexts
284 memset(&mainCPU, sizeof(V6809REGS), 0);
285 mainCPU.RdMem = RdMem6809;
286 mainCPU.WrMem = WrMem6809;
287 mainCPU.cpuFlags |= V6809_ASSERT_LINE_RESET;
289 memset(&soundCPU, sizeof(V6808REGS), 0);
290 soundCPU.RdMem = RdMem6808;
291 soundCPU.WrMem = WrMem6808;
292 soundCPU.cpuFlags |= V6808_ASSERT_LINE_RESET;
295 "ROMs/01", "ROMs/02", "ROMs/03", "ROMs/04", "ROMs/05", "ROMs/06",
296 "ROMs/07", "ROMs/08", "ROMs/09", "ROMs/10", "ROMs/11", "ROMs/12"
299 for(int i=0; i<12; i++)
301 uint32 baseAddress = i * 0x1000;
304 baseAddress += 0x4000;
307 WriteLog("Loading ROM image '%s' at $%04X...\n", ROMs[i], baseAddress);
309 // if (!LoadImg(ROMs[i], grom + (i * 0x1000), 0x1000))
310 if (!LoadImg(ROMs[i], grom + baseAddress, 0x1000))
312 WriteLog("Could not open file '%s'!\n", ROMs[i]);
317 if (!LoadImg(SOUNDROM, srom + 0xF800, 0x800))
319 WriteLog("Could not open file '%s'!\n", SOUNDROM);
323 WriteLog("Stargate ROM images loaded...\n");
324 WriteLog("About to initialize video...\n");
328 cout << "Aborting!" << endl;
332 // Have to do this *after* video init but *before* sound init...!
333 WriteLog("About to load machine state...");
335 if (!LoadMachineState())
336 WriteLog("Machine state file not found!\n");
340 if (!LoadImg(CMOS, gram + 0xCC00, 0x400))
341 WriteLog("CMOS RAM not found!\n");
343 WriteLog("About to intialize audio...\n");
345 // uint8 * keys = SDL_GetKeyState(NULL);
346 keys = SDL_GetKeyState(NULL);
348 // running = true; // Set running status...
349 srom[0xF800] = 0x37; // Fix checksum so ST works...
354 //This didn't work--it still acted like the old way (interrupt @ VC = 0)
355 //gram[0xCB00] = 64*3;
357 WriteLog("Entering main loop...\n");
360 SDL_PumpEvents(); // Force key events into the buffer.
361 gram[0xC804] = gram[0xC806] = gram[0xC80C] = 0; // Reset PIA ports...
363 if (keys[SDLK_ESCAPE])
364 running = false; // ESC to exit...
366 if (keys[SDLK_SEMICOLON])
367 gram[0xC804] |= 0x01; // Fire (;)
369 gram[0xC804] |= 0x02; // Thrust (L)
370 if (keys[SDLK_SPACE])
371 gram[0xC804] |= 0x04; // Smart Bomb (space)
372 if (keys[SDLK_BACKSPACE])
373 gram[0xC804] |= 0x08; // Hyperspace (BkSp)
375 gram[0xC804] |= 0x10; // Two Player Start (2)
377 gram[0xC804] |= 0x20; // One Player Start (1)
378 if (keys[SDLK_RETURN])
379 gram[0xC804] |= 0x40; // Reverse (Enter)
381 gram[0xC804] |= 0x80; // Down (F)
384 gram[0xC806] |= 0x01; // Up (R)
386 gram[0xC806] |= 0x02; // Inviso (A)
389 gram[0xC80C] |= 0x01; // Auto up (F1)
391 gram[0xC80C] |= 0x02; // Advance (F2)
393 gram[0xC80C] |= 0x04; // Right Coin (5)
395 gram[0xC80C] |= 0x08; // High Score Reset (F3)
397 gram[0xC80C] |= 0x10; // Left Coin (3)
399 gram[0xC80C] |= 0x20; // Center Coin (4)
401 gram[0xC80C] |= 0x40; // Slam Switch (F4)
403 if (keys[SDLK_F5]) // Sound CPU self-test (F5)
404 soundCPU.cpuFlags |= V6808_ASSERT_LINE_NMI;
405 if (keys[SDLK_F6]) // Reset the 6808 (F6)
406 soundCPU.cpuFlags |= V6808_ASSERT_LINE_RESET;
409 $CB00 is scanline counter, bits 2-7 (1 frame/240 =69.44... usec)
411 Some places of interest to look at:
413 RdMem: Reading address C80E [=0C, PC=15C3] <- Inside interrupt (read, then discarded)...
414 RdMem: Reading address CB00 [=43, PC=15C6] <- interrupt
415 RdMem: Reading address C80C [=00, PC=0758] <- input (?)
416 RdMem: Reading address C80C [=00, PC=07B9] <- input (?)
417 RdMem: Reading address C806 [=00, PC=078C] <- input
418 RdMem: Reading address C804 [=00, PC=2679] <- input
420 uint32 startTicks = SDL_GetTicks();
421 // long video_clk = 0;
425 //This is where the interrupt mask is restored in CC... Hmm...
426 //This enables interrupts *after* the previous interrupt has occurred... Hmm.
427 //Could $C80F (rom_pia_ctrlb) be the IRQ inhibit? Yes, it is!
429 // the IRQ signal comes into CB1, and is set to VA11
430 pia_1_cb1_w(0, scanline & 0x20);
432 // the COUNT240 signal comes into CA1, and is set to the logical AND of VA10-VA13
435 // the COUNT240 signal comes into CA1, and is set to the logical AND of VA10-VA13
439 //WriteLog("--> Start of frame...\n");
440 for(int i=0; i<3; i++)
442 //Not sure, but this *might* fix IRQ problem...
443 //Checking the PIA IRQ mask for an IRQ seems to work OK. Now if only the timing elsewhere was right...
444 if (gram[0xC80F] & 0x01)
445 mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;//*/
447 Execute6809(&mainCPU, 4000);
448 mainCPU.clock -= 4000; // Remove 4K ticks from clock (in case it overflowed)
449 //Not sure, but this *might* fix IRQ problem...
450 //Checking the PIA IRQ mask for an IRQ seems to work OK. Now if only the timing elsewhere was right...
451 /* if (gram[0xC80F] & 0x01)
452 mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;//*/
454 gram[0xCB00] += 64; // Update video counter...
458 /*if (gram[0xC80E] & 0x01)
459 mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;//*/
462 Execute6809(&mainCPU, 3000);
463 mainCPU.clock -= 3000; // Remove 3K ticks from clock (in case it overflowed)
464 //Not sure, but this *might* fix IRQ problem...
465 //if (gram[0xC80F] & 0x01)
466 //This isn't the right port on the PIA, but it does seem to make it through the demo now...
467 //Lesse if this works... Seems to!
468 if (gram[0xC80D] & 0x01) // Do COUNT240 IRQ (if enabled!)
469 mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;
471 /*if (gram[0xC80F] & 0x01)
472 mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;
473 gram[0xCB00] = 0; //*/
475 gram[0xCB00] += 48; // Update video counter...
477 Execute6809(&mainCPU, 1000);
478 mainCPU.clock -= 1000; // Remove 1K ticks from clock (in case it overflowed)
480 //Ok, this is the interrupt it's looking for, but still...
481 //if (gram[0xC80F] & 0x01)
482 // mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;
484 gram[0xCB00] += 16; // Update video counter...
486 // RenderScreenBuffer();
487 RenderScreenBuffer2(); // 1 frame = 16667 cycles
488 // WriteLog("Main: Rendered back buffer. [6809 PC=%04X]\n", pcr);
490 Execute6809(&mainCPU, 667); // Do QnD VBLANK
492 // 1/60 sec = ? ms (16.6 ms)
493 while (SDL_GetTicks() - startTicks < 16); // Wait for next frame...
496 //Very interesting! It's the palette rotation that's slowing it down!
497 //Fixed now, but this allows the color rotation while the wrong timing is in effect...
498 /*for(int i=0; i<16; i++)
499 WrMem(0xC000 + i, gram[0x9C26 + i]);//*/
502 /*uint16 pc = 0x15BA;
503 for(int i=0; i<200; i++)
504 //while (pc < 0x9000)
505 pc += Decode6809(pc);//*/
509 running = true; // Set running status...
511 InitializeEventList(); // Clear the event list before we use it...
512 SetCallbackTime(FrameCallback, 16666.66666667); // Set frame to fire at 1/60 s interval
513 // SetCallbackTime(BlinkTimer, 250000); // Set up blinking at 1/4 s intervals
514 SetCallbackTime(ScanlineCallback, 520.83333334); // Set scanline callback at 1/32 of frame
515 // SetCallbackTime(ScanlineCallback, 520.83333334*32.00); // Set scanline callback at 1/32 of frame
516 startTicks = SDL_GetTicks();
518 WriteLog("Entering main loop...\n");
522 double timeToNextEvent = GetTimeToNextEvent();
523 Execute6809(&mainCPU, USEC_TO_M6809_CYCLES(timeToNextEvent));
524 //We MUST remove a frame's worth of time in order for the CPU to function... !!! FIX !!!
525 //(Fix so that this is not a requirement!)
526 mainCPU.clock -= USEC_TO_M6809_CYCLES(timeToNextEvent);
532 WriteLog("$C900 = $%02X (0=RAM)\n", gram[0xC900]);
533 WriteLog("PC: %04X, X: %04X, Y: %04X, S: %04X, U: %04X, A: %02X, B: %02X, DP: %02X, CC: %02X\n", mainCPU.pc, mainCPU.x, mainCPU.y, mainCPU.s, mainCPU.u, mainCPU.a, mainCPU.b, mainCPU.dp, mainCPU.cc);
536 /*uint16 pc = mainCPU.pc;//0x15BA;
537 for(int i=0; i<200; i++)
538 //while (pc < 0x9000)
540 pc += Decode6809(pc);
547 pc += Decode6809(pc);
563 static void FrameCallback(void)
565 SDL_PumpEvents(); // Force key events into the buffer.
566 gram[0xC804] = gram[0xC806] = gram[0xC80C] = 0; // Reset PIA ports...
568 if (keys[SDLK_ESCAPE])
569 running = false; // ESC to exit...
571 //Convert this stuff to use the settings module... !!! FIX !!!
572 if (keys[SDLK_SEMICOLON])
573 gram[0xC804] |= 0x01; // Fire (;)
575 gram[0xC804] |= 0x02; // Thrust (L)
576 if (keys[SDLK_SPACE])
577 gram[0xC804] |= 0x04; // Smart Bomb (space)
578 if (keys[SDLK_BACKSPACE])
579 gram[0xC804] |= 0x08; // Hyperspace (BkSp)
581 gram[0xC804] |= 0x10; // Two Player Start (2)
583 gram[0xC804] |= 0x20; // One Player Start (1)
584 if (keys[SDLK_RETURN])
585 gram[0xC804] |= 0x40; // Reverse (Enter)
587 gram[0xC804] |= 0x80; // Down (F)
590 gram[0xC806] |= 0x01; // Up (R)
592 gram[0xC806] |= 0x02; // Inviso (A)
595 gram[0xC80C] |= 0x01; // Auto up (F1)
597 gram[0xC80C] |= 0x02; // Advance (F2)
599 gram[0xC80C] |= 0x04; // Right Coin (5)
601 gram[0xC80C] |= 0x08; // High Score Reset (F3)
603 gram[0xC80C] |= 0x10; // Left Coin (3)
605 gram[0xC80C] |= 0x20; // Center Coin (4)
607 gram[0xC80C] |= 0x40; // Slam Switch (F4)
609 if (keys[SDLK_F5]) // Sound CPU self-test (F5)
610 soundCPU.cpuFlags |= V6808_ASSERT_LINE_NMI;
611 if (keys[SDLK_F6]) // Reset the 6808 (F6)
612 soundCPU.cpuFlags |= V6808_ASSERT_LINE_RESET;
614 RenderScreenBuffer2(); // 1 frame = 1/60 sec ~ 16667 cycles
615 SetCallbackTime(FrameCallback, 16666.66666667);
617 while (SDL_GetTicks() - startTicks < 16); // Wait for next frame...
618 startTicks = SDL_GetTicks();
621 static void ScanlineCallback(void)
623 // CA1 of PIA 1 maps to $C80C-F... <-- Count240 is in PIA1...
624 // What about COUNT240???
626 //wil wok? Yes, but still screws up on the demo...
627 /* if (gram[0xCB00] & 0x20)
628 if (gram[0xC80F] & 0x01)
629 mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;//*/
630 if ((gram[0xCB00] & 0x20) && (gram[0xC80F] & 0x01))
631 mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;//*/
633 //Is $C80E COUNT240? Hmm... Doesn't seem to be. Bleh.
634 /* if (gram[0xCB00] >= 240)
637 gram[0xC80E] = 0x00;//*/
638 // gram[0xC80E] = (gram[0xCB00] >= 240 ? 0xFF : 0x00);
640 gram[0xCB00] += 8; // Update video counter...
642 SetCallbackTime(ScanlineCallback, 520.83333334); // Set scanline callback at 1/32 of frame
647 ; With correct timing, but no color cycling
649 --> Start of frame...
650 WrMem: Writing address C80F with 34 [PC=15C3, $CB00=40]
655 WrMem: Writing address C80F with 35 [PC=1644, $CB00=40]
656 WrMem: Writing address C80F with 34 [PC=15C3, $CB00=80]
664 WrMem: Writing address C80F with 35 [PC=1644, $CB00=80]
665 WrMem: Writing address C80F with 34 [PC=15C3, $CB00=C0]
666 WrMem: Writing address C80F with 35 [PC=1644, $CB00=C0]
669 ; With incorrect timing, but has color cycling
671 --> Start of frame...
672 WrMem: Writing address C80F with 34 [PC=15C3, $CB00=00]
673 At $1609. $6E: 00 ; Color cycling...
678 WrMem: Writing address C80F with 35 [PC=1644, $CB00=00]
679 WrMem: Writing address C80F with 34 [PC=15C3, $CB00=40]
680 WrMem: Writing address C80F with 35 [PC=1644, $CB00=40]
681 WrMem: Writing address C80F with 34 [PC=15C3, $CB00=80]
689 WrMem: Writing address C80F with 35 [PC=1644, $CB00=80]
690 WrMem: Writing address C80F with 34 [PC=15C3, $CB00=C0]
691 WrMem: Writing address C80F with 35 [PC=1644, $CB00=C0]
698 0000-8FFF ROM (for Blaster, 0000-3FFF is a bank of 12 ROMs)
699 0000-97FF Video RAM Bank switched with ROM (96FF for Blaster)
701 0xBB00 Blaster only, Color 0 for each line (256 entry)
702 0xBC00 Blaster only, Color 0 flags, latch color only if bit 0 = 1 (256 entry)
703 Do something else with the bit 1, I do not know what
707 C000-C00F color_registers (16 bytes of BBGGGRRR)
709 C804 widget_pia_dataa (widget = I/O board)
710 C805 widget_pia_ctrla
711 C806 widget_pia_datab
712 C807 widget_pia_ctrlb (CB2 select between player 1 and player 2
713 controls if Table or Joust)
714 bits 5-3 = 110 = player 2
715 bits 5-3 = 111 = player 1
722 bit 2 |-6 bits to sound board
727 bit 7 /Plus CA2 and CB2 = 4 bits to drive the LED 7 segment
730 C900 rom_enable_scr_ctrl Switch between video ram and rom at 0000-97FF
734 C804 widget_pia_dataa (widget = I/O board)
744 C806 widget_pia_datab
752 bit 7 0 = Upright 1 = Table
757 bit 2 Right Coin (High Score Reset in schematics)
758 bit 3 High Score Reset (Left Coin in schematics)
759 bit 4 Left Coin (Center Coin in schematics)
760 bit 5 Center Coin (Right Coin in schematics)
762 bit 7 Hand Shake from sound board
768 static MEMORY_READ_START( williams_readmem )
769 { 0x0000, 0x97ff, MRA_BANK1 },
770 { 0x9800, 0xbfff, MRA_RAM },
771 { 0xc804, 0xc807, pia_0_r },
772 { 0xc80c, 0xc80f, pia_1_r },
773 { 0xcb00, 0xcb00, williams_video_counter_r },
774 { 0xcc00, 0xcfff, MRA_RAM },
775 { 0xd000, 0xffff, MRA_ROM },
779 static MEMORY_WRITE_START( williams_writemem )
780 { 0x0000, 0x97ff, williams_videoram_w, &williams_bank_base, &videoram_size },
781 { 0x9800, 0xbfff, MWA_RAM },
782 { 0xc000, 0xc00f, paletteram_BBGGGRRR_w, &paletteram },
783 { 0xc804, 0xc807, pia_0_w },
784 { 0xc80c, 0xc80f, pia_1_w },
785 { 0xc900, 0xc900, williams_vram_select_w },
786 { 0xca00, 0xca07, williams_blitter_w, &williams_blitterram },
787 { 0xcbff, 0xcbff, watchdog_reset_w },
788 { 0xcc00, 0xcfff, MWA_RAM },
789 { 0xd000, 0xffff, MWA_ROM },
792 static MEMORY_READ_START( sound_readmem )
793 { 0x0000, 0x007f, MRA_RAM },
794 { 0x0400, 0x0403, pia_2_r },
795 { 0x8400, 0x8403, pia_2_r }, // used by Colony 7, perhaps others?
796 { 0xb000, 0xffff, MRA_ROM }, // most games start at $F000, Sinistar starts at $B000
800 static MEMORY_WRITE_START( sound_writemem )
801 { 0x0000, 0x007f, MWA_RAM },
802 { 0x0400, 0x0403, pia_2_w },
803 { 0x8400, 0x8403, pia_2_w }, // used by Colony 7, perhaps others?
804 { 0xb000, 0xffff, MWA_ROM }, // most games start at $F000, Sinistar starts at $B000
807 MACHINE_INIT( williams )
812 // reset the ticket dispenser (Lotto Fun)
813 ticket_dispenser_init(70, TICKET_MOTOR_ACTIVE_LOW, TICKET_STATUS_ACTIVE_HIGH);
815 // set a timer to go off every 16 scanlines, to toggle the VA11 line and update the screen
816 timer_set(cpu_getscanlinetime(0), 0, williams_va11_callback);
818 // also set a timer to go off on scanline 240
819 timer_set(cpu_getscanlinetime(240), 0, williams_count240_callback);
823 static void williams_va11_callback(int scanline)
825 // the IRQ signal comes into CB1, and is set to VA11
826 pia_1_cb1_w(0, scanline & 0x20);
828 // update the screen while we're here
829 force_partial_update(scanline - 1);
831 // set a timer for the next update
833 if (scanline >= 256) scanline = 0;
834 timer_set(cpu_getscanlinetime(scanline), scanline, williams_va11_callback);
838 static void williams_count240_off_callback(int param)
840 // the COUNT240 signal comes into CA1, and is set to the logical AND of VA10-VA13
845 static void williams_count240_callback(int param)
847 // the COUNT240 signal comes into CA1, and is set to the logical AND of VA10-VA13
850 // set a timer to turn it off once the scanline counter resets
851 timer_set(cpu_getscanlinetime(0), 0, williams_count240_off_callback);
853 // set a timer for next frame
854 timer_set(cpu_getscanlinetime(240), 0, williams_count240_callback);
858 static void williams_main_irq(int state)
860 // IRQ to the main CPU
861 cpu_set_irq_line(0, M6809_IRQ_LINE, state ? ASSERT_LINE : CLEAR_LINE);
865 static void williams_main_firq(int state)
867 // FIRQ to the main CPU
868 cpu_set_irq_line(0, M6809_FIRQ_LINE, state ? ASSERT_LINE : CLEAR_LINE);
872 static void williams_snd_irq(int state)
874 // IRQ to the sound CPU
875 cpu_set_irq_line(1, M6800_IRQ_LINE, state ? ASSERT_LINE : CLEAR_LINE);
879 READ_HANDLER( williams_video_counter_r )
881 return cpu_getscanline() & 0xFC;
885 // Special PIA 0 for Stargate, to handle the controls
886 struct pia6821_interface stargate_pia_0_intf =
888 //inputs : A/B,CA/B1,CA/B2 / stargate_input_port_0_r, input_port_1_r, 0, 0, 0, 0,
889 //outputs: A/B,CA/B2 / 0, 0, 0, 0,
893 // Generic PIA 1, maps to input port 2, sound command out, and IRQs
894 struct pia6821_interface williams_pia_1_intf =
896 //inputs : A/B,CA/B1,CA/B2 / input_port_2_r, 0, 0, 0, 0, 0,
897 //outputs: A/B,CA/B2 / 0, williams_snd_cmd_w, 0, 0,
898 //irqs : A/B / williams_main_irq, williams_main_irq
901 // Generic PIA 2, maps to DAC data in and sound IRQs
902 struct pia6821_interface williams_snd_pia_intf =
904 //inputs : A/B,CA/B1,CA/B2 / 0, 0, 0, 0, 0, 0,
905 //outputs: A/B,CA/B2 / DAC_0_data_w, 0, 0, 0,
906 //irqs : A/B / williams_snd_irq, williams_snd_irq
909 static DRIVER_INIT( stargate )
911 // CMOS configuration
912 CONFIGURE_CMOS(0xCC00, 0x400);
915 CONFIGURE_PIAS(stargate_pia_0_intf, williams_pia_1_intf, williams_snd_pia_intf);
919 int cpu_getscanline(void)
921 return (int)(timer_timeelapsed(refresh_timer) * scanline_period_inv);
924 *************************************
926 * Returns time until given scanline
928 *************************************
930 double cpu_getscanlinetime(int scanline)
932 double scantime = timer_starttime(refresh_timer) + (double)scanline * scanline_period;
933 double abstime = timer_get_time();
936 // if we're already past the computed time, count it for the next frame
937 if (abstime >= scantime)
938 scantime += TIME_IN_HZ(Machine->drv->frames_per_second);
940 // compute how long from now until that time
941 result = scantime - abstime;
943 // if it's small, just count a whole frame
944 if (result < TIME_IN_NSEC(1))
945 result = TIME_IN_HZ(Machine->drv->frames_per_second);
949 *************************************
951 * Returns time for one scanline
953 *************************************
955 double cpu_getscanlineperiod(void)
957 return scanline_period;
961 V6809 WrMem: Writing address C80D with 00 [PC=0000, $CB00=00]
962 V6809 WrMem: Writing address C80C with 00 [PC=0000, $CB00=00]
963 V6809 WrMem: Writing address C80D with 3C [PC=0000, $CB00=00]
965 V6809 WrMem: Writing address C80F with 00 [PC=0000, $CB00=00]
966 V6809 WrMem: Writing address C80E with C0 [PC=0000, $CB00=00]
967 V6809 WrMem: Writing address C80F with 3C [PC=0000, $CB00=00]
969 V6809 WrMem: Writing address C80E with C0 [PC=0000, $CB00=00]
970 V6809 WrMem: Writing address C80D with 34 [PC=FE61, $CB00=48]
971 V6809 WrMem: Writing address C80F with 34 [PC=FE61, $CB00=48]
972 V6809 WrMem: Writing address C80E with 00 [PC=FE61, $CB00=48]
974 V6809 WrMem: Writing address C80C with 00 [PC=FD92, $CB00=C8]
975 V6809 WrMem: Writing address C80D with 00 [PC=FD92, $CB00=C8]
976 V6809 WrMem: Writing address C80C with 00 [PC=FD92, $CB00=C8]
977 V6809 WrMem: Writing address C80D with 34 [PC=FD92, $CB00=C8]
979 V6809 WrMem: Writing address C80E with 00 [PC=FD92, $CB00=C8]
980 V6809 WrMem: Writing address C80F with 00 [PC=FD92, $CB00=C8]
981 V6809 WrMem: Writing address C80E with FF [PC=FD92, $CB00=C8]
982 V6809 WrMem: Writing address C80F with 35 [PC=FD92, $CB00=C8]
984 V6809 WrMem: Writing address C804 with 00 [PC=607B, $CB00=D0]
985 V6809 WrMem: Writing address C805 with 00 [PC=607B, $CB00=D0]
986 V6809 WrMem: Writing address C804 with 00 [PC=607B, $CB00=D0]
987 V6809 WrMem: Writing address C805 with 34 [PC=607B, $CB00=D0]
989 V6809 WrMem: Writing address C806 with 00 [PC=607B, $CB00=D0]
990 V6809 WrMem: Writing address C807 with 00 [PC=607B, $CB00=D0]
991 V6809 WrMem: Writing address C806 with 00 [PC=607B, $CB00=D0]
992 V6809 WrMem: Writing address C807 with 3E [PC=607B, $CB00=D0]
994 V6809 WrMem: Writing address C80E with 3F [PC=13CB, $CB00=A8]
995 V6809 WrMem: Writing address C807 with 3C [PC=60B4, $CB00=90]
996 V6809 WrMem: Writing address C80E with 0C [PC=014D, $CB00=80]
998 V6809 WrMem: Writing address C80F with 34 [PC=014D, $CB00=80]
999 V6809 WrMem: Writing address C80F with 35 [PC=014D, $CB00=80]
1000 V6809 WrMem: Writing address C80F with 34 [PC=0013, $CB00=A8]
1001 V6809 WrMem: Writing address C80F with 35 [PC=0013, $CB00=A8]
1008 bit 2 |-6 bits to sound board
1013 bit 7 /Plus CA2 and CB2 = 4 bits to drive the LED 7 segment
1016 CTRLA = IRQA1 (1 bit) IRQA2 (1 bit) CA2 (3 bits) DDR (1 bit) CA1 (2 bits)
1021 00 -> $C80D = PIA2 -> DDR active
1022 00 -> $C80C = PIA2 DDR -> All input?