aiie/apple/noslotclock.cpp

138 lines
2.9 KiB
C++

#include "noslotclock.h"
#define initSequence 0x5CA33AC55CA33AC5LL
/* The no-slot clock works like this...
*
* The NSC is installed in some bank of ROM memory. For our instance,
* it's 0xC300 or 0xC800. When a read or write occurs in these pages
* - and ROM isn't switched out or whatever - then this driver is
* invoked.
*
* (It's the job of applemmu to decide if the right address is being
* called to invoke the read or write here.)
*
* To get the clock to respond, we need to first pass it the init
* Sequence (above). The NSC gets one bit at a time from watching the
* transactions on the bus. So first the driver reads or writes to
* memory address (e.g.) 0xC800 or 0xC801, depending on whether it
* wants to send a 0 or 1 bit; and then, if the NSC sees all of the
* correct bits for the init sequence, it allows responses when
* reading from memory (e.g.) 0xC804. These responses are, again, one
* bit at a time of the current date and time.
*/
NoSlotClock::NoSlotClock(AppleMMU *mmu)
{
this->mmu = mmu;
compareReg = initSequence;
clockReg = 0x00LL;
clockRegPtr = compareRegPtr = 0;
regEnabled = false;
writeEnabled = true;
}
NoSlotClock::~NoSlotClock()
{
}
bool NoSlotClock::read(uint8_t s, uint8_t *d)
{
if (s & 0x04) {
return doRead(d);
}
else {
doWrite(s);
return false;
}
}
void NoSlotClock::write(uint8_t s)
{
if (s & 0x04) {
doRead(0);
} else {
doWrite(s);
}
}
bool NoSlotClock::doRead(uint8_t *d)
{
if (!regEnabled) {
compareReg = initSequence;
compareRegPtr = 0;
writeEnabled = true;
return false;
}
if (d) {
*d = (clockReg & 0x01) ?
((*d) | 1) :
((*d) & ~1);
}
clockRegPtr++;
clockReg >>= 1;
if (clockRegPtr == 64) {
regEnabled = false;
clockRegPtr = 0;
}
return true;
}
void NoSlotClock::doWrite(uint8_t address)
{
if (!writeEnabled) {
return;
}
if (!regEnabled) {
if ((compareReg & 0x01) == (address & 0x01)) {
compareRegPtr++;
compareReg >>= 1;
if (compareRegPtr == 64) {
regEnabled = true;
compareRegPtr = 0;
compareReg = initSequence;
populateClockRegister();
}
} else {
writeEnabled = false;
}
} else {
// The NSC driver is writing a new clock time to the clock...
clockRegPtr++;
clockReg >>= 1;
if (address & 0x01) {
clockReg |= 0x8000000000000000LL;
}
if (clockRegPtr == 64) {
regEnabled = false;
// The clockReg should now contain a BCD4 packed date like
// 0x1708071521140200
// ... 2017, August 07, <day of week?>; 21:14:02.00
// where that <day of week> is clearly suspect. Probably because 2017
// was too far in the future when this driver was written...
clockRegPtr = 0;
updateClockFromRegister();
}
}
}
void NoSlotClock::writeNibble(uint8_t n)
{
for (uint8_t i=0; i<4; i++) {
clockReg <<= 1;
if (n & 0x08) {
clockReg |= 1;
}
n <<= 1;
}
}