1
0
mirror of https://github.com/TomHarte/CLK.git synced 2026-04-22 08:16:42 +00:00

Adds full 8-bit clock addressing; stubs clock into the IIgs.

This commit is contained in:
Thomas Harte
2020-10-29 21:38:36 -04:00
parent 1249fb598b
commit 034056d0cd
2 changed files with 162 additions and 42 deletions
+133 -37
View File
@@ -49,7 +49,7 @@ class ClockStorage {
protected:
static constexpr uint16_t NoResult = 0x100;
static constexpr uint16_t DidWrite = 0x101;
static constexpr uint16_t DidComplete = 0x101;
uint16_t perform(uint8_t command) {
/*
Documented commands:
@@ -74,43 +74,87 @@ class ClockStorage {
All the documentation says about the test register is to set the top
two bits to 0 for normal operation. Abnormal operation is undefined.
*/
switch(phase_) {
case Phase::Command:
// Decode an address.
switch(command & 0x70) {
default:
if(command & 0x40) {
// RAM addresses 0x00 0x0f.
address_ = (command >> 2) & 0xf;
} else return DidComplete; // Unrecognised.
break;
if(!is_writing_) {
// Decode an address; use values >= 0x100 to represent clock time.
address_ = (command >> 2) & 0x1f;
if(address_ < 4) {
address_ |= 0x100;
} else if(address_ >= 0x10) {
address_ &= 0xf;
} else if(address_ >= 0x8 && address_ <= 0xb) {
address_ = 0x10 + (address_ & 0x3);
}
// If this is a read, return a result; otherwise prepare to write.
if(command & 0x80) {
return (address_ & 0x100) ? seconds_[address_ & 0xff] : data_[address_];
}
is_writing_ = true;
return NoResult;
} else {
// First test: is this to the write-protect register?
if(address_ == 0xd) {
write_protect_ = command;
}
// No other writing is permitted if the write protect
// register won't allow it.
if(!(write_protect_ & 0x80)) {
if(address_ & 0x100) {
seconds_[address_ & 0xff] = command;
} else {
data_[address_] = command;
case 0x00:
// A time access.
address_ = SecondsBuffer + ((command >> 2)&3);
break;
case 0x30:
// Either a register access or an extended instruction.
if(command & 0x08) {
address_ = (command & 0x7) << 5;
phase_ = (command & 0x80) ? Phase::SecondAddressByteWrite : Phase::SecondAddressByteRead;
return NoResult;
} else {
address_ = (command & 4) ? RegisterWriteProtect : RegisterTest;
}
break;
case 0x20:
// RAM addresses 0x10 0x13.
address_ = 0x10 + ((command >> 2) & 0x3);
break;
}
}
is_writing_ = false;
return DidWrite;
// If this is a read, return a result; otherwise prepare to write.
if(command & 0x80) {
// The two registers are write-only.
if(address_ == RegisterTest || address_ == RegisterWriteProtect) {
return DidComplete;
}
return (address_ >= SecondsBuffer) ? seconds_[address_ & 0xff] : data_[address_];
}
phase_ = Phase::WriteData;
return NoResult;
case Phase::SecondAddressByteRead:
case Phase::SecondAddressByteWrite:
if(command & 0x83) {
return DidComplete;
}
address_ |= command >> 2;
if(phase_ == Phase::SecondAddressByteRead) {
phase_ = Phase::Command;
return data_[address_]; // Only RAM accesses can get this far.
} else {
phase_ = Phase::WriteData;
}
return NoResult;
case Phase::WriteData:
// First test: is this to the write-protect register?
if(address_ == RegisterWriteProtect) {
write_protect_ = command;
return DidComplete;
}
if(address_ == RegisterTest) {
// No documentation here.
return DidComplete;
}
// No other writing is permitted if the write protect
// register won't allow it.
if(!(write_protect_ & 0x80)) {
if(address_ >= SecondsBuffer) {
seconds_[address_ & 0xff] = command;
} else {
data_[address_] = command;
}
}
phase_ = Phase::Command;
return DidComplete;
}
}
@@ -119,8 +163,20 @@ class ClockStorage {
uint8_t data_[256];
uint8_t seconds_[4];
uint8_t write_protect_;
bool is_writing_ = false;
int address_;
static constexpr int SecondsBuffer = 0x100;
static constexpr int RegisterTest = 0x200;
static constexpr int RegisterWriteProtect = 0x201;
enum class Phase {
Command,
SecondAddressByteRead,
SecondAddressByteWrite,
WriteData
};
Phase phase_ = Phase::Command;
};
/*!
@@ -152,7 +208,7 @@ class SerialClock: public ClockStorage {
default:
result_ = uint8_t(effect);
break;
case ClockStorage::DidWrite:
case ClockStorage::DidComplete:
abort();
break;
}
@@ -186,6 +242,46 @@ class SerialClock: public ClockStorage {
bool previous_clock_ = false;
};
/*!
Provides the parallel interface implemented by the IIgs.
*/
class ParallelClock: public ClockStorage {
public:
void set_control(uint8_t control) {
if(!(control&0x80)) return;
if(control & 0x40) {
// Read from the RTC.
// A no-op for now.
} else {
// Write to the RTC. Which in this implementation also sets up a future read.
data_ = uint8_t(perform(data_));
}
// MAGIC! The transaction took 0 seconds.
// TODO: no magic.
control_ = control & 0x7f;
// Bit 5 is also meant to be 1 or 0 to indicate the final byte.
}
uint8_t get_control() {
return control_;
}
void set_data(uint8_t data) {
data_ = data;
}
uint8_t get_data() {
return data_;
}
private:
uint8_t data_;
uint8_t control_;
};
}
}