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