mirror of
https://github.com/JorjBauer/aiie.git
synced 2024-10-31 09:15:51 +00:00
138 lines
2.9 KiB
C++
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;
|
|
}
|
|
}
|