diff options
author | Johannes Stoelp <johannes.stoelp@gmail.com> | 2023-11-01 18:41:44 +0100 |
---|---|---|
committer | Johannes Stoelp <johannes.stoelp@gmail.com> | 2023-11-01 18:41:44 +0100 |
commit | 291364e1b408d29236034854b7ed30f080e5b6c9 (patch) | |
tree | f55efb5954ea6374295f2e04d98041b766992660 /test/lt_bus_locked.cc | |
parent | ccaae5eb310ae8aabd77f8fe53f181f4afe0365b (diff) | |
download | sysc-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.cc | 168 |
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; +} |