diff --git a/ROMs/apple2.rom b/ROMs/apple2.rom old mode 100755 new mode 100644 diff --git a/ROMs/apple2c.rom b/ROMs/apple2c.rom old mode 100755 new mode 100644 diff --git a/ROMs/apple2e-enhanced.rom b/ROMs/apple2e-enhanced.rom new file mode 100644 index 0000000..65bb648 Binary files /dev/null and b/ROMs/apple2e-enhanced.rom differ diff --git a/ROMs/apple2e.rom b/ROMs/apple2e.rom old mode 100755 new mode 100644 index 65bb648..916b318 Binary files a/ROMs/apple2e.rom and b/ROMs/apple2e.rom differ diff --git a/apple2.cfg b/apple2.cfg index f672918..3aa30c3 100755 --- a/apple2.cfg +++ b/apple2.cfg @@ -4,7 +4,7 @@ # Apple ROM paths -BIOSROM = ./ROMs/apple2.rom +BIOSROM = ./ROMs/apple2e-enhanced.rom diskROM = ./ROMs/disk.rom ROMs = ./ROMs @@ -29,8 +29,8 @@ autoSaveState = 1 #floppyImage2 = ./disks/bt3_character_fixed.dsk # Yes #floppyImage1 = ./disks/Sabotage.dsk -# ??? (//c or //e w/128K required) -#floppyImage1 = ./disks/airheart.dsk +# ??? (//c or //e w/128K required) (dumps to monitor) +floppyImage1 = ./disks/airheart.dsk # Yes #floppyImage1 = ./disks/drol.dsk # Yes @@ -51,6 +51,7 @@ autoSaveState = 1 #floppyImage2 = ./disks/MoebiusIIB.dsk # Yes #floppyImage1 = ./disks/wind_walker_1.dsk +#floppyImage2 = ./disks/wind_walker_2.dsk # Yes #floppyImage1 = ./disks/dino_eggs.dsk # ??? 1, yes; 2, no @@ -74,7 +75,7 @@ autoSaveState = 1 # Yes #floppyImage1 = ./disks/lode_runner.dsk # Yes -floppyImage1 = ./disks/championship_lode_runner.dsk +#floppyImage1 = ./disks/championship_lode_runner.dsk # OpenGL filtering type: 1 - blurry, 0 - sharp diff --git a/src/apple2.cpp b/src/apple2.cpp index 8b6a36f..572d758 100755 --- a/src/apple2.cpp +++ b/src/apple2.cpp @@ -58,17 +58,18 @@ #define THREADED_65C02 #define CPU_THREAD_OVERFLOW_COMPENSATION -//#define DEBUG_LC +#define DEBUG_LC //#define CPU_CLOCK_CHECKING -#define THREAD_DEBUGGING +//#define THREAD_DEBUGGING +#define SOFT_SWITCH_DEBUGGING // Global variables uint8_t ram[0x10000], rom[0x10000]; // RAM & ROM spaces -uint8_t ram2[0x10000]; +uint8_t ram2[0x10000]; // Auxillary RAM uint8_t diskRom[0x100]; // Disk ROM space V65C02REGS mainCPU; // v65C02 execution context -uint8_t appleType = APPLE_TYPE_II; +uint8_t appleType = APPLE_TYPE_IIE; FloppyDrive floppyDrive; // Local variables @@ -77,6 +78,15 @@ static uint8_t lastKeyPressed = 0; static bool keyDown = false; static bool openAppleDown = false; static bool closedAppleDown = false; +static bool store80Mode = false; +static bool vbl = false; +static bool slotCXROM = false; +static bool slotC3ROM = false; +static bool ramrd = false; +static bool ramwrt = false; +static bool altzp = false; +static bool ioudis = true; +bool dhires = false; //static FloppyDrive floppyDrive; @@ -114,6 +124,8 @@ static bool cpuFinished = false; static bool cpuSleep = false; +// NB: Apple //e Manual sez 6502 is running @ 1,022,727 Hz + // Let's try a thread... /* Here's how it works: Execute 1 frame's worth, then sleep. @@ -188,7 +200,7 @@ WriteLog("CPU: Execute65C02(&mainCPU, cycles);\n"); } #endif -WriteLog("CPUThread: Supposedly end of frame...\n"); +//WriteLog("CPUThread: Supposedly end of frame...\n"); #ifdef THREAD_DEBUGGING WriteLog("CPU: SDL_mutexP(cpuMutex);\n"); @@ -288,7 +300,8 @@ if (addr >= 0xC080 && addr <= 0xC08F) { return lastKeyPressed | (keyDown ? 0x80 : 0x00); } - else if ((addr & 0xFFF0) == 0xC010) // Read $C010-$C01F +// else if ((addr & 0xFFF8) == 0xC010) // Read $C010-$C01F + else if (addr == 0xC010) { //This is bogus: keyDown is set to false, so return val NEVER is set... //Fixed... @@ -297,6 +310,112 @@ if (addr >= 0xC080 && addr <= 0xC08F) keyDown = false; return retVal; } + // These are //e locations + else if (addr == 0xC011) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("RDBANK2 (read)\n"); +#endif + return (visibleBank == LC_BANK_2 ? 0x80 : 0x00); + } + else if (addr == 0xC012) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("RDLCRAM (read)\n"); +#endif + return (readRAM ? 0x80 : 0x00); + } + else if (addr == 0xC013) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("RAMRD (read)\n"); +#endif + return (ramrd ? 0x80 : 0x00); + } + else if (addr == 0xC014) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("RAMWRT (read)\n"); +#endif + return (ramwrt ? 0x80 : 0x00); + } + else if (addr == 0xC015) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("SLOTCXROM (read)\n"); +#endif + return (slotCXROM ? 0x80 : 0x00); + } + else if (addr == 0xC016) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("ALTZP (read)\n"); +#endif + return (altzp ? 0x80 : 0x00); + } + else if (addr == 0xC017) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("SLOTC3ROM (read)\n"); +#endif + return (slotC3ROM ? 0x80 : 0x00); + } + else if (addr == 0xC018) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("80STORE (read)\n"); +#endif + return (store80Mode ? 0x80 : 0x00); + } + else if (addr == 0xC019) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("VBL (read)\n"); +#endif + return (vbl ? 0x80 : 0x00); + } + else if (addr == 0xC01A) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("TEXT (read)\n"); +#endif + return (textMode ? 0x80 : 0x00); + } + else if (addr == 0xC01B) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("MIXED (read)\n"); +#endif + return (mixedMode ? 0x80 : 0x00); + } + else if (addr == 0xC01C) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("PAGE2 (read)\n"); +#endif + return (displayPage2 ? 0x80 : 0x00); + } + else if (addr == 0xC01D) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("HIRES (read)\n"); +#endif + return (hiRes ? 0x80 : 0x00); + } + else if (addr == 0xC01E) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("ALTCHARSET (read)\n"); +#endif + return (alternateCharset ? 0x80 : 0x00); + } + else if (addr == 0xC01F) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("80COL (read)\n"); +#endif + return (col80Mode ? 0x80 : 0x00); + } else if ((addr & 0xFFF0) == 0xC030) // Read $C030-$C03F { /* @@ -322,36 +441,76 @@ deltaT to zero. In the sound IRQ, if deltaT > buffer size, then subtract buffer } else if (addr == 0xC050) // Read $C050 { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("TEXT off (read)\n"); +#endif textMode = false; } else if (addr == 0xC051) // Read $C051 { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("TEXT on (read)\n"); +#endif textMode = true; } else if (addr == 0xC052) // Read $C052 { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("MIXED off (read)\n"); +#endif mixedMode = false; } else if (addr == 0xC053) // Read $C053 { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("MIXED on (read)\n"); +#endif mixedMode = true; } else if (addr == 0xC054) // Read $C054 { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("PAGE2 off (read)\n"); +#endif displayPage2 = false; } else if (addr == 0xC055) // Read $C055 { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("PAGE2 on (read)\n"); +#endif displayPage2 = true; } else if (addr == 0xC056) // Read $C056 { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("HIRES off (read)\n"); +#endif hiRes = false; } else if (addr == 0xC057) // Read $C057 { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("HIRES on (read)\n"); +#endif hiRes = true; } + else if (addr == 0xC05E) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("DHIRES on (read)\n"); +#endif + if (ioudis) + dhires = true; + } + else if (addr == 0xC05F) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("DHIRES off (read)\n"); +#endif + if (ioudis) + dhires = false; + } else if (addr == 0xC061) // Read $C061 { // Open Apple key (or push button 0) @@ -362,6 +521,40 @@ deltaT to zero. In the sound IRQ, if deltaT > buffer size, then subtract buffer // Open Apple key (or push button 0) return (closedAppleDown ? 0x80 : 0x00); } + // The way the paddles work is that a strobe is written (or read) to $C070, + // then software counts down the time that it takes for the paddle outputs + // to have bit 7 return to 0. If there are no paddles connected, bit 7 + // stays at 1. + else if (addr == 0xC064) // Paddles 0-3 + { + return 0xFF; + } + else if (addr == 0xC065) + { + return 0xFF; + } + else if (addr == 0xC066) + { + return 0xFF; + } + else if (addr == 0xC067) + { + return 0xFF; + } + else if (addr == 0xC07E) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("IOUDIS (read)\n"); +#endif + return (ioudis ? 0x80 : 0x00); + } + else if (addr == 0xC07F) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("DHIRES (read)\n"); +#endif + return (dhires ? 0x80 : 0x00); + } //Note that this is a kludge: The $D000-$DFFF 4K space is shared (since $C000-$CFFF is //memory mapped) between TWO banks, and that that $E000-$FFFF RAM space is a single bank. @@ -520,62 +713,107 @@ if (addr >= 0xD000 && addr <= 0xD00F) showpath = true; #endif //This sux... - if (addr >= 0xC100 && addr <= 0xCFFF) // The $C000-$CFFF block is *never* RAM -#ifdef LC_DEBUGGING + if (addr >= 0xC100 && addr <= 0xC7FF) // The $C000-$CFFF block is *never* RAM { -#endif - b = rom[addr]; +// Looks like the ][e ref manual got this one wrong: slotCXROM set should mean +// use internal ROM, NOT slot ROM. :-/ +// (fixed now, by setting the switch correctly in the write mem section :-P) + if (!slotCXROM) +// if (slotCXROM) + b = rom[addr]; + else + { + if (addr >= 0xC100 && addr <= 0xC1FF) + b = parallelROM[addr & 0xFF]; + else if (addr >= 0xC600 && addr <= 0xC6FF) + b = diskROM[addr & 0xFF]; + else if (addr >= 0xC300 && addr <= 0xC3FF && !slotC3ROM) + b = rom[addr]; + else + b = 0xFF; +// b = rom[addr]; + } #ifdef LC_DEBUGGING if (showpath) WriteLog("b is from $C100-$CFFF block...\n"); - } #endif + } + else if (addr >= 0xC800 && addr <= 0xCFFF) // 2K peripheral or OS ROM + { + b = rom[addr]; + } else if (addr >= 0xD000) { if (readRAM) { if (addr <= 0xDFFF && visibleBank == LC_BANK_1) #ifdef LC_DEBUGGING - { + { #endif b = ram[addr - 0x1000]; +// b = (ramrd ? ram2[addr - 0x1000] : ram[addr - 0x1000]); #ifdef LC_DEBUGGING if (showpath) WriteLog("b is from LC bank #1 (ram[addr - 0x1000])...\n"); - } + } #endif else #ifdef LC_DEBUGGING - { + { #endif b = ram[addr]; +// b = (ramrd ? ram2[addr] : ram[addr]); #ifdef LC_DEBUGGING if (showpath) WriteLog("b is from LC bank #2 (ram[addr])...\n"); - } + } #endif } else #ifdef LC_DEBUGGING - { + { #endif b = rom[addr]; #ifdef LC_DEBUGGING if (showpath) WriteLog("b is from LC ROM (rom[addr])...\n"); - } + } #endif } else -#ifdef LC_DEBUGGING { +#if 1 + // Check for 80STORE mode (STORE80 takes precedence over RAMRD/WRT)... + if ((((addr >= 0x0400) && (addr <= 0x07FF)) || ((addr >= 0x2000) && (addr <= 0x3FFF))) && store80Mode) + { + if (displayPage2) + b = ram2[addr]; + else + b = ram[addr]; + + return b; + } + + // Finally, check for auxillary/altzp write switches #endif - b = ram[addr]; + if (addr < 0x0200) + b = (altzp ? ram2[addr] : ram[addr]); + else + b = (ramrd ? ram2[addr] : ram[addr]); +// if (ramrd) +// b = ram2[addr]; +// else +// { +// if (altzp) +// b = ram2[addr]; +// else +// b = ram[addr]; +// } #ifdef LC_DEBUGGING if (showpath) WriteLog("b is from ram[addr]...\n"); - } #endif + } #ifdef LC_DEBUGGING if (addr >= 0xD000 && addr <= 0xD00F) @@ -687,12 +925,117 @@ SET80VID = $C00D ;enable 80-column display mode (WR-only) CLRALTCH = $C00E ;use main char set- norm LC, Flash UC (WR-only) SETALTCH = $C00F ;use alt char set- norm inverse, LC; no Flash (WR-only) */ - if (addr == 0xC00E) + if (addr == 0xC000) { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("80STORE off (write)\n"); +#endif + store80Mode = false; + } + else if (addr == 0xC001) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("80STORE on (write)\n"); +#endif + store80Mode = true; + } + else if (addr == 0xC002) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("RAMRD off (write)\n"); +#endif + ramrd = false; + } + else if (addr == 0xC003) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("RAMRD on (write)\n"); +#endif + ramrd = true; + } + else if (addr == 0xC004) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("RAMWRT off (write)\n"); +#endif + ramwrt = false; + } + else if (addr == 0xC005) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("RAMWRT on (write)\n"); +#endif + ramwrt = true; + } + else if (addr == 0xC006) + { + // This is the only soft switch that breaks the usual convention. +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("SLOTCXROM on (write)\n"); +#endif + slotCXROM = true; + } + else if (addr == 0xC007) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("SLOTCXROM off (write)\n"); +#endif + slotCXROM = false; + } + else if (addr == 0xC008) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("ALTZP off (write)\n"); +#endif + altzp = false; + } + else if (addr == 0xC009) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("ALTZP on (write)\n"); +#endif + altzp = true; + } + else if (addr == 0xC00A) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("SLOTC3ROM off (write)\n"); +#endif + slotC3ROM = false; + } + else if (addr == 0xC00B) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("SLOTC3ROM on (write)\n"); +#endif + slotC3ROM = true; + } + else if (addr == 0xC00C) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("80COL off (write)\n"); +#endif + col80Mode = false; + } + else if (addr == 0xC00D) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("80COL on (write)\n"); +#endif + col80Mode = true; + } + else if (addr == 0xC00E) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("ALTCHARSET off (write)\n"); +#endif alternateCharset = false; } else if (addr == 0xC00F) { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("ALTCHARSET on (write)\n"); +#endif alternateCharset = true; } else if ((addr & 0xFFF0) == 0xC010) // Keyboard strobe @@ -704,36 +1047,95 @@ SETALTCH = $C00F ;use alt char set- norm inverse, LC; no Flash (WR-only) } else if (addr == 0xC050) { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("TEXT off (write)\n"); +#endif textMode = false; } else if (addr == 0xC051) { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("TEXT on (write)\n"); +#endif textMode = true; } else if (addr == 0xC052) { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("MIXED off (write)\n"); +#endif mixedMode = false; } else if (addr == 0xC053) { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("MIXED on (write)\n"); +#endif mixedMode = true; } else if (addr == 0xC054) { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("PAGE2 off (write)\n"); +#endif displayPage2 = false; } else if (addr == 0xC055) { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("PAGE2 on (write)\n"); +#endif displayPage2 = true; } else if (addr == 0xC056) { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("HIRES off (write)\n"); +#endif hiRes = false; } else if (addr == 0xC057) { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("HIRES on (write)\n"); +#endif hiRes = true; } + else if (addr == 0xC05E) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("DHIRES on (write)\n"); +#endif + if (ioudis) + dhires = true; + +//static int goDumpDis = 0; +//goDumpDis++; +//if (goDumpDis == 2) +// dumpDis = true; + } + else if (addr == 0xC05F) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("DHIRES off (write)\n"); +#endif + if (ioudis) + dhires = false; + } + else if (addr == 0xC07E) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("IOUDIS on (write)\n"); +#endif + ioudis = true; + } + else if (addr == 0xC07F) + { +#ifdef SOFT_SWITCH_DEBUGGING +WriteLog("IOUDIS off (write)\n"); +#endif + ioudis = false; + } else if ((addr & 0xFFFB) == 0xC080) { #ifdef DEBUG_LC @@ -861,16 +1263,70 @@ if (addr >= 0xD000 && addr <= 0xD00F) { if (writeRAM) { +#if 1 if (addr <= 0xDFFF && visibleBank == LC_BANK_1) ram[addr - 0x1000] = b; else ram[addr] = b; +#else + if (addr <= 0xDFFF && visibleBank == LC_BANK_1) + { + if (ramwrt) + ram2[addr - 0x1000] = b; + else + ram[addr - 0x1000] = b; + } + else + { + if (ramwrt) + ram2[addr] = b; + else + ram[addr] = b; + } +#endif } return; } - ram[addr] = b; + // Check for 80STORE mode (STORE80 takes precedence over RAMRD/WRT)... + if ((((addr >= 0x0400) && (addr <= 0x07FF)) || ((addr >= 0x2000) && (addr <= 0x3FFF))) && store80Mode) + { + if (displayPage2) + ram2[addr] = b; + else + ram[addr] = b; + + return; + } + + // Finally, check for auxillary/altzp write switches +#if 0 + if (ramwrt) + ram2[addr] = b; + else + { + if (altzp) + ram2[addr] = b; + else + ram[addr] = b; + } +#else + if (addr < 0x0200) + { + if (altzp) + ram2[addr] = b; + else + ram[addr] = b; + } + else + { + if (ramwrt) + ram2[addr] = b; + else + ram[addr] = b; + } +#endif } @@ -928,7 +1384,9 @@ int main(int /*argc*/, char * /*argv*/[]) mainCPU.WrMem = WrMem; mainCPU.cpuFlags |= V65C02_ASSERT_LINE_RESET; - if (!LoadImg(settings.BIOSPath, rom + 0xD000, 0x3000)) +// alternateCharset = true; +// if (!LoadImg(settings.BIOSPath, rom + 0xD000, 0x3000)) + if (!LoadImg(settings.BIOSPath, rom + 0xC000, 0x4000)) { WriteLog("Could not open file '%s'!\n", settings.BIOSPath); return -1; @@ -948,7 +1406,7 @@ int main(int /*argc*/, char * /*argv*/[]) //Kill the DOS ROM in slot 6 for now... //not - memcpy(rom + 0xC600, diskROM, 0x100); +// memcpy(rom + 0xC600, diskROM, 0x100); // memcpy(rom + 0xC700, diskROM, 0x100); // Slot 7??? WriteLog("About to initialize video...\n"); @@ -1156,7 +1614,7 @@ Z $DA $9A $DA $9A ESC $9B $9B $9B $9B No xlation */ -static uint64_t lastCPUCycles = 0; +//static uint64_t lastCPUCycles = 0; static uint32_t frameCount = 0; static void FrameCallback(void) { @@ -1179,8 +1637,8 @@ static void FrameCallback(void) //kludge: should have a caps lock thingy here... //or all uppercase for ][+... - if (lastKeyPressed >= 'a' && lastKeyPressed <='z') - lastKeyPressed &= 0xDF; // Convert to upper case... +// if (lastKeyPressed >= 'a' && lastKeyPressed <='z') +// lastKeyPressed &= 0xDF; // Convert to upper case... break; case SDL_KEYDOWN: @@ -1197,10 +1655,16 @@ static void FrameCallback(void) lastKeyPressed = 0x15, keyDown = true; else if (event.key.keysym.sym == SDLK_LEFT) lastKeyPressed = 0x08, keyDown = true; + else if (event.key.keysym.sym == SDLK_UP) + lastKeyPressed = 0x0B, keyDown = true; + else if (event.key.keysym.sym == SDLK_DOWN) + lastKeyPressed = 0x0A, keyDown = true; else if (event.key.keysym.sym == SDLK_RETURN) lastKeyPressed = 0x0D, keyDown = true; else if (event.key.keysym.sym == SDLK_ESCAPE) lastKeyPressed = 0x1B, keyDown = true; + else if (event.key.keysym.sym == SDLK_BACKSPACE) + lastKeyPressed = 0x7F, keyDown = true; // Fix CTRL+key combo... if (event.key.keysym.mod & KMOD_CTRL) @@ -1337,7 +1801,7 @@ if (counter == 60) SDL_Delay(1); // Wait for next frame... startTicks = SDL_GetTicks(); -#if 1 +#if 0 uint64_t cpuCycles = GetCurrentV65C02Clock(); uint32_t cyclesBurned = (uint32_t)(cpuCycles - lastCPUCycles); WriteLog("FrameCallback: used %i cycles\n", cyclesBurned); diff --git a/src/apple2.h b/src/apple2.h index 958bb0b..7696c5a 100755 --- a/src/apple2.h +++ b/src/apple2.h @@ -10,5 +10,7 @@ enum { APPLE_TYPE_II, APPLE_TYPE_IIE, APPLE_TYPE_IIC }; // Global variables (exported) extern uint8_t ram[0x10000], rom[0x10000]; // RAM & ROM pointers +extern uint8_t ram2[0x10000]; // Auxillary RAM extern uint8_t appleType; extern FloppyDrive floppyDrive; +extern bool dhires; diff --git a/src/applevideo.cpp b/src/applevideo.cpp index 919776f..d3060bf 100755 --- a/src/applevideo.cpp +++ b/src/applevideo.cpp @@ -62,12 +62,13 @@ // Global variables -bool flash; -bool textMode; -bool mixedMode; -bool displayPage2; -bool hiRes; -bool alternateCharset; +bool flash = false; +bool textMode = true; +bool mixedMode = false; +bool displayPage2 = false; +bool hiRes = false; +bool alternateCharset = false; +bool col80Mode = false; //void SpawnMessage(const char * text, ...); // Local variables @@ -228,6 +229,7 @@ uint16_t appleHiresToMono[0x200] = { //static uint8_t blurTable[0x800][8]; // Color TV blur table static uint8_t blurTable[0x80][8]; // Color TV blur table +static uint8_t mirrorTable[0x100]; static uint32_t * palette = (uint32_t *)altColors; enum { ST_FIRST_ENTRY = 0, ST_COLOR_TV = 0, ST_WHITE_MONO, ST_GREEN_MONO, ST_LAST_ENTRY }; static uint8_t screenType = ST_COLOR_TV; @@ -235,9 +237,12 @@ static uint8_t screenType = ST_COLOR_TV; // Local functions static void Render40ColumnTextLine(uint8_t line); +static void Render80ColumnTextLine(uint8_t line); static void Render40ColumnText(void); +static void Render80ColumnText(void); static void RenderLoRes(uint16_t toLine = 24); static void RenderHiRes(uint16_t toLine = 192); +static void RenderDHiRes(uint16_t toLine = 192); void SetupBlurTable(void) @@ -294,6 +299,18 @@ void SetupBlurTable(void) } } #endif + + for(int i=0; i<256; i++) + { + mirrorTable[i] = ((i & 0x01) << 7) + | ((i & 0x02) << 5) + | ((i & 0x04) << 3) + | ((i & 0x08) << 1) + | ((i & 0x10) >> 1) + | ((i & 0x20) >> 3) + | ((i & 0x40) >> 5) + | ((i & 0x80) >> 7); + } } @@ -425,10 +442,9 @@ static void Render40ColumnTextLine(uint8_t line) { uint32_t pixel = 0xFF000000; - if (!alternateCharset) + if (alternateCharset) { if (textChar[((chr & 0x3F) * 56) + cx + (cy * 7)]) -// pixel = 0xFFFFFFFF; pixel = pixelOn; if (chr < 0x80) @@ -440,12 +456,9 @@ static void Render40ColumnTextLine(uint8_t line) else { if (textChar2e[(chr * 56) + cx + (cy * 7)]) -// pixel = 0xFFFFFFFF; pixel = pixelOn; } -// scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8) + (cx * 2) + 0 + (cy * VIRTUAL_SCREEN_WIDTH)] = pixel; -// scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8) + (cx * 2) + 1 + (cy * VIRTUAL_SCREEN_WIDTH)] = pixel; scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8 * 2) + (cx * 2) + 0 + (cy * VIRTUAL_SCREEN_WIDTH * 2)] = pixel; scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8 * 2) + (cx * 2) + 1 + (cy * VIRTUAL_SCREEN_WIDTH * 2)] = pixel; @@ -454,8 +467,8 @@ static void Render40ColumnTextLine(uint8_t line) pixel = 0xFF000000; { - scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8 * 2) + (cx * 2) + 0 + (((cy * 2) + 1) * VIRTUAL_SCREEN_WIDTH)] = pixel; - scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8 * 2) + (cx * 2) + 1 + (((cy * 2) + 1) * VIRTUAL_SCREEN_WIDTH)] = pixel; + scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8 * 2) + (cx * 2) + 0 + (((cy * 2) + 1) * VIRTUAL_SCREEN_WIDTH)] = pixel; + scrBuffer[(x * 7 * 2) + (line * VIRTUAL_SCREEN_WIDTH * 8 * 2) + (cx * 2) + 1 + (((cy * 2) + 1) * VIRTUAL_SCREEN_WIDTH)] = pixel; } } } @@ -463,6 +476,65 @@ static void Render40ColumnTextLine(uint8_t line) } +static void Render80ColumnTextLine(uint8_t line) +{ + uint32_t pixelOn = (screenType == ST_GREEN_MONO ? 0xFF61FF61 : 0xFFFFFFFF); + + for(int x=0; x<80; x++) + { +#if 0 +// This is wrong; it should grab from the alt bank if Page2 is set, not main RAM @ $0 + uint8_t chr = ram[lineAddrLoRes[line] + (displayPage2 ? 0x0400 : 0x0000) + x]; + + if (x > 39) + chr = ram2[lineAddrLoRes[line] + (displayPage2 ? 0x0400 : 0x0000) + x - 40]; +#else + uint8_t chr; + + if (x & 0x01) + chr = ram[lineAddrLoRes[line] + (x >> 1)]; + else + chr = ram2[lineAddrLoRes[line] + (x >> 1)]; +#endif + + // Render character at (x, y) + + for(int cy=0; cy<8; cy++) + { + for(int cx=0; cx<7; cx++) + { + uint32_t pixel = 0xFF000000; + + if (alternateCharset) + { + if (textChar[((chr & 0x3F) * 56) + cx + (cy * 7)]) + pixel = pixelOn; + + if (chr < 0x80) + pixel = pixel ^ (screenType == ST_GREEN_MONO ? 0x0061FF61 : 0x00FFFFFF); + + if ((chr & 0xC0) == 0x40 && flash) + pixel = 0xFF000000; + } + else + { + if (textChar2e[(chr * 56) + cx + (cy * 7)]) + pixel = pixelOn; + } + + scrBuffer[(x * 7) + (line * VIRTUAL_SCREEN_WIDTH * 8 * 2) + cx + (cy * 2 * VIRTUAL_SCREEN_WIDTH)] = pixel; + + // QnD method to get blank alternate lines in text mode + if (screenType == ST_GREEN_MONO) + pixel = 0xFF000000; + + scrBuffer[(x * 7) + (line * VIRTUAL_SCREEN_WIDTH * 8 * 2) + cx + (((cy * 2) + 1) * VIRTUAL_SCREEN_WIDTH)] = pixel; + } + } + } +} + + static void Render40ColumnText(void) { for(uint8_t line=0; line<24; line++) @@ -470,6 +542,13 @@ static void Render40ColumnText(void) } +static void Render80ColumnText(void) +{ + for(uint8_t line=0; line<24; line++) + Render80ColumnTextLine(line); +} + + static void RenderLoRes(uint16_t toLine/*= 24*/) { // NOTE: The green mono rendering doesn't skip every other line... !!! FIX !!! @@ -716,6 +795,75 @@ static void RenderHiRes(uint16_t toLine/*= 192*/) } +static void RenderDHiRes(uint16_t toLine/*= 192*/) +{ +// NOTE: Not endian safe. !!! FIX !!! [DONE] +#if 0 + uint32_t pixelOn = (screenType == ST_WHITE_MONO ? 0xFFFFFFFF : 0xFF61FF61); +#else +// Now it is. Now roll this fix into all the other places... !!! FIX !!! +// The colors are set in the 8-bit array as R G B A + uint8_t monoColors[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0x61, 0xFF, 0x61, 0xFF }; + uint32_t * colorPtr = (uint32_t *)monoColors; + uint32_t pixelOn = (screenType == ST_WHITE_MONO ? colorPtr[0] : colorPtr[1]); +#endif + + for(uint16_t y=0; y> 1); + + // We now have 28 pixels (expanded from 14) in word: mask is $0F FF FF FF + // 0ppp 1111 1111 1111 1111 1111 1111 1111 + // 31 27 23 19 15 11 7 3 0 + + if (screenType == ST_COLOR_TV) + { + for(uint8_t i=0; i<7; i++) + { + uint8_t bitPat = (pixels & 0x7F000000) >> 24; + pixels <<= 4; + + for(uint8_t j=0; j<4; j++) + { + uint8_t color = blurTable[bitPat][j]; + scrBuffer[(x * 14) + (i * 4) + j + (((y * 2) + 0) * VIRTUAL_SCREEN_WIDTH)] = palette[color]; + scrBuffer[(x * 14) + (i * 4) + j + (((y * 2) + 1) * VIRTUAL_SCREEN_WIDTH)] = palette[color]; + } + } + + previous3bits = pixels & 0x70000000; + } + else + { + for(int j=0; j<28; j++) + { + scrBuffer[(x * 14) + j + (((y * 2) + 0) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000); + + if (screenType == ST_GREEN_MONO) + pixels &= 0x07FFFFFF; + + scrBuffer[(x * 14) + j + (((y * 2) + 1) * VIRTUAL_SCREEN_WIDTH)] = (pixels & 0x08000000 ? pixelOn : 0xFF000000); + pixels <<= 1; + } + } + } + } +} + + void RenderVideoFrame(void) { //temp... @@ -726,7 +874,10 @@ return;//*/ if (textMode) { // There's prolly more to it than this (like 80 column text), but this'll have to do for now... - Render40ColumnText(); + if (!col80Mode) + Render40ColumnText(); + else + Render80ColumnText(); } else { @@ -751,7 +902,9 @@ return;//*/ } else { - if (hiRes) + if (dhires) + RenderDHiRes(); + else if (hiRes) RenderHiRes(); else RenderLoRes(); diff --git a/src/applevideo.h b/src/applevideo.h index fcb2cac..e0707ac 100755 --- a/src/applevideo.h +++ b/src/applevideo.h @@ -13,6 +13,7 @@ extern bool mixedMode; extern bool displayPage2; extern bool hiRes; extern bool alternateCharset; +extern bool col80Mode; // Functions (exported) diff --git a/src/firmware.h b/src/firmware.h index d27fcc8..63cc197 100755 --- a/src/firmware.h +++ b/src/firmware.h @@ -40,6 +40,25 @@ char hdROM[0x100] = { // Loads at $C700 (slot 7) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x7F, 0xD7, 0x46 }; +char parallelROM[0x100] = { + 0x18, 0xB0, 0x38, 0x48, 0x8A, 0x48, 0x98, 0x48, 0x08, 0x78, 0x20, 0x58, 0xFF, 0xBA, 0x68, 0x68, + 0x68, 0x68, 0xA8, 0xCA, 0x9A, 0x68, 0x28, 0xAA, 0x90, 0x38, 0xBD, 0xB8, 0x05, 0x10, 0x19, 0x98, + 0x29, 0x7F, 0x49, 0x30, 0xC9, 0x0A, 0x90, 0x3B, 0xC9, 0x78, 0xB0, 0x29, 0x49, 0x3D, 0xF0, 0x21, + 0x98, 0x29, 0x9F, 0x9D, 0x38, 0x06, 0x90, 0x7E, 0xBD, 0xB8, 0x06, 0x30, 0x14, 0xA5, 0x24, 0xDD, + 0x38, 0x07, 0xB0, 0x0D, 0xC9, 0x11, 0xB0, 0x09, 0x09, 0xF0, 0x3D, 0x38, 0x07, 0x65, 0x24, 0x85, + 0x24, 0x4A, 0x38, 0xB0, 0x6D, 0x18, 0x6A, 0x3D, 0xB8, 0x06, 0x90, 0x02, 0x49, 0x81, 0x9D, 0xB8, + 0x06, 0xD0, 0x53, 0xA0, 0x0A, 0x7D, 0x38, 0x05, 0x88, 0xD0, 0xFA, 0x9D, 0xB8, 0x04, 0x9D, 0x38, + 0x05, 0x38, 0xB0, 0x43, 0xC5, 0x24, 0x90, 0x3A, 0x68, 0xA8, 0x68, 0xAA, 0x68, 0x4C, 0xF0, 0xFD, + 0x90, 0xFE, 0xB0, 0xFE, 0x99, 0x80, 0xC0, 0x90, 0x37, 0x49, 0x07, 0xA8, 0x49, 0x0A, 0x0A, 0xD0, + 0x06, 0xB8, 0x85, 0x24, 0x9D, 0x38, 0x07, 0xBD, 0xB8, 0x06, 0x4A, 0x70, 0x02, 0xB0, 0x23, 0x0A, + 0x0A, 0xA9, 0x27, 0xB0, 0xCF, 0xBD, 0x38, 0x07, 0xFD, 0xB8, 0x04, 0xC9, 0xF8, 0x90, 0x03, 0x69, + 0x27, 0xAC, 0xA9, 0x00, 0x85, 0x24, 0x18, 0x7E, 0xB8, 0x05, 0x68, 0xA8, 0x68, 0xAA, 0x68, 0x60, + 0x90, 0x27, 0xB0, 0x00, 0x10, 0x11, 0xA9, 0x89, 0x9D, 0x38, 0x06, 0x9D, 0xB8, 0x06, 0xA9, 0x28, + 0x9D, 0xB8, 0x04, 0xA9, 0x02, 0x85, 0x36, 0x98, 0x5D, 0x38, 0x06, 0x0A, 0xF0, 0x90, 0x5E, 0xB8, + 0x05, 0x98, 0x48, 0x8A, 0x0A, 0x0A, 0x0A, 0x0A, 0xA8, 0xBD, 0x38, 0x07, 0xC5, 0x24, 0x68, 0xB0, + 0x05, 0x48, 0x29, 0x80, 0x09, 0x20, 0x2C, 0x58, 0xFF, 0xF0, 0x03, 0xFE, 0x38, 0x07, 0x70, 0x84 +}; + // Various firmware from the IIe ROM file... //Not sure what the heck this is... diff --git a/src/sound.cpp b/src/sound.cpp index 0d794c9..22a027d 100755 --- a/src/sound.cpp +++ b/src/sound.cpp @@ -162,7 +162,7 @@ static void SDLSoundCallback(void * /*userdata*/, Uint8 * buffer8, int length8) // Let's try using a mutex for shared resource consumption... //Actually, I think Lock/UnlockAudio() does this already... -WriteLog("SDLSoundCallback: soundBufferPos = %i\n", soundBufferPos); +//WriteLog("SDLSoundCallback: soundBufferPos = %i\n", soundBufferPos); SDL_mutexP(mutex2); // Recast this as a 16-bit type... diff --git a/src/v65c02.cpp b/src/v65c02.cpp index 7f86895..e10006c 100755 --- a/src/v65c02.cpp +++ b/src/v65c02.cpp @@ -2844,8 +2844,14 @@ FBEF: 60 602 RTS2B RTS //int instCount[256]; #ifdef __DEBUG__ bool dumpDis = false; +//bool dumpDis = true; #endif +/* +On //e, $FCAA is the delay routine. (seems to not have changed from ][+) +*/ + + //Note: could enforce regs.clock to zero on starting the CPU with an Init() function... //bleh. //static uint32_t limit = 0; @@ -2899,6 +2905,47 @@ if (regs.pc == 0x444E) }//*/ #endif +#if 0 +/*if (regs.pc == 0x0801) +{ + WriteLog("\n*** DISK BOOT subroutine...\n\n"); + dumpDis = true; +}//*/ +if (regs.pc == 0xE000) +{ +#if 0 + WriteLog("\n*** Dump of $E000 routine ***\n\n"); + + for(uint32_t addr=0xE000; addr<0xF000;) + { + addr += Decode65C02(addr); + WriteLog("\n"); + } +#endif + WriteLog("\n*** DISK part II subroutine...\n\n"); + dumpDis = true; +}//*/ +if (regs.pc == 0xD000) +{ + WriteLog("\n*** CUSTOM DISK READ subroutine...\n\n"); + dumpDis = false; +}//*/ +if (regs.pc == 0xD1BE) +{ +// WriteLog("\n*** DISK part II subroutine...\n\n"); + dumpDis = true; +}//*/ +if (regs.pc == 0xD200) +{ + WriteLog("\n*** CUSTOM SCREEN subroutine...\n\n"); + dumpDis = false; +}//*/ +if (regs.pc == 0xD269) +{ +// WriteLog("\n*** DISK part II subroutine...\n\n"); + dumpDis = true; +}//*/ +#endif #ifdef __DEBUGMON__ //WAIT is commented out here because it's called by BELL1... if (regs.pc == 0xFCA8)