2 // mmu.cpp: Memory management
5 // (C) 2013 Underground Software
7 // JLH = James Hammons <jlhamm@acm.org>
10 // --- ---------- ------------------------------------------------------------
11 // JLH 09/27/2013 Created this file
16 #include "applevideo.h"
25 // Address Map enumeration
26 enum { AM_RAM, AM_ROM, AM_BANKED, AM_READ, AM_WRITE, AM_READ_WRITE, AM_END_OF_LIST };
28 // Macros for function pointers
29 #define READFUNC(x) uint8_t (* x)(uint16_t)
30 #define WRITEFUNC(x) void (* x)(uint16_t, uint8_t)
33 uint8_t ** addrPtrRead[0x10000];
34 uint8_t ** addrPtrWrite[0x10000];
35 uint16_t addrOffset[0x10000];
37 READFUNC(funcMapRead[0x10000]);
38 WRITEFUNC(funcMapWrite[0x10000]);
51 #define ADDRESS_MAP_END { 0x0000, 0x0000, AM_END_OF_LIST, 0, 0, 0, 0 }
53 // Dunno if I like this approach or not...
55 // AM_RANGE(0x0000, 0xBFFF) AM_RAM AM_BASE(ram) AM_SHARE(1)
56 // AM_RANGE(0xC000, 0xC001) AM_READWRITE(readFunc, writeFunc)
59 // Would need a pointer for 80STORE as well...
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)
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)
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)
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);
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);
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 },
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 },
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 },
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 },
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 }
198 void SetupAddressMap(void)
200 for(uint32_t i=0; i<0x10000; i++)
202 funcMapRead[i] = ReadNOP;
203 funcMapWrite[i] = WriteNOP;
211 while (memoryMap[i].type != AM_END_OF_LIST)
213 switch (memoryMap[i].type)
216 for(uint32_t j=memoryMap[i].start; j<=memoryMap[i].end; j++)
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]);
228 for(uint32_t j=memoryMap[i].start; j<=memoryMap[i].end; j++)
230 funcMapRead[j] = ReadMemory;
231 addrPtrRead[j] = memoryMap[i].memory;
232 addrOffset[j] = j - memoryMap[i].start;
237 for(uint32_t j=memoryMap[i].start; j<=memoryMap[i].end; j++)
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;
248 for(uint32_t j=memoryMap[i].start; j<=memoryMap[i].end; j++)
249 funcMapRead[j] = memoryMap[i].read;
253 for(uint32_t j=memoryMap[i].start; j<=memoryMap[i].end; j++)
254 funcMapWrite[j] = memoryMap[i].write;
258 for(uint32_t j=memoryMap[i].start; j<=memoryMap[i].end; j++)
260 funcMapRead[j] = memoryMap[i].read;
261 funcMapWrite[j] = memoryMap[i].write;
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. :-)
279 // Reset the MMU state after a power down event
281 void ResetMMUPointers(void)
285 mainMemoryTextR = (displayPage2 ? &ram2[0x0400] : &ram[0x0400]);
286 mainMemoryTextW = (displayPage2 ? &ram2[0x0400] : &ram[0x0400]);
290 mainMemoryTextR = (ramwrt ? &ram2[0x0400] : &ram[0x0400]);
291 mainMemoryTextW = (ramwrt ? &ram2[0x0400] : &ram[0x0400]);
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]);
299 slot6Memory = (slotCXROM ? &diskROM[0] : &rom[0xC600]);
300 slot3Memory = (slotC3ROM ? &rom[0] : &rom[0xC300]);
301 pageZeroMemory = (altzp ? &ram2[0x0000] : &ram[0x0000]);
307 // Built-in functions
309 uint8_t ReadNOP(uint16_t)
315 void WriteNOP(uint16_t, uint8_t)
320 uint8_t ReadMemory(uint16_t address)
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]];
329 void WriteMemory(uint16_t address, uint8_t byte)
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
334 if ((*addrPtrWrite[address]) == 0)
337 (*addrPtrWrite[address])[addrOffset[address]] = byte;
342 // The main memory access functions used by V65C02
344 uint8_t AppleReadMem(uint16_t address)
346 return (*(funcMapRead[address]))(address);
350 void AppleWriteMem(uint16_t address, uint8_t byte)
352 (*(funcMapWrite[address]))(address, byte);
357 // Actual emulated I/O functions follow
359 uint8_t ReadKeyboard(uint16_t /*addr*/)
361 return lastKeyPressed | ((uint8_t)keyDown << 7);
365 void Switch80STORE(uint16_t address, uint8_t)
367 store80Mode = (bool)(address & 0x01);
368 WriteLog("Setting 80STORE to %s...\n", (store80Mode ? "ON" : "off"));
372 mainMemoryTextR = (displayPage2 ? &ram2[0x0400] : &ram[0x0400]);
373 mainMemoryTextW = (displayPage2 ? &ram2[0x0400] : &ram[0x0400]);
377 mainMemoryTextR = (ramwrt ? &ram2[0x0400] : &ram[0x0400]);
378 mainMemoryTextW = (ramwrt ? &ram2[0x0400] : &ram[0x0400]);
383 void SwitchRAMRD(uint16_t address, uint8_t)
385 ramrd = (bool)(address & 0x01);
386 mainMemoryR = (ramrd ? &ram2[0x0200] : &ram[0x0200]);
387 mainMemoryHGRR = (ramrd ? &ram2[0x2000] : &ram[0x2000]);
392 mainMemoryTextR = (ramrd ? &ram2[0x0400] : &ram[0x0400]);
396 void SwitchRAMWRT(uint16_t address, uint8_t)
398 ramwrt = (bool)(address & 0x01);
399 mainMemoryW = (ramwrt ? &ram2[0x0200] : &ram[0x0200]);
400 mainMemoryHGRW = (ramwrt ? &ram2[0x2000] : &ram[0x2000]);
405 mainMemoryTextW = (ramwrt ? &ram2[0x0400] : &ram[0x0400]);
409 void SwitchSLOTCXROM(uint16_t address, uint8_t)
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]);
419 void SwitchALTZP(uint16_t address, uint8_t)
421 altzp = (bool)(address & 0x01);
422 pageZeroMemory = (altzp ? &ram2[0x0000] : &ram[0x0000]);
426 //extern bool dumpDis;
428 void SwitchSLOTC3ROM(uint16_t address, uint8_t)
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];
440 void Switch80COL(uint16_t address, uint8_t)
442 col80Mode = (bool)(address & 0x01);
446 void SwitchALTCHARSET(uint16_t address, uint8_t)
448 alternateCharset = (bool)(address & 0x01);
452 uint8_t ReadKeyStrobe(uint16_t)
454 uint8_t byte = lastKeyPressed | ((uint8_t)keyDown << 7);
460 uint8_t ReadBANK2(uint16_t)
462 return (lcState < 0x04 ? 0x80 : 0x00);
466 uint8_t ReadLCRAM(uint16_t)
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);
474 uint8_t ReadRAMRD(uint16_t)
476 return (uint8_t)ramrd << 7;
480 uint8_t ReadRAMWRT(uint16_t)
482 return (uint8_t)ramwrt << 7;
486 uint8_t ReadSLOTCXROM(uint16_t)
488 return (uint8_t)slotCXROM << 7;
492 uint8_t ReadALTZP(uint16_t)
494 return (uint8_t)altzp << 7;
498 uint8_t ReadSLOTC3ROM(uint16_t)
501 return (uint8_t)slotC3ROM << 7;
505 uint8_t Read80STORE(uint16_t)
507 return (uint8_t)store80Mode << 7;
511 uint8_t ReadVBL(uint16_t)
513 return (uint8_t)vbl << 7;
517 uint8_t ReadTEXT(uint16_t)
519 return (uint8_t)textMode << 7;
523 uint8_t ReadMIXED(uint16_t)
525 return (uint8_t)mixedMode << 7;
529 uint8_t ReadPAGE2(uint16_t)
531 return (uint8_t)displayPage2 << 7;
535 uint8_t ReadHIRES(uint16_t)
537 return (uint8_t)hiRes << 7;
541 uint8_t ReadALTCHARSET(uint16_t)
543 return (uint8_t)alternateCharset << 7;
547 uint8_t Read80COL(uint16_t)
549 return (uint8_t)col80Mode << 7;
553 void WriteKeyStrobe(uint16_t, uint8_t)
559 uint8_t ReadSpeaker(uint16_t)
566 void WriteSpeaker(uint16_t, uint8_t)
572 uint8_t SwitchLCR(uint16_t address)
574 lcState = address & 0x0B;
580 void SwitchLCW(uint16_t address, uint8_t)
582 lcState = address & 0x0B;
593 WriteLog("SwitchLC: Read RAM bank 2, no write\n");
595 // [R ] Read RAM bank 2; no write
596 lcBankMemoryR = (altzp ? &ram2[0xD000] : &ram[0xD000]);
598 upperMemoryR = (altzp ? &ram2[0xE000] : &ram[0xE000]);
603 WriteLog("SwitchLC: Read ROM, write bank 2\n");
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]);
613 WriteLog("SwitchLC: Read ROM, no write\n");
615 // [R ] Read ROM; no write
616 lcBankMemoryR = &rom[0xD000];
618 upperMemoryR = &rom[0xE000];
623 WriteLog("SwitchLC: Read/write bank 2\n");
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]);
632 // [R ] Read RAM bank 1; no write
633 lcBankMemoryR = (altzp ? &ram2[0xC000] : &ram[0xC000]);
635 upperMemoryR = (altzp ? &ram2[0xE000] : &ram[0xE000]);
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]);
646 // [R ] Read ROM; no write
647 lcBankMemoryR = &rom[0xD000];
649 upperMemoryR = &rom[0xE000];
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]);
663 uint8_t SwitchTEXTR(uint16_t address)
665 WriteLog("Setting TEXT to %s...\n", (address & 0x01 ? "ON" : "off"));
666 textMode = (bool)(address & 0x01);
671 void SwitchTEXTW(uint16_t address, uint8_t)
673 WriteLog("Setting TEXT to %s...\n", (address & 0x01 ? "ON" : "off"));
674 textMode = (bool)(address & 0x01);
678 uint8_t SwitchMIXEDR(uint16_t address)
680 WriteLog("Setting MIXED to %s...\n", (address & 0x01 ? "ON" : "off"));
681 mixedMode = (bool)(address & 0x01);
686 void SwitchMIXEDW(uint16_t address, uint8_t)
688 WriteLog("Setting MIXED to %s...\n", (address & 0x01 ? "ON" : "off"));
689 mixedMode = (bool)(address & 0x01);
693 uint8_t SwitchPAGE2R(uint16_t address)
695 WriteLog("Setting PAGE2 to %s...\n", (address & 0x01 ? "ON" : "off"));
696 displayPage2 = (bool)(address & 0x01);
700 mainMemoryTextR = (displayPage2 ? &ram2[0x0400] : &ram[0x0400]);
701 mainMemoryTextW = (displayPage2 ? &ram2[0x0400] : &ram[0x0400]);
708 void SwitchPAGE2W(uint16_t address, uint8_t)
710 WriteLog("Setting PAGE2 to %s...\n", (address & 0x01 ? "ON" : "off"));
711 displayPage2 = (bool)(address & 0x01);
715 mainMemoryTextR = (displayPage2 ? &ram2[0x0400] : &ram[0x0400]);
716 mainMemoryTextW = (displayPage2 ? &ram2[0x0400] : &ram[0x0400]);
721 uint8_t SwitchHIRESR(uint16_t address)
723 WriteLog("Setting HIRES to %s...\n", (address & 0x01 ? "ON" : "off"));
724 hiRes = (bool)(address & 0x01);
729 void SwitchHIRESW(uint16_t address, uint8_t)
731 WriteLog("Setting HIRES to %s...\n", (address & 0x01 ? "ON" : "off"));
732 hiRes = (bool)(address & 0x01);
736 uint8_t SwitchDHIRESR(uint16_t address)
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
741 dhires = !((bool)(address & 0x01));
747 void SwitchDHIRESW(uint16_t address, uint8_t)
749 WriteLog("Setting DHIRES to %s (ioudis = %s)...\n", ((address & 0x01) ^ 0x01 ? "ON" : "off"), (ioudis ? "ON" : "off"));
751 dhires = !((bool)(address & 0x01));
755 void SwitchIOUDIS(uint16_t address, uint8_t)
757 ioudis = !((bool)(address & 0x01));
761 uint8_t Slot6R(uint16_t address)
763 //WriteLog("Slot6R: address = %X\n", address & 0x0F);
764 // HandleSlot6(address, 0);
766 uint8_t state = address & 0x0F;
778 floppyDrive.ControlStepper(state);
782 floppyDrive.ControlMotor(state & 0x01);
786 floppyDrive.DriveEnable(state & 0x01);
789 return floppyDrive.ReadWrite();
792 return floppyDrive.GetLatchValue();
795 floppyDrive.SetReadMode();
798 floppyDrive.SetWriteMode();
806 void Slot6W(uint16_t address, uint8_t byte)
808 //WriteLog("Slot6W: address = %X, byte= %X\n", address & 0x0F, byte);
809 // HandleSlot6(address, byte);
810 uint8_t state = address & 0x0F;
822 floppyDrive.ControlStepper(state);
826 floppyDrive.ControlMotor(state & 0x01);
830 floppyDrive.DriveEnable(state & 0x01);
833 floppyDrive.ReadWrite();
836 floppyDrive.SetLatchValue(byte);
839 floppyDrive.SetReadMode();
842 floppyDrive.SetWriteMode();
848 void HandleSlot6(uint16_t address, uint8_t byte)
853 uint8_t ReadButton0(uint16_t)
855 return (uint8_t)openAppleDown << 7;
859 uint8_t ReadButton1(uint16_t)
861 return (uint8_t)closedAppleDown << 7;
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
869 // NB: This is really paddles 0-3, not just 0 :-P
870 uint8_t ReadPaddle0(uint16_t)
876 uint8_t ReadIOUDIS(uint16_t)
878 return (uint8_t)ioudis << 7;
882 uint8_t ReadDHIRES(uint16_t)
884 return (uint8_t)dhires << 7;