From a3931674dced32f4ce6437cf1e13e9b8a1646278 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 26 Mar 2024 21:33:46 -0400 Subject: [PATCH] Seemingly navigate I2C correctly. --- Components/I2C/I2C.cpp | 87 +++++++++++++++++---------- Components/I2C/I2C.hpp | 7 ++- Machines/Acorn/Archimedes/CMOSRAM.hpp | 39 +++++++++--- 3 files changed, 92 insertions(+), 41 deletions(-) diff --git a/Components/I2C/I2C.cpp b/Components/I2C/I2C.cpp index 195ba55bc..a39f09f97 100644 --- a/Components/I2C/I2C.cpp +++ b/Components/I2C/I2C.cpp @@ -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 next) { if(next) { - peripheral_response_ = static_cast((*next) << 1); - peripheral_bits_ = 9; - set_state(State::PostingByte); + peripheral_response_ = static_cast(*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(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; } diff --git a/Components/I2C/I2C.hpp b/Components/I2C/I2C.hpp index 1f276e07a..870b84416 100644 --- a/Components/I2C/I2C.hpp +++ b/Components/I2C/I2C.hpp @@ -38,6 +38,7 @@ public: private: bool data_ = false; bool clock_ = false; + bool in_bit_ = false; std::unordered_map 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; }; diff --git a/Machines/Acorn/Archimedes/CMOSRAM.hpp b/Machines/Acorn/Archimedes/CMOSRAM.hpp index 58f1c9b26..9a3c5e5e0 100644 --- a/Machines/Acorn/Archimedes/CMOSRAM.hpp +++ b/Machines/Acorn/Archimedes/CMOSRAM.hpp @@ -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 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. } }