#include "models/lt_bus.h" #include "utils/log.h" #include #include 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 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 { 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 p_sock0{"sock0"}; tlm_utils::simple_initiator_socket p_sock1{"sock1"}; tlm_utils::simple_initiator_socket 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& 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& 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; }