1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-08-13 00:25:26 +00:00

Seemingly navigate I2C correctly.

This commit is contained in:
Thomas Harte
2024-03-26 21:33:46 -04:00
parent bd4ef5ec57
commit a3931674dc
3 changed files with 92 additions and 41 deletions

View File

@@ -24,7 +24,7 @@ void Bus::set_data(bool pulled) {
bool Bus::data() { bool Bus::data() {
bool result = data_; bool result = data_;
if(peripheral_bits_) { if(peripheral_bits_) {
result |= !(peripheral_response_ & 0x200); result |= !(peripheral_response_ & 0x80);
} }
return result; return result;
} }
@@ -41,34 +41,51 @@ void Bus::set_clock_data(bool clock_pulled, bool data_pulled) {
return; return;
} }
const bool prior_clock = clock_;
const bool prior_data = data_; const bool prior_data = data_;
clock_ = clock_pulled; clock_ = clock_pulled;
data_ = data_pulled; data_ = data_pulled;
if(clock_) { if(peripheral_bits_) {
// Trailing edge of clock => bit has been consumed.
if(!prior_clock && clock_) {
logger.info().append("<< %d", (peripheral_response_ >> 7) & 1);
--peripheral_bits_;
peripheral_response_ <<= 1;
if(!peripheral_bits_) {
signal(Event::FinishedOutput);
}
}
return; return;
} }
if(prior_data != data_) { if(!clock_ && prior_data != data_) {
// Data transition outside of a clock cycle => start or stop.
in_bit_ = false;
if(data_) { if(data_) {
// logger.info().append("S"); logger.info().append("S");
signal(Event::Start); signal(Event::Start);
} else { } else {
// logger.info().append("P"); logger.info().append("W");
signal(Event::Stop); signal(Event::Stop);
} }
} else { } else if(clock_ != prior_clock) {
if(peripheral_bits_) { // Bits: wait until the falling edge of the cycle.
--peripheral_bits_; if(!clock_) {
peripheral_response_ <<= 1; // Rising edge: clock period begins.
} in_bit_ = true;
} else if(in_bit_) {
// Falling edge: clock period ends (assuming it began; otherwise this is prep, post-start bit).
in_bit_ = false;
if(data_) { if(data_) {
// logger.info().append("0"); logger.info().append("0");
signal(Event::Zero); signal(Event::Zero);
} else { } else {
// logger.info().append("1"); logger.info().append("1");
signal(Event::One); signal(Event::One);
}
} }
} }
} }
@@ -82,7 +99,7 @@ void Bus::signal(Event event) {
const auto acknowledge = [&]() { const auto acknowledge = [&]() {
// Post an acknowledgement bit. // Post an acknowledgement bit.
peripheral_response_ = 0; peripheral_response_ = 0;
peripheral_bits_ = 2; peripheral_bits_ = 1;
}; };
const auto set_state = [&](State state) { const auto set_state = [&](State state) {
@@ -93,11 +110,10 @@ void Bus::signal(Event event) {
const auto enqueue = [&](std::optional<uint8_t> next) { const auto enqueue = [&](std::optional<uint8_t> next) {
if(next) { if(next) {
peripheral_response_ = static_cast<uint16_t>((*next) << 1); peripheral_response_ = static_cast<uint16_t>(*next);
peripheral_bits_ = 9; peripheral_bits_ = 8;
set_state(State::PostingByte); set_state(State::AwaitingByteAcknowledge);
} else { } else {
acknowledge();
set_state(State::AwaitingAddress); set_state(State::AwaitingAddress);
} }
}; };
@@ -123,7 +139,6 @@ void Bus::signal(Event event) {
case State::CollectingAddress: case State::CollectingAddress:
capture_bit(); capture_bit();
if(input_count_ == 8) { if(input_count_ == 8) {
auto pair = peripherals_.find(uint8_t(input_) & 0xfe); auto pair = peripherals_.find(uint8_t(input_) & 0xfe);
if(pair != peripherals_.end()) { if(pair != peripherals_.end()) {
@@ -132,8 +147,7 @@ void Bus::signal(Event event) {
if(input_&1) { if(input_&1) {
acknowledge(); acknowledge();
set_state(State::PostingByte); set_state(State::CompletingWriteAcknowledge);
// enqueue(active_peripheral_->read());
} else { } else {
acknowledge(); acknowledge();
set_state(State::ReceivingByte); set_state(State::ReceivingByte);
@@ -145,11 +159,9 @@ void Bus::signal(Event event) {
break; break;
case State::ReceivingByte: case State::ReceivingByte:
// Run down the clock on the acknowledge bit. if(event == Event::FinishedOutput) {
if(peripheral_bits_) {
return; return;
} }
capture_bit(); capture_bit();
if(input_count_ == 8) { if(input_count_ == 8) {
active_peripheral_->write(static_cast<uint8_t>(input_)); active_peripheral_->write(static_cast<uint8_t>(input_));
@@ -158,13 +170,24 @@ void Bus::signal(Event event) {
} }
break; break;
case State::PostingByte: case State::CompletingWriteAcknowledge:
// Finish whatever is enqueued. if(event != Event::FinishedOutput) {
if(peripheral_bits_) { break;
return; }
enqueue(active_peripheral_->read());
break;
case State::AwaitingByteAcknowledge:
if(event == Event::FinishedOutput) {
break;
}
if(event != Event::Zero) {
logger.info().append("Peripheral byte not acknowledged");
state_ = State::AwaitingAddress;
break;
} }
// Add a new byte (including its acknowledge bit). // Add a new byte if there is one.
enqueue(active_peripheral_->read()); enqueue(active_peripheral_->read());
break; break;
} }

View File

@@ -38,6 +38,7 @@ public:
private: private:
bool data_ = false; bool data_ = false;
bool clock_ = false; bool clock_ = false;
bool in_bit_ = false;
std::unordered_map<int, Peripheral *> peripherals_; std::unordered_map<int, Peripheral *> peripherals_;
uint16_t input_ = 0xffff; uint16_t input_ = 0xffff;
@@ -48,7 +49,7 @@ private:
int peripheral_bits_ = 0; int peripheral_bits_ = 0;
enum class Event { enum class Event {
Zero, One, Start, Stop, Zero, One, Start, Stop, FinishedOutput,
}; };
void signal(Event); void signal(Event);
@@ -56,7 +57,9 @@ private:
AwaitingAddress, AwaitingAddress,
CollectingAddress, CollectingAddress,
PostingByte, CompletingWriteAcknowledge,
AwaitingByteAcknowledge,
ReceivingByte, ReceivingByte,
} state_ = State::AwaitingAddress; } state_ = State::AwaitingAddress;
}; };

View File

@@ -1,15 +1,16 @@
// //
// CMOSRAM.hpp // CMOSRAM.hpp
// Clock Signal // Clock Signal
// //
// Created by Thomas Harte on 20/03/2024. // Created by Thomas Harte on 20/03/2024.
// Copyright © 2024 Thomas Harte. All rights reserved. // Copyright © 2024 Thomas Harte. All rights reserved.
// //
#pragma once #pragma once
#include "../../../Components/I2C/I2C.hpp" #include "../../../Components/I2C/I2C.hpp"
namespace Archimedes { namespace Archimedes {
struct CMOSRAM: public I2C::Peripheral { struct CMOSRAM: public I2C::Peripheral {
@@ -18,16 +19,40 @@ struct CMOSRAM: public I2C::Peripheral {
} }
std::optional<uint8_t> read() override { std::optional<uint8_t> read() override {
return 0; // VERY TEMPORARY. For now, borrowed from Arcem.
// To replace with whatever the system-written default is.
static constexpr uint8_t defaults[] = {
0x00, 0x83, 0x55, 0x16, 0x14, 0x09, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0x14, 0x00, 0x6f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d,
0x00, 0xfe, 0x00, 0xeb, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x10, 0x50, 0x20, 0x08, 0x0a, 0x2c,
0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x5c, 0x13, 0x00, 0x00, 0x04, 0xfd, 0x08, 0x01, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static_assert(sizeof(defaults) == 256);
const uint8_t result = defaults[address_];
++address_;
return result;
} }
void write(uint8_t value) override { void write(uint8_t value) override {
if(expecting_address_) { if(expecting_address_) {
address_ = value; address_ = value;
expecting_address_ = false;
} else { } else {
printf("Write to %d\n", address_);
++address_; ++address_;
// TODO: write to RAM. // TODO: write.
} }
} }