mirror of
https://github.com/TomHarte/CLK.git
synced 2025-04-05 04:37:41 +00:00
Extend I2C state machine.
This commit is contained in:
parent
2712d50e05
commit
7b1f800387
@ -14,7 +14,11 @@ void Bus::set_data(bool pulled) {
|
||||
set_clock_data(clock_, pulled);
|
||||
}
|
||||
bool Bus::data() {
|
||||
return data_;
|
||||
bool result = data_;
|
||||
if(peripheral_bits_) {
|
||||
result |= !(peripheral_response_ & 0x80);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void Bus::set_clock(bool pulled) {
|
||||
@ -25,43 +29,81 @@ bool Bus::clock() {
|
||||
}
|
||||
|
||||
void Bus::set_clock_data(bool clock_pulled, bool data_pulled) {
|
||||
const bool has_new_bit = clock_pulled && !clock_;
|
||||
const bool prior_clock = clock_;
|
||||
const bool prior_data = data_;
|
||||
clock_ = clock_pulled;
|
||||
data_ = data_pulled;
|
||||
|
||||
// TODO: "Stop condition: SDA goes high after SCL (?)".
|
||||
// Advance peripheral input from peripheral if clock
|
||||
// transitions from high to low.
|
||||
if(peripheral_bits_ && prior_clock && !clock_) {
|
||||
--peripheral_bits_;
|
||||
peripheral_response_ <<= 1;
|
||||
}
|
||||
|
||||
if(has_new_bit) {
|
||||
// Test for a start bit.
|
||||
//
|
||||
// "Start condition: SDA goes low before SCL".
|
||||
if(input_count_ < 0 && data_) {
|
||||
input_count_ = 0;
|
||||
}
|
||||
|
||||
// Accumulate if started.
|
||||
if(input_count_ >= 0) {
|
||||
const auto capture_bit = [&]() {
|
||||
if(prior_clock && !clock_) {
|
||||
input_ = uint16_t((input_ << 1) | (data_pulled ? 0 : 1));
|
||||
++input_count_;
|
||||
}
|
||||
};
|
||||
|
||||
// Test for meaning.
|
||||
switch(phase_) {
|
||||
case Phase::AwaitingAddress:
|
||||
if(input_count_ == 9) {
|
||||
printf("Calling %02x?", uint8_t(input_));
|
||||
// Check for stop condition at any time.
|
||||
// "A LOW-to-HIGH transition of the data line
|
||||
// while the clock is HIGH is defined as the STOP condition".
|
||||
if(prior_data && !data_ && !clock_) {
|
||||
printf("Stopped\n");
|
||||
phase_ = Phase::AwaitingStart;
|
||||
}
|
||||
|
||||
auto pair = peripherals_.find(uint8_t(input_));
|
||||
if(pair != peripherals_.end()) {
|
||||
active_peripheral_ = pair->second;
|
||||
// TODO: device found; pull data low for the next clock.
|
||||
}
|
||||
switch(phase_) {
|
||||
case Phase::AwaitingStart:
|
||||
// "A HIGH-to-LOW transition of the data line while
|
||||
// the clock is HIGH is defined as the START condition"
|
||||
if(!prior_data && data_ && !clock_) {
|
||||
phase_ = Phase::CollectingAddress;
|
||||
input_count_ = 0;
|
||||
input_ = 0;
|
||||
printf("Waiting for [remainder of] address\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case Phase::CollectingAddress:
|
||||
capture_bit();
|
||||
if(input_count_ == 8) {
|
||||
printf("Addressed %02x?\n", uint8_t(input_));
|
||||
|
||||
auto pair = peripherals_.find(uint8_t(input_));
|
||||
if(pair != peripherals_.end()) {
|
||||
active_peripheral_ = pair->second;
|
||||
|
||||
peripheral_response_ = 0;
|
||||
peripheral_bits_ = 2;
|
||||
phase_ = Phase::AwaitingByte;
|
||||
printf("Waiting for byte\n");
|
||||
} else {
|
||||
phase_ = Phase::AwaitingStart;
|
||||
printf("No device\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case Phase::CollectingData:
|
||||
break;
|
||||
}
|
||||
case Phase::AwaitingByte:
|
||||
if(data_ && clock_) {
|
||||
printf("Beginning byte\n");
|
||||
phase_ = Phase::CollectingByte;
|
||||
input_count_ = 0;
|
||||
input_ = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case Phase::CollectingByte:
|
||||
capture_bit();
|
||||
if(input_count_ == 8) {
|
||||
printf("Got byte %02x?\n", uint8_t(input_));
|
||||
phase_ = Phase::AwaitingByte;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,11 +40,15 @@ private:
|
||||
int input_count_ = -1;
|
||||
|
||||
Peripheral *active_peripheral_ = nullptr;
|
||||
uint16_t peripheral_response_ = 0xffff;
|
||||
int peripheral_bits_ = 0;
|
||||
|
||||
enum class Phase {
|
||||
AwaitingAddress,
|
||||
CollectingData,
|
||||
} phase_ = Phase::AwaitingAddress;
|
||||
AwaitingStart,
|
||||
CollectingAddress,
|
||||
AwaitingByte,
|
||||
CollectingByte,
|
||||
} phase_ = Phase::AwaitingStart;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -72,6 +72,10 @@ static_assert(BitMask<15, 14>::value == 49152);
|
||||
|
||||
namespace Archimedes {
|
||||
|
||||
struct CMOSRAM: public I2C::Peripheral {
|
||||
|
||||
};
|
||||
|
||||
/// Models a half-duplex serial link between two parties, framing bytes with one start bit and two stop bits.
|
||||
struct HalfDuplexSerial {
|
||||
static constexpr uint16_t ShiftMask = 0b1111'1110'0000'0000;
|
||||
@ -541,15 +545,15 @@ struct Interrupts {
|
||||
return true;
|
||||
|
||||
case 0x335'0018 & AddressMask:
|
||||
logger.error().append("TODO: latch B write");
|
||||
logger.error().append("TODO: latch B write: %02x", value);
|
||||
return true;
|
||||
|
||||
case 0x335'0040 & AddressMask:
|
||||
logger.error().append("TODO: latch A write");
|
||||
logger.error().append("TODO: latch A write: %02x", value);
|
||||
return true;
|
||||
|
||||
case 0x335'0048 & AddressMask:
|
||||
logger.error().append("TODO: latch C write");
|
||||
logger.error().append("TODO: latch C write: %02x", value);
|
||||
return true;
|
||||
|
||||
case 0x336'0000 & AddressMask:
|
||||
@ -576,6 +580,8 @@ struct Interrupts {
|
||||
irq_a_.status = IRQA::SetAlways | IRQA::PowerOnReset;
|
||||
irq_b_.status = 0x00;
|
||||
fiq_.status = 0x80; // 'set always'.
|
||||
|
||||
i2c_.add_peripheral(&cmos_, 0xa0);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -612,6 +618,7 @@ private:
|
||||
|
||||
// The I2C bus.
|
||||
I2C::Bus i2c_;
|
||||
CMOSRAM cmos_;
|
||||
};
|
||||
|
||||
/// Primarily models the MEMC.
|
||||
|
@ -215,8 +215,8 @@
|
||||
4B228CDB24DA41890077EF25 /* ScanTarget.metal in Sources */ = {isa = PBXBuildFile; fileRef = 4B228CDA24DA41880077EF25 /* ScanTarget.metal */; };
|
||||
4B2530F4244E6774007980BF /* fm.json in Resources */ = {isa = PBXBuildFile; fileRef = 4B2530F3244E6773007980BF /* fm.json */; };
|
||||
4B25B5F925BD083C00362C84 /* DiskIIDrive.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B80CD6D2568A82600176FCC /* DiskIIDrive.cpp */; };
|
||||
4B2A1CD52BA62066004496CE /* I2C.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A1CD32BA62066004496CE /* I2C.cpp */; };
|
||||
4B2A1CD62BA62066004496CE /* I2C.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A1CD32BA62066004496CE /* I2C.cpp */; };
|
||||
4B2A1CDC2BA775C5004496CE /* I2C.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A1CD92BA775C5004496CE /* I2C.cpp */; };
|
||||
4B2A1CDD2BA775C5004496CE /* I2C.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A1CD92BA775C5004496CE /* I2C.cpp */; };
|
||||
4B2A332D1DB86821002876E3 /* OricOptions.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B2A332B1DB86821002876E3 /* OricOptions.xib */; };
|
||||
4B2A539F1D117D36003C6002 /* CSAudioQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A53911D117D36003C6002 /* CSAudioQueue.m */; };
|
||||
4B2B3A4B1F9B8FA70062DABF /* Typer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2B3A471F9B8FA70062DABF /* Typer.cpp */; };
|
||||
@ -1353,8 +1353,8 @@
|
||||
4B24095A1C45DF85004DA684 /* Stepper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Stepper.hpp; sourceTree = "<group>"; };
|
||||
4B2530F3244E6773007980BF /* fm.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = fm.json; sourceTree = "<group>"; };
|
||||
4B262BFF29691F55002EC0F7 /* PersonalityTraits.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = PersonalityTraits.hpp; sourceTree = "<group>"; };
|
||||
4B2A1CD32BA62066004496CE /* I2C.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = I2C.cpp; path = I2C/I2C.cpp; sourceTree = "<group>"; };
|
||||
4B2A1CD42BA62066004496CE /* I2C.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = I2C.hpp; path = I2C/I2C.hpp; sourceTree = "<group>"; };
|
||||
4B2A1CD92BA775C5004496CE /* I2C.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = I2C.cpp; sourceTree = "<group>"; };
|
||||
4B2A1CDA2BA775C5004496CE /* I2C.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = I2C.hpp; sourceTree = "<group>"; };
|
||||
4B2A332C1DB86821002876E3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = "Clock Signal/Base.lproj/OricOptions.xib"; sourceTree = SOURCE_ROOT; };
|
||||
4B2A3B5A29993DFA007CE366 /* Storage.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Storage.hpp; sourceTree = "<group>"; };
|
||||
4B2A3B5B29995FF6007CE366 /* LineBuffer.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = LineBuffer.hpp; sourceTree = "<group>"; };
|
||||
@ -2810,6 +2810,15 @@
|
||||
path = "FM Synthesis";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4B2A1CDB2BA775C5004496CE /* I2C */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B2A1CD92BA775C5004496CE /* I2C.cpp */,
|
||||
4B2A1CDA2BA775C5004496CE /* I2C.hpp */,
|
||||
);
|
||||
path = I2C;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4B2A538F1D117D36003C6002 /* Audio */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -4825,13 +4834,12 @@
|
||||
4B595FAA2086DFBA0083CAA8 /* AudioToggle */,
|
||||
4B4A762D1DB1A35C007AAE2E /* AY38910 */,
|
||||
4B302181208A550100773308 /* DiskII */,
|
||||
4B2A1CDB2BA775C5004496CE /* I2C */,
|
||||
4B4B1A39200198C900A0F866 /* KonamiSCC */,
|
||||
4BC23A212467600E001A6030 /* OPx */,
|
||||
4BF0BC6E2973318E00CCA2B5 /* RP5C01 */,
|
||||
4B0ACBFF237756EC008902D0 /* Serial */,
|
||||
4BB0A6582044FD3000FB3688 /* SN76489 */,
|
||||
4B2A1CD32BA62066004496CE /* I2C.cpp */,
|
||||
4B2A1CD42BA62066004496CE /* I2C.hpp */,
|
||||
);
|
||||
name = Components;
|
||||
path = ../../Components;
|
||||
@ -5880,7 +5888,7 @@
|
||||
4B055A9E1FAE85DA0060FFFF /* G64.cpp in Sources */,
|
||||
4B055AB81FAE860F0060FFFF /* ZX80O81P.cpp in Sources */,
|
||||
4B055AB01FAE86070060FFFF /* PulseQueuedTape.cpp in Sources */,
|
||||
4B2A1CD62BA62066004496CE /* I2C.cpp in Sources */,
|
||||
4B2A1CDD2BA775C5004496CE /* I2C.cpp in Sources */,
|
||||
4B0F1C1D2604EA1000B85C66 /* Keyboard.cpp in Sources */,
|
||||
4B055AAC1FAE85FD0060FFFF /* PCMSegment.cpp in Sources */,
|
||||
4BB307BC235001C300457D33 /* 6850.cpp in Sources */,
|
||||
@ -6076,7 +6084,7 @@
|
||||
4B4518A11F75FD1C00926311 /* D64.cpp in Sources */,
|
||||
4BCE0052227CE8CA000CA200 /* DiskIICard.cpp in Sources */,
|
||||
4BF0BC68297108D600CCA2B5 /* MemorySlotHandler.cpp in Sources */,
|
||||
4B2A1CD52BA62066004496CE /* I2C.cpp in Sources */,
|
||||
4B2A1CDC2BA775C5004496CE /* I2C.cpp in Sources */,
|
||||
4BCF1FA41DADC3DD0039D2E7 /* Oric.cpp in Sources */,
|
||||
4BD67DCB209BE4D700AB2146 /* StaticAnalyser.cpp in Sources */,
|
||||
4BB4BFB922A4372F0069048D /* StaticAnalyser.cpp in Sources */,
|
||||
|
Loading…
x
Reference in New Issue
Block a user