1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-01 22:41:32 +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 result = data_;
if(peripheral_bits_) {
result |= !(peripheral_response_ & 0x200);
result |= !(peripheral_response_ & 0x80);
}
return result;
}
@ -41,34 +41,51 @@ void Bus::set_clock_data(bool clock_pulled, bool data_pulled) {
return;
}
const bool prior_clock = clock_;
const bool prior_data = data_;
clock_ = clock_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;
}
if(prior_data != data_) {
if(!clock_ && prior_data != data_) {
// Data transition outside of a clock cycle => start or stop.
in_bit_ = false;
if(data_) {
// logger.info().append("S");
logger.info().append("S");
signal(Event::Start);
} else {
// logger.info().append("P");
logger.info().append("W");
signal(Event::Stop);
}
} else {
if(peripheral_bits_) {
--peripheral_bits_;
peripheral_response_ <<= 1;
}
} else if(clock_ != prior_clock) {
// Bits: wait until the falling edge of the cycle.
if(!clock_) {
// 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_) {
// logger.info().append("0");
signal(Event::Zero);
} else {
// logger.info().append("1");
signal(Event::One);
if(data_) {
logger.info().append("0");
signal(Event::Zero);
} else {
logger.info().append("1");
signal(Event::One);
}
}
}
}
@ -82,7 +99,7 @@ void Bus::signal(Event event) {
const auto acknowledge = [&]() {
// Post an acknowledgement bit.
peripheral_response_ = 0;
peripheral_bits_ = 2;
peripheral_bits_ = 1;
};
const auto set_state = [&](State state) {
@ -93,11 +110,10 @@ void Bus::signal(Event event) {
const auto enqueue = [&](std::optional<uint8_t> next) {
if(next) {
peripheral_response_ = static_cast<uint16_t>((*next) << 1);
peripheral_bits_ = 9;
set_state(State::PostingByte);
peripheral_response_ = static_cast<uint16_t>(*next);
peripheral_bits_ = 8;
set_state(State::AwaitingByteAcknowledge);
} else {
acknowledge();
set_state(State::AwaitingAddress);
}
};
@ -123,7 +139,6 @@ void Bus::signal(Event event) {
case State::CollectingAddress:
capture_bit();
if(input_count_ == 8) {
auto pair = peripherals_.find(uint8_t(input_) & 0xfe);
if(pair != peripherals_.end()) {
@ -132,8 +147,7 @@ void Bus::signal(Event event) {
if(input_&1) {
acknowledge();
set_state(State::PostingByte);
// enqueue(active_peripheral_->read());
set_state(State::CompletingWriteAcknowledge);
} else {
acknowledge();
set_state(State::ReceivingByte);
@ -145,11 +159,9 @@ void Bus::signal(Event event) {
break;
case State::ReceivingByte:
// Run down the clock on the acknowledge bit.
if(peripheral_bits_) {
if(event == Event::FinishedOutput) {
return;
}
capture_bit();
if(input_count_ == 8) {
active_peripheral_->write(static_cast<uint8_t>(input_));
@ -158,13 +170,24 @@ void Bus::signal(Event event) {
}
break;
case State::PostingByte:
// Finish whatever is enqueued.
if(peripheral_bits_) {
return;
case State::CompletingWriteAcknowledge:
if(event != Event::FinishedOutput) {
break;
}
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());
break;
}

View File

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

View File

@ -1,15 +1,16 @@
//
// CMOSRAM.hpp
// Clock Signal
// CMOSRAM.hpp
// Clock Signal
//
// Created by Thomas Harte on 20/03/2024.
// Copyright © 2024 Thomas Harte. All rights reserved.
// Created by Thomas Harte on 20/03/2024.
// Copyright © 2024 Thomas Harte. All rights reserved.
//
#pragma once
#include "../../../Components/I2C/I2C.hpp"
namespace Archimedes {
struct CMOSRAM: public I2C::Peripheral {
@ -18,16 +19,40 @@ struct CMOSRAM: public I2C::Peripheral {
}
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 {
if(expecting_address_) {
address_ = value;
expecting_address_ = false;
} else {
printf("Write to %d\n", address_);
++address_;
// TODO: write to RAM.
// TODO: write.
}
}