ZeroRAMBank.h
/*
* This file is part of libsidplayfp, a SID player engine.
*
* Copyright 2012-2015 Leandro Nini <drfiemost@users.sourceforge.net>
* Copyright 2009-2014 VICE Project
* Copyright 2010 Antti Lankila
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef ZERORAMBANK_H
#define ZERORAMBANK_H
#include <stdint.h>
#include "Bank.h"
#include "SystemRAMBank.h"
#include "pla.h"
#include "Event.h"
#include "sidcxx11.h"
namespace libsidplayfp
{
template <int Bit>
class dataBit
{
private:
static constexpr event_clock_t C64_CPU6510_DATA_PORT_FALL_OFF_CYCLES = 350000;
static constexpr event_clock_t C64_CPU8500_DATA_PORT_FALL_OFF_CYCLES = 1500000; // Curently unused
private:
event_clock_t dataSetClk;
bool isFallingOff;
uint8_t dataSet;
public:
void reset()
{
isFallingOff = false;
dataSet = 0;
}
uint8_t readBit(event_clock_t phi2time)
{
if (isFallingOff && (dataSetClk < phi2time))
{
// discharge the "capacitor"
reset();
}
return dataSet;
}
void writeBit(event_clock_t phi2time, uint8_t value)
{
dataSetClk = phi2time + C64_CPU6510_DATA_PORT_FALL_OFF_CYCLES;
dataSet = value & (1 << Bit);
isFallingOff = true;
}
};
class ZeroRAMBank final : public Bank
{
private:
// not emulated
static bool const tape_sense = false;
private:
PLA &pla;
SystemRAMBank &ramBank;
dataBit<6> dataBit6;
dataBit<7> dataBit7;
uint8_t dir;
uint8_t data;
uint8_t dataRead;
uint8_t procPortPins;
private:
void updateCpuPort()
{
// Update data pins for which direction is OUTPUT
procPortPins = (procPortPins & ~dir) | (data & dir);
dataRead = (data | ~dir) & (procPortPins | 0x17);
pla.setCpuPort((data | ~dir) & 0x07);
if ((dir & 0x20) == 0)
{
dataRead &= ~0x20;
}
if (tape_sense && (dir & 0x10) == 0)
{
dataRead &= ~0x10;
}
}
public:
ZeroRAMBank(PLA &pla, SystemRAMBank &ramBank) :
pla(pla),
ramBank(ramBank)
{}
void reset()
{
dataBit6.reset();
dataBit7.reset();
dir = 0;
data = 0x3f;
dataRead = 0x3f;
procPortPins = 0x3f;
updateCpuPort();
}
uint8_t peek(uint_least16_t address) override
{
switch (address)
{
case 0:
return dir;
case 1:
{
uint8_t retval = dataRead;
// for unused bits in input mode, the value comes from the "capacitor"
// set real value of bit 6
if (!(dir & 0x40))
{
retval &= ~0x40;
retval |= dataBit6.readBit(pla.getPhi2Time());
}
// set real value of bit 7
if (!(dir & 0x80))
{
retval &= ~0x80;
retval |= dataBit7.readBit(pla.getPhi2Time());
}
return retval;
}
default:
return ramBank.peek(address);
}
}
void poke(uint_least16_t address, uint8_t value) override
{
switch (address)
{
case 0:
// when switching an unused bit from output (where it contained a
// stable value) to input mode (where the input is floating), some
// of the charge is transferred to the floating input
if (dir != value)
{
// check if bit 6 has flipped from 1 to 0
if ((dir & 0x40) && !(value & 0x40))
dataBit6.writeBit(pla.getPhi2Time(), data);
// check if bit 7 has flipped from 1 to 0
if ((dir & 0x80) && !(value & 0x80))
dataBit7.writeBit(pla.getPhi2Time(), data);
dir = value;
updateCpuPort();
}
value = pla.getLastReadByte();
break;
case 1:
// when writing to an unused bit that is output, charge the "capacitor",
// otherwise don't touch it
if (dir & 0x40)
dataBit6.writeBit(pla.getPhi2Time(), value);
if (dir & 0x80)
dataBit7.writeBit(pla.getPhi2Time(), value);
if (data != value)
{
data = value;
updateCpuPort();
}
value = pla.getLastReadByte();
break;
default:
break;
}
ramBank.poke(address, value);
}
};
}
#endif
libsidplayfp::Bank
Definition Bank.h:36
libsidplayfp::PLA
Definition pla.h:35
libsidplayfp::SystemRAMBank
Definition SystemRAMBank.h:39
libsidplayfp::SystemRAMBank::peek
uint8_t peek(uint_least16_t address) override
Definition SystemRAMBank.h:72
libsidplayfp::SystemRAMBank::poke
void poke(uint_least16_t address, uint8_t value) override
Definition SystemRAMBank.h:77
libsidplayfp::ZeroRAMBank
Definition ZeroRAMBank.h:132
libsidplayfp::ZeroRAMBank::poke
void poke(uint_least16_t address, uint8_t value) override
Definition ZeroRAMBank.h:233
libsidplayfp::ZeroRAMBank::peek
uint8_t peek(uint_least16_t address) override
Definition ZeroRAMBank.h:200
libsidplayfp::dataBit
Definition ZeroRAMBank.h:56