]> Shamusworld >> Repos - stargem2/blob - src/stargem2.cpp
d1b7431a5bd092e45230c190f6d8c6dbee176f4f
[stargem2] / src / stargem2.cpp
1 //
2 // Stargate Emulator (StarGem2) v2.0 SDL
3 //
4 // by James L. Hammons
5 // (C) 2006 Underground Software
6 //
7 // JLH = James L. Hammons <jlhamm@acm.org>
8 //
9 // WHO  WHEN        WHAT
10 // ---  ----------  ------------------------------------------------------------
11 // JLH  06/15/2006  Added changelog ;-)
12 // JLH  06/15/2006  Switched over to timeslice execution code
13 // JLH  07/15/2009  Solved problem with DEMO mode (IRQ handling)
14 //
15
16 #include "SDL.h"
17 #include <fstream>
18 #include <string>
19 #include <iomanip>
20 #include <iostream>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <time.h>
24 #include "types.h"
25 #include "log.h"
26 #include "v6808.h"
27 #include "v6809.h"
28 #include "video.h"
29 #include "sound.h"
30 #include "timing.h"
31 #include "settings.h"
32 #include "dis6809.h"
33 #include "dis6808.h"
34
35 //#define __DEBUG__
36 //#define LOG_PIA1_IO
37
38 using namespace std;
39
40 #define SOUNDROM        "ROMs/sg.snd"
41 #define CMOS            "cmos.ram"
42 #define SAVESTATE       "sg2.state"
43
44 #define FRAME_DURATION_IN_CYCLES                (M6809_CLOCK_SPEED_IN_HZ / 60.0)
45 #define SCANLINE_DURATION_IN_CYCLES             (FRAME_DURATION_IN_CYCLES / 256.0)
46 // Interesting... This (1/16) causes the machine to crash in the demo (if run from clean start, otherwise it FUs demo)!
47 // (1/32) fucks up the demo...
48 // (1/64) works. Weird!
49 //#define SG2_PIA_CALLBACK_DURATION             ((FRAME_DURATION_IN_CYCLES * M6809_CYCLE_IN_USEC) / 16.0)
50 #define SG2_PIA_CALLBACK_DURATION               ((FRAME_DURATION_IN_CYCLES * M6809_CYCLE_IN_USEC) / 64.0)
51
52 // Global variables
53
54 uint8 gram[0x10000], grom[0x10000], sram[0x10000], srom[0x10000]; // RAM & ROM spaces
55 V6809REGS mainCPU;
56 V6808REGS soundCPU;
57 uint8 color[16];
58 uint32 palette[256];
59 bool paletteDirty = false;
60
61 // Local variables
62
63 static bool running = true;                                             // Machine running state flag...
64 static uint32 startTicks;
65 static uint8 * keys;                                                    // SDL raw keyboard matrix
66 static uint64 clockFrameStart;                                  // V6809 clock at the start of the frame
67
68 // Function prototypes
69
70 uint8 RdMem6809(uint16 addr);
71 void WrMem6809(uint16 addr, uint8 b);
72 uint8 RdMem6808(uint16 addr);
73 void WrMem6808(uint16 addr, uint8 b);
74 bool LoadImg(const char * filename, uint8 * ram, int size);
75 void SaveCMOS(void);
76 bool LoadMachineState(void);
77 void SaveMachineState(void);
78
79 // Local timer callback functions
80
81 static void FrameCallback(void);
82 static void ScanlineCallback(void);
83
84
85 //
86 // Main loop
87 //
88 int main(int /*argc*/, char * /*argv*/[])
89 {
90         InitLog("stargem2.log");
91         WriteLog("StarGem2 - A portable Stargate emulator by James L. Hammons\n");
92         WriteLog("(C) 2009 Underground Software\n\n");
93
94         LoadSettings();
95
96         // Initialize Williams' palette (RGB coded as: 3 bits red, 3 bits green, 2 bits blue)
97         for(uint32 i=0; i<256; i++)
98                 palette[i] =
99 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
100                 (((i & 0x01) * 33 + ((i & 0x02) >> 1) * 71 + ((i & 0x04) >> 2) * 151) << 24)
101                         | ((((i & 0x08) >> 3) * 33 + ((i & 0x10) >> 4) * 71 + ((i & 0x20) >> 5) * 151) << 16)
102                         | ((((i & 0x40) >> 6) * 71 + ((i & 0x80) >> 7) * 151) << 8) | 0xFF;
103 #else
104                 ((i & 0x01) * 33 + ((i & 0x02) >> 1) * 71 + ((i & 0x04) >> 2) * 151)
105                         | ((((i & 0x08) >> 3) * 33 + ((i & 0x10) >> 4) * 71 + ((i & 0x20) >> 5) * 151) << 8)
106                         | ((((i & 0x40) >> 6) * 71 + ((i & 0x80) >> 7) * 151) << 16) | 0xFF000000;
107 #endif
108
109         // Zero out memory
110         memset(gram, 0, 0x10000);
111         memset(grom, 0, 0x10000);
112         memset(sram, 0, 0x10000);
113         memset(srom, 0, 0x10000);
114
115         // Set up V6809 & V6808 execution contexts
116
117         memset(&mainCPU, 0, sizeof(V6809REGS));
118         mainCPU.RdMem = RdMem6809;
119         mainCPU.WrMem = WrMem6809;
120         mainCPU.cpuFlags |= V6809_ASSERT_LINE_RESET;
121
122         memset(&soundCPU, 0, sizeof(V6808REGS));
123         soundCPU.RdMem = RdMem6808;
124         soundCPU.WrMem = WrMem6808;
125         soundCPU.cpuFlags |= V6808_ASSERT_LINE_RESET;
126
127         char ROMs[12][8] = {
128                 "ROMs/01", "ROMs/02", "ROMs/03", "ROMs/04", "ROMs/05", "ROMs/06",
129                 "ROMs/07", "ROMs/08", "ROMs/09", "ROMs/10", "ROMs/11", "ROMs/12"
130                 };
131
132         for(int i=0; i<12; i++)
133         {
134                 uint32 baseAddress = i * 0x1000;
135
136                 if (i > 8)
137                         baseAddress += 0x4000;
138
139                 if (!LoadImg(ROMs[i], grom + baseAddress, 0x1000))
140                 {
141                         WriteLog("Could not open file '%s'!\n", ROMs[i]);
142                         return -1;
143                 }
144         }
145
146         if (!LoadImg(SOUNDROM, srom + 0xF800, 0x800))
147         {
148                 WriteLog("Could not open file '%s'!\n", SOUNDROM);
149                 return -1;
150         }
151
152         WriteLog("Stargate ROM images loaded...\n");
153         WriteLog("About to initialize video...\n");
154
155         if (!InitVideo())
156         {
157                 cout << "Aborting!" << endl;
158                 return -1;
159         }
160
161         // Have to do this *after* video init but *before* sound init...!
162         WriteLog("About to load machine state...");
163
164         if (!LoadMachineState())
165                 WriteLog("Machine state file not found!\n");
166         else
167                 WriteLog("done!\n");
168
169         if (!LoadImg(CMOS, gram + 0xCC00, 0x400))
170                 WriteLog("CMOS RAM not found!\n");
171
172         WriteLog("About to intialize audio...\n");
173         SoundInit();
174         keys = SDL_GetKeyState(NULL);
175         srom[0xF800] = 0x37;                                            // Fix checksum so ST works...
176         running = true;                                                         // Set running status...
177
178         InitializeEventList();                                          // Clear the event list before we use it...
179         SetCallbackTime(FrameCallback, FRAME_DURATION_IN_CYCLES * M6809_CYCLE_IN_USEC);
180         SetCallbackTime(ScanlineCallback, SG2_PIA_CALLBACK_DURATION);
181         clockFrameStart = mainCPU.clock;
182         startTicks = SDL_GetTicks();
183
184         WriteLog("Entering main loop...\n");
185
186         while (running)
187         {
188                 double timeToNextEvent = GetTimeToNextEvent();
189                 Execute6809(&mainCPU, USEC_TO_M6809_CYCLES(timeToNextEvent));
190                 HandleNextEvent();
191         }
192
193 #ifdef __DEBUG__
194 WriteLog("\n");
195 WriteLog("$C900 = $%02X (0=RAM)\n", gram[0xC900]);
196 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);
197 WriteLog("\n");
198
199 /*uint16 pc = mainCPU.pc;//0x15BA;
200 for(int i=0; i<200; i++)
201 //while (pc < 0x9000)
202 {
203         pc += Decode6809(pc);
204         WriteLog("\n");
205 }//*/
206
207 /*uint32 pc = 0;
208 while (pc < 0xFFFF)
209 {
210         pc += Decode6809(pc);
211         WriteLog("\n");
212 }//*/
213 #endif
214
215         SoundDone();
216         VideoDone();
217         SaveCMOS();
218         SaveMachineState();
219         LogDone();
220
221         return 0;
222 }
223
224 //
225 // Load a file into RAM/ROM image space
226 //
227 bool LoadImg(const char * filename, uint8 * ram, int size)
228 {
229         FILE * fp = fopen(filename, "rb");
230
231         if (fp == NULL)
232                 return false;
233
234         size_t ignoredResult = fread(ram, 1, size, fp);
235         fclose(fp);
236
237         return true;
238 }
239
240 //
241 // Save CMOS ram
242 //
243 void SaveCMOS(void)
244 {
245         FILE * fp = fopen(CMOS, "wb");
246
247         if (fp != NULL)
248         {
249                 size_t ignoredResult = fwrite(gram + 0xCC00, 1, 1024, fp);
250                 fclose(fp);
251         }
252         else
253                 WriteLog("CMOS RAM not saved!\n");
254 }
255
256 //
257 // Load state save file
258 //
259 bool LoadMachineState(void)
260 {
261         FILE * fp = fopen(SAVESTATE, "rb");
262
263         if (fp == NULL)
264                 return false;
265
266         // This is kinda crappy--we don't do any sanity checking here!!!
267         size_t ignoredResult = fread(gram, 1, 0x10000, fp);
268         ignoredResult = fread(sram, 1, 0x10000, fp);
269         ignoredResult = fread(&mainCPU, 1, sizeof(V6809REGS), fp);
270         ignoredResult = fread(&soundCPU, 1, sizeof(V6808REGS), fp);
271         fclose(fp);
272
273         // Set up backbuffer... ;-)
274         for(uint16 i=0x0006; i<0x97F8; i++)                                     // Screen memory
275                 WrMem6809(i, gram[i]);
276
277         for(uint16 i=0xC000; i<=0xC00F; i++)                            // Palette memory
278                 WrMem6809(i, gram[i]);
279
280         paletteDirty = true;
281
282         mainCPU.RdMem = RdMem6809;                                                      // Make sure our function pointers are
283         mainCPU.WrMem = WrMem6809;                                                      // pointing to the right places!
284         soundCPU.RdMem = RdMem6808;
285         soundCPU.WrMem = WrMem6808;
286         mainCPU.clock = 0;                                                                      // Zero out our clocks...
287         soundCPU.clock = 0;
288         mainCPU.clockOverrun = 0;                                                       // And overrun values...
289 //notyet        soundCPU.clockOverrun = 0;
290
291         return true;
292 }
293
294 //
295 // Save state save file
296 //
297 void SaveMachineState(void)
298 {
299         FILE * fp = fopen(SAVESTATE, "wb");
300
301         if (fp != NULL)
302         {
303                 size_t ignoredResult = fwrite(gram, 1, 0x10000, fp);
304                 ignoredResult = fwrite(sram, 1, 0x10000, fp);
305                 ignoredResult = fwrite(&mainCPU, 1, sizeof(V6809REGS), fp);
306                 ignoredResult = fwrite(&soundCPU, 1, sizeof(V6808REGS), fp);
307                 fclose(fp);
308         }
309         else
310                 WriteLog("Machine state not saved!\n");
311 }
312
313 //
314 // 6809 memory functions
315 //
316
317 #ifdef LOG_PIA1_IO
318 char piaRegsName[4][10] = { "PORTA", "PACTL", "PORTB", "PBCTL" };
319 #endif
320 uint8 RdMem6809(uint16 addr)
321 {
322         uint8 b;
323
324         if (addr >= 0x9000 && addr <= 0xCFFF)           // No ROM between $9000 - $CFFF...
325                 b = gram[addr];
326         else
327         {
328                 if (!gram[0xC900] && addr <= 0x8FFF)    // Check RAM $C900 bank switch
329                         b = gram[addr];
330                 else
331                         b = grom[addr];
332         }
333
334         // A wee kludge (though I doubt it reads from anywhere other than $CB00)...
335         if ((addr & 0xFF00) == 0xCB00)
336 #if 0
337                 b = gram[0xCB00] & 0xFC;                                // Only bits 2-7 are connected...
338 #else
339         {
340 //Interesting, this code ALSO fucks up the demo...
341 //Except when the correct code is called in the scanline callback function...
342                 uint32 elapsedCycles = (uint32)(GetCurrentV6809Clock() - clockFrameStart);
343                 uint32 scanline = (uint32)((double)elapsedCycles / SCANLINE_DURATION_IN_CYCLES);
344 //Changes here don't seem to do much...
345 //              uint32 scanline = (uint32)(((double)elapsedCycles * M6809_CYCLE_IN_USEC) / 70.0);
346                 b = (uint8)scanline & 0xFC;                             // Only bits 2-7 are connected...
347         }
348 #endif
349
350         // More kludge...
351         if ((addr == 0xC80C) && (gram[0xC80D] & 0x04))  // Read PORTA and DDR is set to Output
352         {
353                 ClearLine(V6809_ASSERT_LINE_IRQ);                       // Then clear the IRQ
354 //OK, this ALSO fucks up the execution of the demo...
355 // Which means that the timing is still off. :-/
356 //              mainCPU.cpuFlags &= ~V6809_ASSERT_LINE_IRQ;                     // Then clear the IRQ
357         }
358
359         if ((addr == 0xC80E) && (gram[0xC80F] & 0x04))  // Read PORTB and DDR is set to Output
360         {
361                 ClearLine(V6809_ASSERT_LINE_IRQ);                       // Then clear the IRQ
362 //OK, this ALSO fucks up the execution of the demo...
363 //              mainCPU.cpuFlags &= ~V6809_ASSERT_LINE_IRQ;                     // Then clear the IRQ
364         }
365
366 //temp...
367 /*extern uint16 pcr;
368 //if (addr >= 0xC000 && addr <= 0xCBFF)
369 if (addr == 0x9C59)
370         WriteLog("RdMem: Reading address %04X [=%02X, PC=%04X]\n", addr, b, pcr);//*/
371 #ifdef LOG_PIA1_IO
372 /*if (addr >= 0xC80C && addr <= 0xC80F)
373         WriteLog("V6809 RdMem: Reading PIA (%s) address %04X [<-%02X, PC=%04X]\n", piaRegsName[addr&0x03], addr, b, GetCurrentV6809PC());//*/
374 #endif
375         return b;
376 }
377
378 void WrMem6809(uint16 addr, uint8 b)
379 {
380 //temp...
381 //extern V6809REGS regs;
382 //if (addr >= 0xC800 && addr <= 0xCBFE)
383 //if (addr == 0xC80F || addr == 0xC80D)
384 //      WriteLog("WrMem: Writing address %04X with %02X [PC=%04X, $CB00=%02X]\n", addr, b, regs.pc, gram[0xCB00]);//*/
385 //if (addr == 0xC80E)
386 /*if (addr >= 0xC800 && addr <= 0xC80F)
387         WriteLog("V6809 WrMem: Writing address %04X with %02X [PC=%04X, $CB00=%02X]\n", addr, b, mainCPU.pc, gram[0xCB00]);//*/
388
389         gram[addr] = b;
390
391         if (addr >= 0x0006 && addr < 0x97F7)                    // 304 pixels  152-128=24-16=8
392         {
393                 // NOTE: Screen was 304 x 256, but we truncate the vertical dimension here...
394                 uint16 sx = (addr >> 7) & 0x01FE, sy = addr & 0x00FF;
395
396                 if (sy > 5 && sy < 246)
397                 {
398                         uint32 saddr = 8 + sx + ((sy - 6) * 320);       // Calc screen address
399                         scrBuffer[saddr + 0] = palette[color[b >> 4]];
400                         scrBuffer[saddr + 1] = palette[color[b & 0x0F]];
401                 }
402         }
403         else if (addr >= 0xC000 && addr <= 0xC00F)
404         {
405 // This approach doesn't take the BG color to the edges of the screen
406                 color[addr - 0xC000] = b;
407                 paletteDirty = true;
408         }
409         else if (addr == 0xC80E)
410         {
411                 sram[0x0402] = b;                                                               // Connect PIAs in 6809 & 6808
412                 soundCPU.cpuFlags |= V6808_ASSERT_LINE_IRQ;             // Start sound IRQ
413         }
414
415 #ifdef LOG_PIA1_IO
416 //if (addr >= 0xC80C && addr <= 0xC80F)
417 if (addr == 0xC80D)
418         WriteLog("V6809 WrMem: Writing PIA (%s) address %04X [->%02X, PC=%04X]\n", piaRegsName[addr&0x03], addr, b, GetCurrentV6809PC());//*/
419 #endif
420 }
421
422 //
423 // 6808 memory functions
424 //
425
426 uint8 RdMem6808(uint16 addr)
427 {
428         return (addr < 0xF000 ? sram[addr] : srom[addr]);
429 }
430
431 void WrMem6808(uint16 addr, uint8 b)
432 {
433         sram[addr] = b;
434
435         // A total guess, but let's try it...
436 //It probably depends on how the PIA is configured, so this is most likely wrong.
437 // It is wrong: IRQs are cleared on PIA PORTx reads!
438 //      if (addr == 0x0401)
439 //              soundCPU.cpuFlags &= ~V6808_ASSERT_LINE_IRQ;
440 }
441
442 static void FrameCallback(void)
443 {
444         SDL_PumpEvents();                                                       // Force key events into the buffer.
445         gram[0xC804] = gram[0xC806] = gram[0xC80C] = 0; // Reset PIA ports...
446
447         if (keys[SDLK_ESCAPE])
448                 running = false;                                                // ESC to exit...
449
450         if (keys[settings.keyBindings[S_KEY_FIRE]])                     gram[0xC804] |= 0x01;
451         if (keys[settings.keyBindings[S_KEY_THRUST]])           gram[0xC804] |= 0x02;
452         if (keys[settings.keyBindings[S_KEY_SMARTBOMB]])        gram[0xC804] |= 0x04;
453         if (keys[settings.keyBindings[S_KEY_HYPERSPACE]])       gram[0xC804] |= 0x08;
454         if (keys[settings.keyBindings[S_KEY_2P_START]])         gram[0xC804] |= 0x10;
455         if (keys[settings.keyBindings[S_KEY_1P_START]])         gram[0xC804] |= 0x20;
456         if (keys[settings.keyBindings[S_KEY_REVERSE]])          gram[0xC804] |= 0x40;
457         if (keys[settings.keyBindings[S_KEY_DOWN]])                     gram[0xC804] |= 0x80;
458
459         if (keys[settings.keyBindings[S_KEY_UP]])                       gram[0xC806] |= 0x01;
460         if (keys[settings.keyBindings[S_KEY_INVISO]])           gram[0xC806] |= 0x02;
461
462         if (keys[settings.keyBindings[S_KEY_AUTO_UP]])          gram[0xC80C] |= 0x01;
463         if (keys[settings.keyBindings[S_KEY_ADVANCE]])          gram[0xC80C] |= 0x02;
464         if (keys[settings.keyBindings[S_KEY_RIGHT_COIN]])       gram[0xC80C] |= 0x04;
465         if (keys[settings.keyBindings[S_KEY_HS_RESET]])         gram[0xC80C] |= 0x08;
466         if (keys[settings.keyBindings[S_KEY_LEFT_COIN]])        gram[0xC80C] |= 0x10;
467         if (keys[settings.keyBindings[S_KEY_CENTER_COIN]])      gram[0xC80C] |= 0x20;
468         if (keys[settings.keyBindings[S_KEY_SLAM_SWITCH]])      gram[0xC80C] |= 0x40;
469
470         if (keys[SDLK_F5])                                                      // Sound CPU self-test (F5)
471                 soundCPU.cpuFlags |= V6808_ASSERT_LINE_NMI;
472         if (keys[SDLK_F6])                                                      // Reset the 6808 (F6)
473                 soundCPU.cpuFlags |= V6808_ASSERT_LINE_RESET;
474
475         if (paletteDirty)
476         {
477                 for(uint32 addr=0x0006; addr<0x97F7; addr++)
478                 {
479                         uint16 sx = (addr >> 7) & 0x01FE, sy = addr & 0x00FF;
480
481                         if (sy > 5 && sy < 246)
482                         {
483                                 uint32 saddr = 8 + sx + ((sy - 6) * 320);       // Calc screen address
484                                 uint8 sb = gram[addr];
485
486                                 scrBuffer[saddr + 0] = palette[color[sb >> 4]];
487                                 scrBuffer[saddr + 1] = palette[color[sb & 0x0F]];
488                         }
489                 }
490
491                 paletteDirty = false;
492         }
493
494         RenderScreenBuffer();                                           // 1 frame = 1/60 sec ~ 16667 cycles
495         clockFrameStart = mainCPU.clock;
496
497         // Wait for next frame...
498         while (SDL_GetTicks() - startTicks < 16)
499                 SDL_Delay(1);
500
501         startTicks = SDL_GetTicks();
502         SetCallbackTime(FrameCallback, FRAME_DURATION_IN_CYCLES * M6809_CYCLE_IN_USEC);
503 }
504
505 static void ScanlineCallback(void)
506 {
507 #if 0
508         if ((gram[0xCB00] & 0x20) && (gram[0xC80F] & 0x01))
509                 mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;//*/
510 #else
511         mainCPU.cpuFlags &= ~V6809_ASSERT_LINE_IRQ;
512
513         if ((RdMem6809(0xCB00) & 0x20) && (gram[0xC80F] & 0x01))
514                 mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;//*/
515 #endif
516
517 /*
518 The problem is that this is already asserted above, by virtue of the fact that
519 240 = $F0 = bit 5 is set! So this does nothing! So obviously, the above IRQ assertion
520 is wrong--just need to figure out how the write of $20 and $00 affects the PBCTRL in the PIA.
521 It looks like Stargate never asserts the COUNT240 IRQ, and could be because of the above...
522
523 Apparently, COUNT240 is unimportant, at least as far as STARGATE is concerned...
524 */
525 //      if ((gram[0xCB00] >= 240) && (gram[0xC80D] & 0x09))     // Do COUNT240 IRQ (if enabled!)
526 //              mainCPU.cpuFlags |= V6809_ASSERT_LINE_IRQ;
527
528         // This should set everything between $CB00-CBFF...
529 //      gram[0xCB00] += 8;                                                      // Update video counter...
530 //      gram[0xCB00] += 4;                                                      // Update video counter...
531
532         SetCallbackTime(ScanlineCallback, SG2_PIA_CALLBACK_DURATION);
533 }
534
535
536 /*
537 ; With correct timing, but no color cycling
538
539 --> Start of frame...
540 WrMem: Writing address C80F with 34 [PC=15C3, $CB00=40]
541 At $07AD. $6E: 00
542 At $0B66. $6E: 00
543 At $0CF4. $6E: 00
544 At $0CCB. $6E: 00
545 WrMem: Writing address C80F with 35 [PC=1644, $CB00=40]
546 WrMem: Writing address C80F with 34 [PC=15C3, $CB00=80]
547 At $0718. $6E: 01
548 At $07AD. $6E: 01
549 At $0BB8. $6E: 01
550 At $0927. $6E: 01
551 At $0CF4. $6E: 01
552 At $0B66. $6E: 01
553 At $16C8. $6E: 01
554 WrMem: Writing address C80F with 35 [PC=1644, $CB00=80]
555 WrMem: Writing address C80F with 34 [PC=15C3, $CB00=C0]
556 WrMem: Writing address C80F with 35 [PC=1644, $CB00=C0]
557
558
559 ; With incorrect timing, but has color cycling
560
561 --> Start of frame...
562 WrMem: Writing address C80F with 34 [PC=15C3, $CB00=00]
563 At $1609. $6E: 00                       ; Color cycling...
564 At $07AD. $6E: 00
565 At $0B66. $6E: 00
566 At $0CF4. $6E: 00
567 At $0CCB. $6E: 00
568 WrMem: Writing address C80F with 35 [PC=1644, $CB00=00]
569 WrMem: Writing address C80F with 34 [PC=15C3, $CB00=40]
570 WrMem: Writing address C80F with 35 [PC=1644, $CB00=40]
571 WrMem: Writing address C80F with 34 [PC=15C3, $CB00=80]
572 At $0718. $6E: 01
573 At $07AD. $6E: 01
574 At $0BB8. $6E: 01
575 At $0927. $6E: 01
576 At $0CF4. $6E: 01
577 At $0B66. $6E: 01
578 At $16C8. $6E: 01
579 WrMem: Writing address C80F with 35 [PC=1644, $CB00=80]
580 WrMem: Writing address C80F with 34 [PC=15C3, $CB00=C0]
581 WrMem: Writing address C80F with 35 [PC=1644, $CB00=C0]
582
583
584
585         Stargate
586         --------
587
588         0000-8FFF ROM   (for Blaster, 0000-3FFF is a bank of 12 ROMs)
589         0000-97FF Video  RAM Bank switched with ROM (96FF for Blaster)
590         9800-BFFF RAM
591                 0xBB00 Blaster only, Color 0 for each line (256 entry)
592                 0xBC00 Blaster only, Color 0 flags, latch color only if bit 0 = 1 (256 entry)
593                     Do something else with the bit 1, I do not know what
594         C000-CFFF I/O
595         D000-FFFF ROM
596
597         C000-C00F color_registers  (16 bytes of BBGGGRRR)
598
599         C804 widget_pia_dataa (widget = I/O board)
600         C805 widget_pia_ctrla
601         C806 widget_pia_datab
602         C807 widget_pia_ctrlb (CB2 select between player 1 and player 2
603                                controls if Table or Joust)
604               bits 5-3 = 110 = player 2
605               bits 5-3 = 111 = player 1
606
607         C80C rom_pia_dataa
608         C80D rom_pia_ctrla
609         C80E rom_pia_datab
610               bit 0 \
611               bit 1 |
612               bit 2 |-6 bits to sound board
613               bit 3 |
614               bit 4 |
615               bit 5 /
616               bit 6 \
617               bit 7 /Plus CA2 and CB2 = 4 bits to drive the LED 7 segment
618         C80F rom_pia_ctrlb
619
620         C900 rom_enable_scr_ctrl  Switch between video ram and rom at 0000-97FF
621
622         Stargate
623         --------
624         C804 widget_pia_dataa (widget = I/O board)
625           bit 0  Fire
626           bit 1  Thrust
627           bit 2  Smart Bomb
628           bit 3  HyperSpace
629           bit 4  2 Players
630           bit 5  1 Player
631           bit 6  Reverse
632           bit 7  Down
633
634         C806 widget_pia_datab
635           bit 0  Up
636           bit 1  Inviso
637           bit 2
638           bit 3
639           bit 4
640           bit 5
641           bit 6
642           bit 7  0 = Upright  1 = Table
643
644         C80C rom_pia_dataa
645           bit 0  Auto Up
646           bit 1  Advance
647           bit 2  Right Coin        (High Score Reset in schematics)
648           bit 3  High Score Reset  (Left Coin in schematics)
649           bit 4  Left Coin         (Center Coin in schematics)
650           bit 5  Center Coin       (Right Coin in schematics)
651           bit 6  Slam Door Tilt
652           bit 7  Hand Shake from sound board
653 */
654
655
656 /*
657
658 static MEMORY_READ_START( williams_readmem )
659         { 0x0000, 0x97ff, MRA_BANK1 },
660         { 0x9800, 0xbfff, MRA_RAM },
661         { 0xc804, 0xc807, pia_0_r },
662         { 0xc80c, 0xc80f, pia_1_r },
663         { 0xcb00, 0xcb00, williams_video_counter_r },
664         { 0xcc00, 0xcfff, MRA_RAM },
665         { 0xd000, 0xffff, MRA_ROM },
666 MEMORY_END
667
668
669 static MEMORY_WRITE_START( williams_writemem )
670         { 0x0000, 0x97ff, williams_videoram_w, &williams_bank_base, &videoram_size },
671         { 0x9800, 0xbfff, MWA_RAM },
672         { 0xc000, 0xc00f, paletteram_BBGGGRRR_w, &paletteram },
673         { 0xc804, 0xc807, pia_0_w },
674         { 0xc80c, 0xc80f, pia_1_w },
675         { 0xc900, 0xc900, williams_vram_select_w },
676         { 0xca00, 0xca07, williams_blitter_w, &williams_blitterram },
677         { 0xcbff, 0xcbff, watchdog_reset_w },
678         { 0xcc00, 0xcfff, MWA_RAM },
679         { 0xd000, 0xffff, MWA_ROM },
680 MEMORY_END
681
682 static MEMORY_READ_START( sound_readmem )
683         { 0x0000, 0x007f, MRA_RAM },
684         { 0x0400, 0x0403, pia_2_r },
685         { 0x8400, 0x8403, pia_2_r },    // used by Colony 7, perhaps others?
686         { 0xb000, 0xffff, MRA_ROM },    // most games start at $F000, Sinistar starts at $B000
687 MEMORY_END
688
689
690 static MEMORY_WRITE_START( sound_writemem )
691         { 0x0000, 0x007f, MWA_RAM },
692         { 0x0400, 0x0403, pia_2_w },
693         { 0x8400, 0x8403, pia_2_w },    // used by Colony 7, perhaps others?
694         { 0xb000, 0xffff, MWA_ROM },    // most games start at $F000, Sinistar starts at $B000
695 MEMORY_END
696
697 MACHINE_INIT( williams )
698 {
699         // reset the PIAs
700         pia_reset();
701
702         // reset the ticket dispenser (Lotto Fun)
703         ticket_dispenser_init(70, TICKET_MOTOR_ACTIVE_LOW, TICKET_STATUS_ACTIVE_HIGH);
704
705         // set a timer to go off every 16 scanlines, to toggle the VA11 line and update the screen
706         timer_set(cpu_getscanlinetime(0), 0, williams_va11_callback);
707
708         // also set a timer to go off on scanline 240
709         timer_set(cpu_getscanlinetime(240), 0, williams_count240_callback);
710 }
711
712
713 static void williams_va11_callback(int scanline)
714 {
715         // the IRQ signal comes into CB1, and is set to VA11
716         pia_1_cb1_w(0, scanline & 0x20);
717
718         // update the screen while we're here
719         force_partial_update(scanline - 1);
720
721         // set a timer for the next update
722         scanline += 8;
723         if (scanline >= 256) scanline = 0;
724         timer_set(cpu_getscanlinetime(scanline), scanline, williams_va11_callback);
725 }
726
727
728 static void williams_count240_off_callback(int param)
729 {
730         // the COUNT240 signal comes into CA1, and is set to the logical AND of VA10-VA13
731         pia_1_ca1_w(0, 0);
732 }
733
734
735 static void williams_count240_callback(int param)
736 {
737         // the COUNT240 signal comes into CA1, and is set to the logical AND of VA10-VA13
738         pia_1_ca1_w(0, 1);
739
740         // set a timer to turn it off once the scanline counter resets
741         timer_set(cpu_getscanlinetime(0), 0, williams_count240_off_callback);
742
743         // set a timer for next frame
744         timer_set(cpu_getscanlinetime(240), 0, williams_count240_callback);
745 }
746
747
748 static void williams_main_irq(int state)
749 {
750         // IRQ to the main CPU
751         cpu_set_irq_line(0, M6809_IRQ_LINE, state ? ASSERT_LINE : CLEAR_LINE);
752 }
753
754
755 static void williams_main_firq(int state)
756 {
757         // FIRQ to the main CPU
758         cpu_set_irq_line(0, M6809_FIRQ_LINE, state ? ASSERT_LINE : CLEAR_LINE);
759 }
760
761
762 static void williams_snd_irq(int state)
763 {
764         // IRQ to the sound CPU
765         cpu_set_irq_line(1, M6800_IRQ_LINE, state ? ASSERT_LINE : CLEAR_LINE);
766 }
767
768
769 READ_HANDLER( williams_video_counter_r )
770 {
771         return cpu_getscanline() & 0xFC;
772 }
773
774
775 // Special PIA 0 for Stargate, to handle the controls
776 struct pia6821_interface stargate_pia_0_intf =
777 {
778         //inputs : A/B,CA/B1,CA/B2 / stargate_input_port_0_r, input_port_1_r, 0, 0, 0, 0,
779         //outputs: A/B,CA/B2       / 0, 0, 0, 0,
780         //irqs   : A/B             / 0, 0
781 };
782
783 // Generic PIA 1, maps to input port 2, sound command out, and IRQs
784 struct pia6821_interface williams_pia_1_intf =
785 {
786         //inputs : A/B,CA/B1,CA/B2 / input_port_2_r, 0, 0, 0, 0, 0,
787         //outputs: A/B,CA/B2       / 0, williams_snd_cmd_w, 0, 0,
788         //irqs   : A/B             / williams_main_irq, williams_main_irq
789 };
790
791 // Generic PIA 2, maps to DAC data in and sound IRQs
792 struct pia6821_interface williams_snd_pia_intf =
793 {
794         //inputs : A/B,CA/B1,CA/B2 / 0, 0, 0, 0, 0, 0,
795         //outputs: A/B,CA/B2       / DAC_0_data_w, 0, 0, 0,
796         //irqs   : A/B             / williams_snd_irq, williams_snd_irq
797 };
798
799 static DRIVER_INIT( stargate )
800 {
801         // CMOS configuration
802         CONFIGURE_CMOS(0xCC00, 0x400);
803
804         // PIA configuration
805         CONFIGURE_PIAS(stargate_pia_0_intf, williams_pia_1_intf, williams_snd_pia_intf);
806 }
807
808
809 int cpu_getscanline(void)
810 {
811         return (int)(timer_timeelapsed(refresh_timer) * scanline_period_inv);
812 }
813
814  *************************************
815  *
816  *      Returns time until given scanline
817  *
818  *************************************
819
820 double cpu_getscanlinetime(int scanline)
821 {
822         double scantime = timer_starttime(refresh_timer) + (double)scanline * scanline_period;
823         double abstime = timer_get_time();
824         double result;
825
826         // if we're already past the computed time, count it for the next frame
827         if (abstime >= scantime)
828                 scantime += TIME_IN_HZ(Machine->drv->frames_per_second);
829
830         // compute how long from now until that time
831         result = scantime - abstime;
832
833         // if it's small, just count a whole frame
834         if (result < TIME_IN_NSEC(1))
835                 result = TIME_IN_HZ(Machine->drv->frames_per_second);
836         return result;
837 }
838
839  *************************************
840  *
841  *      Returns time for one scanline
842  *
843  *************************************
844
845 double cpu_getscanlineperiod(void)
846 {
847         return scanline_period;
848 }
849
850
851 V6809 WrMem: Writing address C80D with 00 [PC=0000, $CB00=00]
852 V6809 WrMem: Writing address C80C with 00 [PC=0000, $CB00=00]
853 V6809 WrMem: Writing address C80D with 3C [PC=0000, $CB00=00]
854
855 V6809 WrMem: Writing address C80F with 00 [PC=0000, $CB00=00]
856 V6809 WrMem: Writing address C80E with C0 [PC=0000, $CB00=00]
857 V6809 WrMem: Writing address C80F with 3C [PC=0000, $CB00=00]
858
859 V6809 WrMem: Writing address C80E with C0 [PC=0000, $CB00=00]
860 V6809 WrMem: Writing address C80D with 34 [PC=FE61, $CB00=48]
861 V6809 WrMem: Writing address C80F with 34 [PC=FE61, $CB00=48]
862 V6809 WrMem: Writing address C80E with 00 [PC=FE61, $CB00=48]
863
864 V6809 WrMem: Writing address C80C with 00 [PC=FD92, $CB00=C8]
865 V6809 WrMem: Writing address C80D with 00 [PC=FD92, $CB00=C8]
866 V6809 WrMem: Writing address C80C with 00 [PC=FD92, $CB00=C8]
867 V6809 WrMem: Writing address C80D with 34 [PC=FD92, $CB00=C8]
868
869 V6809 WrMem: Writing address C80E with 00 [PC=FD92, $CB00=C8]
870 V6809 WrMem: Writing address C80F with 00 [PC=FD92, $CB00=C8]
871 V6809 WrMem: Writing address C80E with FF [PC=FD92, $CB00=C8]
872 V6809 WrMem: Writing address C80F with 35 [PC=FD92, $CB00=C8]
873
874 V6809 WrMem: Writing address C804 with 00 [PC=607B, $CB00=D0]
875 V6809 WrMem: Writing address C805 with 00 [PC=607B, $CB00=D0]
876 V6809 WrMem: Writing address C804 with 00 [PC=607B, $CB00=D0]
877 V6809 WrMem: Writing address C805 with 34 [PC=607B, $CB00=D0]
878
879 V6809 WrMem: Writing address C806 with 00 [PC=607B, $CB00=D0]
880 V6809 WrMem: Writing address C807 with 00 [PC=607B, $CB00=D0]
881 V6809 WrMem: Writing address C806 with 00 [PC=607B, $CB00=D0]
882 V6809 WrMem: Writing address C807 with 3E [PC=607B, $CB00=D0]
883
884 V6809 WrMem: Writing address C80E with 3F [PC=13CB, $CB00=A8]
885 V6809 WrMem: Writing address C807 with 3C [PC=60B4, $CB00=90]
886 V6809 WrMem: Writing address C80E with 0C [PC=014D, $CB00=80]
887
888 V6809 WrMem: Writing address C80F with 34 [PC=014D, $CB00=80]
889 V6809 WrMem: Writing address C80F with 35 [PC=014D, $CB00=80]
890 V6809 WrMem: Writing address C80F with 34 [PC=0013, $CB00=A8]
891 V6809 WrMem: Writing address C80F with 35 [PC=0013, $CB00=A8]
892
893         C80C rom_pia_dataa
894         C80D rom_pia_ctrla
895         C80E rom_pia_datab
896               bit 0 \
897               bit 1 |
898               bit 2 |-6 bits to sound board
899               bit 3 |
900               bit 4 |
901               bit 5 /
902               bit 6 \
903               bit 7 /Plus CA2 and CB2 = 4 bits to drive the LED 7 segment
904         C80F rom_pia_ctrlb
905
906 CTRLA = IRQA1 (1 bit) IRQA2 (1 bit) CA2 (3 bits) DDR (1 bit) CA1 (2 bits)
907
908
909 PIA initialization:
910
911 00 -> $C80D = PIA2     -> DDR active
912 00 -> $C80C = PIA2 DDR -> All input?
913
914
915
916 */
917
918 #if 0
919
920 #define PIA_IRQ1                                (0x80)
921 #define PIA_IRQ2                                (0x40)
922
923 #define IRQ1_ENABLED(c)                 ( (((c) >> 0) & 0x01))
924 #define C1_LOW_TO_HIGH(c)               ( (((c) >> 1) & 0x01))
925 #define C1_HIGH_TO_LOW(c)               (!(((c) >> 1) & 0x01))
926 #define OUTPUT_SELECTED(c)              ( (((c) >> 2) & 0x01))
927 #define IRQ2_ENABLED(c)                 ( (((c) >> 3) & 0x01))
928 #define STROBE_E_RESET(c)               ( (((c) >> 3) & 0x01))
929 #define STROBE_C1_RESET(c)              (!(((c) >> 3) & 0x01))
930 #define C2_SET(c)                               ( (((c) >> 3) & 0x01))
931 #define C2_LOW_TO_HIGH(c)               ( (((c) >> 4) & 0x01))
932 #define C2_HIGH_TO_LOW(c)               (!(((c) >> 4) & 0x01))
933 #define C2_SET_MODE(c)                  ( (((c) >> 4) & 0x01))
934 #define C2_STROBE_MODE(c)               (!(((c) >> 4) & 0x01))
935 #define C2_OUTPUT(c)                    ( (((c) >> 5) & 0x01))
936 #define C2_INPUT(c)                             (!(((c) >> 5) & 0x01))
937
938 WRITE8_DEVICE_HANDLER( pia6821_ca1_w )
939 {
940         pia6821_state *p = get_token(device);
941
942         /* limit the data to 0 or 1 */
943         data = data ? TRUE : FALSE;
944
945         LOG(("PIA #%s: set input CA1 = %d\n", device->tag, data));
946
947         /* the new state has caused a transition */
948         if ((p->in_ca1 != data) &&
949                 ((data && C1_LOW_TO_HIGH(p->ctl_a)) || (!data && C1_HIGH_TO_LOW(p->ctl_a))))
950         {
951                 LOG(("PIA #%s: CA1 triggering\n", device->tag));
952
953                 /* mark the IRQ */
954                 p->irq_a1 = TRUE;
955
956                 /* update externals */
957                 update_interrupts(device);
958
959                 /* CA2 is configured as output and in read strobe mode and cleared by a CA1 transition */
960                 if (C2_OUTPUT(p->ctl_a) && C2_STROBE_MODE(p->ctl_a) && STROBE_C1_RESET(p->ctl_a))
961                         set_out_ca2(device, TRUE);
962         }
963
964         /* set the new value for CA1 */
965         p->in_ca1 = data;
966         p->in_ca1_pushed = TRUE;
967 }
968
969 WRITE8_DEVICE_HANDLER( pia6821_cb1_w )
970 {
971         pia6821_state *p = get_token(device);
972
973         /* limit the data to 0 or 1 */
974         data = data ? 1 : 0;
975
976         LOG(("PIA #%s: set input CB1 = %d\n", device->tag, data));
977
978         /* the new state has caused a transition */
979         if ((p->in_cb1 != data) &&
980                 ((data && C1_LOW_TO_HIGH(p->ctl_b)) || (!data && C1_HIGH_TO_LOW(p->ctl_b))))
981         {
982                 LOG(("PIA #%s: CB1 triggering\n", device->tag));
983
984                 /* mark the IRQ */
985                 p->irq_b1 = 1;
986
987                 /* update externals */
988                 update_interrupts(device);
989
990                 /* If CB2 is configured as a write-strobe output which is reset by a CB1
991            transition, this reset will only happen when a read from port B implicitly
992            clears the IRQ B1 flag.  So we handle the CB2 reset there.  Note that this
993            is different from what happens with port A. */
994         }
995
996         /* set the new value for CB1 */
997         p->in_cb1 = data;
998         p->in_cb1_pushed = TRUE;
999 }
1000
1001 static void update_interrupts(const device_config *device)
1002 {
1003         pia6821_state *p = get_token(device);
1004         int new_state;
1005
1006         /* start with IRQ A */
1007         new_state = (p->irq_a1 && IRQ1_ENABLED(p->ctl_a)) || (p->irq_a2 && IRQ2_ENABLED(p->ctl_a));
1008
1009         if (new_state != p->irq_a_state)
1010         {
1011                 p->irq_a_state = new_state;
1012                 devcb_call_write_line(&p->irq_a_func, p->irq_a_state);
1013         }
1014
1015         /* then do IRQ B */
1016         new_state = (p->irq_b1 && IRQ1_ENABLED(p->ctl_b)) || (p->irq_b2 && IRQ2_ENABLED(p->ctl_b));
1017
1018         if (new_state != p->irq_b_state)
1019         {
1020                 p->irq_b_state = new_state;
1021                 devcb_call_write_line(&p->irq_b_func, p->irq_b_state);
1022         }
1023 }
1024
1025 static void control_b_w(const device_config *device, UINT8 data)
1026 {
1027         pia6821_state *p = get_token(device);
1028         int temp;
1029
1030         /* bit 7 and 6 are read only */
1031         data &= 0x3f;
1032
1033         LOG(("PIA #%s: control B write = %02X\n", device->tag, data));
1034
1035         /* update the control register */
1036         p->ctl_b = data;
1037
1038         if (C2_SET_MODE(p->ctl_b))
1039                 /* set/reset mode - bit value determines the new output */
1040                 temp = C2_SET(p->ctl_b);
1041         else
1042                 /* strobe mode - output is always high unless strobed */
1043                 temp = TRUE;
1044
1045         set_out_cb2(device, temp);
1046
1047         /* update externals */
1048         update_interrupts(device);
1049 }
1050
1051 static void control_a_w(const device_config *device, UINT8 data)
1052 {
1053         pia6821_state *p = get_token(device);
1054
1055         /* bit 7 and 6 are read only */
1056         data &= 0x3f;
1057
1058         LOG(("PIA #%s: control A write = %02X\n", device->tag, data));
1059
1060         /* update the control register */
1061         p->ctl_a = data;
1062
1063         /* CA2 is configured as output */
1064         if (C2_OUTPUT(p->ctl_a))
1065         {
1066                 int temp;
1067
1068                 if (C2_SET_MODE(p->ctl_a))
1069                         /* set/reset mode - bit value determines the new output */
1070                         temp = C2_SET(p->ctl_a);
1071                 else
1072                         /* strobe mode - output is always high unless strobed */
1073                         temp = TRUE;
1074
1075                 set_out_ca2(device, temp);
1076         }
1077
1078         /* update externals */
1079         update_interrupts(device);
1080 }
1081
1082
1083 CTRL REGISTER:
1084
1085 B7        B6        B5 B4 B3     B2   B1 B0
1086 --------------------------------------------------
1087 IRQA(B)1  IRQA(B)2  CA(B)2 Ctrl  DDR  CA(B)1 Ctrl
1088
1089 Bits 6 & 7 are RO. IRQs are cleared on read of PORTA when not in DDR mode
1090 DDR: 0: DDR selected, 1: Output register selected
1091 CA1(CB1) Ctrl: B0: 0/1 Dis/enable interrupt IRQA(B)
1092                B1: 0/1 IRQ set by Hi-to-Lo/Lo-to-Hi transition on CA(B)1
1093 CA2(CB2) Ctrl: If B5==0, B4 & B3 are similar to B1 & B0
1094
1095 Entering main loop...
1096 V6809 WrMem: Writing PIA (PACTL) address C80D [->00, PC=F4DC] --> Set DDR on PORTA, IRQs off
1097 V6809 WrMem: Writing PIA (PORTA) address C80C [->00, PC=F4DF] --> Set DDR to all input on PORTA
1098 V6809 WrMem: Writing PIA (PACTL) address C80D [->3C, PC=F4E4] --> Set Output on PORTA, Set CA2 = 1, disable IRQA1
1099 V6809 WrMem: Writing PIA (PBCTL) address C80F [->00, PC=F4E7] --> Set DDR on PORTB, IRQs off
1100 V6809 WrMem: Writing PIA (PORTB) address C80E [->C0, PC=F4EC] --> Set DDR to output on 6,7 input on 0-5 on PORTB
1101 V6809 WrMem: Writing PIA (PBCTL) address C80F [->3C, PC=F4F1] --> Set Output on PORTA, Set CB2 = 1, disable IRQB1
1102 V6809 WrMem: Writing PIA (PORTB) address C80E [->C0, PC=F4F6] --> Send 1s on bits 6 & 7 on PORTB
1103 V6809 WrMem: Writing PIA (PACTL) address C80D [->34, PC=F523] --> Set Output on PORTA, Set CA2 = 0, disable IRQA1
1104 V6809 WrMem: Writing PIA (PBCTL) address C80F [->34, PC=F526] --> Set Output on PORTB, Set CB2 = 0, disable IRQB1
1105 V6809 WrMem: Writing PIA (PORTB) address C80E [->00, PC=F529] --> Send 0s on bits 6 & 7 on PORTB
1106 V6809 WrMem: Writing PIA (PORTA) address C80C [->00, PC=6076] --> Do nothing
1107 V6809 WrMem: Writing PIA (PACTL) address C80D [->00, PC=6076] --> Set DDR on PORTA, IRQs off
1108 V6809 WrMem: Writing PIA (PORTA) address C80C [->00, PC=607B] --> Set DDR to all input on PORTA
1109 V6809 WrMem: Writing PIA (PACTL) address C80D [->34, PC=607B] --> Set Output on PORTA, Set CA2 = 0, disable IRQA1
1110 V6809 WrMem: Writing PIA (PORTB) address C80E [->00, PC=6076] --> Send 0s on bits 6 & 7 on PORTB
1111 V6809 WrMem: Writing PIA (PBCTL) address C80F [->00, PC=6076] --> Set DDR on PORTB, IRQs off
1112 V6809 WrMem: Writing PIA (PORTB) address C80E [->FF, PC=607B] --> Set DDR to all output on PORTB
1113 V6809 WrMem: Writing PIA (PBCTL) address C80F [->35, PC=607B] --> Set Output on PORTB, Set CB2 = 0, enable IRQB1
1114 V6809 WrMem: Writing PIA (PORTB) address C80E [->3F, PC=6088] --> Send $3F on PORTB
1115 V6809 WrMem: Writing PIA (PORTB) address C80E [->0C, PC=60DB] --> Send $0C on PORTB
1116 V6809 WrMem: Writing PIA (PBCTL) address C80F [->34, PC=15C3] --> Set Output on PORTB, Set CB2 = 0, disable IRQB1
1117  6809 RdMem: Reading PIA (PORTB) address C80E [=0C, PC=15C6]  --> Clear IRQBs
1118  6809 RdMem: Reading PIA (PORTA) address C80C [=00, PC=075B]  --> Clear IRQAs
1119  6809 RdMem: Reading PIA (PORTA) address C80C [=00, PC=07B9]  --> Clear IRQAs
1120
1121 V6809 WrMem: Writing PIA (PBCTL) address C80F [->35, PC=1644] --> Set Output on PORTB, Set CB2 = 0, enable IRQB1
1122 V6809 WrMem: Writing PIA (PBCTL) address C80F [->34, PC=15C3] --> Set Output on PORTB, Set CB2 = 0, disable IRQB1
1123  6809 RdMem: Reading PIA (PORTB) address C80E [=0C, PC=15C6]  --> Clear IRQBs
1124 V6809 WrMem: Writing PIA (PBCTL) address C80F [->35, PC=1644]
1125 V6809 WrMem: Writing PIA (PBCTL) address C80F [->34, PC=15C3]
1126  6809 RdMem: Reading PIA (PORTB) address C80E [=0C, PC=15C6]
1127 V6809 WrMem: Writing PIA (PBCTL) address C80F [->35, PC=1644]
1128 V6809 WrMem: Writing PIA (PBCTL) address C80F [->34, PC=15C3]
1129  6809 RdMem: Reading PIA (PORTB) address C80E [=0C, PC=15C6]
1130 V6809 WrMem: Writing PIA (PBCTL) address C80F [->35, PC=1644]
1131 V6809 WrMem: Writing PIA (PBCTL) address C80F [->34, PC=15C3]
1132  6809 RdMem: Reading PIA (PORTB) address C80E [=0C, PC=15C6]
1133 V6809 WrMem: Writing PIA (PBCTL) address C80F [->35, PC=1644]
1134 V6809 WrMem: Writing PIA (PBCTL) address C80F [->34, PC=15C3]
1135  6809 RdMem: Reading PIA (PORTB) address C80E [=0C, PC=15C6]
1136 V6809 WrMem: Writing PIA (PBCTL) address C80F [->35, PC=1644]
1137 V6809 WrMem: Writing PIA (PBCTL) address C80F [->34, PC=15C3]
1138  6809 RdMem: Reading PIA (PORTB) address C80E [=0C, PC=15C6]
1139
1140 #endif