112855Sgabeblack@google.com 212855Sgabeblack@google.com// Unit test for nb2b adapter in simple_target_socket, PEQ, and instance-specific extensions 312855Sgabeblack@google.com// Checks for bug in original version of simple_target_socket 412855Sgabeblack@google.com 512855Sgabeblack@google.com#include <iomanip> 612855Sgabeblack@google.com 712855Sgabeblack@google.com#define SC_INCLUDE_DYNAMIC_PROCESSES 812855Sgabeblack@google.com 912855Sgabeblack@google.com#include "systemc" 1012855Sgabeblack@google.comusing namespace sc_core; 1112855Sgabeblack@google.comusing namespace sc_dt; 1212855Sgabeblack@google.comusing namespace std; 1312855Sgabeblack@google.com 1412855Sgabeblack@google.com#include "tlm.h" 1512855Sgabeblack@google.com#include "tlm_utils/simple_initiator_socket.h" 1612855Sgabeblack@google.com#include "tlm_utils/simple_target_socket.h" 1712855Sgabeblack@google.com#include "tlm_utils/multi_passthrough_initiator_socket.h" 1812855Sgabeblack@google.com#include "tlm_utils/multi_passthrough_target_socket.h" 1912855Sgabeblack@google.com#include "tlm_utils/peq_with_cb_and_phase.h" 2012855Sgabeblack@google.com#include "tlm_utils/instance_specific_extensions.h" 2112855Sgabeblack@google.com 2212855Sgabeblack@google.com#include "mm.h" 2312855Sgabeblack@google.com 2412855Sgabeblack@google.com 2512855Sgabeblack@google.comint rand_ps() 2612855Sgabeblack@google.com{ 2712855Sgabeblack@google.com int n = rand() % 100; 2812855Sgabeblack@google.com n = n * n * n; 2912855Sgabeblack@google.com return n / 100; 3012855Sgabeblack@google.com} 3112855Sgabeblack@google.com 3212855Sgabeblack@google.com 3312855Sgabeblack@google.comstruct Initiator: sc_module 3412855Sgabeblack@google.com{ 3512855Sgabeblack@google.com tlm_utils::simple_initiator_socket<Initiator> socket; 3612855Sgabeblack@google.com 3712855Sgabeblack@google.com SC_CTOR(Initiator) 3812855Sgabeblack@google.com : socket("socket") 3912855Sgabeblack@google.com , request_in_progress(0) 4012855Sgabeblack@google.com , m_peq(this, &Initiator::peq_cb) 4112855Sgabeblack@google.com { 4212855Sgabeblack@google.com socket.register_nb_transport_bw(this, &Initiator::nb_transport_bw); 4312855Sgabeblack@google.com 4412855Sgabeblack@google.com SC_THREAD(thread_process); 4512855Sgabeblack@google.com } 4612855Sgabeblack@google.com 4712855Sgabeblack@google.com void thread_process() 4812855Sgabeblack@google.com { 4912855Sgabeblack@google.com tlm::tlm_generic_payload* trans; 5012855Sgabeblack@google.com tlm::tlm_phase phase; 5112855Sgabeblack@google.com sc_time delay; 5212855Sgabeblack@google.com 5312855Sgabeblack@google.com trans = m_mm.allocate(); 5412855Sgabeblack@google.com trans->acquire(); 5512855Sgabeblack@google.com 5612855Sgabeblack@google.com int adr = 0; 5712855Sgabeblack@google.com data[0] = adr; 5812855Sgabeblack@google.com 5912855Sgabeblack@google.com trans->set_command( tlm::TLM_WRITE_COMMAND ); 6012855Sgabeblack@google.com trans->set_address( adr ); 6112855Sgabeblack@google.com trans->set_data_ptr( reinterpret_cast<unsigned char*>(&data[0]) ); 6212855Sgabeblack@google.com trans->set_data_length( 4 ); 6312855Sgabeblack@google.com trans->set_streaming_width( 4 ); 6412855Sgabeblack@google.com trans->set_byte_enable_ptr( 0 ); 6512855Sgabeblack@google.com trans->set_dmi_allowed( false ); 6612855Sgabeblack@google.com trans->set_response_status( tlm::TLM_INCOMPLETE_RESPONSE ); 6712855Sgabeblack@google.com 6812855Sgabeblack@google.com socket->b_transport( *trans, delay ); 6912855Sgabeblack@google.com 7012855Sgabeblack@google.com trans->release(); 7112855Sgabeblack@google.com 7212855Sgabeblack@google.com for (int i = 0; i < 5000; i++) 7312855Sgabeblack@google.com { 7412855Sgabeblack@google.com int adr = rand(); 7512855Sgabeblack@google.com tlm::tlm_command cmd = static_cast<tlm::tlm_command>(rand() % 2); 7612855Sgabeblack@google.com if (cmd == tlm::TLM_WRITE_COMMAND) data[i % 16] = adr; 7712855Sgabeblack@google.com 7812855Sgabeblack@google.com // Grab a new transaction from the memory manager 7912855Sgabeblack@google.com trans = m_mm.allocate(); 8012855Sgabeblack@google.com trans->acquire(); 8112855Sgabeblack@google.com 8212855Sgabeblack@google.com trans->set_command( cmd ); 8312855Sgabeblack@google.com trans->set_address( adr ); 8412855Sgabeblack@google.com trans->set_data_ptr( reinterpret_cast<unsigned char*>(&data[i % 16]) ); 8512855Sgabeblack@google.com trans->set_data_length( 4 ); 8612855Sgabeblack@google.com trans->set_streaming_width( 4 ); 8712855Sgabeblack@google.com trans->set_byte_enable_ptr( 0 ); 8812855Sgabeblack@google.com trans->set_dmi_allowed( false ); 8912855Sgabeblack@google.com trans->set_response_status( tlm::TLM_INCOMPLETE_RESPONSE ); 9012855Sgabeblack@google.com 9112855Sgabeblack@google.com if (request_in_progress) 9212855Sgabeblack@google.com wait(end_request_event); 9312855Sgabeblack@google.com request_in_progress = trans; 9412855Sgabeblack@google.com phase = tlm::BEGIN_REQ; 9512855Sgabeblack@google.com 9612855Sgabeblack@google.com delay = sc_time(rand_ps(), SC_PS); 9712855Sgabeblack@google.com 9812855Sgabeblack@google.com tlm::tlm_sync_enum status; 9912855Sgabeblack@google.com status = socket->nb_transport_fw( *trans, phase, delay ); 10012855Sgabeblack@google.com previous_time = sc_time_stamp() + delay; 10112855Sgabeblack@google.com 10212855Sgabeblack@google.com if (status == tlm::TLM_UPDATED) 10312855Sgabeblack@google.com { 10412855Sgabeblack@google.com m_peq.notify( *trans, phase, delay ); 10512855Sgabeblack@google.com } 10612855Sgabeblack@google.com else if (status == tlm::TLM_COMPLETED) 10712855Sgabeblack@google.com { 10812855Sgabeblack@google.com request_in_progress = 0; 10912855Sgabeblack@google.com 11012855Sgabeblack@google.com check_transaction( *trans ); 11112855Sgabeblack@google.com 11212855Sgabeblack@google.com trans->release(); 11312855Sgabeblack@google.com } 11412855Sgabeblack@google.com wait( sc_time(rand_ps(), SC_PS) ); 11512855Sgabeblack@google.com } 11612855Sgabeblack@google.com } 11712855Sgabeblack@google.com 11812855Sgabeblack@google.com virtual tlm::tlm_sync_enum nb_transport_bw( tlm::tlm_generic_payload& trans, 11912855Sgabeblack@google.com tlm::tlm_phase& phase, sc_time& delay ) 12012855Sgabeblack@google.com { 12112855Sgabeblack@google.com if (sc_time_stamp() + delay < previous_time) 12212855Sgabeblack@google.com SC_REPORT_FATAL("TLM-2", "nb_transport_bw called with decreasing timing annotation"); 12312855Sgabeblack@google.com previous_time = sc_time_stamp() + delay; 12412855Sgabeblack@google.com 12512855Sgabeblack@google.com m_peq.notify( trans, phase, delay ); 12612855Sgabeblack@google.com return tlm::TLM_ACCEPTED; 12712855Sgabeblack@google.com } 12812855Sgabeblack@google.com 12912855Sgabeblack@google.com void peq_cb(tlm::tlm_generic_payload& trans, const tlm::tlm_phase& phase) 13012855Sgabeblack@google.com { 13112855Sgabeblack@google.com if (phase == tlm::END_REQ || (&trans == request_in_progress && phase == tlm::BEGIN_RESP)) 13212855Sgabeblack@google.com { 13312855Sgabeblack@google.com request_in_progress = 0; 13412855Sgabeblack@google.com end_request_event.notify(); 13512855Sgabeblack@google.com } 13612855Sgabeblack@google.com else if (phase == tlm::BEGIN_REQ || phase == tlm::END_RESP) 13712855Sgabeblack@google.com SC_REPORT_FATAL("TLM-2", "Illegal transaction phase received by initiator"); 13812855Sgabeblack@google.com 13912855Sgabeblack@google.com if (phase == tlm::BEGIN_RESP) 14012855Sgabeblack@google.com { 14112855Sgabeblack@google.com check_transaction( trans ); 14212855Sgabeblack@google.com 14312855Sgabeblack@google.com tlm::tlm_phase fw_phase = tlm::END_RESP; 14412855Sgabeblack@google.com sc_time delay = sc_time(rand_ps(), SC_PS); 14512855Sgabeblack@google.com socket->nb_transport_fw( trans, fw_phase, delay ); 14612855Sgabeblack@google.com previous_time = sc_time_stamp() + delay; 14712855Sgabeblack@google.com 14812855Sgabeblack@google.com trans.release(); 14912855Sgabeblack@google.com } 15012855Sgabeblack@google.com } 15112855Sgabeblack@google.com 15212855Sgabeblack@google.com void check_transaction(tlm::tlm_generic_payload& trans) 15312855Sgabeblack@google.com { 15412855Sgabeblack@google.com if ( trans.is_response_error() ) 15512855Sgabeblack@google.com { 15612855Sgabeblack@google.com char txt[100]; 15712855Sgabeblack@google.com sprintf(txt, "Transaction returned with error, response status = %s", 15812855Sgabeblack@google.com trans.get_response_string().c_str()); 15912855Sgabeblack@google.com SC_REPORT_ERROR("TLM-2", txt); 16012855Sgabeblack@google.com } 16112855Sgabeblack@google.com 16212855Sgabeblack@google.com tlm::tlm_command cmd = trans.get_command(); 16312855Sgabeblack@google.com sc_dt::uint64 adr = trans.get_address(); 16412855Sgabeblack@google.com int* ptr = reinterpret_cast<int*>( trans.get_data_ptr() ); 16512855Sgabeblack@google.com 16612855Sgabeblack@google.com if (cmd == tlm::TLM_READ_COMMAND) 16712855Sgabeblack@google.com sc_assert( *ptr == -int(adr) ); 16812855Sgabeblack@google.com } 16912855Sgabeblack@google.com 17012855Sgabeblack@google.com mm m_mm; 17112855Sgabeblack@google.com int data[16]; 17212855Sgabeblack@google.com tlm::tlm_generic_payload* request_in_progress; 17312855Sgabeblack@google.com sc_event end_request_event; 17412855Sgabeblack@google.com tlm_utils::peq_with_cb_and_phase<Initiator> m_peq; 17512855Sgabeblack@google.com sc_time previous_time; 17612855Sgabeblack@google.com}; 17712855Sgabeblack@google.com 17812855Sgabeblack@google.com 17912855Sgabeblack@google.com// Dumb interconnect that simply routes transactions through 18012855Sgabeblack@google.com 18112855Sgabeblack@google.comstruct Interconnect: sc_module 18212855Sgabeblack@google.com{ 18312855Sgabeblack@google.com tlm_utils::multi_passthrough_target_socket<Interconnect, 32> targ_socket; 18412855Sgabeblack@google.com tlm_utils::multi_passthrough_initiator_socket<Interconnect, 32> init_socket; 18512855Sgabeblack@google.com 18612855Sgabeblack@google.com Interconnect(sc_module_name _name, unsigned int _offset) 18712855Sgabeblack@google.com : sc_module(_name) 18812855Sgabeblack@google.com , targ_socket("targ_socket") 18912855Sgabeblack@google.com , init_socket("init_socket") 19012855Sgabeblack@google.com , offset(_offset) 19112855Sgabeblack@google.com { 19212855Sgabeblack@google.com targ_socket.register_b_transport (this, &Interconnect::b_transport); 19312855Sgabeblack@google.com targ_socket.register_nb_transport_fw (this, &Interconnect::nb_transport_fw); 19412855Sgabeblack@google.com targ_socket.register_get_direct_mem_ptr (this, &Interconnect::get_direct_mem_ptr); 19512855Sgabeblack@google.com targ_socket.register_transport_dbg (this, &Interconnect::transport_dbg); 19612855Sgabeblack@google.com init_socket.register_nb_transport_bw (this, &Interconnect::nb_transport_bw); 19712855Sgabeblack@google.com init_socket.register_invalidate_direct_mem_ptr(this, &Interconnect::invalidate_direct_mem_ptr); 19812855Sgabeblack@google.com } 19912855Sgabeblack@google.com 20012855Sgabeblack@google.com void end_of_elaboration() 20112855Sgabeblack@google.com { 20212855Sgabeblack@google.com if ( targ_socket.size() != init_socket.size() ) 20312855Sgabeblack@google.com SC_REPORT_ERROR("TLM-2", "#initiators != #targets in Interconnect"); 20412855Sgabeblack@google.com } 20512855Sgabeblack@google.com 20612855Sgabeblack@google.com virtual void b_transport( int id, tlm::tlm_generic_payload& trans, sc_time& delay ) 20712855Sgabeblack@google.com { 20812855Sgabeblack@google.com unsigned int target = (id + offset) % init_socket.size(); // Route-through 20912855Sgabeblack@google.com 21012855Sgabeblack@google.com init_socket[target]->b_transport( trans, delay ); 21112855Sgabeblack@google.com } 21212855Sgabeblack@google.com 21312855Sgabeblack@google.com 21412855Sgabeblack@google.com struct route_extension: tlm_utils::instance_specific_extension<route_extension> 21512855Sgabeblack@google.com { 21612855Sgabeblack@google.com int id; 21712855Sgabeblack@google.com }; 21812855Sgabeblack@google.com 21912855Sgabeblack@google.com tlm_utils::instance_specific_extension_accessor accessor; 22012855Sgabeblack@google.com 22112855Sgabeblack@google.com 22212855Sgabeblack@google.com virtual tlm::tlm_sync_enum nb_transport_fw( int id, tlm::tlm_generic_payload& trans, 22312855Sgabeblack@google.com tlm::tlm_phase& phase, sc_time& delay ) 22412855Sgabeblack@google.com { 22512855Sgabeblack@google.com route_extension* ext = 0; 22612855Sgabeblack@google.com if (phase == tlm::BEGIN_REQ) 22712855Sgabeblack@google.com { 22812855Sgabeblack@google.com ext = new route_extension; 22912855Sgabeblack@google.com ext->id = id; 23012855Sgabeblack@google.com accessor(trans).set_extension(ext); 23112855Sgabeblack@google.com } 23212855Sgabeblack@google.com 23312855Sgabeblack@google.com unsigned int target = (id + offset) % init_socket.size(); // Route-through 23412855Sgabeblack@google.com 23512855Sgabeblack@google.com tlm::tlm_sync_enum status; 23612855Sgabeblack@google.com status = init_socket[target]->nb_transport_fw( trans, phase, delay ); 23712855Sgabeblack@google.com 23812855Sgabeblack@google.com if (status == tlm::TLM_COMPLETED) 23912855Sgabeblack@google.com { 24012855Sgabeblack@google.com accessor(trans).clear_extension(ext); 24112855Sgabeblack@google.com delete ext; 24212855Sgabeblack@google.com } 24312855Sgabeblack@google.com 24412855Sgabeblack@google.com return status; 24512855Sgabeblack@google.com } 24612855Sgabeblack@google.com 24712855Sgabeblack@google.com virtual bool get_direct_mem_ptr( int id, tlm::tlm_generic_payload& trans, 24812855Sgabeblack@google.com tlm::tlm_dmi& dmi_data) 24912855Sgabeblack@google.com { 25012855Sgabeblack@google.com unsigned int target = (id + offset) % init_socket.size(); // Route-through 25112855Sgabeblack@google.com 25212855Sgabeblack@google.com bool status = init_socket[target]->get_direct_mem_ptr( trans, dmi_data ); 25312855Sgabeblack@google.com 25412855Sgabeblack@google.com return status; 25512855Sgabeblack@google.com } 25612855Sgabeblack@google.com 25712855Sgabeblack@google.com virtual unsigned int transport_dbg( int id, tlm::tlm_generic_payload& trans ) 25812855Sgabeblack@google.com { 25912855Sgabeblack@google.com unsigned int target = (id + offset) % init_socket.size(); // Route-through 26012855Sgabeblack@google.com 26112855Sgabeblack@google.com return init_socket[target]->transport_dbg( trans ); 26212855Sgabeblack@google.com } 26312855Sgabeblack@google.com 26412855Sgabeblack@google.com 26512855Sgabeblack@google.com virtual tlm::tlm_sync_enum nb_transport_bw( int id, tlm::tlm_generic_payload& trans, 26612855Sgabeblack@google.com tlm::tlm_phase& phase, sc_time& delay ) 26712855Sgabeblack@google.com { 26812855Sgabeblack@google.com route_extension* ext = 0; 26912855Sgabeblack@google.com accessor(trans).get_extension(ext); 27012855Sgabeblack@google.com sc_assert(ext); 27112855Sgabeblack@google.com 27212855Sgabeblack@google.com tlm::tlm_sync_enum status; 27312855Sgabeblack@google.com status = targ_socket[ ext->id ]->nb_transport_bw( trans, phase, delay ); 27412855Sgabeblack@google.com 27512855Sgabeblack@google.com if (status == tlm::TLM_COMPLETED) 27612855Sgabeblack@google.com { 27712855Sgabeblack@google.com accessor(trans).clear_extension(ext); 27812855Sgabeblack@google.com delete ext; 27912855Sgabeblack@google.com } 28012855Sgabeblack@google.com 28112855Sgabeblack@google.com return status; 28212855Sgabeblack@google.com } 28312855Sgabeblack@google.com 28412855Sgabeblack@google.com virtual void invalidate_direct_mem_ptr( int id, sc_dt::uint64 start_range, 28512855Sgabeblack@google.com sc_dt::uint64 end_range ) 28612855Sgabeblack@google.com { 28712855Sgabeblack@google.com for (unsigned int i = 0; i < targ_socket.size(); i++) 28812855Sgabeblack@google.com targ_socket[i]->invalidate_direct_mem_ptr(start_range, end_range); 28912855Sgabeblack@google.com } 29012855Sgabeblack@google.com 29112855Sgabeblack@google.com unsigned int offset; 29212855Sgabeblack@google.com}; 29312855Sgabeblack@google.com 29412855Sgabeblack@google.com 29512855Sgabeblack@google.comstruct Target: sc_module 29612855Sgabeblack@google.com{ 29712855Sgabeblack@google.com tlm_utils::simple_target_socket<Target> socket; 29812855Sgabeblack@google.com 29912855Sgabeblack@google.com SC_CTOR(Target) 30012855Sgabeblack@google.com : socket("socket") 30112855Sgabeblack@google.com { 30212855Sgabeblack@google.com socket.register_b_transport (this, &Target::b_transport); 30312855Sgabeblack@google.com } 30412855Sgabeblack@google.com 30512855Sgabeblack@google.com virtual void b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ) 30612855Sgabeblack@google.com { 30712855Sgabeblack@google.com execute_transaction(trans); 30812855Sgabeblack@google.com } 30912855Sgabeblack@google.com 31012855Sgabeblack@google.com 31112855Sgabeblack@google.com void execute_transaction(tlm::tlm_generic_payload& trans) 31212855Sgabeblack@google.com { 31312855Sgabeblack@google.com tlm::tlm_command cmd = trans.get_command(); 31412855Sgabeblack@google.com sc_dt::uint64 adr = trans.get_address(); 31512855Sgabeblack@google.com unsigned char* ptr = trans.get_data_ptr(); 31612855Sgabeblack@google.com unsigned int len = trans.get_data_length(); 31712855Sgabeblack@google.com unsigned char* byt = trans.get_byte_enable_ptr(); 31812855Sgabeblack@google.com unsigned int wid = trans.get_streaming_width(); 31912855Sgabeblack@google.com 32012855Sgabeblack@google.com if (byt != 0) { 32112855Sgabeblack@google.com trans.set_response_status( tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE ); 32212855Sgabeblack@google.com return; 32312855Sgabeblack@google.com } 32412855Sgabeblack@google.com if (len > 4 || wid < len) { 32512855Sgabeblack@google.com trans.set_response_status( tlm::TLM_BURST_ERROR_RESPONSE ); 32612855Sgabeblack@google.com return; 32712855Sgabeblack@google.com } 32812855Sgabeblack@google.com 32912855Sgabeblack@google.com if ( cmd == tlm::TLM_READ_COMMAND ) 33012855Sgabeblack@google.com { 33112855Sgabeblack@google.com *reinterpret_cast<int*>(ptr) = -int(adr); 33212855Sgabeblack@google.com } 33312855Sgabeblack@google.com else if ( cmd == tlm::TLM_WRITE_COMMAND ) 33412855Sgabeblack@google.com { 33512855Sgabeblack@google.com sc_assert( *reinterpret_cast<unsigned int*>(ptr) == adr ); 33612855Sgabeblack@google.com } 33712855Sgabeblack@google.com 33812855Sgabeblack@google.com trans.set_response_status( tlm::TLM_OK_RESPONSE ); 33912855Sgabeblack@google.com } 34012855Sgabeblack@google.com 34112855Sgabeblack@google.com}; 34212855Sgabeblack@google.com 34312855Sgabeblack@google.com 34412855Sgabeblack@google.comSC_MODULE(Top) 34512855Sgabeblack@google.com{ 34612855Sgabeblack@google.com Initiator *initiator1; 34712855Sgabeblack@google.com Initiator *initiator2; 34812855Sgabeblack@google.com Interconnect *interconnect; 34912855Sgabeblack@google.com Target *target1; 35012855Sgabeblack@google.com Target *target2; 35112855Sgabeblack@google.com 35212855Sgabeblack@google.com SC_CTOR(Top) 35312855Sgabeblack@google.com { 35412855Sgabeblack@google.com initiator1 = new Initiator ("initiator1"); 35512855Sgabeblack@google.com initiator2 = new Initiator ("initiator2"); 35612855Sgabeblack@google.com interconnect = new Interconnect("interconnect", 1); 35712855Sgabeblack@google.com target1 = new Target ("target1"); 35812855Sgabeblack@google.com target2 = new Target ("target2"); 35912855Sgabeblack@google.com 36012855Sgabeblack@google.com initiator1->socket.bind(interconnect->targ_socket); 36112855Sgabeblack@google.com initiator2->socket.bind(interconnect->targ_socket); 36212855Sgabeblack@google.com interconnect->init_socket.bind(target1->socket); 36312855Sgabeblack@google.com interconnect->init_socket.bind(target2->socket); 36412855Sgabeblack@google.com } 36512855Sgabeblack@google.com}; 36612855Sgabeblack@google.com 36712855Sgabeblack@google.com 36812855Sgabeblack@google.comint sc_main(int argc, char* argv[]) 36912855Sgabeblack@google.com{ 37012855Sgabeblack@google.com cout << "Unit test for nb2b adapter, PEQ, and instance-specific extensions. Should remain silent\n"; 37112855Sgabeblack@google.com 37212855Sgabeblack@google.com Top top("top"); 37312855Sgabeblack@google.com sc_start(); 37412855Sgabeblack@google.com return 0; 37512855Sgabeblack@google.com} 37612855Sgabeblack@google.com 377