diff options
author | Gabe Black <gabeblack@google.com> | 2018-05-24 01:37:55 -0700 |
---|---|---|
committer | Gabe Black <gabeblack@google.com> | 2018-08-08 10:09:54 +0000 |
commit | 16fa8d7cc8c92f5ab879e4cf9c6c0bbb3567860f (patch) | |
tree | 7b6faaacb4574a555e561534aa4a8508c0624c32 /src/systemc/tests/tlm/nb2b_adapter | |
parent | 7235d3b5211d0ba8f528d930a4c1e7ad62eec51a (diff) | |
download | gem5-16fa8d7cc8c92f5ab879e4cf9c6c0bbb3567860f.tar.xz |
systemc: Import tests from the Accellera systemc distribution.
Change-Id: Iad76b398949a55d768a34d027a2d8e3739953da6
Reviewed-on: https://gem5-review.googlesource.com/10845
Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Maintainer: Gabe Black <gabeblack@google.com>
Diffstat (limited to 'src/systemc/tests/tlm/nb2b_adapter')
-rw-r--r-- | src/systemc/tests/tlm/nb2b_adapter/golden/nb2b_adapter.log | 2 | ||||
-rw-r--r-- | src/systemc/tests/tlm/nb2b_adapter/mm.h | 85 | ||||
-rw-r--r-- | src/systemc/tests/tlm/nb2b_adapter/nb2b_adapter.cpp | 376 |
3 files changed, 463 insertions, 0 deletions
diff --git a/src/systemc/tests/tlm/nb2b_adapter/golden/nb2b_adapter.log b/src/systemc/tests/tlm/nb2b_adapter/golden/nb2b_adapter.log new file mode 100644 index 000000000..e8b02e2f3 --- /dev/null +++ b/src/systemc/tests/tlm/nb2b_adapter/golden/nb2b_adapter.log @@ -0,0 +1,2 @@ +SystemC Simulation +Unit test for nb2b adapter, PEQ, and instance-specific extensions. Should remain silent diff --git a/src/systemc/tests/tlm/nb2b_adapter/mm.h b/src/systemc/tests/tlm/nb2b_adapter/mm.h new file mode 100644 index 000000000..c91dd3ed5 --- /dev/null +++ b/src/systemc/tests/tlm/nb2b_adapter/mm.h @@ -0,0 +1,85 @@ + +// ******************************************************************* +// User-defined memory manager, which maintains a pool of transactions +// ******************************************************************* + +#include "tlm.h" + +class mm: public tlm::tlm_mm_interface +{ + typedef tlm::tlm_generic_payload gp_t; + +public: + mm() : free_list(0), empties(0) {} + + virtual ~mm() + { + gp_t* ptr; + + while (free_list) + { + ptr = free_list->trans; + + // Delete generic payload and all extensions + sc_assert(ptr); + delete ptr; + + free_list = free_list->next; + } + + while (empties) + { + access* x = empties; + empties = empties->next; + + // Delete free list access struct + delete x; + } + } + + gp_t* allocate(); + void free(gp_t* trans); + +private: + struct access + { + gp_t* trans; + access* next; + access* prev; + }; + + access* free_list; + access* empties; +}; + +mm::gp_t* mm::allocate() +{ + gp_t* ptr; + if (free_list) + { + ptr = free_list->trans; + empties = free_list; + free_list = free_list->next; + } + else + { + ptr = new gp_t(this); + } + return ptr; +} + +void mm::free(gp_t* trans) +{ + trans->reset(); // Delete auto extensions + if (!empties) + { + empties = new access; + empties->next = free_list; + empties->prev = 0; + if (free_list) + free_list->prev = empties; + } + free_list = empties; + free_list->trans = trans; + empties = free_list->prev; +} diff --git a/src/systemc/tests/tlm/nb2b_adapter/nb2b_adapter.cpp b/src/systemc/tests/tlm/nb2b_adapter/nb2b_adapter.cpp new file mode 100644 index 000000000..cde8b30bf --- /dev/null +++ b/src/systemc/tests/tlm/nb2b_adapter/nb2b_adapter.cpp @@ -0,0 +1,376 @@ + +// Unit test for nb2b adapter in simple_target_socket, PEQ, and instance-specific extensions +// Checks for bug in original version of simple_target_socket + +#include <iomanip> + +#define SC_INCLUDE_DYNAMIC_PROCESSES + +#include "systemc" +using namespace sc_core; +using namespace sc_dt; +using namespace std; + +#include "tlm.h" +#include "tlm_utils/simple_initiator_socket.h" +#include "tlm_utils/simple_target_socket.h" +#include "tlm_utils/multi_passthrough_initiator_socket.h" +#include "tlm_utils/multi_passthrough_target_socket.h" +#include "tlm_utils/peq_with_cb_and_phase.h" +#include "tlm_utils/instance_specific_extensions.h" + +#include "mm.h" + + +int rand_ps() +{ + int n = rand() % 100; + n = n * n * n; + return n / 100; +} + + +struct Initiator: sc_module +{ + tlm_utils::simple_initiator_socket<Initiator> socket; + + SC_CTOR(Initiator) + : socket("socket") + , request_in_progress(0) + , m_peq(this, &Initiator::peq_cb) + { + socket.register_nb_transport_bw(this, &Initiator::nb_transport_bw); + + SC_THREAD(thread_process); + } + + void thread_process() + { + tlm::tlm_generic_payload* trans; + tlm::tlm_phase phase; + sc_time delay; + + trans = m_mm.allocate(); + trans->acquire(); + + int adr = 0; + data[0] = adr; + + trans->set_command( tlm::TLM_WRITE_COMMAND ); + trans->set_address( adr ); + trans->set_data_ptr( reinterpret_cast<unsigned char*>(&data[0]) ); + trans->set_data_length( 4 ); + trans->set_streaming_width( 4 ); + trans->set_byte_enable_ptr( 0 ); + trans->set_dmi_allowed( false ); + trans->set_response_status( tlm::TLM_INCOMPLETE_RESPONSE ); + + socket->b_transport( *trans, delay ); + + trans->release(); + + for (int i = 0; i < 5000; i++) + { + int adr = rand(); + tlm::tlm_command cmd = static_cast<tlm::tlm_command>(rand() % 2); + if (cmd == tlm::TLM_WRITE_COMMAND) data[i % 16] = adr; + + // Grab a new transaction from the memory manager + trans = m_mm.allocate(); + trans->acquire(); + + trans->set_command( cmd ); + trans->set_address( adr ); + trans->set_data_ptr( reinterpret_cast<unsigned char*>(&data[i % 16]) ); + trans->set_data_length( 4 ); + trans->set_streaming_width( 4 ); + trans->set_byte_enable_ptr( 0 ); + trans->set_dmi_allowed( false ); + trans->set_response_status( tlm::TLM_INCOMPLETE_RESPONSE ); + + if (request_in_progress) + wait(end_request_event); + request_in_progress = trans; + phase = tlm::BEGIN_REQ; + + delay = sc_time(rand_ps(), SC_PS); + + tlm::tlm_sync_enum status; + status = socket->nb_transport_fw( *trans, phase, delay ); + previous_time = sc_time_stamp() + delay; + + if (status == tlm::TLM_UPDATED) + { + m_peq.notify( *trans, phase, delay ); + } + else if (status == tlm::TLM_COMPLETED) + { + request_in_progress = 0; + + check_transaction( *trans ); + + trans->release(); + } + wait( sc_time(rand_ps(), SC_PS) ); + } + } + + virtual tlm::tlm_sync_enum nb_transport_bw( tlm::tlm_generic_payload& trans, + tlm::tlm_phase& phase, sc_time& delay ) + { + if (sc_time_stamp() + delay < previous_time) + SC_REPORT_FATAL("TLM-2", "nb_transport_bw called with decreasing timing annotation"); + previous_time = sc_time_stamp() + delay; + + m_peq.notify( trans, phase, delay ); + return tlm::TLM_ACCEPTED; + } + + void peq_cb(tlm::tlm_generic_payload& trans, const tlm::tlm_phase& phase) + { + if (phase == tlm::END_REQ || (&trans == request_in_progress && phase == tlm::BEGIN_RESP)) + { + request_in_progress = 0; + end_request_event.notify(); + } + else if (phase == tlm::BEGIN_REQ || phase == tlm::END_RESP) + SC_REPORT_FATAL("TLM-2", "Illegal transaction phase received by initiator"); + + if (phase == tlm::BEGIN_RESP) + { + check_transaction( trans ); + + tlm::tlm_phase fw_phase = tlm::END_RESP; + sc_time delay = sc_time(rand_ps(), SC_PS); + socket->nb_transport_fw( trans, fw_phase, delay ); + previous_time = sc_time_stamp() + delay; + + trans.release(); + } + } + + void check_transaction(tlm::tlm_generic_payload& trans) + { + if ( trans.is_response_error() ) + { + char txt[100]; + sprintf(txt, "Transaction returned with error, response status = %s", + trans.get_response_string().c_str()); + SC_REPORT_ERROR("TLM-2", txt); + } + + tlm::tlm_command cmd = trans.get_command(); + sc_dt::uint64 adr = trans.get_address(); + int* ptr = reinterpret_cast<int*>( trans.get_data_ptr() ); + + if (cmd == tlm::TLM_READ_COMMAND) + sc_assert( *ptr == -int(adr) ); + } + + mm m_mm; + int data[16]; + tlm::tlm_generic_payload* request_in_progress; + sc_event end_request_event; + tlm_utils::peq_with_cb_and_phase<Initiator> m_peq; + sc_time previous_time; +}; + + +// Dumb interconnect that simply routes transactions through + +struct Interconnect: sc_module +{ + tlm_utils::multi_passthrough_target_socket<Interconnect, 32> targ_socket; + tlm_utils::multi_passthrough_initiator_socket<Interconnect, 32> init_socket; + + Interconnect(sc_module_name _name, unsigned int _offset) + : sc_module(_name) + , targ_socket("targ_socket") + , init_socket("init_socket") + , offset(_offset) + { + targ_socket.register_b_transport (this, &Interconnect::b_transport); + targ_socket.register_nb_transport_fw (this, &Interconnect::nb_transport_fw); + targ_socket.register_get_direct_mem_ptr (this, &Interconnect::get_direct_mem_ptr); + targ_socket.register_transport_dbg (this, &Interconnect::transport_dbg); + init_socket.register_nb_transport_bw (this, &Interconnect::nb_transport_bw); + init_socket.register_invalidate_direct_mem_ptr(this, &Interconnect::invalidate_direct_mem_ptr); + } + + void end_of_elaboration() + { + if ( targ_socket.size() != init_socket.size() ) + SC_REPORT_ERROR("TLM-2", "#initiators != #targets in Interconnect"); + } + + virtual void b_transport( int id, tlm::tlm_generic_payload& trans, sc_time& delay ) + { + unsigned int target = (id + offset) % init_socket.size(); // Route-through + + init_socket[target]->b_transport( trans, delay ); + } + + + struct route_extension: tlm_utils::instance_specific_extension<route_extension> + { + int id; + }; + + tlm_utils::instance_specific_extension_accessor accessor; + + + virtual tlm::tlm_sync_enum nb_transport_fw( int id, tlm::tlm_generic_payload& trans, + tlm::tlm_phase& phase, sc_time& delay ) + { + route_extension* ext = 0; + if (phase == tlm::BEGIN_REQ) + { + ext = new route_extension; + ext->id = id; + accessor(trans).set_extension(ext); + } + + unsigned int target = (id + offset) % init_socket.size(); // Route-through + + tlm::tlm_sync_enum status; + status = init_socket[target]->nb_transport_fw( trans, phase, delay ); + + if (status == tlm::TLM_COMPLETED) + { + accessor(trans).clear_extension(ext); + delete ext; + } + + return status; + } + + virtual bool get_direct_mem_ptr( int id, tlm::tlm_generic_payload& trans, + tlm::tlm_dmi& dmi_data) + { + unsigned int target = (id + offset) % init_socket.size(); // Route-through + + bool status = init_socket[target]->get_direct_mem_ptr( trans, dmi_data ); + + return status; + } + + virtual unsigned int transport_dbg( int id, tlm::tlm_generic_payload& trans ) + { + unsigned int target = (id + offset) % init_socket.size(); // Route-through + + return init_socket[target]->transport_dbg( trans ); + } + + + virtual tlm::tlm_sync_enum nb_transport_bw( int id, tlm::tlm_generic_payload& trans, + tlm::tlm_phase& phase, sc_time& delay ) + { + route_extension* ext = 0; + accessor(trans).get_extension(ext); + sc_assert(ext); + + tlm::tlm_sync_enum status; + status = targ_socket[ ext->id ]->nb_transport_bw( trans, phase, delay ); + + if (status == tlm::TLM_COMPLETED) + { + accessor(trans).clear_extension(ext); + delete ext; + } + + return status; + } + + virtual void invalidate_direct_mem_ptr( int id, sc_dt::uint64 start_range, + sc_dt::uint64 end_range ) + { + for (unsigned int i = 0; i < targ_socket.size(); i++) + targ_socket[i]->invalidate_direct_mem_ptr(start_range, end_range); + } + + unsigned int offset; +}; + + +struct Target: sc_module +{ + tlm_utils::simple_target_socket<Target> socket; + + SC_CTOR(Target) + : socket("socket") + { + socket.register_b_transport (this, &Target::b_transport); + } + + virtual void b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ) + { + execute_transaction(trans); + } + + + void execute_transaction(tlm::tlm_generic_payload& trans) + { + tlm::tlm_command cmd = trans.get_command(); + sc_dt::uint64 adr = trans.get_address(); + unsigned char* ptr = trans.get_data_ptr(); + unsigned int len = trans.get_data_length(); + unsigned char* byt = trans.get_byte_enable_ptr(); + unsigned int wid = trans.get_streaming_width(); + + if (byt != 0) { + trans.set_response_status( tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE ); + return; + } + if (len > 4 || wid < len) { + trans.set_response_status( tlm::TLM_BURST_ERROR_RESPONSE ); + return; + } + + if ( cmd == tlm::TLM_READ_COMMAND ) + { + *reinterpret_cast<int*>(ptr) = -int(adr); + } + else if ( cmd == tlm::TLM_WRITE_COMMAND ) + { + sc_assert( *reinterpret_cast<unsigned int*>(ptr) == adr ); + } + + trans.set_response_status( tlm::TLM_OK_RESPONSE ); + } + +}; + + +SC_MODULE(Top) +{ + Initiator *initiator1; + Initiator *initiator2; + Interconnect *interconnect; + Target *target1; + Target *target2; + + SC_CTOR(Top) + { + initiator1 = new Initiator ("initiator1"); + initiator2 = new Initiator ("initiator2"); + interconnect = new Interconnect("interconnect", 1); + target1 = new Target ("target1"); + target2 = new Target ("target2"); + + initiator1->socket.bind(interconnect->targ_socket); + initiator2->socket.bind(interconnect->targ_socket); + interconnect->init_socket.bind(target1->socket); + interconnect->init_socket.bind(target2->socket); + } +}; + + +int sc_main(int argc, char* argv[]) +{ + cout << "Unit test for nb2b adapter, PEQ, and instance-specific extensions. Should remain silent\n"; + + Top top("top"); + sc_start(); + return 0; +} + |