pi1541/src/iec_bus.cpp
Stephen White 5ac2fe8c45 Buttons in browse mode can change the selected ROM
Holding down the first button and pressing one of the other buttons will select different ROMs (if they have been specified in the options.txt file)
2018-07-29 14:22:14 +10:00

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] = { 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));
}