aiie/teensy/teensy-clock.cpp

137 lines
3.3 KiB
C++

#include <string.h> // memset
#include <TimeLib.h>
#include "teensy-clock.h"
#include "applemmu.h" // for FLOATING
/*
* http://apple2online.com/web_documents/prodos_technical_notes.pdf
*
* When ProDOS calls a clock card, the card deposits an ASCII string
* in the GETLN input buffer in the form: 07,04,14,22,46,57. The
* string translates as the following:
*
* 07 = the month, July
* 04 = the day of the week (00 = Sun)
* 14 = the date (00 to 31)
* 22 = the hour (00 to 23)
* 46 = the minute (00 to 59)
* 57 = the second (00 to 59)
*/
static void timeToProDOS(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute,
uint8_t proDOStimeOut[4])
{
proDOStimeOut[0] = ((year % 100) << 1) | (month >> 3);
proDOStimeOut[1] = ((month & 0x0F) << 5) | (day & 0x1F);
proDOStimeOut[2] = hour & 0x1F;
proDOStimeOut[3] = minute & 0x3F;
}
TeensyClock::TeensyClock(AppleMMU *mmu)
{
this->mmu = mmu;
}
TeensyClock::~TeensyClock()
{
}
bool TeensyClock::Serialize(int8_t fd)
{
return true;
}
bool TeensyClock::Deserialize(int8_t fd)
{
return true;
}
void TeensyClock::Reset()
{
}
uint8_t TeensyClock::readSwitches(uint8_t s)
{
// When any switch is read, we'll put the current time in the prodos time buffer
tmElements_t tm;
breakTime(now(), tm);
// Put the date/time in the official ProDOS buffer
uint8_t prodosOut[4];
timeToProDOS(tm.Year, tm.Month, tm.Day, tm.Hour, tm.Minute, prodosOut);
mmu->write(0xBF90, prodosOut[0]);
mmu->write(0xBF91, prodosOut[1]);
mmu->write(0xBF92, prodosOut[2]);
mmu->write(0xBF93, prodosOut[3]);
// and also generate a date/time that contains seconds, but not a
// year, which it also consumes
char ts[18];
sprintf(ts, "%.2d,%.2d,%.2d,%.2d,%.2d,%.2d",
tm.Month,
tm.Wday - 1, // Sunday should be 0, not 1
tm.Day,
tm.Hour,
tm.Minute,
tm.Second);
uint8_t i = 0;
while (ts[i]) {
mmu->write(0x200 + i, ts[i] | 0x80);
i++;
}
return FLOATING;
}
void TeensyClock::writeSwitches(uint8_t s, uint8_t v)
{
// printf("unimplemented write to the clock - 0x%X\n", v);
}
// FIXME: this assumes slot #5
void TeensyClock::loadROM(uint8_t *toWhere)
{
memset(toWhere, 0xEA, 256); // fill the page with NOPs
// ProDOS only needs these 4 bytes to recognize that a clock is present
toWhere[0x00] = 0x08; // PHP
toWhere[0x02] = 0x28; // PLP
toWhere[0x04] = 0x58; // CLI
toWhere[0x06] = 0x70; // BVS
// Pad out those bytes so they will return control well. The program
// at c500 becomes
//
// C500: PHP ; push to stack
// NOP ; filler (filled in by memory clear)
// PLP ; pop from stack
// RTS ; return
// CLI ; required to detect driver, but not used
// NOP ; filled in by memory clear
// BVS ; required to detect driver, but not used
toWhere[0x03] = 0x60; // RTS
// And it needs a small routing here to read/write it:
// 0x08: read
toWhere[0x08] = 0x4C; // JMP $C510
toWhere[0x09] = 0x10;
toWhere[0x0A] = 0xC5;
// 0x0b: write
toWhere[0x0B] = 0x8D; // STA $C0D0 (slot 5's first switch)
toWhere[0x0C] = 0xD0;
toWhere[0x0D] = 0xC0;
toWhere[0x0E] = 0x60; // RTS
// simple read
toWhere[0x10] = 0xAD; // LDA $C0D0 (slot 5's first switch)
toWhere[0x11] = 0xD0;
toWhere[0x12] = 0xC0;
toWhere[0x13] = 0x60; // RTS
}