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
48 #define SOUNDROM "sg.snd"
49 #define CMOS "cmos.ram"
50 #define SAVESTATE "sg2.state"
54 uint8 * gram, * grom, * sram, * srom; // RAM & ROM pointers
62 //static uint8 lastKeyPressed = 0;
63 //static bool keyDown = false;
65 //static FloppyDrive floppyDrive;
67 //enum { LC_BANK_1, LC_BANK_2 };
69 //static uint8 visibleBank = LC_BANK_1;
70 //static bool readRAM = false;
71 //static bool writeRAM = false;
73 static bool running = true; // Machine running state flag...
74 static uint32 startTicks;
75 static uint8 * keys; // SDL raw keyboard matrix
77 // Local timer callback functions
79 static void FrameCallback(void);
80 static void ScanlineCallback(void);
84 // 6809 memory functions
87 uint8 RdMem6809(uint16 addr)
91 if (addr >= 0x9000 && addr <= 0xCFFF) // No ROM between $9000 - $CFFF...
95 if (!gram[0xC900] && addr <= 0x8FFF) // Check RAM $C900 bank switch
101 //Is $C80E COUNT240? Hmm... No.
105 //if (addr >= 0xC000 && addr <= 0xCBFF)
107 WriteLog("RdMem: Reading address %04X [=%02X, PC=%04X]\n", addr, b, pcr);//*/
108 /*if (addr >= 0xC80D && addr <= 0xC80F)
109 WriteLog("V6809 RdMem: Reading address %04X [=%02X, PC=%04X]\n", addr, b, mainCPU.pc);//*/
114 void WrMem6809(uint16 addr, uint8 b)
117 //extern V6809REGS regs;
118 //if (addr >= 0xC800 && addr <= 0xCBFE)
119 //if (addr == 0xC80F || addr == 0xC80D)
120 // WriteLog("WrMem: Writing address %04X with %02X [PC=%04X, $CB00=%02X]\n", addr, b, regs.pc, gram[0xCB00]);//*/
121 //if (addr == 0xC80E)
122 /*if (addr >= 0xC800 && addr <= 0xC80F)
123 WriteLog("V6809 WrMem: Writing address %04X with %02X [PC=%04X, $CB00=%02X]\n", addr, b, mainCPU.pc, gram[0xCB00]);//*/
127 if (addr > 0x0006 && addr < 0x97F7) // 304 pixels 152-128=24-16=8
129 // NOTE: Screen was 304 x 256, but we truncate the vertical dimension here...
130 uint16 sx = (addr >> 7) & 0x01FE, sy = addr & 0x00FF;
132 if (sy > 5 && sy < 246)
134 uint32 saddr = 8 + sx + ((sy - 6) * 320); // Calc screen address
135 //Hmm. This approach won't work with palette color cycling...
137 scrBuffer[saddr + 0] = b >> 4;
138 scrBuffer[saddr + 1] = b & 0x0F;
140 scrBuffer[saddr + 0] = palette[color[b >> 4]];
141 scrBuffer[saddr + 1] = palette[color[b & 0x0F]];
145 else if (addr >= 0xC000 && addr <= 0xC00F)
146 //Let's see if we can fix the color cycling here... [DONE]
148 color[addr - 0xC000] = b; // color[] from VIDEO.CPP (not any more!)
151 // A better strategy here would probably be to set a flag when the color register changes,
152 // then change it before doing the render.
153 // ALSO: This approach doesn't take the color to the edges of the screen
154 color[addr - 0xC000] = b;
156 for(uint32 addr=0x0007; addr<0x97F7; addr++)
158 uint16 sx = (addr >> 7) & 0x01FE, sy = addr & 0x00FF;
160 if (sy > 5 && sy < 246)
162 uint32 saddr = 8 + sx + ((sy - 6) * 320); // Calc screen address
163 uint8 sb = gram[addr];
165 scrBuffer[saddr + 0] = palette[color[sb >> 4]];
166 scrBuffer[saddr + 1] = palette[color[sb & 0x0F]];
171 else if (addr == 0xC80E)
173 sram[0x0402] = b; // Connect PIAs in 6809 & 6808
174 soundCPU.cpuFlags |= V6808_ASSERT_LINE_IRQ; // Start sound IRQ
179 // 6808 memory functions
182 uint8 RdMem6808(uint16 addr)
184 return (addr < 0xF000 ? sram[addr] : srom[addr]);
187 void WrMem6808(uint16 addr, uint8 b)
193 // Load a file into RAM/ROM image space
195 bool LoadImg(char * filename, uint8 * ram, int size)
199 strcpy(pathname, settings.BIOSPath);
200 strcat(pathname, filename);
202 FILE * fp = fopen(pathname, "rb");
206 WriteLog("Could not open file '%s'!\n", pathname);
210 fread(ram, 1, size, fp);
221 FILE * fp = fopen(CMOS, "wb");
225 fwrite(gram + 0xCC00, 1, 1024, fp);
229 WriteLog("CMOS RAM not saved!\n");
233 // Load state save file
235 bool LoadMachineState(void)
237 FILE * fp = fopen(SAVESTATE, "rb");
242 // This is kinda crappy--we don't do any sanity checking here!!!
243 fread(gram, 1, 0x10000, fp);
244 fread(sram, 1, 0x10000, fp);
245 fread(&mainCPU, 1, sizeof(V6809REGS), fp);
246 fread(&soundCPU, 1, sizeof(V6808REGS), fp);
249 for(int i=0x0006; i<0x97F8; i++) // Set up backbuffer... ;-)
250 WrMem6809(i, gram[i]);
252 mainCPU.RdMem = RdMem6809; // Make sure our function pointers are
253 mainCPU.WrMem = WrMem6809; // pointing to the right places!
254 soundCPU.RdMem = RdMem6808;
255 soundCPU.WrMem = WrMem6808;
261 // Save state save file
263 void SaveMachineState(void)
265 FILE * fp = fopen(SAVESTATE, "wb");
269 fwrite(gram, 1, 0x10000, fp);
270 fwrite(sram, 1, 0x10000, fp);
271 fwrite(&mainCPU, 1, sizeof(V6809REGS), fp);
272 fwrite(&soundCPU, 1, sizeof(V6808REGS), fp);
276 WriteLog("Machine state not saved!\n");
282 int main(int /*argc*/, char * /*argv*/[])
284 // bool running; // Machine running state flag...
287 InitLog("stargem2.log");
288 WriteLog("StarGem2 - A portable Stargate emulator by James L. Hammons\n");
290 // Initialize Williams' palette (RGB coded as: 3 bits red, 3 bits green, 2 bits blue)
291 for(uint32 i=0; i<256; i++)
293 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
294 (((i & 0x01) * 33 + ((i & 0x02) >> 1) * 71 + ((i & 0x04) >> 2) * 151) << 24)
295 | ((((i & 0x08) >> 3) * 33 + ((i & 0x10) >> 4) * 71 + ((i & 0x20) >> 5) * 151) << 16)
296 | ((((i & 0x40) >> 6) * 71 + ((i & 0x80) >> 7) * 151) << 8) | 0xFF;
298 ((i & 0x01) * 33 + ((i & 0x02) >> 1) * 71 + ((i & 0x04) >> 2) * 151)
299 | ((((i & 0x08) >> 3) * 33 + ((i & 0x10) >> 4) * 71 + ((i & 0x20) >> 5) * 151) << 8)
300 | ((((i & 0x40) >> 6) * 71 + ((i & 0x80) >> 7) * 151) << 16) | 0xFF000000;
303 gram = new uint8[0x10000];
304 grom = new uint8[0x10000];
305 sram = new uint8[0x10000];
306 srom = new uint8[0x10000];
310 WriteLog("Could not allocate RAM space!\nAborting!\n");
313 else if (grom == NULL)
315 WriteLog("Could not allocate ROM space!\nAborting!\n");
318 else if (sram == NULL)
320 WriteLog("Could not allocate sRAM space!\nAborting!\n");
323 else if (srom == NULL)
325 WriteLog("Could not allocate sROM space!\nAborting!\n");
330 for(long i=0; i<0x10000; i++)
331 gram[i] = grom[i] = sram[i] = srom[i] = 0;
333 // Set up V6809 & V6808 execution contexts
335 memset(&mainCPU, sizeof(V6809REGS), 0);
336 mainCPU.RdMem = RdMem6809;
337 mainCPU.WrMem = WrMem6809;
338 mainCPU.cpuFlags |= V6809_ASSERT_LINE_RESET;
340 memset(&soundCPU, sizeof(V6808REGS), 0);
341 soundCPU.RdMem = RdMem6808;
342 soundCPU.WrMem = WrMem6808;
343 soundCPU.cpuFlags |= V6808_ASSERT_LINE_RESET;
345 if (!LoadImg(CMOS, gram + 0xCC00, 0x400))
346 WriteLog("CMOS RAM not found!\n");
348 if (!LoadImg(ROM1, grom + 0x0000, 0x1000))
351 if (!LoadImg(ROM2, grom + 0x1000, 0x1000))
354 if (!LoadImg(ROM3, grom + 0x2000, 0x1000))
357 if (!LoadImg(ROM4, grom + 0x3000, 0x1000))
360 if (!LoadImg(ROM5, grom + 0x4000, 0x1000))
363 if (!LoadImg(ROM6, grom + 0x5000, 0x1000))
366 if (!LoadImg(ROM7, grom + 0x6000, 0x1000))
369 if (!LoadImg(ROM8, grom + 0x7000, 0x1000))
372 if (!LoadImg(ROM9, grom + 0x8000, 0x1000))
375 if (!LoadImg(ROM10, grom + 0xD000, 0x1000))
378 if (!LoadImg(ROM11, grom + 0xE000, 0x1000))
381 if (!LoadImg(ROM12, grom + 0xF000, 0x1000))
384 if (!LoadImg(SOUNDROM, srom + 0xF800, 0x800))
387 WriteLog("Stargate ROM images loaded...\n");
388 WriteLog("About to initialize video...\n");
392 cout << "Aborting!" << endl;
396 // Have to do this *after* video init but *before* sound init...!
397 if (!LoadMachineState())
398 WriteLog("Machine state file not found!\n");
400 WriteLog("About to intialize audio...\n");
402 // uint8 * keys = SDL_GetKeyState(NULL);
403 keys = SDL_GetKeyState(NULL);
405 // running = true; // Set running status...
406 srom[0xF800] = 0x37; // Fix checksum so ST works...
411 //This didn't work--it still acted like the old way (interrupt @ VC = 0)
412 //gram[0xCB00] = 64*3;
414 WriteLog("Entering main loop...\n");
417 SDL_PumpEvents(); // Force key events into the buffer.
418 gram[0xC804] = gram[0xC806] = gram[0xC80C] = 0; // Reset PIA ports...
420 if (keys[SDLK_ESCAPE])
421 running = false; // ESC to exit...
423 if (keys[SDLK_SEMICOLON])
424 gram[0xC804] |= 0x01; // Fire (;)
426 gram[0xC804] |= 0x02; // Thrust (L)
427 if (keys[SDLK_SPACE])
428 gram[0xC804] |= 0x04; // Smart Bomb (space)
429 if (keys[SDLK_BACKSPACE])
430 gram[0xC804] |= 0x08; // Hyperspace (BkSp)
432 gram[0xC804] |= 0x10; // Two Player Start (2)
434 gram[0xC804] |= 0x20; // One Player Start (1)
435 if (keys[SDLK_RETURN])
436 gram[0xC804] |= 0x40; // Reverse (Enter)
438 gram[0xC804] |= 0x80; // Down (F)
441 gram[0xC806] |= 0x01; // Up (R)
443 gram[0xC806] |= 0x02; // Inviso (A)
446 gram[0xC80C] |= 0x01; // Auto up (F1)
448 gram[0xC80C] |= 0x02; // Advance (F2)
450 gram[0xC80C] |= 0x04; // Right Coin (5)
452 gram[0xC80C] |= 0x08; // High Score Reset (F3)
454 gram[0xC80C] |= 0x10; // Left Coin (3)
456 gram[0xC80C] |= 0x20; // Center Coin (4)
458 gram[0xC80C] |= 0x40; // Slam Switch (F4)
460 if (keys[SDLK_F5]) // Sound CPU self-test (F5)
461 soundCPU.cpuFlags |= V6808_ASSERT_LINE_NMI;
462 if (keys[SDLK_F6]) // Reset the 6808 (F6)
463 soundCPU.cpuFlags |= V6808_ASSERT_LINE_RESET;
466 $CB00 is scanline counter, bits 2-7 (1 frame/240 =69.44... usec)
468 Some places of interest to look at:
470 RdMem: Reading address C80E [=0C, PC=15C3] <- Inside interrupt (read, then discarded)...
471 RdMem: Reading address CB00 [=43, PC=15C6] <- interrupt
472 RdMem: Reading address C80C [=00, PC=0758] <- input (?)
473 RdMem: Reading address C80C [=00, PC=07B9] <- input (?)
474 RdMem: Reading address C806 [=00, PC=078C] <- input
475 RdMem: Reading address C804 [=00, PC=2679] <- input
477 uint32 startTicks = SDL_GetTicks();
478 // long video_clk = 0;
482 //This is where the interrupt mask is restored in CC... Hmm...
483 //This enables interrupts *after* the previous interrupt has occurred... Hmm.
484 //Could $C80F (rom_pia_ctrlb) be the IRQ inhibit? Yes, it is!
486 // the IRQ signal comes into CB1, and is set to VA11
487 pia_1_cb1_w(0, scanline & 0x20);
489 // the COUNT240 signal comes into CA1, and is set to the logical AND of VA10-VA13
492 // the COUNT240 signal comes into CA1, and is set to the logical AND of VA10-VA13
496 //WriteLog("--> Start of frame...\n");
497 for(int i=0; i<3; i++)
499 //Not sure, but this *might* fix IRQ problem...
500 //Checking the PIA IRQ mask for an IRQ seems to work OK. Now if only the timing elsewhere was right...
501 if (gram[0xC80F] & 0x01)
502 mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;//*/
504 Execute6809(&mainCPU, 4000);
505 mainCPU.clock -= 4000; // Remove 4K ticks from clock (in case it overflowed)
506 //Not sure, but this *might* fix IRQ problem...
507 //Checking the PIA IRQ mask for an IRQ seems to work OK. Now if only the timing elsewhere was right...
508 /* if (gram[0xC80F] & 0x01)
509 mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;//*/
511 gram[0xCB00] += 64; // Update video counter...
515 /*if (gram[0xC80E] & 0x01)
516 mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;//*/
519 Execute6809(&mainCPU, 3000);
520 mainCPU.clock -= 3000; // Remove 3K ticks from clock (in case it overflowed)
521 //Not sure, but this *might* fix IRQ problem...
522 //if (gram[0xC80F] & 0x01)
523 //This isn't the right port on the PIA, but it does seem to make it through the demo now...
524 //Lesse if this works... Seems to!
525 if (gram[0xC80D] & 0x01) // Do COUNT240 IRQ (if enabled!)
526 mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;
528 /*if (gram[0xC80F] & 0x01)
529 mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;
530 gram[0xCB00] = 0; //*/
532 gram[0xCB00] += 48; // Update video counter...
534 Execute6809(&mainCPU, 1000);
535 mainCPU.clock -= 1000; // Remove 1K ticks from clock (in case it overflowed)
537 //Ok, this is the interrupt it's looking for, but still...
538 //if (gram[0xC80F] & 0x01)
539 // mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;
541 gram[0xCB00] += 16; // Update video counter...
543 // RenderScreenBuffer();
544 RenderScreenBuffer2(); // 1 frame = 16667 cycles
545 // WriteLog("Main: Rendered back buffer. [6809 PC=%04X]\n", pcr);
547 Execute6809(&mainCPU, 667); // Do QnD VBLANK
549 // 1/60 sec = ? ms (16.6 ms)
550 while (SDL_GetTicks() - startTicks < 16); // Wait for next frame...
553 //Very interesting! It's the palette rotation that's slowing it down!
554 //Fixed now, but this allows the color rotation while the wrong timing is in effect...
555 /*for(int i=0; i<16; i++)
556 WrMem(0xC000 + i, gram[0x9C26 + i]);//*/
559 /*uint16 pc = 0x15BA;
560 for(int i=0; i<200; i++)
561 //while (pc < 0x9000)
562 pc += Decode6809(pc);//*/
566 running = true; // Set running status...
568 InitializeEventList(); // Clear the event list before we use it...
569 SetCallbackTime(FrameCallback, 16666.66666667); // Set frame to fire at 1/60 s interval
570 // SetCallbackTime(BlinkTimer, 250000); // Set up blinking at 1/4 s intervals
571 SetCallbackTime(ScanlineCallback, 520.83333334); // Set scanline callback at 1/32 of frame
572 // SetCallbackTime(ScanlineCallback, 520.83333334*32.00); // Set scanline callback at 1/32 of frame
573 startTicks = SDL_GetTicks();
575 WriteLog("Entering main loop...\n");
579 double timeToNextEvent = GetTimeToNextEvent();
580 Execute6809(&mainCPU, USEC_TO_M6809_CYCLES(timeToNextEvent));
581 //We MUST remove a frame's worth of time in order for the CPU to function... !!! FIX !!!
582 //(Fix so that this is not a requirement!)
583 mainCPU.clock -= USEC_TO_M6809_CYCLES(timeToNextEvent);
595 delete[] gram; // Deallocate RAM & ROM spaces
603 static void FrameCallback(void)
605 SDL_PumpEvents(); // Force key events into the buffer.
606 gram[0xC804] = gram[0xC806] = gram[0xC80C] = 0; // Reset PIA ports...
608 if (keys[SDLK_ESCAPE])
609 running = false; // ESC to exit...
611 //Convert this stuff to use the settings module... !!! FIX !!!
612 if (keys[SDLK_SEMICOLON])
613 gram[0xC804] |= 0x01; // Fire (;)
615 gram[0xC804] |= 0x02; // Thrust (L)
616 if (keys[SDLK_SPACE])
617 gram[0xC804] |= 0x04; // Smart Bomb (space)
618 if (keys[SDLK_BACKSPACE])
619 gram[0xC804] |= 0x08; // Hyperspace (BkSp)
621 gram[0xC804] |= 0x10; // Two Player Start (2)
623 gram[0xC804] |= 0x20; // One Player Start (1)
624 if (keys[SDLK_RETURN])
625 gram[0xC804] |= 0x40; // Reverse (Enter)
627 gram[0xC804] |= 0x80; // Down (F)
630 gram[0xC806] |= 0x01; // Up (R)
632 gram[0xC806] |= 0x02; // Inviso (A)
635 gram[0xC80C] |= 0x01; // Auto up (F1)
637 gram[0xC80C] |= 0x02; // Advance (F2)
639 gram[0xC80C] |= 0x04; // Right Coin (5)
641 gram[0xC80C] |= 0x08; // High Score Reset (F3)
643 gram[0xC80C] |= 0x10; // Left Coin (3)
645 gram[0xC80C] |= 0x20; // Center Coin (4)
647 gram[0xC80C] |= 0x40; // Slam Switch (F4)
649 if (keys[SDLK_F5]) // Sound CPU self-test (F5)
650 soundCPU.cpuFlags |= V6808_ASSERT_LINE_NMI;
651 if (keys[SDLK_F6]) // Reset the 6808 (F6)
652 soundCPU.cpuFlags |= V6808_ASSERT_LINE_RESET;
654 RenderScreenBuffer2(); // 1 frame = 1/60 sec ~ 16667 cycles
655 SetCallbackTime(FrameCallback, 16666.66666667);
657 while (SDL_GetTicks() - startTicks < 16); // Wait for next frame...
658 startTicks = SDL_GetTicks();
661 static void ScanlineCallback(void)
663 // CA1 of PIA 1 maps to $C80C-F... <-- Count240 is in PIA1...
664 // What about COUNT240???
666 //wil wok? Yes, but still screws up on the demo...
667 /* if (gram[0xCB00] & 0x20)
668 if (gram[0xC80F] & 0x01)
669 mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;//*/
670 if ((gram[0xCB00] & 0x20) && (gram[0xC80F] & 0x01))
671 mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;//*/
673 //Is $C80E COUNT240? Hmm... Doesn't seem to be. Bleh.
674 /* if (gram[0xCB00] >= 240)
677 gram[0xC80E] = 0x00;//*/
678 // gram[0xC80E] = (gram[0xCB00] >= 240 ? 0xFF : 0x00);
680 gram[0xCB00] += 8; // Update video counter...
682 SetCallbackTime(ScanlineCallback, 520.83333334); // Set scanline callback at 1/32 of frame
687 ; With correct timing, but no color cycling
689 --> Start of frame...
690 WrMem: Writing address C80F with 34 [PC=15C3, $CB00=40]
695 WrMem: Writing address C80F with 35 [PC=1644, $CB00=40]
696 WrMem: Writing address C80F with 34 [PC=15C3, $CB00=80]
704 WrMem: Writing address C80F with 35 [PC=1644, $CB00=80]
705 WrMem: Writing address C80F with 34 [PC=15C3, $CB00=C0]
706 WrMem: Writing address C80F with 35 [PC=1644, $CB00=C0]
709 ; With incorrect timing, but has color cycling
711 --> Start of frame...
712 WrMem: Writing address C80F with 34 [PC=15C3, $CB00=00]
713 At $1609. $6E: 00 ; Color cycling...
718 WrMem: Writing address C80F with 35 [PC=1644, $CB00=00]
719 WrMem: Writing address C80F with 34 [PC=15C3, $CB00=40]
720 WrMem: Writing address C80F with 35 [PC=1644, $CB00=40]
721 WrMem: Writing address C80F with 34 [PC=15C3, $CB00=80]
729 WrMem: Writing address C80F with 35 [PC=1644, $CB00=80]
730 WrMem: Writing address C80F with 34 [PC=15C3, $CB00=C0]
731 WrMem: Writing address C80F with 35 [PC=1644, $CB00=C0]
738 0000-8FFF ROM (for Blaster, 0000-3FFF is a bank of 12 ROMs)
739 0000-97FF Video RAM Bank switched with ROM (96FF for Blaster)
741 0xBB00 Blaster only, Color 0 for each line (256 entry)
742 0xBC00 Blaster only, Color 0 flags, latch color only if bit 0 = 1 (256 entry)
743 Do something else with the bit 1, I do not know what
747 C000-C00F color_registers (16 bytes of BBGGGRRR)
749 C804 widget_pia_dataa (widget = I/O board)
750 C805 widget_pia_ctrla
751 C806 widget_pia_datab
752 C807 widget_pia_ctrlb (CB2 select between player 1 and player 2
753 controls if Table or Joust)
754 bits 5-3 = 110 = player 2
755 bits 5-3 = 111 = player 1
762 bit 2 |-6 bits to sound board
767 bit 7 /Plus CA2 and CB2 = 4 bits to drive the LED 7 segment
770 C900 rom_enable_scr_ctrl Switch between video ram and rom at 0000-97FF
774 C804 widget_pia_dataa (widget = I/O board)
784 C806 widget_pia_datab
792 bit 7 0 = Upright 1 = Table
797 bit 2 Right Coin (High Score Reset in schematics)
798 bit 3 High Score Reset (Left Coin in schematics)
799 bit 4 Left Coin (Center Coin in schematics)
800 bit 5 Center Coin (Right Coin in schematics)
802 bit 7 Hand Shake from sound board
808 static MEMORY_READ_START( williams_readmem )
809 { 0x0000, 0x97ff, MRA_BANK1 },
810 { 0x9800, 0xbfff, MRA_RAM },
811 { 0xc804, 0xc807, pia_0_r },
812 { 0xc80c, 0xc80f, pia_1_r },
813 { 0xcb00, 0xcb00, williams_video_counter_r },
814 { 0xcc00, 0xcfff, MRA_RAM },
815 { 0xd000, 0xffff, MRA_ROM },
819 static MEMORY_WRITE_START( williams_writemem )
820 { 0x0000, 0x97ff, williams_videoram_w, &williams_bank_base, &videoram_size },
821 { 0x9800, 0xbfff, MWA_RAM },
822 { 0xc000, 0xc00f, paletteram_BBGGGRRR_w, &paletteram },
823 { 0xc804, 0xc807, pia_0_w },
824 { 0xc80c, 0xc80f, pia_1_w },
825 { 0xc900, 0xc900, williams_vram_select_w },
826 { 0xca00, 0xca07, williams_blitter_w, &williams_blitterram },
827 { 0xcbff, 0xcbff, watchdog_reset_w },
828 { 0xcc00, 0xcfff, MWA_RAM },
829 { 0xd000, 0xffff, MWA_ROM },
832 static MEMORY_READ_START( sound_readmem )
833 { 0x0000, 0x007f, MRA_RAM },
834 { 0x0400, 0x0403, pia_2_r },
835 { 0x8400, 0x8403, pia_2_r }, // used by Colony 7, perhaps others?
836 { 0xb000, 0xffff, MRA_ROM }, // most games start at $F000, Sinistar starts at $B000
840 static MEMORY_WRITE_START( sound_writemem )
841 { 0x0000, 0x007f, MWA_RAM },
842 { 0x0400, 0x0403, pia_2_w },
843 { 0x8400, 0x8403, pia_2_w }, // used by Colony 7, perhaps others?
844 { 0xb000, 0xffff, MWA_ROM }, // most games start at $F000, Sinistar starts at $B000
847 MACHINE_INIT( williams )
852 // reset the ticket dispenser (Lotto Fun)
853 ticket_dispenser_init(70, TICKET_MOTOR_ACTIVE_LOW, TICKET_STATUS_ACTIVE_HIGH);
855 // set a timer to go off every 16 scanlines, to toggle the VA11 line and update the screen
856 timer_set(cpu_getscanlinetime(0), 0, williams_va11_callback);
858 // also set a timer to go off on scanline 240
859 timer_set(cpu_getscanlinetime(240), 0, williams_count240_callback);
863 static void williams_va11_callback(int scanline)
865 // the IRQ signal comes into CB1, and is set to VA11
866 pia_1_cb1_w(0, scanline & 0x20);
868 // update the screen while we're here
869 force_partial_update(scanline - 1);
871 // set a timer for the next update
873 if (scanline >= 256) scanline = 0;
874 timer_set(cpu_getscanlinetime(scanline), scanline, williams_va11_callback);
878 static void williams_count240_off_callback(int param)
880 // the COUNT240 signal comes into CA1, and is set to the logical AND of VA10-VA13
885 static void williams_count240_callback(int param)
887 // the COUNT240 signal comes into CA1, and is set to the logical AND of VA10-VA13
890 // set a timer to turn it off once the scanline counter resets
891 timer_set(cpu_getscanlinetime(0), 0, williams_count240_off_callback);
893 // set a timer for next frame
894 timer_set(cpu_getscanlinetime(240), 0, williams_count240_callback);
898 static void williams_main_irq(int state)
900 // IRQ to the main CPU
901 cpu_set_irq_line(0, M6809_IRQ_LINE, state ? ASSERT_LINE : CLEAR_LINE);
905 static void williams_main_firq(int state)
907 // FIRQ to the main CPU
908 cpu_set_irq_line(0, M6809_FIRQ_LINE, state ? ASSERT_LINE : CLEAR_LINE);
912 static void williams_snd_irq(int state)
914 // IRQ to the sound CPU
915 cpu_set_irq_line(1, M6800_IRQ_LINE, state ? ASSERT_LINE : CLEAR_LINE);
919 READ_HANDLER( williams_video_counter_r )
921 return cpu_getscanline() & 0xFC;
925 // Special PIA 0 for Stargate, to handle the controls
926 struct pia6821_interface stargate_pia_0_intf =
928 //inputs : A/B,CA/B1,CA/B2 / stargate_input_port_0_r, input_port_1_r, 0, 0, 0, 0,
929 //outputs: A/B,CA/B2 / 0, 0, 0, 0,
933 // Generic PIA 1, maps to input port 2, sound command out, and IRQs
934 struct pia6821_interface williams_pia_1_intf =
936 //inputs : A/B,CA/B1,CA/B2 / input_port_2_r, 0, 0, 0, 0, 0,
937 //outputs: A/B,CA/B2 / 0, williams_snd_cmd_w, 0, 0,
938 //irqs : A/B / williams_main_irq, williams_main_irq
941 // Generic PIA 2, maps to DAC data in and sound IRQs
942 struct pia6821_interface williams_snd_pia_intf =
944 //inputs : A/B,CA/B1,CA/B2 / 0, 0, 0, 0, 0, 0,
945 //outputs: A/B,CA/B2 / DAC_0_data_w, 0, 0, 0,
946 //irqs : A/B / williams_snd_irq, williams_snd_irq
949 static DRIVER_INIT( stargate )
951 // CMOS configuration
952 CONFIGURE_CMOS(0xCC00, 0x400);
955 CONFIGURE_PIAS(stargate_pia_0_intf, williams_pia_1_intf, williams_snd_pia_intf);
959 int cpu_getscanline(void)
961 return (int)(timer_timeelapsed(refresh_timer) * scanline_period_inv);
964 *************************************
966 * Returns time until given scanline
968 *************************************
970 double cpu_getscanlinetime(int scanline)
972 double scantime = timer_starttime(refresh_timer) + (double)scanline * scanline_period;
973 double abstime = timer_get_time();
976 // if we're already past the computed time, count it for the next frame
977 if (abstime >= scantime)
978 scantime += TIME_IN_HZ(Machine->drv->frames_per_second);
980 // compute how long from now until that time
981 result = scantime - abstime;
983 // if it's small, just count a whole frame
984 if (result < TIME_IN_NSEC(1))
985 result = TIME_IN_HZ(Machine->drv->frames_per_second);
989 *************************************
991 * Returns time for one scanline
993 *************************************
995 double cpu_getscanlineperiod(void)
997 return scanline_period;
1001 V6809 WrMem: Writing address C80D with 00 [PC=0000, $CB00=00]
1002 V6809 WrMem: Writing address C80C with 00 [PC=0000, $CB00=00]
1003 V6809 WrMem: Writing address C80D with 3C [PC=0000, $CB00=00]
1005 V6809 WrMem: Writing address C80F with 00 [PC=0000, $CB00=00]
1006 V6809 WrMem: Writing address C80E with C0 [PC=0000, $CB00=00]
1007 V6809 WrMem: Writing address C80F with 3C [PC=0000, $CB00=00]
1009 V6809 WrMem: Writing address C80E with C0 [PC=0000, $CB00=00]
1010 V6809 WrMem: Writing address C80D with 34 [PC=FE61, $CB00=48]
1011 V6809 WrMem: Writing address C80F with 34 [PC=FE61, $CB00=48]
1012 V6809 WrMem: Writing address C80E with 00 [PC=FE61, $CB00=48]
1014 V6809 WrMem: Writing address C80C with 00 [PC=FD92, $CB00=C8]
1015 V6809 WrMem: Writing address C80D with 00 [PC=FD92, $CB00=C8]
1016 V6809 WrMem: Writing address C80C with 00 [PC=FD92, $CB00=C8]
1017 V6809 WrMem: Writing address C80D with 34 [PC=FD92, $CB00=C8]
1019 V6809 WrMem: Writing address C80E with 00 [PC=FD92, $CB00=C8]
1020 V6809 WrMem: Writing address C80F with 00 [PC=FD92, $CB00=C8]
1021 V6809 WrMem: Writing address C80E with FF [PC=FD92, $CB00=C8]
1022 V6809 WrMem: Writing address C80F with 35 [PC=FD92, $CB00=C8]
1024 V6809 WrMem: Writing address C804 with 00 [PC=607B, $CB00=D0]
1025 V6809 WrMem: Writing address C805 with 00 [PC=607B, $CB00=D0]
1026 V6809 WrMem: Writing address C804 with 00 [PC=607B, $CB00=D0]
1027 V6809 WrMem: Writing address C805 with 34 [PC=607B, $CB00=D0]
1029 V6809 WrMem: Writing address C806 with 00 [PC=607B, $CB00=D0]
1030 V6809 WrMem: Writing address C807 with 00 [PC=607B, $CB00=D0]
1031 V6809 WrMem: Writing address C806 with 00 [PC=607B, $CB00=D0]
1032 V6809 WrMem: Writing address C807 with 3E [PC=607B, $CB00=D0]
1034 V6809 WrMem: Writing address C80E with 3F [PC=13CB, $CB00=A8]
1035 V6809 WrMem: Writing address C807 with 3C [PC=60B4, $CB00=90]
1036 V6809 WrMem: Writing address C80E with 0C [PC=014D, $CB00=80]
1038 V6809 WrMem: Writing address C80F with 34 [PC=014D, $CB00=80]
1039 V6809 WrMem: Writing address C80F with 35 [PC=014D, $CB00=80]
1040 V6809 WrMem: Writing address C80F with 34 [PC=0013, $CB00=A8]
1041 V6809 WrMem: Writing address C80F with 35 [PC=0013, $CB00=A8]
1048 bit 2 |-6 bits to sound board
1053 bit 7 /Plus CA2 and CB2 = 4 bits to drive the LED 7 segment
1056 CTRLA = IRQA1 (1 bit) IRQA2 (1 bit) CA2 (3 bits) DDR (1 bit) CA1 (2 bits)
1061 00 -> $C80D = PIA2 -> DDR active
1062 00 -> $C80C = PIA2 DDR -> All input?