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