nb2b_adapter.cpp revision 12855:588919e0e4aa
1 2// Unit test for nb2b adapter in simple_target_socket, PEQ, and instance-specific extensions 3// Checks for bug in original version of simple_target_socket 4 5#include <iomanip> 6 7#define SC_INCLUDE_DYNAMIC_PROCESSES 8 9#include "systemc" 10using namespace sc_core; 11using namespace sc_dt; 12using namespace std; 13 14#include "tlm.h" 15#include "tlm_utils/simple_initiator_socket.h" 16#include "tlm_utils/simple_target_socket.h" 17#include "tlm_utils/multi_passthrough_initiator_socket.h" 18#include "tlm_utils/multi_passthrough_target_socket.h" 19#include "tlm_utils/peq_with_cb_and_phase.h" 20#include "tlm_utils/instance_specific_extensions.h" 21 22#include "mm.h" 23 24 25int rand_ps() 26{ 27 int n = rand() % 100; 28 n = n * n * n; 29 return n / 100; 30} 31 32 33struct Initiator: sc_module 34{ 35 tlm_utils::simple_initiator_socket<Initiator> socket; 36 37 SC_CTOR(Initiator) 38 : socket("socket") 39 , request_in_progress(0) 40 , m_peq(this, &Initiator::peq_cb) 41 { 42 socket.register_nb_transport_bw(this, &Initiator::nb_transport_bw); 43 44 SC_THREAD(thread_process); 45 } 46 47 void thread_process() 48 { 49 tlm::tlm_generic_payload* trans; 50 tlm::tlm_phase phase; 51 sc_time delay; 52 53 trans = m_mm.allocate(); 54 trans->acquire(); 55 56 int adr = 0; 57 data[0] = adr; 58 59 trans->set_command( tlm::TLM_WRITE_COMMAND ); 60 trans->set_address( adr ); 61 trans->set_data_ptr( reinterpret_cast<unsigned char*>(&data[0]) ); 62 trans->set_data_length( 4 ); 63 trans->set_streaming_width( 4 ); 64 trans->set_byte_enable_ptr( 0 ); 65 trans->set_dmi_allowed( false ); 66 trans->set_response_status( tlm::TLM_INCOMPLETE_RESPONSE ); 67 68 socket->b_transport( *trans, delay ); 69 70 trans->release(); 71 72 for (int i = 0; i < 5000; i++) 73 { 74 int adr = rand(); 75 tlm::tlm_command cmd = static_cast<tlm::tlm_command>(rand() % 2); 76 if (cmd == tlm::TLM_WRITE_COMMAND) data[i % 16] = adr; 77 78 // Grab a new transaction from the memory manager 79 trans = m_mm.allocate(); 80 trans->acquire(); 81 82 trans->set_command( cmd ); 83 trans->set_address( adr ); 84 trans->set_data_ptr( reinterpret_cast<unsigned char*>(&data[i % 16]) ); 85 trans->set_data_length( 4 ); 86 trans->set_streaming_width( 4 ); 87 trans->set_byte_enable_ptr( 0 ); 88 trans->set_dmi_allowed( false ); 89 trans->set_response_status( tlm::TLM_INCOMPLETE_RESPONSE ); 90 91 if (request_in_progress) 92 wait(end_request_event); 93 request_in_progress = trans; 94 phase = tlm::BEGIN_REQ; 95 96 delay = sc_time(rand_ps(), SC_PS); 97 98 tlm::tlm_sync_enum status; 99 status = socket->nb_transport_fw( *trans, phase, delay ); 100 previous_time = sc_time_stamp() + delay; 101 102 if (status == tlm::TLM_UPDATED) 103 { 104 m_peq.notify( *trans, phase, delay ); 105 } 106 else if (status == tlm::TLM_COMPLETED) 107 { 108 request_in_progress = 0; 109 110 check_transaction( *trans ); 111 112 trans->release(); 113 } 114 wait( sc_time(rand_ps(), SC_PS) ); 115 } 116 } 117 118 virtual tlm::tlm_sync_enum nb_transport_bw( tlm::tlm_generic_payload& trans, 119 tlm::tlm_phase& phase, sc_time& delay ) 120 { 121 if (sc_time_stamp() + delay < previous_time) 122 SC_REPORT_FATAL("TLM-2", "nb_transport_bw called with decreasing timing annotation"); 123 previous_time = sc_time_stamp() + delay; 124 125 m_peq.notify( trans, phase, delay ); 126 return tlm::TLM_ACCEPTED; 127 } 128 129 void peq_cb(tlm::tlm_generic_payload& trans, const tlm::tlm_phase& phase) 130 { 131 if (phase == tlm::END_REQ || (&trans == request_in_progress && phase == tlm::BEGIN_RESP)) 132 { 133 request_in_progress = 0; 134 end_request_event.notify(); 135 } 136 else if (phase == tlm::BEGIN_REQ || phase == tlm::END_RESP) 137 SC_REPORT_FATAL("TLM-2", "Illegal transaction phase received by initiator"); 138 139 if (phase == tlm::BEGIN_RESP) 140 { 141 check_transaction( trans ); 142 143 tlm::tlm_phase fw_phase = tlm::END_RESP; 144 sc_time delay = sc_time(rand_ps(), SC_PS); 145 socket->nb_transport_fw( trans, fw_phase, delay ); 146 previous_time = sc_time_stamp() + delay; 147 148 trans.release(); 149 } 150 } 151 152 void check_transaction(tlm::tlm_generic_payload& trans) 153 { 154 if ( trans.is_response_error() ) 155 { 156 char txt[100]; 157 sprintf(txt, "Transaction returned with error, response status = %s", 158 trans.get_response_string().c_str()); 159 SC_REPORT_ERROR("TLM-2", txt); 160 } 161 162 tlm::tlm_command cmd = trans.get_command(); 163 sc_dt::uint64 adr = trans.get_address(); 164 int* ptr = reinterpret_cast<int*>( trans.get_data_ptr() ); 165 166 if (cmd == tlm::TLM_READ_COMMAND) 167 sc_assert( *ptr == -int(adr) ); 168 } 169 170 mm m_mm; 171 int data[16]; 172 tlm::tlm_generic_payload* request_in_progress; 173 sc_event end_request_event; 174 tlm_utils::peq_with_cb_and_phase<Initiator> m_peq; 175 sc_time previous_time; 176}; 177 178 179// Dumb interconnect that simply routes transactions through 180 181struct Interconnect: sc_module 182{ 183 tlm_utils::multi_passthrough_target_socket<Interconnect, 32> targ_socket; 184 tlm_utils::multi_passthrough_initiator_socket<Interconnect, 32> init_socket; 185 186 Interconnect(sc_module_name _name, unsigned int _offset) 187 : sc_module(_name) 188 , targ_socket("targ_socket") 189 , init_socket("init_socket") 190 , offset(_offset) 191 { 192 targ_socket.register_b_transport (this, &Interconnect::b_transport); 193 targ_socket.register_nb_transport_fw (this, &Interconnect::nb_transport_fw); 194 targ_socket.register_get_direct_mem_ptr (this, &Interconnect::get_direct_mem_ptr); 195 targ_socket.register_transport_dbg (this, &Interconnect::transport_dbg); 196 init_socket.register_nb_transport_bw (this, &Interconnect::nb_transport_bw); 197 init_socket.register_invalidate_direct_mem_ptr(this, &Interconnect::invalidate_direct_mem_ptr); 198 } 199 200 void end_of_elaboration() 201 { 202 if ( targ_socket.size() != init_socket.size() ) 203 SC_REPORT_ERROR("TLM-2", "#initiators != #targets in Interconnect"); 204 } 205 206 virtual void b_transport( int id, tlm::tlm_generic_payload& trans, sc_time& delay ) 207 { 208 unsigned int target = (id + offset) % init_socket.size(); // Route-through 209 210 init_socket[target]->b_transport( trans, delay ); 211 } 212 213 214 struct route_extension: tlm_utils::instance_specific_extension<route_extension> 215 { 216 int id; 217 }; 218 219 tlm_utils::instance_specific_extension_accessor accessor; 220 221 222 virtual tlm::tlm_sync_enum nb_transport_fw( int id, tlm::tlm_generic_payload& trans, 223 tlm::tlm_phase& phase, sc_time& delay ) 224 { 225 route_extension* ext = 0; 226 if (phase == tlm::BEGIN_REQ) 227 { 228 ext = new route_extension; 229 ext->id = id; 230 accessor(trans).set_extension(ext); 231 } 232 233 unsigned int target = (id + offset) % init_socket.size(); // Route-through 234 235 tlm::tlm_sync_enum status; 236 status = init_socket[target]->nb_transport_fw( trans, phase, delay ); 237 238 if (status == tlm::TLM_COMPLETED) 239 { 240 accessor(trans).clear_extension(ext); 241 delete ext; 242 } 243 244 return status; 245 } 246 247 virtual bool get_direct_mem_ptr( int id, tlm::tlm_generic_payload& trans, 248 tlm::tlm_dmi& dmi_data) 249 { 250 unsigned int target = (id + offset) % init_socket.size(); // Route-through 251 252 bool status = init_socket[target]->get_direct_mem_ptr( trans, dmi_data ); 253 254 return status; 255 } 256 257 virtual unsigned int transport_dbg( int id, tlm::tlm_generic_payload& trans ) 258 { 259 unsigned int target = (id + offset) % init_socket.size(); // Route-through 260 261 return init_socket[target]->transport_dbg( trans ); 262 } 263 264 265 virtual tlm::tlm_sync_enum nb_transport_bw( int id, tlm::tlm_generic_payload& trans, 266 tlm::tlm_phase& phase, sc_time& delay ) 267 { 268 route_extension* ext = 0; 269 accessor(trans).get_extension(ext); 270 sc_assert(ext); 271 272 tlm::tlm_sync_enum status; 273 status = targ_socket[ ext->id ]->nb_transport_bw( trans, phase, delay ); 274 275 if (status == tlm::TLM_COMPLETED) 276 { 277 accessor(trans).clear_extension(ext); 278 delete ext; 279 } 280 281 return status; 282 } 283 284 virtual void invalidate_direct_mem_ptr( int id, sc_dt::uint64 start_range, 285 sc_dt::uint64 end_range ) 286 { 287 for (unsigned int i = 0; i < targ_socket.size(); i++) 288 targ_socket[i]->invalidate_direct_mem_ptr(start_range, end_range); 289 } 290 291 unsigned int offset; 292}; 293 294 295struct Target: sc_module 296{ 297 tlm_utils::simple_target_socket<Target> socket; 298 299 SC_CTOR(Target) 300 : socket("socket") 301 { 302 socket.register_b_transport (this, &Target::b_transport); 303 } 304 305 virtual void b_transport( tlm::tlm_generic_payload& trans, sc_time& delay ) 306 { 307 execute_transaction(trans); 308 } 309 310 311 void execute_transaction(tlm::tlm_generic_payload& trans) 312 { 313 tlm::tlm_command cmd = trans.get_command(); 314 sc_dt::uint64 adr = trans.get_address(); 315 unsigned char* ptr = trans.get_data_ptr(); 316 unsigned int len = trans.get_data_length(); 317 unsigned char* byt = trans.get_byte_enable_ptr(); 318 unsigned int wid = trans.get_streaming_width(); 319 320 if (byt != 0) { 321 trans.set_response_status( tlm::TLM_BYTE_ENABLE_ERROR_RESPONSE ); 322 return; 323 } 324 if (len > 4 || wid < len) { 325 trans.set_response_status( tlm::TLM_BURST_ERROR_RESPONSE ); 326 return; 327 } 328 329 if ( cmd == tlm::TLM_READ_COMMAND ) 330 { 331 *reinterpret_cast<int*>(ptr) = -int(adr); 332 } 333 else if ( cmd == tlm::TLM_WRITE_COMMAND ) 334 { 335 sc_assert( *reinterpret_cast<unsigned int*>(ptr) == adr ); 336 } 337 338 trans.set_response_status( tlm::TLM_OK_RESPONSE ); 339 } 340 341}; 342 343 344SC_MODULE(Top) 345{ 346 Initiator *initiator1; 347 Initiator *initiator2; 348 Interconnect *interconnect; 349 Target *target1; 350 Target *target2; 351 352 SC_CTOR(Top) 353 { 354 initiator1 = new Initiator ("initiator1"); 355 initiator2 = new Initiator ("initiator2"); 356 interconnect = new Interconnect("interconnect", 1); 357 target1 = new Target ("target1"); 358 target2 = new Target ("target2"); 359 360 initiator1->socket.bind(interconnect->targ_socket); 361 initiator2->socket.bind(interconnect->targ_socket); 362 interconnect->init_socket.bind(target1->socket); 363 interconnect->init_socket.bind(target2->socket); 364 } 365}; 366 367 368int sc_main(int argc, char* argv[]) 369{ 370 cout << "Unit test for nb2b adapter, PEQ, and instance-specific extensions. Should remain silent\n"; 371 372 Top top("top"); 373 sc_start(); 374 return 0; 375} 376 377