]> Shamusworld >> Repos - apple2/blob - src/mmu.cpp
Connected POWER function to GUI.
[apple2] / src / mmu.cpp
1 //
2 // mmu.cpp: Memory management
3 //
4 // by James Hammons
5 // (C) 2013 Underground Software
6 //
7 // JLH = James Hammons <jlhamm@acm.org>
8 //
9 // WHO  WHEN        WHAT
10 // ---  ----------  ------------------------------------------------------------
11 // JLH  09/27/2013  Created this file
12
13
14 #include "mmu.h"
15 #include "apple2.h"
16 #include "applevideo.h"
17 #include "firmware.h"
18 #include "log.h"
19 #include "sound.h"
20
21
22 // Debug defines
23 //#define LC_DEBUG
24
25 // Address Map enumeration
26 enum { AM_RAM, AM_ROM, AM_BANKED, AM_READ, AM_WRITE, AM_READ_WRITE, AM_END_OF_LIST };
27
28 // Macros for function pointers
29 // The typedef would be something like:
30 //typedef ReadFunc (uint8_t (*)(uint16_t));
31 //typedef WriteFunc (void (*)(uint16_t, uint8_t));
32 #define READFUNC(x) uint8_t (* x)(uint16_t)
33 #define WRITEFUNC(x) void (* x)(uint16_t, uint8_t)
34
35 // Internal vars
36 uint8_t ** addrPtrRead[0x10000];
37 uint8_t ** addrPtrWrite[0x10000];
38 uint16_t addrOffset[0x10000];
39
40 READFUNC(funcMapRead[0x10000]);
41 WRITEFUNC(funcMapWrite[0x10000]);
42
43 struct AddressMap
44 {
45         uint16_t start;
46         uint16_t end;
47         int type;
48         uint8_t ** memory;
49         uint8_t ** altMemory;
50         READFUNC(read);
51         WRITEFUNC(write);
52 };
53
54
55 // Dunno if I like this approach or not...
56 //ADDRESS_MAP_START()
57 //      AM_RANGE(0x0000, 0xBFFF) AM_RAM AM_BASE(ram) AM_SHARE(1)
58 //      AM_RANGE(0xC000, 0xC001) AM_READWRITE(readFunc, writeFunc)
59 //ADDRESS_MAP_END
60
61 // Would need a pointer for 80STORE as well...
62
63 uint8_t * pageZeroMemory  = &ram[0x0000];       // $0000 - $01FF
64 uint8_t * mainMemoryR     = &ram[0x0200];       // $0200 - $BFFF (read)
65 uint8_t * mainMemoryW     = &ram[0x0200];       // $0200 - $BFFF (write)
66
67 uint8_t * mainMemoryTextR = &ram[0x0400];       // $0400 - $07FF (read)
68 uint8_t * mainMemoryTextW = &ram[0x0400];       // $0400 - $07FF (write)
69 uint8_t * mainMemoryHGRR  = &ram[0x2000];       // $2000 - $3FFF (read)
70 uint8_t * mainMemoryHGRW  = &ram[0x2000];       // $2000 - $3FFF (write)
71
72 uint8_t * slotMemory      = &rom[0xC100];       // $C100 - $CFFF
73 uint8_t * slot3Memory     = &rom[0xC300];       // $C300 - $C3FF
74 uint8_t * slot6Memory     = &diskROM[0];        // $C600 - $C6FF
75 uint8_t * lcBankMemoryR   = &ram[0xD000];       // $D000 - $DFFF (read)
76 uint8_t * lcBankMemoryW   = &ram[0xD000];       // $D000 - $DFFF (write)
77 uint8_t * upperMemoryR    = &ram[0xE000];       // $E000 - $FFFF (read)
78 uint8_t * upperMemoryW    = &ram[0xE000];       // $E000 - $FFFF (write)
79
80
81 // Function prototypes
82 uint8_t ReadNOP(uint16_t);
83 void WriteNOP(uint16_t, uint8_t);
84 uint8_t ReadMemory(uint16_t);
85 void WriteMemory(uint16_t, uint8_t);
86 uint8_t ReadKeyboard(uint16_t);
87 void Switch80STORE(uint16_t, uint8_t);
88 void SwitchRAMRD(uint16_t, uint8_t);
89 void SwitchRAMWRT(uint16_t, uint8_t);
90 void SwitchSLOTCXROM(uint16_t, uint8_t);
91 void SwitchALTZP(uint16_t, uint8_t);
92 void SwitchSLOTC3ROM(uint16_t, uint8_t);
93 void Switch80COL(uint16_t, uint8_t);
94 void SwitchALTCHARSET(uint16_t, uint8_t);
95 uint8_t ReadKeyStrobe(uint16_t);
96 uint8_t ReadBANK2(uint16_t);
97 uint8_t ReadLCRAM(uint16_t);
98 uint8_t ReadRAMRD(uint16_t);
99 uint8_t ReadRAMWRT(uint16_t);
100 uint8_t ReadSLOTCXROM(uint16_t);
101 uint8_t ReadALTZP(uint16_t);
102 uint8_t ReadSLOTC3ROM(uint16_t);
103 uint8_t Read80STORE(uint16_t);
104 uint8_t ReadVBL(uint16_t);
105 uint8_t ReadTEXT(uint16_t);
106 uint8_t ReadMIXED(uint16_t);
107 uint8_t ReadPAGE2(uint16_t);
108 uint8_t ReadHIRES(uint16_t);
109 uint8_t ReadALTCHARSET(uint16_t);
110 uint8_t Read80COL(uint16_t);
111 void WriteKeyStrobe(uint16_t, uint8_t);
112 uint8_t ReadSpeaker(uint16_t);
113 void WriteSpeaker(uint16_t, uint8_t);
114 uint8_t SwitchLCR(uint16_t);
115 void SwitchLCW(uint16_t, uint8_t);
116 void SwitchLC(void);
117 uint8_t SwitchTEXTR(uint16_t);
118 void SwitchTEXTW(uint16_t, uint8_t);
119 uint8_t SwitchMIXEDR(uint16_t);
120 void SwitchMIXEDW(uint16_t, uint8_t);
121 uint8_t SwitchPAGE2R(uint16_t);
122 void SwitchPAGE2W(uint16_t, uint8_t);
123 uint8_t SwitchHIRESR(uint16_t);
124 void SwitchHIRESW(uint16_t, uint8_t);
125 uint8_t SwitchDHIRESR(uint16_t);
126 void SwitchDHIRESW(uint16_t, uint8_t);
127 void SwitchIOUDIS(uint16_t, uint8_t);
128 uint8_t Slot6R(uint16_t);
129 void Slot6W(uint16_t, uint8_t);
130 void HandleSlot6(uint16_t, uint8_t);
131 uint8_t ReadButton0(uint16_t);
132 uint8_t ReadButton1(uint16_t);
133 uint8_t ReadPaddle0(uint16_t);
134 uint8_t ReadIOUDIS(uint16_t);
135 uint8_t ReadDHIRES(uint16_t);
136 //uint8_t SwitchR(uint16_t);
137 //void SwitchW(uint16_t, uint8_t);
138
139
140 // The main Apple //e memory map
141 AddressMap memoryMap[] = {
142         { 0x0000, 0x01FF, AM_RAM, &pageZeroMemory, 0, 0, 0 },
143         { 0x0200, 0xBFFF, AM_BANKED, &mainMemoryR, &mainMemoryW, 0, 0 },
144
145         // These will overlay over the previously written memory accessors
146         { 0x0400, 0x07FF, AM_BANKED, &mainMemoryTextR, &mainMemoryTextW, 0, 0 },
147         { 0x2000, 0x3FFF, AM_BANKED, &mainMemoryHGRR, &mainMemoryHGRW, 0, 0 },
148
149         { 0xC000, 0xC001, AM_READ_WRITE, 0, 0, ReadKeyboard, Switch80STORE },
150         { 0xC002, 0xC003, AM_READ_WRITE, 0, 0, ReadKeyboard, SwitchRAMRD },
151         { 0xC004, 0xC005, AM_READ_WRITE, 0, 0, ReadKeyboard, SwitchRAMWRT },
152         { 0xC006, 0xC007, AM_READ_WRITE, 0, 0, ReadKeyboard, SwitchSLOTCXROM },
153         { 0xC008, 0xC009, AM_READ_WRITE, 0, 0, ReadKeyboard, SwitchALTZP },
154         { 0xC00A, 0xC00B, AM_READ_WRITE, 0, 0, ReadKeyboard, SwitchSLOTC3ROM },
155         { 0xC00C, 0xC00D, AM_READ_WRITE, 0, 0, ReadKeyboard, Switch80COL },
156         { 0xC00E, 0xC00F, AM_READ_WRITE, 0, 0, ReadKeyboard, SwitchALTCHARSET },
157         { 0xC010, 0xC010, AM_READ_WRITE, 0, 0, ReadKeyStrobe, WriteKeyStrobe },
158         { 0xC011, 0xC011, AM_READ_WRITE, 0, 0, ReadBANK2, WriteKeyStrobe },
159         { 0xC012, 0xC012, AM_READ_WRITE, 0, 0, ReadLCRAM, WriteKeyStrobe },
160         { 0xC013, 0xC013, AM_READ_WRITE, 0, 0, ReadRAMRD, WriteKeyStrobe },
161         { 0xC014, 0xC014, AM_READ_WRITE, 0, 0, ReadRAMWRT, WriteKeyStrobe },
162         { 0xC015, 0xC015, AM_READ_WRITE, 0, 0, ReadSLOTCXROM, WriteKeyStrobe },
163         { 0xC016, 0xC016, AM_READ_WRITE, 0, 0, ReadALTZP, WriteKeyStrobe },
164         { 0xC017, 0xC017, AM_READ_WRITE, 0, 0, ReadSLOTC3ROM, WriteKeyStrobe },
165         { 0xC018, 0xC018, AM_READ_WRITE, 0, 0, Read80STORE, WriteKeyStrobe },
166         { 0xC019, 0xC019, AM_READ_WRITE, 0, 0, ReadVBL, WriteKeyStrobe },
167         { 0xC01A, 0xC01A, AM_READ_WRITE, 0, 0, ReadTEXT, WriteKeyStrobe },
168         { 0xC01B, 0xC01B, AM_READ_WRITE, 0, 0, ReadMIXED, WriteKeyStrobe },
169         { 0xC01C, 0xC01C, AM_READ_WRITE, 0, 0, ReadPAGE2, WriteKeyStrobe },
170         { 0xC01D, 0xC01D, AM_READ_WRITE, 0, 0, ReadHIRES, WriteKeyStrobe },
171         { 0xC01E, 0xC01E, AM_READ_WRITE, 0, 0, ReadALTCHARSET, WriteKeyStrobe },
172         { 0xC01F, 0xC01F, AM_READ_WRITE, 0, 0, Read80COL, WriteKeyStrobe },
173         { 0xC030, 0xC03F, AM_READ_WRITE, 0, 0, ReadSpeaker, WriteSpeaker },
174         { 0xC050, 0xC051, AM_READ_WRITE, 0, 0, SwitchTEXTR, SwitchTEXTW },
175         { 0xC052, 0xC053, AM_READ_WRITE, 0, 0, SwitchMIXEDR, SwitchMIXEDW },
176         { 0xC054, 0xC055, AM_READ_WRITE, 0, 0, SwitchPAGE2R, SwitchPAGE2W },
177         { 0xC056, 0xC057, AM_READ_WRITE, 0, 0, SwitchHIRESR, SwitchHIRESW },
178         { 0xC05E, 0xC05F, AM_READ_WRITE, 0, 0, SwitchDHIRESR, SwitchDHIRESW },
179         { 0xC061, 0xC061, AM_READ, 0, 0, ReadButton0, 0 },
180         { 0xC062, 0xC062, AM_READ, 0, 0, ReadButton1, 0 },
181         { 0xC064, 0xC067, AM_READ, 0, 0, ReadPaddle0, 0 },
182 //      { 0xC07E, 0xC07F, AM_READ_WRITE, 0, 0, SwitchIOUDISR, SwitchIOUDISW },
183         { 0xC07E, 0xC07E, AM_READ_WRITE, 0, 0, ReadIOUDIS, SwitchIOUDIS },
184         { 0xC07F, 0xC07F, AM_READ_WRITE, 0, 0, ReadDHIRES, SwitchIOUDIS },
185         { 0xC080, 0xC08F, AM_READ_WRITE, 0, 0, SwitchLCR, SwitchLCW },
186         { 0xC0E0, 0xC0EF, AM_READ_WRITE, 0, 0, Slot6R, Slot6W },
187         { 0xC100, 0xCFFF, AM_ROM, &slotMemory, 0, 0, 0 },
188
189         // This will overlay the slotMemory accessors for slot 6 ROM
190         { 0xC300, 0xC3FF, AM_ROM, &slot3Memory, 0, 0, 0 },
191         { 0xC600, 0xC6FF, AM_ROM, &slot6Memory, 0, 0, 0 },
192
193         { 0xD000, 0xDFFF, AM_BANKED, &lcBankMemoryR, &lcBankMemoryW, 0, 0 },
194         { 0xE000, 0xFFFF, AM_BANKED, &upperMemoryR, &upperMemoryW, 0, 0 },
195         { 0x0000, 0x0000, AM_END_OF_LIST, 0, 0, 0, 0 }
196 };
197
198
199 void SetupAddressMap(void)
200 {
201         for(uint32_t i=0; i<0x10000; i++)
202         {
203                 funcMapRead[i] = ReadNOP;
204                 funcMapWrite[i] = WriteNOP;
205                 addrPtrRead[i] = 0;
206                 addrPtrWrite[i] = 0;
207                 addrOffset[i] = 0;
208         }
209
210         uint32_t i=0;
211
212         while (memoryMap[i].type != AM_END_OF_LIST)
213         {
214                 switch (memoryMap[i].type)
215                 {
216                 case AM_RAM:
217                         for(uint32_t j=memoryMap[i].start; j<=memoryMap[i].end; j++)
218                         {
219                                 funcMapRead[j] = ReadMemory;
220                                 funcMapWrite[j] = WriteMemory;
221                                 addrPtrRead[j] = memoryMap[i].memory;
222                                 addrPtrWrite[j] = memoryMap[i].memory;
223                                 addrOffset[j] = j - memoryMap[i].start;
224 //WriteLog("SetupAddressMap: j=$%04X, addrOffset[j]=$%04X\n", j, addrOffset[j]);
225                         }
226
227                         break;
228                 case AM_ROM:
229                         for(uint32_t j=memoryMap[i].start; j<=memoryMap[i].end; j++)
230                         {
231                                 funcMapRead[j] = ReadMemory;
232                                 addrPtrRead[j] = memoryMap[i].memory;
233                                 addrOffset[j] = j - memoryMap[i].start;
234                         }
235
236                         break;
237                 case AM_BANKED:
238                         for(uint32_t j=memoryMap[i].start; j<=memoryMap[i].end; j++)
239                         {
240                                 funcMapRead[j] = ReadMemory;
241                                 funcMapWrite[j] = WriteMemory;
242                                 addrPtrRead[j] = memoryMap[i].memory;
243                                 addrPtrWrite[j] = memoryMap[i].altMemory;
244                                 addrOffset[j] = j - memoryMap[i].start;
245                         }
246
247                         break;
248                 case AM_READ:
249                         for(uint32_t j=memoryMap[i].start; j<=memoryMap[i].end; j++)
250                                 funcMapRead[j] = memoryMap[i].read;
251
252                         break;
253                 case AM_WRITE:
254                         for(uint32_t j=memoryMap[i].start; j<=memoryMap[i].end; j++)
255                                 funcMapWrite[j] = memoryMap[i].write;
256
257                         break;
258                 case AM_READ_WRITE:
259                         for(uint32_t j=memoryMap[i].start; j<=memoryMap[i].end; j++)
260                         {
261                                 funcMapRead[j] = memoryMap[i].read;
262                                 funcMapWrite[j] = memoryMap[i].write;
263                         }
264
265                         break;
266                 }
267
268                 i++;
269         };
270
271         // This should correctly set up the LC pointers, but it doesn't
272         // for some reason... :-/
273         // It's because we were storing pointers directly, instead of pointers
274         // to the pointer... It's complicated. :-)
275         SwitchLC();
276 }
277
278
279 //
280 // Built-in functions
281 //
282 uint8_t ReadNOP(uint16_t)
283 {
284         return 0;
285 }
286
287
288 void WriteNOP(uint16_t, uint8_t)
289 {
290 }
291
292
293 uint8_t ReadMemory(uint16_t address)
294 {
295 //WriteLog("ReadMemory: addr=$%04X, addrPtrRead[addr]=$%X, addrOffset[addr]=$%X, val=$%02X\n", address, addrPtrRead[address], addrOffset[address], addrPtrRead[address][addrOffset[address]]);
296         // We are guaranteed a valid address here by the setup function, so there's
297         // no need to do any checking here.
298         return (*addrPtrRead[address])[addrOffset[address]];
299 }
300
301
302 void WriteMemory(uint16_t address, uint8_t byte)
303 {
304         // We can write protect memory this way, but it adds a branch to the mix. :-/
305         // (this can be avoided by setting up another bank of memory which we
306         //  ignore... hmm...)
307         if ((*addrPtrWrite[address]) == 0)
308                 return;
309
310         (*addrPtrWrite[address])[addrOffset[address]] = byte;
311 }
312
313
314 //
315 // The main memory access functions used by V65C02
316 //
317 uint8_t AppleReadMem(uint16_t address)
318 {
319         return (*(funcMapRead[address]))(address);
320 }
321
322
323 void AppleWriteMem(uint16_t address, uint8_t byte)
324 {
325         (*(funcMapWrite[address]))(address, byte);
326 }
327
328
329 //
330 // Actual emulated I/O functions follow
331 //
332 uint8_t ReadKeyboard(uint16_t /*addr*/)
333 {
334         return lastKeyPressed | ((uint8_t)keyDown << 7);
335 }
336
337
338 void Switch80STORE(uint16_t address, uint8_t)
339 {
340         store80Mode = (bool)(address & 0x01);
341 WriteLog("Setting 80STORE to %s...\n", (store80Mode ? "ON" : "off"));
342
343         if (store80Mode)
344         {
345                 mainMemoryTextR = (displayPage2 ? &ram2[0x0400] : &ram[0x0400]);
346                 mainMemoryTextW = (displayPage2 ? &ram2[0x0400] : &ram[0x0400]);
347 //              mainMemoryHGRR = (displayPage2 ? &ram2[0x2000] : &ram[0x2000]);
348 //              mainMemoryHGRW = (displayPage2 ? &ram2[0x2000] : &ram[0x2000]);
349         }
350         else
351         {
352                 mainMemoryTextR = (ramwrt ? &ram2[0x0400] : &ram[0x0400]);
353                 mainMemoryTextW = (ramwrt ? &ram2[0x0400] : &ram[0x0400]);
354 //              mainMemoryHGRR = (ramwrt ? &ram2[0x2000] : &ram[0x2000]);
355 //              mainMemoryHGRW = (ramwrt ? &ram2[0x2000] : &ram[0x2000]);
356         }
357 }
358
359
360 void SwitchRAMRD(uint16_t address, uint8_t)
361 {
362         ramrd = (bool)(address & 0x01);
363         mainMemoryR = (ramrd ? &ram2[0x0200] : &ram[0x0200]);
364         mainMemoryHGRR = (ramrd ? &ram2[0x2000] : &ram[0x2000]);
365
366         if (store80Mode)
367                 return;
368
369         mainMemoryTextR = (ramrd ? &ram2[0x0400] : &ram[0x0400]);
370 }
371
372
373 void SwitchRAMWRT(uint16_t address, uint8_t)
374 {
375         ramwrt = (bool)(address & 0x01);
376         mainMemoryW = (ramwrt ?  &ram2[0x0200] : &ram[0x0200]);
377         mainMemoryHGRW = (ramwrt ? &ram2[0x2000] : &ram[0x2000]);
378
379         if (store80Mode)
380                 return;
381
382         mainMemoryTextW = (ramwrt ? &ram2[0x0400] : &ram[0x0400]);
383 }
384
385
386 void SwitchSLOTCXROM(uint16_t address, uint8_t)
387 {
388 //WriteLog("Setting SLOTCXROM to %s...\n", ((address & 0x01) ^ 0x01 ? "ON" : "off"));
389         // This is the only soft switch that breaks the usual convention.
390         slotCXROM = !((bool)(address & 0x01));
391 //      slot3Memory = (slotCXROM ? &rom[0] : &rom[0xC300]);
392         slot6Memory = (slotCXROM ? &diskROM[0] : &rom[0xC600]);
393 }
394
395
396 void SwitchALTZP(uint16_t address, uint8_t)
397 {
398         altzp = (bool)(address & 0x01);
399         pageZeroMemory = (altzp ? &ram2[0x0000] : &ram[0x0000]);
400         SwitchLC();
401 }
402
403 //extern bool dumpDis;
404
405 void SwitchSLOTC3ROM(uint16_t address, uint8_t)
406 {
407 //dumpDis = true;
408 //WriteLog("Setting SLOTC3ROM to %s...\n", (address & 0x01 ? "ON" : "off"));
409         slotC3ROM = (bool)(address & 0x01);
410 //      slotC3ROM = false;
411 // Seems the h/w forces this with an 80 column card in slot 3...
412         slot3Memory = (slotC3ROM ? &rom[0] : &rom[0xC300]);
413 //      slot3Memory = &rom[0xC300];
414 }
415
416
417 void Switch80COL(uint16_t address, uint8_t)
418 {
419         col80Mode = (bool)(address & 0x01);
420 }
421
422
423 void SwitchALTCHARSET(uint16_t address, uint8_t)
424 {
425         alternateCharset = (bool)(address & 0x01);
426 }
427
428
429 uint8_t ReadKeyStrobe(uint16_t)
430 {
431         uint8_t byte = lastKeyPressed | ((uint8_t)keyDown << 7);
432         keyDown = false;
433         return byte;
434 }
435
436
437 uint8_t ReadBANK2(uint16_t)
438 {
439         return (lcState < 0x04 ? 0x80 : 0x00);
440 }
441
442
443 uint8_t ReadLCRAM(uint16_t)
444 {
445         // If bits 0 & 1 are set, but not at the same time, then it's ROM
446         uint8_t lcROM = (lcState & 0x1) ^ ((lcState & 0x02) >> 1);
447         return (lcROM ? 0x00 : 0x80);
448 }
449
450
451 uint8_t ReadRAMRD(uint16_t)
452 {
453         return (uint8_t)ramrd << 7;
454 }
455
456
457 uint8_t ReadRAMWRT(uint16_t)
458 {
459         return (uint8_t)ramwrt << 7;
460 }
461
462
463 uint8_t ReadSLOTCXROM(uint16_t)
464 {
465         return (uint8_t)slotCXROM << 7;
466 }
467
468
469 uint8_t ReadALTZP(uint16_t)
470 {
471         return (uint8_t)altzp << 7;
472 }
473
474
475 uint8_t ReadSLOTC3ROM(uint16_t)
476 {
477 //      return 0;
478         return (uint8_t)slotC3ROM << 7;
479 }
480
481
482 uint8_t Read80STORE(uint16_t)
483 {
484         return (uint8_t)store80Mode << 7;
485 }
486
487
488 uint8_t ReadVBL(uint16_t)
489 {
490         return (uint8_t)vbl << 7;
491 }
492
493
494 uint8_t ReadTEXT(uint16_t)
495 {
496         return (uint8_t)textMode << 7;
497 }
498
499
500 uint8_t ReadMIXED(uint16_t)
501 {
502         return (uint8_t)mixedMode << 7;
503 }
504
505
506 uint8_t ReadPAGE2(uint16_t)
507 {
508         return (uint8_t)displayPage2 << 7;
509 }
510
511
512 uint8_t ReadHIRES(uint16_t)
513 {
514         return (uint8_t)hiRes << 7;
515 }
516
517
518 uint8_t ReadALTCHARSET(uint16_t)
519 {
520         return (uint8_t)alternateCharset << 7;
521 }
522
523
524 uint8_t Read80COL(uint16_t)
525 {
526         return (uint8_t)col80Mode << 7;
527 }
528
529
530 void WriteKeyStrobe(uint16_t, uint8_t)
531 {
532         keyDown = false;
533 }
534
535
536 uint8_t ReadSpeaker(uint16_t)
537 {
538         ToggleSpeaker();
539         return 0;
540 }
541
542
543 void WriteSpeaker(uint16_t, uint8_t)
544 {
545         ToggleSpeaker();
546 }
547
548
549 uint8_t SwitchLCR(uint16_t address)
550 {
551         lcState = address & 0x0B;
552         SwitchLC();
553         return 0;
554 }
555
556
557 void SwitchLCW(uint16_t address, uint8_t)
558 {
559         lcState = address & 0x0B;
560         SwitchLC();
561 }
562
563
564 void SwitchLC(void)
565 {
566         switch (lcState)
567         {
568         case 0x00:
569 #ifdef LC_DEBUG
570 WriteLog("SwitchLC: Read RAM bank 2, no write\n");
571 #endif
572                 // [R ] Read RAM bank 2; no write
573                 lcBankMemoryR = (altzp ? &ram2[0xD000] : &ram[0xD000]);
574                 lcBankMemoryW = 0;
575                 upperMemoryR = (altzp ? &ram2[0xE000] : &ram[0xE000]);
576                 upperMemoryW = 0;
577                 break;
578         case 0x01:
579 #ifdef LC_DEBUG
580 WriteLog("SwitchLC: Read ROM, write bank 2\n");
581 #endif
582                 // [RR] Read ROM; write RAM bank 2
583                 lcBankMemoryR = &rom[0xD000];
584                 lcBankMemoryW = (altzp ? &ram2[0xD000] : &ram[0xD000]);
585                 upperMemoryR = &rom[0xE000];
586                 upperMemoryW = (altzp ? &ram2[0xE000] : &ram[0xE000]);
587                 break;
588         case 0x02:
589 #ifdef LC_DEBUG
590 WriteLog("SwitchLC: Read ROM, no write\n");
591 #endif
592                 // [R ] Read ROM; no write
593                 lcBankMemoryR = &rom[0xD000];
594                 lcBankMemoryW = 0;
595                 upperMemoryR = &rom[0xE000];
596                 upperMemoryW = 0;
597                 break;
598         case 0x03:
599 #ifdef LC_DEBUG
600 WriteLog("SwitchLC: Read/write bank 2\n");
601 #endif
602                 // [RR] Read RAM bank 2; write RAM bank 2
603                 lcBankMemoryR = (altzp ? &ram2[0xD000] : &ram[0xD000]);
604                 lcBankMemoryW = (altzp ? &ram2[0xD000] : &ram[0xD000]);
605                 upperMemoryR = (altzp ? &ram2[0xE000] : &ram[0xE000]);
606                 upperMemoryW = (altzp ? &ram2[0xE000] : &ram[0xE000]);
607                 break;
608         case 0x08:
609                 // [R ] Read RAM bank 1; no write
610                 lcBankMemoryR = (altzp ? &ram2[0xC000] : &ram[0xC000]);
611                 lcBankMemoryW = 0;
612                 upperMemoryR = (altzp ? &ram2[0xE000] : &ram[0xE000]);
613                 upperMemoryW = 0;
614                 break;
615         case 0x09:
616                 // [RR] Read ROM; write RAM bank 1
617                 lcBankMemoryR = &rom[0xD000];
618                 lcBankMemoryW = (altzp ? &ram2[0xC000] : &ram[0xC000]);
619                 upperMemoryR = &rom[0xE000];
620                 upperMemoryW = (altzp ? &ram2[0xE000] : &ram[0xE000]);
621                 break;
622         case 0x0A:
623                 // [R ] Read ROM; no write
624                 lcBankMemoryR = &rom[0xD000];
625                 lcBankMemoryW = 0;
626                 upperMemoryR = &rom[0xE000];
627                 upperMemoryW = 0;
628                 break;
629         case 0x0B:
630                 // [RR] Read RAM bank 1; write RAM bank 1
631                 lcBankMemoryR = (altzp ? &ram2[0xC000] : &ram[0xC000]);
632                 lcBankMemoryW = (altzp ? &ram2[0xC000] : &ram[0xC000]);
633                 upperMemoryR = (altzp ? &ram2[0xE000] : &ram[0xE000]);
634                 upperMemoryW = (altzp ? &ram2[0xE000] : &ram[0xE000]);
635                 break;
636         }
637 }
638
639
640 uint8_t SwitchTEXTR(uint16_t address)
641 {
642 WriteLog("Setting TEXT to %s...\n", (address & 0x01 ? "ON" : "off"));
643         textMode = (bool)(address & 0x01);
644         return 0;
645 }
646
647
648 void SwitchTEXTW(uint16_t address, uint8_t)
649 {
650 WriteLog("Setting TEXT to %s...\n", (address & 0x01 ? "ON" : "off"));
651         textMode = (bool)(address & 0x01);
652 }
653
654
655 uint8_t SwitchMIXEDR(uint16_t address)
656 {
657 WriteLog("Setting MIXED to %s...\n", (address & 0x01 ? "ON" : "off"));
658         mixedMode = (bool)(address & 0x01);
659         return 0;
660 }
661
662
663 void SwitchMIXEDW(uint16_t address, uint8_t)
664 {
665 WriteLog("Setting MIXED to %s...\n", (address & 0x01 ? "ON" : "off"));
666         mixedMode = (bool)(address & 0x01);
667 }
668
669
670 uint8_t SwitchPAGE2R(uint16_t address)
671 {
672 WriteLog("Setting PAGE2 to %s...\n", (address & 0x01 ? "ON" : "off"));
673         displayPage2 = (bool)(address & 0x01);
674
675         if (store80Mode)
676         {
677                 mainMemoryTextR = (displayPage2 ? &ram2[0x0400] : &ram[0x0400]);
678                 mainMemoryTextW = (displayPage2 ? &ram2[0x0400] : &ram[0x0400]);
679 //              mainMemoryHGRR = (displayPage2 ? &ram2[0x2000] : &ram[0x2000]);
680 //              mainMemoryHGRW = (displayPage2 ? &ram2[0x2000] : &ram[0x2000]);
681         }
682
683         return 0;
684 }
685
686
687 void SwitchPAGE2W(uint16_t address, uint8_t)
688 {
689 WriteLog("Setting PAGE2 to %s...\n", (address & 0x01 ? "ON" : "off"));
690         displayPage2 = (bool)(address & 0x01);
691
692         if (store80Mode)
693         {
694                 mainMemoryTextR = (displayPage2 ? &ram2[0x0400] : &ram[0x0400]);
695                 mainMemoryTextW = (displayPage2 ? &ram2[0x0400] : &ram[0x0400]);
696 //              mainMemoryHGRR = (displayPage2 ? &ram2[0x2000] : &ram[0x2000]);
697 //              mainMemoryHGRW = (displayPage2 ? &ram2[0x2000] : &ram[0x2000]);
698         }
699 }
700
701
702 uint8_t SwitchHIRESR(uint16_t address)
703 {
704 WriteLog("Setting HIRES to %s...\n", (address & 0x01 ? "ON" : "off"));
705         hiRes = (bool)(address & 0x01);
706         return 0;
707 }
708
709
710 void SwitchHIRESW(uint16_t address, uint8_t)
711 {
712 WriteLog("Setting HIRES to %s...\n", (address & 0x01 ? "ON" : "off"));
713         hiRes = (bool)(address & 0x01);
714 }
715
716
717 uint8_t SwitchDHIRESR(uint16_t address)
718 {
719 WriteLog("Setting DHIRES to %s (ioudis = %s)...\n", ((address & 0x01) ^ 0x01 ? "ON" : "off"), (ioudis ? "ON" : "off"));
720         // Hmm, this breaks convention too, like SLOTCXROM
721         if (ioudis)
722                 dhires = !((bool)(address & 0x01));
723
724         return 0;
725 }
726
727
728 void SwitchDHIRESW(uint16_t address, uint8_t)
729 {
730 WriteLog("Setting DHIRES to %s (ioudis = %s)...\n", ((address & 0x01) ^ 0x01 ? "ON" : "off"), (ioudis ? "ON" : "off"));
731         if (ioudis)
732                 dhires = !((bool)(address & 0x01));
733 }
734
735
736 void SwitchIOUDIS(uint16_t address, uint8_t)
737 {
738         ioudis = !((bool)(address & 0x01));
739 }
740
741
742 uint8_t Slot6R(uint16_t address)
743 {
744 //WriteLog("Slot6R: address = %X\n", address & 0x0F);
745 //      HandleSlot6(address, 0);
746 //      return 0;
747         uint8_t state = address & 0x0F;
748
749         switch (state)
750         {
751         case 0x00:
752         case 0x01:
753         case 0x02:
754         case 0x03:
755         case 0x04:
756         case 0x05:
757         case 0x06:
758         case 0x07:
759                 floppyDrive.ControlStepper(state);
760                 break;
761         case 0x08:
762         case 0x09:
763                 floppyDrive.ControlMotor(state & 0x01);
764                 break;
765         case 0x0A:
766         case 0x0B:
767                 floppyDrive.DriveEnable(state & 0x01);
768                 break;
769         case 0x0C:
770                 return floppyDrive.ReadWrite();
771                 break;
772         case 0x0D:
773                 return floppyDrive.GetLatchValue();
774                 break;
775         case 0x0E:
776                 floppyDrive.SetReadMode();
777                 break;
778         case 0x0F:
779                 floppyDrive.SetWriteMode();
780                 break;
781         }
782
783         return 0;
784 }
785
786
787 void Slot6W(uint16_t address, uint8_t byte)
788 {
789 //WriteLog("Slot6W: address = %X, byte= %X\n", address & 0x0F, byte);
790 //      HandleSlot6(address, byte);
791         uint8_t state = address & 0x0F;
792
793         switch (state)
794         {
795         case 0x00:
796         case 0x01:
797         case 0x02:
798         case 0x03:
799         case 0x04:
800         case 0x05:
801         case 0x06:
802         case 0x07:
803                 floppyDrive.ControlStepper(state);
804                 break;
805         case 0x08:
806         case 0x09:
807                 floppyDrive.ControlMotor(state & 0x01);
808                 break;
809         case 0x0A:
810         case 0x0B:
811                 floppyDrive.DriveEnable(state & 0x01);
812                 break;
813         case 0x0C:
814                 floppyDrive.ReadWrite();
815                 break;
816         case 0x0D:
817                 floppyDrive.SetLatchValue(byte);
818                 break;
819         case 0x0E:
820                 floppyDrive.SetReadMode();
821                 break;
822         case 0x0F:
823                 floppyDrive.SetWriteMode();
824                 break;
825         }
826 }
827
828
829 void HandleSlot6(uint16_t address, uint8_t byte)
830 {
831 }
832
833
834 uint8_t ReadButton0(uint16_t)
835 {
836         return (uint8_t)openAppleDown << 7;
837 }
838
839
840 uint8_t ReadButton1(uint16_t)
841 {
842         return (uint8_t)closedAppleDown << 7;
843 }
844
845
846 // The way the paddles work is that a strobe is written (or read) to $C070,
847 // then software counts down the time that it takes for the paddle outputs
848 // to have bit 7 return to 0. If there are no paddles connected, bit 7
849 // stays at 1.
850 // NB: This is really paddles 0-3, not just 0 :-P
851 uint8_t ReadPaddle0(uint16_t)
852 {
853         return 0xFF;
854 }
855
856
857 uint8_t ReadIOUDIS(uint16_t)
858 {
859         return (uint8_t)ioudis << 7;
860 }
861
862
863 uint8_t ReadDHIRES(uint16_t)
864 {
865         return (uint8_t)dhires << 7;
866 }
867
868