diff --git a/src/Drive.cpp b/src/Drive.cpp index 060f431..91682c0 100644 --- a/src/Drive.cpp +++ b/src/Drive.cpp @@ -358,6 +358,7 @@ void Drive::Reset() #if defined(EXPERIMENTALZERO) LED = false; cyclesForBit = 0; + UE7Counter = 16; #endif headTrackPos = 18*2; // Start with the head over track 19 (Very later Vorpal ie Cakifornia Games) need to have had the last head movement -ve CLOCK_SEL_AB = 3; // Track 18 will use speed zone 3 (encoder/decoder (ie UE7Counter) clocked at 1.2307Mhz) @@ -568,20 +569,71 @@ bool Drive::Update() #define min(a,b) (((a) < (b)) ? (a) : (b)) #define max(a,b) (((a) > (b)) ? (a) : (b)) -void Drive::DriveLoopRead() +void Drive::DriveLoopReadNoFluxNoCycles() +{ + unsigned int cycles = 16; + fluxReversalCyclesLeft -= 16; + cyclesLeftForBit -= 16; + while (true) + { + if (cycles < UE7Counter) + { + UE7Counter -= cycles; + cycles = 0; + return; + } + + cycles -= UE7Counter; + + UE7Counter = 16 - CLOCK_SEL_AB; // A and B inputs of UE7 come from the VIA's CLOCK SEL A/B outputs (ie PB5/6) ie preload the encoder/decoder clock for the current density settings. + // The decoder consists of UF4 and UE5A. The ecoder has two outputs, Pin 1 of UE5A is the serial data output and pin 2 of UF4 (output B) is the serial clock output. + ++UF4Counter &= 0xf; // Clock and clamp UF4. + // The UD2 read shift register is clocked by serial clock (the rising edge of encoder/decoder's UF4 B output (serial clock)) + // - ie on counts 2, 6, 10 and 14 (2 is the only count that outputs a 1 into readShiftRegister as the MSB bits of the count NORed together for other values are 0) + if ((UF4Counter & 0x3) == 2) + { + readShiftRegister <<= 1; + readShiftRegister |= (UF4Counter == 2); // Emulate UE5A and only shift in a 1 when pins 6 (output C) and 7 (output D) (bits 2 and 3 of UF4Counter are 0. ie the first count of the bit cell) + + writeShiftRegister <<= 1; + // Note: SYNC can only trigger during reading as R/!W line is one of UC2's inputs. + if (((readShiftRegister & 0x3ff) == 0x3ff)) // if the last 10 bits are 1s then SYNC + { + UE3Counter = 0; // Phase lock on to byte boundary + m_pVIA->GetPortB()->SetInput(0x80, false); // PB7 active low SYNC + } + else + { + m_pVIA->GetPortB()->SetInput(0x80, true); // SYNC not asserted if not following the SYNC bits + UE3Counter++; + } + } + // UC5B (NOR used to invert UF4's output B serial clock) output high when UF4 counts 0,1,4,5,8,9,12 and 13 + else if (((UF4Counter & 2) == 0) && (UE3Counter == 8)) // Phase locked on to byte boundary + { + UE3Counter = 0; + SO = (m_pVIA->GetFCR() & m6522::FCR_CA2_OUTPUT_MODE0) != 0; // bit 2 of the FCR indicates "Byte Ready Active" turned on or not. + writeShiftRegister = (u8)(readShiftRegister & 0xff); + m_pVIA->GetPortA()->SetInput(writeShiftRegister); + } + }; +} + +void Drive::DriveLoopReadNoFlux() { unsigned int minCycles; - unsigned int cycles = 0; + unsigned int cycles = 16; + + fluxReversalCyclesLeft -= 16; while (true) { - minCycles = min(min(cyclesLeftForBit, fluxReversalCyclesLeft), 16 - max(UE7Counter, cycles)); + minCycles = min(min(cyclesLeftForBit, cycles), UE7Counter); cyclesLeftForBit -= minCycles; - fluxReversalCyclesLeft -= minCycles; - cycles += minCycles; - UE7Counter += minCycles; + cycles -= minCycles; + UE7Counter -= minCycles; - if (cycles == 16) + if (cycles == 0) return; if (cyclesLeftForBit == 0) @@ -605,14 +657,9 @@ void Drive::DriveLoopRead() } } - if (fluxReversalCyclesLeft == 0)//Not entirely right, a flux reversal will be skipped if a bit read was going to happen + if (UE7Counter == 0x0) // The count carry (bit 4) clocks UF4. { - ResetEncoderDecoder(2 * 16, /*25 * 16*/23 * 16); // Trigger a random noise generated zero crossing and start seeing more anywhere between 2us and 25us after this one. - } - - if (UE7Counter == 0x10) // The count carry (bit 4) clocks UF4. - { - UE7Counter = CLOCK_SEL_AB; // A and B inputs of UE7 come from the VIA's CLOCK SEL A/B outputs (ie PB5/6) ie preload the encoder/decoder clock for the current density settings. + UE7Counter = 16 - CLOCK_SEL_AB; // A and B inputs of UE7 come from the VIA's CLOCK SEL A/B outputs (ie PB5/6) ie preload the encoder/decoder clock for the current density settings. // The decoder consists of UF4 and UE5A. The ecoder has two outputs, Pin 1 of UE5A is the serial data output and pin 2 of UF4 (output B) is the serial clock output. ++UF4Counter &= 0xf; // Clock and clamp UF4. // The UD2 read shift register is clocked by serial clock (the rising edge of encoder/decoder's UF4 B output (serial clock)) @@ -644,21 +691,32 @@ void Drive::DriveLoopRead() m_pVIA->GetPortA()->SetInput(writeShiftRegister); } } - - }; } - -void Drive::DriveLoopWrite() +void Drive::DriveLoopReadNoCycles() { - const unsigned int cycleStep = 16 - CLOCK_SEL_AB; - unsigned int cycles = 16 - UE7Counter; - while(cycles < 16) + unsigned int minCycles; + unsigned int cycles = 16; + + cyclesLeftForBit -= 16; + while (true) { - //No check is required. This loops is all about the UE7Counter. - //if (UE7Counter == 0x10) // The count carry (bit 4) clocks UF4. + minCycles = min(cycles, min(UE7Counter, fluxReversalCyclesLeft)); + fluxReversalCyclesLeft -= minCycles; + cycles -= minCycles; + UE7Counter -= minCycles; + + if (cycles == 0) + return; + + if (fluxReversalCyclesLeft == 0)//Not entirely right, a flux reversal will be skipped if a bit read was going to happen { - UE7Counter = CLOCK_SEL_AB; // A and B inputs of UE7 come from the VIA's CLOCK SEL A/B outputs (ie PB5/6) ie preload the encoder/decoder clock for the current density settings. + ResetEncoderDecoder(2 * 16, /*25 * 16*/23 * 16); // Trigger a random noise generated zero crossing and start seeing more anywhere between 2us and 25us after this one. + } + + if (UE7Counter == 0x0) // The count carry (bit 4) clocks UF4. + { + UE7Counter = 16 - CLOCK_SEL_AB; // A and B inputs of UE7 come from the VIA's CLOCK SEL A/B outputs (ie PB5/6) ie preload the encoder/decoder clock for the current density settings. // The decoder consists of UF4 and UE5A. The ecoder has two outputs, Pin 1 of UE5A is the serial data output and pin 2 of UF4 (output B) is the serial clock output. ++UF4Counter &= 0xf; // Clock and clamp UF4. // The UD2 read shift register is clocked by serial clock (the rising edge of encoder/decoder's UF4 B output (serial clock)) @@ -668,28 +726,166 @@ void Drive::DriveLoopWrite() readShiftRegister <<= 1; readShiftRegister |= (UF4Counter == 2); // Emulate UE5A and only shift in a 1 when pins 6 (output C) and 7 (output D) (bits 2 and 3 of UF4Counter are 0. ie the first count of the bit cell) - SetNextBit((writeShiftRegister & 0x80)); - writeShiftRegister <<= 1; // Note: SYNC can only trigger during reading as R/!W line is one of UC2's inputs. - UE3Counter++; + if (((readShiftRegister & 0x3ff) == 0x3ff)) // if the last 10 bits are 1s then SYNC + { + UE3Counter = 0; // Phase lock on to byte boundary + m_pVIA->GetPortB()->SetInput(0x80, false); // PB7 active low SYNC + } + else + { + m_pVIA->GetPortB()->SetInput(0x80, true); // SYNC not asserted if not following the SYNC bits + UE3Counter++; + } } // UC5B (NOR used to invert UF4's output B serial clock) output high when UF4 counts 0,1,4,5,8,9,12 and 13 else if (((UF4Counter & 2) == 0) && (UE3Counter == 8)) // Phase locked on to byte boundary { UE3Counter = 0; SO = (m_pVIA->GetFCR() & m6522::FCR_CA2_OUTPUT_MODE0) != 0; // bit 2 of the FCR indicates "Byte Ready Active" turned on or not. - writeShiftRegister = m_pVIA->GetPortA()->GetOutput(); - } - - if ((16-cycles) < cycleStep) - { - UE7Counter += 16 - cycles; - return; + writeShiftRegister = (u8)(readShiftRegister & 0xff); + m_pVIA->GetPortA()->SetInput(writeShiftRegister); } } - UE7Counter += cycleStep; - cycles += cycleStep; + }; +} +void Drive::DriveLoopRead() +{ + + if (fluxReversalCyclesLeft > 16 && cyclesLeftForBit > 16) + { + DriveLoopReadNoFluxNoCycles(); + return; + } + + if (fluxReversalCyclesLeft > 16) + { + DriveLoopReadNoFlux(); + return; + } + + if (cyclesLeftForBit > 16) + { + DriveLoopReadNoCycles(); + return; + } + + unsigned int minCycles; + unsigned int cycles = 16; + + while (true) + { + minCycles = min(min(cyclesLeftForBit, cycles), min(UE7Counter, fluxReversalCyclesLeft)); + cyclesLeftForBit -= minCycles; + fluxReversalCyclesLeft -= minCycles; + cycles -= minCycles; + UE7Counter -= minCycles; + + if (cycles == 0) + return; + + if (cyclesLeftForBit == 0) + { + //which is faster? single loop ceil check or the 3 lines below? + float fn = 2.0f * cyclesPerBit - cyclesForBit; + cyclesLeftForBit = (int)fn; + cyclesForBit = cyclesPerBit; + if (fn != (float)cyclesLeftForBit) { + ++cyclesLeftForBit; + ++cyclesForBit; + } + + //cyclesForBit -= cyclesPerBit; + //cyclesLeftForBit = ceil(cyclesPerBit - cyclesForBit); + //cyclesForBit += cyclesLeftForBit; + + if (GetNextBit()) + { + ResetEncoderDecoder(18 * 16, /*20 * 16*/ 2 * 16); + } + } + + if (fluxReversalCyclesLeft == 0)//Not entirely right, a flux reversal will be skipped if a bit read was going to happen + { + ResetEncoderDecoder(2 * 16, /*25 * 16*/23 * 16); // Trigger a random noise generated zero crossing and start seeing more anywhere between 2us and 25us after this one. + } + + if (UE7Counter == 0x0) // The count carry (bit 4) clocks UF4. + { + UE7Counter = 16-CLOCK_SEL_AB; // A and B inputs of UE7 come from the VIA's CLOCK SEL A/B outputs (ie PB5/6) ie preload the encoder/decoder clock for the current density settings. + // The decoder consists of UF4 and UE5A. The ecoder has two outputs, Pin 1 of UE5A is the serial data output and pin 2 of UF4 (output B) is the serial clock output. + ++UF4Counter &= 0xf; // Clock and clamp UF4. + // The UD2 read shift register is clocked by serial clock (the rising edge of encoder/decoder's UF4 B output (serial clock)) + // - ie on counts 2, 6, 10 and 14 (2 is the only count that outputs a 1 into readShiftRegister as the MSB bits of the count NORed together for other values are 0) + //if ((UF4Counter & 0x3) == 2) + if (UF4Counter == 2 || UF4Counter == 6) //You'd think the bit operation should be faster... + { + readShiftRegister <<= 1; + readShiftRegister |= (UF4Counter == 2); // Emulate UE5A and only shift in a 1 when pins 6 (output C) and 7 (output D) (bits 2 and 3 of UF4Counter are 0. ie the first count of the bit cell) + + writeShiftRegister <<= 1; + // Note: SYNC can only trigger during reading as R/!W line is one of UC2's inputs. + if (((readShiftRegister & 0x3ff) == 0x3ff)) // if the last 10 bits are 1s then SYNC + { + UE3Counter = 0; // Phase lock on to byte boundary + m_pVIA->GetPortB()->SetInput(0x80, false); // PB7 active low SYNC + } + else + { + m_pVIA->GetPortB()->SetInput(0x80, true); // SYNC not asserted if not following the SYNC bits + UE3Counter++; + } + } + // UC5B (NOR used to invert UF4's output B serial clock) output high when UF4 counts 0,1,4,5,8,9,12 and 13 + else if (((UF4Counter & 2) == 0) && (UE3Counter == 8)) // Phase locked on to byte boundary + { + UE3Counter = 0; + SO = (m_pVIA->GetFCR() & m6522::FCR_CA2_OUTPUT_MODE0) != 0; // bit 2 of the FCR indicates "Byte Ready Active" turned on or not. + writeShiftRegister = (u8)(readShiftRegister & 0xff); + m_pVIA->GetPortA()->SetInput(writeShiftRegister); + } + } + }; +} + +void Drive::DriveLoopWrite() +{ + unsigned int cycles = 16; + while(true) + { + if (cycles < UE7Counter) + { + UE7Counter -= cycles; + cycles = 0; + return; + } + + cycles -= UE7Counter; + + UE7Counter = 16 - CLOCK_SEL_AB; // A and B inputs of UE7 come from the VIA's CLOCK SEL A/B outputs (ie PB5/6) ie preload the encoder/decoder clock for the current density settings. + // The decoder consists of UF4 and UE5A. The ecoder has two outputs, Pin 1 of UE5A is the serial data output and pin 2 of UF4 (output B) is the serial clock output. + ++UF4Counter &= 0xf; // Clock and clamp UF4. + // The UD2 read shift register is clocked by serial clock (the rising edge of encoder/decoder's UF4 B output (serial clock)) + // - ie on counts 2, 6, 10 and 14 (2 is the only count that outputs a 1 into readShiftRegister as the MSB bits of the count NORed together for other values are 0) + if ((UF4Counter & 0x3) == 2) + { + readShiftRegister <<= 1; + readShiftRegister |= (UF4Counter == 2); // Emulate UE5A and only shift in a 1 when pins 6 (output C) and 7 (output D) (bits 2 and 3 of UF4Counter are 0. ie the first count of the bit cell) + + SetNextBit((writeShiftRegister & 0x80)); + + writeShiftRegister <<= 1; + // Note: SYNC can only trigger during reading as R/!W line is one of UC2's inputs. + UE3Counter++; + } + // UC5B (NOR used to invert UF4's output B serial clock) output high when UF4 counts 0,1,4,5,8,9,12 and 13 + else if (((UF4Counter & 2) == 0) && (UE3Counter == 8)) // Phase locked on to byte boundary + { + UE3Counter = 0; + SO = (m_pVIA->GetFCR() & m6522::FCR_CA2_OUTPUT_MODE0) != 0; // bit 2 of the FCR indicates "Byte Ready Active" turned on or not. + writeShiftRegister = m_pVIA->GetPortA()->GetOutput(); + } } } #endif \ No newline at end of file diff --git a/src/Drive.h b/src/Drive.h index 3d15553..a3f5498 100644 --- a/src/Drive.h +++ b/src/Drive.h @@ -51,6 +51,9 @@ public: #if defined(EXPERIMENTALZERO) void DriveLoopWrite(); void DriveLoopRead(); + void DriveLoopReadNoFluxNoCycles(); + void DriveLoopReadNoFlux(); + void DriveLoopReadNoCycles(); #endif void Insert(DiskImage* diskImage); @@ -69,7 +72,7 @@ private: int32_t localSeed; inline void ResetEncoderDecoder(unsigned int min, unsigned int /*max*/span) { - UE7Counter = CLOCK_SEL_AB; // A and B inputs of UE7 come from the VIA's CLOCK SEL A/B outputs (ie PB5/6) + UE7Counter = 16 - CLOCK_SEL_AB; // A and B inputs of UE7 come from the VIA's CLOCK SEL A/B outputs (ie PB5/6) UF4Counter = 0; localSeed = ((localSeed * 1103515245) + 12345) & 0x7fffffff; fluxReversalCyclesLeft = (span) * (localSeed >> 11) + min; diff --git a/src/Pi1581.cpp b/src/Pi1581.cpp index a581e26..ff2b068 100644 --- a/src/Pi1581.cpp +++ b/src/Pi1581.cpp @@ -93,6 +93,7 @@ extern u16 pc; u8 read6502_1581(u16 address) { u8 value = 0; +#if not defined(EXPERIMENTALZERO) if (address & 0x8000) { value = roms.Read1581(address); @@ -115,6 +116,7 @@ u8 read6502_1581(u16 address) { value = address >> 8; // Empty address bus } +#endif return value; } @@ -127,6 +129,7 @@ u8 peek6502_1581(u16 address) void write6502_1581(u16 address, const u8 value) { +#if not defined(EXPERIMENTALZERO) if (address & 0x8000) { return; @@ -145,6 +148,7 @@ void write6502_1581(u16 address, const u8 value) { s_u8Memory[address & 0x1fff] = value; } +#endif } static void CIAPortA_OnPortOut(void* pUserData, unsigned char status) diff --git a/src/iec_bus.h b/src/iec_bus.h index 553b5e0..b6eb057 100644 --- a/src/iec_bus.h +++ b/src/iec_bus.h @@ -277,7 +277,7 @@ public: RPI_SetGpioPinFunction((rpi_gpio_pin_t)PIGPIO_OUT_SRQ, FS_OUTPUT); } - +#if not defined(EXPERIMENTALZERO) // Set up audio. write32(CM_PWMDIV, CM_PASSWORD + 0x2000); write32(CM_PWMCTL, CM_PASSWORD + CM_ENAB + CM_SRC_OSCILLATOR); // Use Default 100MHz Clock @@ -285,7 +285,7 @@ public: write32(PWM_RNG1, 0x1B4); // 8bit 44100Hz Mono write32(PWM_RNG2, 0x1B4); write32(PWM_CTL, PWM_USEF2 + PWM_PWEN2 + PWM_USEF1 + PWM_PWEN1 + PWM_CLRF1); - +#endif int buttonCount = sizeof(ButtonPinFlags) / sizeof(unsigned); for (index = 0; index < buttonCount; ++index) diff --git a/src/main.cpp b/src/main.cpp index e925e01..a601855 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -101,7 +101,9 @@ u8 s_u8Memory[0xc000]; int numberOfUSBMassStorageDevices = 0; DiskCaddy diskCaddy; Pi1541 pi1541; +#if not defined(EXPERIMENTALZERO) Pi1581 pi1581; +#endif CEMMCDevice m_EMMC; Screen screen; ScreenLCD* screenLCD = 0; @@ -118,8 +120,9 @@ bool USBKeyboardDetected = false; bool selectedViaIECCommands = false; u16 pc; +#if not defined(EXPERIMENTALZERO) SpinLock core0RefreshingScreen; - +#endif unsigned int screenWidth = 1024; unsigned int screenHeight = 768; @@ -609,6 +612,7 @@ EmulatingMode BeginEmulating(FileBrowser* fileBrowser, const char* filenameForIc DiskImage* diskImage = diskCaddy.SelectFirstImage(); if (diskImage) { +#if not defined(EXPERIMENTALZERO) if (diskImage->IsD81()) { pi1581.Insert(diskImage); @@ -617,6 +621,7 @@ EmulatingMode BeginEmulating(FileBrowser* fileBrowser, const char* filenameForIc return EMULATING_1581; } else +#endif { pi1541.drive.Insert(diskImage); fileBrowser->DisplayDiskInfo(diskImage, filenameForIcon); @@ -668,7 +673,9 @@ void GlobalSetDeviceID(u8 id) deviceID = id; m_IEC_Commands.SetDeviceId(id); pi1541.SetDeviceID(id); +#if not defined(EXPERIMENTALZERO) pi1581.SetDeviceID(id); +#endif } void CheckAutoMountImage(EXIT_TYPE reset_reason , FileBrowser* fileBrowser) @@ -712,10 +719,6 @@ EXIT_TYPE Emulate1541(FileBrowser* fileBrowser) if (numberOfImagesMax > 10) numberOfImagesMax = 10; - core0RefreshingScreen.Acquire(); - diskCaddy.Display(); - core0RefreshingScreen.Release(); - inputMappings->directDiskSwapRequest = 0; // Force an update on all the buttons now before we start emulation mode. IEC_Bus::ReadBrowseMode(); @@ -731,8 +734,6 @@ EXIT_TYPE Emulate1541(FileBrowser* fileBrowser) pi1541.Reset(); // will call IEC_Bus::Reset(); IEC_Bus::OutputLED = false; IEC_Bus::LetSRQBePulledHigh(); - float avgTimer = 0.0f; - ctBefore = read32(ARM_SYSTIMER_CLO); //resetWhileEmulating = false; @@ -756,7 +757,6 @@ EXIT_TYPE Emulate1541(FileBrowser* fileBrowser) } bool buttonState = false; bool prevButtonState = false; - while (true) { @@ -776,7 +776,7 @@ EXIT_TYPE Emulate1541(FileBrowser* fileBrowser) } m6502.Step(); // If the CPU reads or writes to the VIA then clk and data can change - + if (refreshOutsAfterCPUStep) IEC_Bus::RefreshOuts1541(); // Now output all outputs. @@ -829,13 +829,13 @@ EXIT_TYPE Emulate1541(FileBrowser* fileBrowser) prevButtonState = buttonState; - do + do { ctAfter = read32(ARM_SYSTIMER_CLO); } while (ctAfter == ctBefore); // Sync to the 1MHz clock - ctBefore = ctAfter; + ctBefore = ctAfter; IEC_Bus::ReadEmulationMode1541(); IEC_Bus::RefreshOuts1541(); // Now output all outputs. @@ -1274,8 +1274,9 @@ void emulator() IEC_Bus::Reset(); IEC_Bus::LetSRQBePulledHigh(); - +#if not defined(EXPERIMENTALZERO) core0RefreshingScreen.Acquire(); +#endif IEC_Bus::WaitMicroSeconds(100); roms.ResetCurrentROMIndex(); @@ -1285,9 +1286,9 @@ void emulator() fileBrowser->ClearSelections(); fileBrowser->RefeshDisplay(); // Just redisplay the current folder. - +#if not defined(EXPERIMENTALZERO) core0RefreshingScreen.Release(); - +#endif selectedViaIECCommands = false; inputMappings->Reset(); @@ -1590,7 +1591,7 @@ static void CheckOptions() deviceID = (u8)options.GetDeviceID(); DEBUG_LOG("DeviceID = %d\r\n", deviceID); - +#if not defined(EXPERIMENTALZERO) const char* FontROMName = options.GetRomFontName(); if (FontROMName) { @@ -1625,7 +1626,7 @@ static void CheckOptions() //DEBUG_LOG("Read ROM %s from options\r\n", ROMName); } } - +#endif const char* ROMName1581 = options.GetRomName1581(); if (ROMName1581) {