184 lines
5.6 KiB
C++
184 lines
5.6 KiB
C++
// 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 <http://www.gnu.org/licenses/>.
|
|
|
|
#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];
|
|
bool IEC_Bus::InputButtonPrev[5];
|
|
u32 IEC_Bus::validInputCount[5];
|
|
u32 IEC_Bus::inputRepeatThreshold[5];
|
|
u32 IEC_Bus::inputRepeat[5];
|
|
u32 IEC_Bus::inputRepeatPrev[5];
|
|
|
|
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));
|
|
}
|