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