// Pi1541 - A Commodore 1541 disk drive emulator // Copyright(C) 2018 Stephen White // // This file is part of Pi1541. // // Pi1541 is free software : you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Pi1541 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Pi1541. If not, see . #include "iec_bus.h" static int buttonCount = sizeof(ButtonPinFlags) / sizeof(unsigned); u32 IEC_Bus::PIGPIO_MASK_IN_ATN = 1 << PIGPIO_ATN; u32 IEC_Bus::PIGPIO_MASK_IN_DATA = 1 << PIGPIO_DATA; u32 IEC_Bus::PIGPIO_MASK_IN_CLOCK = 1 << PIGPIO_CLOCK; u32 IEC_Bus::PIGPIO_MASK_IN_SRQ = 1 << PIGPIO_SRQ; u32 IEC_Bus::PIGPIO_MASK_IN_RESET = 1 << PIGPIO_RESET; bool IEC_Bus::PI_Atn = false; bool IEC_Bus::PI_Data = false; bool IEC_Bus::PI_Clock = false; bool IEC_Bus::PI_Reset = false; bool IEC_Bus::VIA_Atna = false; bool IEC_Bus::VIA_Data = false; bool IEC_Bus::VIA_Clock = false; bool IEC_Bus::DataSetToOut = false; bool IEC_Bus::AtnaDataSetToOut = false; bool IEC_Bus::ClockSetToOut = false; bool IEC_Bus::OutputLED = false; bool IEC_Bus::OutputSound = false; bool IEC_Bus::Resetting = false; bool IEC_Bus::splitIECLines = false; bool IEC_Bus::invertIECInputs = false; bool IEC_Bus::invertIECOutputs = true; bool IEC_Bus::ignoreReset = false; u32 IEC_Bus::myOutsGPFSEL1 = 0; u32 IEC_Bus::myOutsGPFSEL0 = 0; bool IEC_Bus::InputButton[5] = { 0 }; bool IEC_Bus::InputButtonPrev[5] = { 0 }; u32 IEC_Bus::validInputCount[5] = { 0 }; u32 IEC_Bus::inputRepeatThreshold[5]; u32 IEC_Bus::inputRepeat[5] = { 0 }; u32 IEC_Bus::inputRepeatPrev[5] = { 0 }; m6522* IEC_Bus::VIA = 0; u32 IEC_Bus::emulationModeCheckButtonIndex = 0; void IEC_Bus::ReadBrowseMode(void) { IOPort* portB = 0; unsigned gplev0 = read32(ARM_GPIO_GPLEV0); int index; for (index = 0; index < buttonCount; ++index) { UpdateButton(index, gplev0); } bool ATNIn = (gplev0 & PIGPIO_MASK_IN_ATN) == (invertIECInputs ? PIGPIO_MASK_IN_ATN : 0); if (PI_Atn != ATNIn) { PI_Atn = ATNIn; } if (portB && (portB->GetDirection() & 0x10) == 0) AtnaDataSetToOut = false; // If the ATNA PB4 gets set to an input then we can't be pulling data low. (Maniac Mansion does this) if (!AtnaDataSetToOut && !DataSetToOut) // only sense if we have not brought the line low (because we can't as we have the pin set to output but we can simulate in software) { bool DATAIn = (gplev0 & PIGPIO_MASK_IN_DATA) == (invertIECInputs ? PIGPIO_MASK_IN_DATA : 0); if (PI_Data != DATAIn) { PI_Data = DATAIn; } } else { PI_Data = true; } if (!ClockSetToOut) // only sense if we have not brought the line low (because we can't as we have the pin set to output but we can simulate in software) { bool CLOCKIn = (gplev0 & PIGPIO_MASK_IN_CLOCK) == (invertIECInputs ? PIGPIO_MASK_IN_CLOCK : 0); if (PI_Clock != CLOCKIn) { PI_Clock = CLOCKIn; } } else { PI_Clock = true; } Resetting = !ignoreReset && ((gplev0 & PIGPIO_MASK_IN_RESET) == (invertIECInputs ? PIGPIO_MASK_IN_RESET : 0)); } void IEC_Bus::ReadEmulationMode(void) { IOPort* portB = 0; unsigned gplev0 = read32(ARM_GPIO_GPLEV0); int buttonIndex; for (buttonIndex = 0; buttonIndex < 3; ++buttonIndex) { UpdateButton(buttonIndex, gplev0); } // Doing it this way screws with the debounce counters. //UpdateButton(emulationModeCheckButtonIndex, gplev0); //emulationModeCheckButtonIndex++; //emulationModeCheckButtonIndex %= buttonCount; portB = VIA->GetPortB(); bool ATNIn = (gplev0 & PIGPIO_MASK_IN_ATN) == (invertIECInputs ? PIGPIO_MASK_IN_ATN : 0); if (PI_Atn != ATNIn) { PI_Atn = ATNIn; //if (VIA) { if ((portB->GetDirection() & 0x10) != 0) { // Emulate the XOR gate UD3 // We only need to do this when fully emulating, iec commands do this internally AtnaDataSetToOut = (VIA_Atna != PI_Atn); } portB->SetInput(VIAPORTPINS_ATNIN, ATNIn); //is inverted and then connected to pb7 and ca1 VIA->InputCA1(ATNIn); } } if (portB && (portB->GetDirection() & 0x10) == 0) AtnaDataSetToOut = false; // If the ATNA PB4 gets set to an input then we can't be pulling data low. (Maniac Mansion does this) if (!AtnaDataSetToOut && !DataSetToOut) // only sense if we have not brought the line low (because we can't as we have the pin set to output but we can simulate in software) { bool DATAIn = (gplev0 & PIGPIO_MASK_IN_DATA) == (invertIECInputs ? PIGPIO_MASK_IN_DATA : 0); if (PI_Data != DATAIn) { PI_Data = DATAIn; portB->SetInput(VIAPORTPINS_DATAIN, DATAIn); // VIA DATAin pb0 output from inverted DIN 5 DATA } } else { PI_Data = true; portB->SetInput(VIAPORTPINS_DATAIN, true); // simulate the read in software } if (!ClockSetToOut) // only sense if we have not brought the line low (because we can't as we have the pin set to output but we can simulate in software) { bool CLOCKIn = (gplev0 & PIGPIO_MASK_IN_CLOCK) == (invertIECInputs ? PIGPIO_MASK_IN_CLOCK : 0); if (PI_Clock != CLOCKIn) { PI_Clock = CLOCKIn; portB->SetInput(VIAPORTPINS_CLOCKIN, CLOCKIn); // VIA CLKin pb2 output from inverted DIN 4 CLK } } else { PI_Clock = true; portB->SetInput(VIAPORTPINS_CLOCKIN, true); // simulate the read in software } Resetting = !ignoreReset && ((gplev0 & PIGPIO_MASK_IN_RESET) == (invertIECInputs ? PIGPIO_MASK_IN_RESET : 0)); }