aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohannes Stoelp <johannes.stoelp@gmail.com>2023-11-01 18:41:44 +0100
committerJohannes Stoelp <johannes.stoelp@gmail.com>2023-11-01 18:41:44 +0100
commit291364e1b408d29236034854b7ed30f080e5b6c9 (patch)
treef55efb5954ea6374295f2e04d98041b766992660 /src
parentccaae5eb310ae8aabd77f8fe53f181f4afe0365b (diff)
downloadsysc-playground-291364e1b408d29236034854b7ed30f080e5b6c9.tar.gz
sysc-playground-291364e1b408d29236034854b7ed30f080e5b6c9.zip
lt_bus: add initial support for global bus locking
Diffstat (limited to 'src')
-rw-r--r--src/models/lt_bus.h101
1 files changed, 95 insertions, 6 deletions
diff --git a/src/models/lt_bus.h b/src/models/lt_bus.h
index cf09d99..86b181e 100644
--- a/src/models/lt_bus.h
+++ b/src/models/lt_bus.h
@@ -7,10 +7,42 @@
#include "utils/tlm_target_socket_tagged.h"
#include "utils/types.h"
+#include <sysc/kernel/sc_event.h>
+
#include <algorithm>
#include <memory>
#include <vector>
+// TLM bus lock extension.
+//
+// This extension is used to implemented the bus locking scheme.
+// The protocol is as follows. Once an initiator sends a locked transaction,
+// the bus will be locked by that initiator after all currently pending
+// transactions are finished. The bus is locked until the locking initiator
+// sends an unlocked transaction.
+struct [[nodiscard]] bus_lock : tlm::tlm_extension<bus_lock> {
+ bool is_lock{false};
+
+ constexpr explicit bus_lock() = default;
+ constexpr explicit bus_lock(const bus_lock&) = default;
+
+ virtual tlm_extension_base* clone() const override {
+ return new bus_lock(*this);
+ }
+
+ virtual void copy_from(const tlm_extension_base& ext) override {
+ if (&ext == this) {
+ // Copy from self, nop.
+ return;
+ }
+
+ assert(typeid(this) == typeid(ext));
+ const bus_lock& other = static_cast<const bus_lock&>(ext);
+
+ is_lock = other.is_lock;
+ }
+};
+
class lt_bus : public sc_core::sc_module {
using target_socket = tlm_target_socket_tagged<lt_bus>;
using target_socket_ptr = std::unique_ptr<target_socket>;
@@ -116,14 +148,60 @@ class lt_bus : public sc_core::sc_module {
// -- TLM_FW_TRANSPORT_IF ----------------------------------------------------
- void b_transport(usize, tlm::tlm_generic_payload& tx, sc_core::sc_time& t) {
+ void b_transport(usize idx,
+ tlm::tlm_generic_payload& tx,
+ sc_core::sc_time& t) {
if (const auto r = decode(tx)) {
- const auto tx_start = tx.get_address();
- assert(r.start <= tx_start);
+ const auto do_tx = [&]() {
+ const auto tx_start = tx.get_address();
+ assert(r.start <= tx_start);
- tx.set_address(tx_start - r.start);
- (*r.sock)->b_transport(tx, t);
- tx.set_address(tx_start);
+ tx.set_address(tx_start - r.start);
+ (*r.sock)->b_transport(tx, t);
+ tx.set_address(tx_start);
+ };
+
+ while (m_bl.is_locked && (m_bl.idx != idx)) {
+ wait(m_bl.ev_no_pending_tx);
+ }
+
+ const auto* ext = tx.get_extension<bus_lock>();
+ if (ext && ext->is_lock) {
+ assert(!m_bl.is_locked);
+
+ m_bl.is_locked = true;
+ m_bl.idx = idx;
+
+ if (m_bl.pending_tx) {
+ wait(m_bl.ev_no_pending_tx);
+ }
+ assert(m_bl.pending_tx == 0);
+
+ // Invalidate DMI pointers for the whole address space. This forces all
+ // initiators on the slow path and through the bus, which can than
+ // enforce the exclusive access.
+ for (auto& sock : m_initiators) {
+ (*sock)->invalidate_direct_mem_ptr(0, -1ull);
+ }
+
+ do_tx();
+ assert(m_bl.pending_tx == 0);
+ } else {
+ assert(!m_bl.is_locked || (m_bl.is_locked && m_bl.idx == idx));
+
+ m_bl.pending_tx++;
+ do_tx();
+ m_bl.pending_tx--;
+
+ if (m_bl.is_locked && m_bl.idx == idx) {
+ assert(m_bl.pending_tx == 0);
+ m_bl.is_locked = false;
+ }
+
+ if (m_bl.pending_tx == 0) {
+ m_bl.ev_no_pending_tx.notify(sc_core::SC_ZERO_TIME);
+ }
+ }
} else {
tx.set_response_status(tlm::TLM_ADDRESS_ERROR_RESPONSE);
}
@@ -132,6 +210,10 @@ class lt_bus : public sc_core::sc_module {
bool get_direct_mem_ptr(usize,
tlm::tlm_generic_payload& tx,
tlm::tlm_dmi& dmi) {
+ if (m_bl.is_locked) {
+ return false;
+ }
+
if (const auto r = decode(tx)) {
const auto tx_start = tx.get_address();
assert(r.start <= tx_start);
@@ -245,6 +327,13 @@ class lt_bus : public sc_core::sc_module {
std::vector<initiator_socket_ptr> m_targets;
// Address range mappings to BUS TARGETs (m_tragets).
std::vector<mapping> m_mappings;
+
+ struct bus_lock_state {
+ bool is_locked{false};
+ usize idx{0};
+ usize pending_tx{0};
+ sc_core::sc_event ev_no_pending_tx;
+ } m_bl;
};
#endif