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:
@@ -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_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user