From 35ec4f29b249777d7cef5b86d90b444dd2b03e14 Mon Sep 17 00:00:00 2001 From: nick_westgate Date: Sun, 12 Mar 2006 09:05:39 +0000 Subject: [PATCH] Added floating bus emulation. Summary of changes: AppleWin.cpp: Made dwCyclesThisFrame global -> g_dwCyclesThisFrame. CPU.cpp: Made InternalCpuExecute()'s nCyclesLeft static -> nInternalCyclesLeft. CPU.cpp: Added CpuGetCyclesThisFrame(). Memory.cpp: Added MemGet80Store(). Memory.cpp: Added MemReadFloatingBus(). Memory.cpp: Added MemReadFloatingBus(BYTE const highbit). Memory.cpp: Changed NullIo() to call MemReadFloatingBus(). Video.cpp: Added video scanner constants and VideoGetScannerAddress(bool* pbVblBar_OUT). Video.cpp: Changed VideoCheckVbl() to call VideoGetScannerAddress(). Various files: Replaced MemReturnRandomData() calls with MemReadFloatingBus(). --- AppleWin/source/Applewin.cpp | 11 +-- AppleWin/source/Applewin.h | 4 +- AppleWin/source/CPU.cpp | 20 +++-- AppleWin/source/CPU.h | 1 + AppleWin/source/Joystick.cpp | 6 +- AppleWin/source/Memory.cpp | 72 ++++++++--------- AppleWin/source/Memory.h | 3 + AppleWin/source/Speaker.cpp | 2 +- AppleWin/source/Video.cpp | 150 +++++++++++++++++++++++++++++++++-- AppleWin/source/Video.h | 1 + 10 files changed, 211 insertions(+), 59 deletions(-) diff --git a/AppleWin/source/Applewin.cpp b/AppleWin/source/Applewin.cpp index 96b58926..dc100e26 100644 --- a/AppleWin/source/Applewin.cpp +++ b/AppleWin/source/Applewin.cpp @@ -53,6 +53,8 @@ double g_fCurrentCLK6502 = CLK_6502; // Affected by Config dialog's speed slide static double g_fMHz = 1.0; // Affected by Config dialog's speed slider bar int g_nCpuCyclesFeedback = 0; +DWORD g_dwCyclesThisFrame = 0; + FILE* g_fh = NULL; bool g_bDisableDirectSound = false; @@ -86,7 +88,6 @@ ULONGLONG g_nPerfFreq = 0; void ContinueExecution() { - static DWORD dwCyclesThisFrame = 0; static BOOL pageflipping = 0; //? const double fUsecPerSec = 1.e6; @@ -128,7 +129,7 @@ void ContinueExecution() DWORD dwExecutedCycles = CpuExecute(nCyclesToExecute); - dwCyclesThisFrame += dwExecutedCycles; + g_dwCyclesThisFrame += dwExecutedCycles; // @@ -137,7 +138,7 @@ void ContinueExecution() CheckFastPaging(); DiskUpdatePosition(dwExecutedCycles); JoyUpdatePosition(); - VideoUpdateVbl(dwCyclesThisFrame); + VideoUpdateVbl(g_dwCyclesThisFrame); SpkrUpdate(cyclenum); CommUpdate(cyclenum); @@ -182,9 +183,9 @@ void ContinueExecution() // - if(dwCyclesThisFrame >= dwClksPerFrame) + if(g_dwCyclesThisFrame >= dwClksPerFrame) { - dwCyclesThisFrame -= dwClksPerFrame; + g_dwCyclesThisFrame -= dwClksPerFrame; if(mode != MODE_LOGO) { diff --git a/AppleWin/source/Applewin.h b/AppleWin/source/Applewin.h index b1d7a692..b2dc1106 100644 --- a/AppleWin/source/Applewin.h +++ b/AppleWin/source/Applewin.h @@ -18,7 +18,9 @@ extern BOOL restart; extern DWORD g_dwSpeed; extern double g_fCurrentCLK6502; -extern int g_nCpuCyclesFeedback; +extern int g_nCpuCyclesFeedback; +extern DWORD g_dwCyclesThisFrame; + extern FILE* g_fh; // Filehandle for log file extern bool g_bDisableDirectSound; // Cmd line switch: don't init DS (so no MB support) diff --git a/AppleWin/source/CPU.cpp b/AppleWin/source/CPU.cpp index df698902..9a5f1742 100644 --- a/AppleWin/source/CPU.cpp +++ b/AppleWin/source/CPU.cpp @@ -104,6 +104,8 @@ unsigned __int64 g_nCumulativeCycles = 0; static ULONG g_nCyclesSubmitted; // Number of cycles submitted to CpuExecute() static ULONG g_nCyclesExecuted; +static signed long nInternalCyclesLeft; + /**************************************************************************** * * GENERAL PURPOSE MACROS @@ -132,10 +134,10 @@ static ULONG g_nCyclesExecuted; regs.sp = 0x1FF; #define READ ( \ ((addr & 0xFF00) == 0xC000) \ - ? ioread[addr & 0xFF](regs.pc,(BYTE)addr,0,0,nCyclesLeft) \ + ? ioread[addr & 0xFF](regs.pc,(BYTE)addr,0,0,nInternalCyclesLeft) \ : ( \ (((addr & 0xFF00) == 0xC400) || ((addr & 0xFF00) == 0xC500)) \ - ? CxReadFunc(regs.pc, addr, 0, 0, nCyclesLeft) \ + ? CxReadFunc(regs.pc, addr, 0, 0, nInternalCyclesLeft) \ : *(mem+addr) \ ) \ ) @@ -152,9 +154,9 @@ static ULONG g_nCyclesExecuted; if (page) \ *(page+(addr & 0xFF)) = (BYTE)(a); \ else if ((addr & 0xFF00) == 0xC000) \ - iowrite[addr & 0xFF](regs.pc,(BYTE)addr,1,(BYTE)(a),nCyclesLeft); \ + iowrite[addr & 0xFF](regs.pc,(BYTE)addr,1,(BYTE)(a),nInternalCyclesLeft); \ else if(((addr & 0xFF00) == 0xC400) || ((addr & 0xFF00) == 0xC500)) \ - CxWriteFunc(regs.pc, addr, 1, (BYTE)(a), nCyclesLeft); \ + CxWriteFunc(regs.pc, addr, 1, (BYTE)(a), nInternalCyclesLeft); \ } // @@ -483,7 +485,7 @@ static DWORD InternalCpuExecute (DWORD totalcycles) do { - signed long nCyclesLeft = (totalcycles<<8) - (cycles<<8); + nInternalCyclesLeft = (totalcycles<<8) - (cycles<<8); USHORT uExtraCycles = 0; if(regs.bIRQ && !(regs.ps & AF_INTERRUPT)) @@ -819,6 +821,14 @@ void CpuCalcCycles(ULONG nCyclesLeft) //=========================================================================== +ULONG CpuGetCyclesThisFrame() +{ + CpuCalcCycles(nInternalCyclesLeft); // TODO: simplify the whole cycle system! + return g_dwCyclesThisFrame + g_nCyclesExecuted; +} + +//=========================================================================== + DWORD CpuExecute (DWORD cycles) { static BOOL laststep = 0; diff --git a/AppleWin/source/CPU.h b/AppleWin/source/CPU.h index ababc027..0183364f 100644 --- a/AppleWin/source/CPU.h +++ b/AppleWin/source/CPU.h @@ -22,6 +22,7 @@ void CpuDestroy (); void CpuCalcCycles(ULONG nCyclesLeft); DWORD CpuExecute (DWORD); void CpuGetCode (WORD,LPBYTE *,DWORD *); +ULONG CpuGetCyclesThisFrame(); void CpuInitialize (); void CpuReinitialize (); void CpuResetCompilerData (); diff --git a/AppleWin/source/Joystick.cpp b/AppleWin/source/Joystick.cpp index 24e51486..b9d05c67 100644 --- a/AppleWin/source/Joystick.cpp +++ b/AppleWin/source/Joystick.cpp @@ -395,7 +395,7 @@ BYTE __stdcall JoyReadButton (WORD, BYTE address, BYTE, BYTE, ULONG) break; } - return MemReturnRandomData(pressed); + return MemReadFloatingBus(pressed); } //=========================================================================== @@ -431,7 +431,7 @@ BYTE __stdcall JoyReadPosition (WORD programcounter, BYTE address, BYTE, BYTE, U BOOL nPdlCntrActive = g_nCumulativeCycles <= (g_nJoyCntrResetCycle + (unsigned __int64) ((double)nPdlPos * PDL_CNTR_INTERVAL)); - return MemReturnRandomData(nPdlCntrActive); + return MemReadFloatingBus(nPdlCntrActive); } //=========================================================================== @@ -453,7 +453,7 @@ BYTE __stdcall JoyResetPosition (WORD, BYTE, BYTE, BYTE, ULONG nCyclesLeft) if(joyinfo[joytype[1]].device == DEVICE_JOYSTICK) CheckJoystick1(); - return MemReturnRandomData(1); + return MemReadFloatingBus(); } //=========================================================================== diff --git a/AppleWin/source/Memory.cpp b/AppleWin/source/Memory.cpp index db76ffb0..066874a2 100644 --- a/AppleWin/source/Memory.cpp +++ b/AppleWin/source/Memory.cpp @@ -616,37 +616,14 @@ void BackMainImage () { //=========================================================================== BYTE __stdcall NullIo (WORD programcounter, BYTE address, BYTE write, BYTE value, ULONG nCycles) { - if ((address & 0xF0) == 0xA0) { - static const BYTE retval[16] = {0x58,0xFC,0x5B,0xFF,0x58,0xFC,0x5B,0xFF, - 0x0B,0x10,0x00,0x00,0xFF,0xFF,0xFF,0xFF}; - return retval[address & 15]; - } - else if ((address >= 0xB0) && (address <= 0xCF)) { - BYTE r = (BYTE)(rand() & 0xFF); - if (r >= 0x10) - return 0xA0; - else if (r >= 8) - return (r > 0xC) ? 0xFF : 0x00; - else - return (address & 0xF7); - } - else if ((address & 0xF0) == 0xD0) { - BYTE r = (BYTE)(rand() & 0xFF); - if (r >= 0xC0) - return 0xC0; - else if (r >= 0x80) - return 0x80; - else if ((address == 0xD0) || (address == 0xDF)) - return 0; - else if (r >= 0x40) - return 0x40; - else if (r >= 0x30) - return 0x90; - else - return 0; - } - else - return MemReturnRandomData(1); + if (!write) + { + return MemReadFloatingBus(); + } + else + { + return 0; + } } //=========================================================================== @@ -837,6 +814,13 @@ void MemDestroy () { ZeroMemory(memshadow,sizeof(memshadow)); } +//=========================================================================== + +bool MemGet80Store() +{ + return SW_80STORE != 0; +} + //=========================================================================== LPBYTE MemGetAuxPtr (WORD offset) { @@ -1018,6 +1002,21 @@ BYTE MemReturnRandomData (BYTE highbit) { return retval[r & 15] | (highbit ? 0x80 : 0); } +//=========================================================================== + +BYTE MemReadFloatingBus() +{ + return*(LPBYTE)(mem + VideoGetScannerAddress()); +} + +//=========================================================================== + +BYTE MemReadFloatingBus(BYTE const highbit) +{ + BYTE r = *(LPBYTE)(mem + VideoGetScannerAddress()); + return (r & ~0x80) | ((highbit) ? 0x80 : 0); +} + //=========================================================================== void MemSetFastPaging (BOOL on) { if (fastpaging && modechanging) { @@ -1110,13 +1109,13 @@ BYTE __stdcall MemSetPaging (WORD programcounter, BYTE address, BYTE write, BYTE if ((address >= 4) && (address <= 5) && ((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D)) { modechanging = 1; - return write ? 0 : MemReturnRandomData(1); + return write ? 0 : MemReadFloatingBus(1); } if ((address >= 0x80) && (address <= 0x8F) && (programcounter < 0xC000) && (((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0048D) || ((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D))) { modechanging = 1; - return write ? 0 : MemReturnRandomData(1); + return write ? 0 : MemReadFloatingBus(1); } // IF THE MEMORY PAGING MODE HAS CHANGED, UPDATE OUR MEMORY IMAGES AND @@ -1142,10 +1141,9 @@ BYTE __stdcall MemSetPaging (WORD programcounter, BYTE address, BYTE write, BYTE } if ((address <= 1) || ((address >= 0x54) && (address <= 0x57))) - VideoSetMode(programcounter,address,write,value,0); - return write ? 0 - : MemReturnRandomData(((address == 0x54) || (address == 0x55)) - ? (SW_PAGE2 != 0) : 1); + return VideoSetMode(programcounter,address,write,value,0); + + return write ? 0 : MemReadFloatingBus(); } //=========================================================================== diff --git a/AppleWin/source/Memory.h b/AppleWin/source/Memory.h index 62ca6352..c5a97aeb 100644 --- a/AppleWin/source/Memory.h +++ b/AppleWin/source/Memory.h @@ -24,9 +24,12 @@ extern UINT g_uMaxExPages; // user requested ram pages (from cmd line) #endif void MemDestroy (); +bool MemGet80Store(); LPBYTE MemGetAuxPtr (WORD); LPBYTE MemGetMainPtr (WORD); void MemInitialize (); +BYTE MemReadFloatingBus(); +BYTE MemReadFloatingBus(BYTE highbit); void MemReset (); void MemResetPaging (); BYTE MemReturnRandomData (BYTE highbit); diff --git a/AppleWin/source/Speaker.cpp b/AppleWin/source/Speaker.cpp index bd760432..13a94afa 100644 --- a/AppleWin/source/Speaker.cpp +++ b/AppleWin/source/Speaker.cpp @@ -492,7 +492,7 @@ BYTE __stdcall SpkrToggle (WORD, BYTE address, BYTE write, BYTE, ULONG nCyclesLe } - return MemReturnRandomData(1); + return MemReadFloatingBus(); } //============================================================================= diff --git a/AppleWin/source/Video.cpp b/AppleWin/source/Video.cpp index ba3f16f0..c8693f67 100644 --- a/AppleWin/source/Video.cpp +++ b/AppleWin/source/Video.cpp @@ -150,6 +150,23 @@ enum Color_Palette_Index_e #define HGR_MATRIX_YOFFSET 2 // For tv emulation mode +// video scanner constants +int const kHBurstClock = 53; // clock when Color Burst starts +int const kHBurstClocks = 4; // clocks per Color Burst duration +int const kHClock0State = 0x18; // H[543210] = 011000 +int const kHClocks = 65; // clocks per horizontal scan (including HBL) +int const kHPEClock = 40; // clock when HPE (horizontal preset enable) goes low +int const kHPresetClock = 41; // clock when H state presets +int const kHSyncClock = 49; // clock when HSync starts +int const kHSyncClocks = 4; // clocks per HSync duration +int const kNTSCScanLines = 262; // total scan lines including VBL (NTSC) +int const kNTSCVSyncLine = 224; // line when VSync starts (NTSC) +int const kPALScanLines = 312; // total scan lines including VBL (PAL) +int const kPALVSyncLine = 264; // line when VSync starts (PAL) +int const kVLine0State = 0x100; // V[543210CBA] = 100000000 +int const kVPresetLine = 256; // line when V state presets +int const kVSyncLines = 4; // lines per VSync duration + typedef BOOL (*UpdateFunc_t)(int,int,int,int,int); static BYTE celldirty[40][32]; @@ -195,6 +212,8 @@ DWORD videotype = VT_COLOR_TVEMU; static bool g_bTextFlashState = false; static bool g_bTextFlashFlag = false; +static bool bVideoScannerNTSC = true; // NTSC video scanning (or PAL) + //------------------------------------- // Video consts: @@ -1430,7 +1449,7 @@ void VideoBenchmark () { DiskUpdatePosition(executedcycles); JoyUpdatePosition(); VideoUpdateVbl(0); - } + } } if (cycle & 1) FillMemory(mem+0x2000,0x2000,0xAA); @@ -1465,7 +1484,7 @@ void VideoBenchmark () { //=========================================================================== BYTE __stdcall VideoCheckMode (WORD, BYTE address, BYTE, BYTE, ULONG) { if (address == 0x7F) - return MemReturnRandomData(SW_DHIRES != 0); + return MemReadFloatingBus(SW_DHIRES != 0); else { BOOL result = 0; switch (address) { @@ -1526,13 +1545,18 @@ BYTE __stdcall VideoCheckVbl (WORD, BYTE, BYTE, BYTE, ULONG) BBBE F0 F5 BEQ $BBB5 BBC0 C9 0F CMP #$0F BBC2 F0 F1 BEQ $BBB5 - */ // return MemReturnRandomData(dwVBlCounter <= nVBlStop_NTSC); if (dwVBlCounter <= nVBlStop_NTSC) return (BYTE)(dwVBlCounter & 0x7F); // 0x00; else return 0x80 | ((BYTE)(dwVBlCounter & 1)); + */ + + bool bVblBar; + VideoGetScannerAddress(&bVblBar); + BYTE r = KeybGetKeycode(); + return (r & ~0x80) | ((bVblBar) ? 0x80 : 0); } //=========================================================================== @@ -1957,10 +1981,7 @@ BYTE __stdcall VideoSetMode (WORD, BYTE address, BYTE write, BYTE, ULONG) { } lastpageflip = emulmsec; } - if (address == 0x50) - return VideoCheckVbl(0,0,0,0,0); - else - return MemReturnRandomData(1); + return MemReadFloatingBus(); } //=========================================================================== @@ -2006,6 +2027,8 @@ DWORD VideoGetSnapshot(SS_IO_Video* pSS) return 0; } +//=========================================================================== + DWORD VideoSetSnapshot(SS_IO_Video* pSS) { charoffs = !pSS->bAltCharSet ? 0 : 256; @@ -2018,3 +2041,116 @@ DWORD VideoSetSnapshot(SS_IO_Video* pSS) return 0; } + +//=========================================================================== + +WORD VideoGetScannerAddress(bool* pbVblBar_OUT) +{ + // get video scanner position + // + int nCycles = CpuGetCyclesThisFrame(); + + // machine state switches + // + int nHires = (SW_HIRES) ? 1 : 0; + int nPage2 = (SW_PAGE2) ? 1 : 0; + int n80Store = (MemGet80Store()) ? 1 : 0; + + // calculate video parameters according to display standard + // + int nScanLines = bVideoScannerNTSC ? kNTSCScanLines : kPALScanLines; + int nVSyncLine = bVideoScannerNTSC ? kNTSCVSyncLine : kPALVSyncLine; + int nScanCycles = nScanLines * kHClocks; + + // calculate horizontal scanning state + // + int nHClock = (nCycles + kHPEClock) % kHClocks; // which horizontal scanning clock + int nHState = kHClock0State + nHClock; // H state bits + if (nHClock >= kHPresetClock) // check for horizontal preset + { + nHState -= 1; // correct for state preset (two 0 states) + } + int h_0 = (nHState >> 0) & 1; // get horizontal state bits + int h_1 = (nHState >> 1) & 1; + int h_2 = (nHState >> 2) & 1; + int h_3 = (nHState >> 3) & 1; + int h_4 = (nHState >> 4) & 1; + int h_5 = (nHState >> 5) & 1; + + // calculate vertical scanning state + // + int nVLine = nCycles / kHClocks; // which vertical scanning line + int nVState = kVLine0State + nVLine; // V state bits + if ((nVLine >= kVPresetLine)) // check for previous vertical state preset + { + nVState -= nScanLines; // compensate for preset + } + int v_A = (nVState >> 0) & 1; // get vertical state bits + int v_B = (nVState >> 1) & 1; + int v_C = (nVState >> 2) & 1; + int v_0 = (nVState >> 3) & 1; + int v_1 = (nVState >> 4) & 1; + int v_2 = (nVState >> 5) & 1; + int v_3 = (nVState >> 6) & 1; + int v_4 = (nVState >> 7) & 1; + int v_5 = (nVState >> 8) & 1; + + // calculate scanning memory address + // + if (SW_HIRES && SW_MIXED && (v_4 & v_2)) + { + nHires = 0; // (address is in text memory) + } + + int nAddend0 = 0x68; // 1 1 0 1 + int nAddend1 = (h_5 << 5) | (h_4 << 4) | (h_3 << 3); + int nAddend2 = (v_4 << 6) | (v_3 << 5) | (v_4 << 4) | (v_3 << 3); + int nSum = (nAddend0 + nAddend1 + nAddend2) & (0x0F << 3); + + int nAddress = 0; + nAddress |= h_0 << 0; // a0 + nAddress |= h_1 << 1; // a1 + nAddress |= h_2 << 2; // a2 + nAddress |= nSum; // a3 - aa6 + nAddress |= v_0 << 7; // a7 + nAddress |= v_1 << 8; // a8 + nAddress |= v_2 << 9; // a9 + nAddress |= ((nHires) ? v_A : (1 ^ (nPage2 & (1 ^ n80Store)))) << 10; // a10 + nAddress |= ((nHires) ? v_B : (nPage2 & (1 ^ n80Store))) << 11; // a11 + if (nHires) // hires? + { + // Y: insert hires only address bits + // + nAddress |= v_C << 12; // a12 + nAddress |= (1 ^ (nPage2 & (1 ^ n80Store))) << 13; // a13 + nAddress |= (nPage2 & (1 ^ n80Store)) << 14; // a14 + } + else + { + // N: text, so no higher address bits unless Apple ][, not Apple //e + // + if ((!apple2e) && // Apple ][? + (kHPEClock <= nHClock) && // Y: HBL? + (nHClock <= (kHClocks - 1))) + { + nAddress |= 1 << 12; // Y: a12 (add $1000 to address!) + } + } + + // update VBL' state + // + if (pbVblBar_OUT != NULL) + { + if (v_4 & v_3) // VBL? + { + *pbVblBar_OUT = false; // Y: VBL' is false + } + else + { + *pbVblBar_OUT = true; // N: VBL' is true + } + } + return static_cast(nAddress); +} + +//=========================================================================== diff --git a/AppleWin/source/Video.h b/AppleWin/source/Video.h index 61580812..000f90bf 100644 --- a/AppleWin/source/Video.h +++ b/AppleWin/source/Video.h @@ -32,6 +32,7 @@ void VideoRedrawScreen (); void VideoRefreshScreen (); void VideoReinitialize (); void VideoResetState (); +WORD VideoGetScannerAddress(bool* pbVblBar_OUT = NULL); void VideoUpdateVbl (DWORD dwCyclesThisFrame); void VideoUpdateFlash(); bool VideoGetSW80COL();