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