aboutsummaryrefslogtreecommitdiff
path: root/test/lt_bus_locked.cc
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 /test/lt_bus_locked.cc
parentccaae5eb310ae8aabd77f8fe53f181f4afe0365b (diff)
downloadsysc-playground-291364e1b408d29236034854b7ed30f080e5b6c9.tar.gz
sysc-playground-291364e1b408d29236034854b7ed30f080e5b6c9.zip
lt_bus: add initial support for global bus locking
Diffstat (limited to 'test/lt_bus_locked.cc')
-rw-r--r--test/lt_bus_locked.cc168
1 files changed, 168 insertions, 0 deletions
diff --git a/test/lt_bus_locked.cc b/test/lt_bus_locked.cc
new file mode 100644
index 0000000..55357a8
--- /dev/null
+++ b/test/lt_bus_locked.cc
@@ -0,0 +1,168 @@
+#include "models/lt_bus.h"
+#include "utils/log.h"
+
+#include <tlm_utils/simple_initiator_socket.h>
+#include <tlm_utils/simple_target_socket.h>
+
+using sc_core::SC_NS;
+using sc_core::sc_time;
+using sc_core::sc_time_stamp;
+using sc_core::SC_ZERO_TIME;
+
+// -- TARGET -------------------------------------------------------------------
+
+struct target : public sc_core::sc_module {
+ explicit target(sc_core::sc_module_name nm) : sc_module(std::move(nm)) {
+ p_sock.register_b_transport(this, &target::b_transport);
+ p_sock.register_get_direct_mem_ptr(this, &target::get_direct_mem_ptr);
+ }
+
+ tlm_utils::simple_target_socket<target> p_sock{"sock"};
+
+ private:
+ void b_transport(tlm::tlm_generic_payload& tx, sc_core::sc_time&) {
+ CLOGM(YELLOW, "transport 0x%llx w: %d r: %d", tx.get_address(),
+ tx.is_write(), tx.is_read());
+
+ // Miss-use byte enable len for sleep duration.
+ if (u32 len = tx.get_byte_enable_length()) {
+ CLOGM(YELLOW, "wait(%u)", len);
+ wait(sc_time(len, SC_NS));
+ }
+
+ tx.set_response_status(tlm::TLM_OK_RESPONSE);
+ }
+
+ bool get_direct_mem_ptr(tlm::tlm_generic_payload&, tlm::tlm_dmi&) {
+ return true;
+ }
+};
+
+// -- INITIATOR ----------------------------------------------------------------
+
+struct initiator : public sc_core::sc_module {
+ SC_HAS_PROCESS(initiator);
+
+ explicit initiator(sc_core::sc_module_name nm) : sc_module(std::move(nm)) {
+ SC_THREAD(run0);
+ SC_THREAD(run1);
+ SC_THREAD(run2);
+ }
+
+ tlm_utils::simple_initiator_socket<initiator> p_sock0{"sock0"};
+ tlm_utils::simple_initiator_socket<initiator> p_sock1{"sock1"};
+ tlm_utils::simple_initiator_socket<initiator> p_sock2{"sock2"};
+
+ private:
+ void setup_tx(tlm::tlm_generic_payload& tx, u64 addr, u32 len) const {
+ tx.set_command(tlm::TLM_WRITE_COMMAND);
+ tx.set_address(addr);
+ tx.set_data_ptr(nullptr);
+ tx.set_data_length(4);
+ tx.set_byte_enable_ptr(nullptr);
+ tx.set_byte_enable_length(len);
+ tx.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);
+ tx.set_dmi_allowed(false);
+ }
+
+ void send_tx(tlm_utils::simple_initiator_socket<initiator>& sock,
+ u64 addr,
+ u32 len,
+ bool lock = false) {
+ tlm::tlm_generic_payload tx;
+ setup_tx(tx, addr, len);
+
+ auto* bl = new bus_lock;
+ bl->is_lock = lock;
+ tx.set_extension(bl);
+
+ CLOGM(CYAN, "[%s] ACCESS @0x%lx lock=%d", sock.name(), addr, lock);
+
+ sc_core::sc_time t;
+ sock->b_transport(tx, t);
+
+ CLOGM(CYAN, "[%s] ACCESS ok: %d (%s)", sock.name(), tx.is_response_ok(),
+ tx.get_response_string().c_str());
+ }
+
+ bool get_dmi(tlm_utils::simple_initiator_socket<initiator>& sock, u64 addr) {
+ tlm::tlm_generic_payload tx;
+ setup_tx(tx, addr, 1 /* len */);
+
+ tlm::tlm_dmi dmi;
+ return sock->get_direct_mem_ptr(tx, dmi);
+ }
+
+ void run0() {
+ // Lock the bus.
+ send_tx(p_sock0, 0x1000, 0, true); // @0ns
+ // Spend some time, keep the bus locked.
+ wait(500, SC_NS);
+ // Unlock the bus.
+ send_tx(p_sock0, 0x1000, 0, false); // @500ns
+ assert(sc_time_stamp() == sc_time(500, SC_NS));
+
+ // -- 500ns --
+
+ wait(10, SC_NS);
+ LOGM("------------------------------------------------------------");
+ wait(90, SC_NS);
+
+ // Waiting for bus lock, as run1 & run2 have currently an outstanding tx.
+ assert(sc_time_stamp() == sc_time(600, SC_NS));
+ send_tx(p_sock0, 0x1000, 0, true); // @600ns
+ assert(sc_time_stamp() == sc_time(750, SC_NS));
+ }
+
+ void run1() {
+ wait(10, SC_NS);
+ // No dmi while bus is locked.
+ assert(get_dmi(p_sock1, 0x2000) == false);
+
+ send_tx(p_sock1, 0x2000, 0); // @10ns
+ assert(sc_time_stamp() == sc_time(500, SC_NS));
+
+ // -- 500ns --
+
+ wait(50, SC_NS);
+ send_tx(p_sock1, 0x2000, 100); // @550ns
+ assert(sc_time_stamp() == sc_time(650, SC_NS));
+ }
+
+ void run2() {
+ wait(20, SC_NS);
+ // No dmi while bus is locked.
+ assert(get_dmi(p_sock2, 0x3000) == false);
+
+ send_tx(p_sock2, 0x3000, 0);
+ assert(sc_time_stamp() == sc_time(500, SC_NS));
+
+ // -- 500ns --
+
+ wait(50, SC_NS);
+ send_tx(p_sock1, 0x3000, 200); // @550ns
+ assert(sc_time_stamp() == sc_time(750, SC_NS));
+ }
+};
+
+// -- SC_MAIN ------------------------------------------------------------------
+
+extern "C" int sc_main(int, char*[]) {
+ lt_bus bus{"bus"};
+
+ target target1{"target1"};
+
+ initiator init1{"init1"};
+
+ bus.attach_target(target1.p_sock, 0x0000, 0xffff);
+
+ bus.attach_initiator(init1.p_sock0);
+ bus.attach_initiator(init1.p_sock1);
+ bus.attach_initiator(init1.p_sock2);
+
+ bus.show_mmap();
+
+ sc_core::sc_start();
+
+ return 0;
+}