1 2// Filename: tlm2_base_protocol_checker.h 3 4//---------------------------------------------------------------------- 5// Copyright (c) 2008-2013 by Doulos Ltd. 6// 7// Licensed under the Apache License, Version 2.0 (the "License"); 8// you may not use this file except in compliance with the License. 9// You may obtain a copy of the License at 10// 11// http://www.apache.org/licenses/LICENSE-2.0 12// 13// Unless required by applicable law or agreed to in writing, software 14// distributed under the License is distributed on an "AS IS" BASIS, 15// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16// See the License for the specific language governing permissions and 17// limitations under the License. 18//---------------------------------------------------------------------- 19 20// Author: John Aynsley, Doulos 21 22// Version 1, 11 July 2008 23// Version 2, 16 July 2008 Only generate ref_count > 1 warning from 1st checker of path 24// Version 3, 17 July 2008 Support compilation under SystemC 2.1.v1 25// Version 4, 12 Aug 2008 Add header #include <map> 26// Version 5, 08 Sep 2008 Fix bugs in message text 27// Version 6, 01 Aug 2010 Update messages to refer to OSCI TLM-2.0 LRM of July 2009 28// Version 7, 25 Oct 2011 Minor bug fix for certain compilers: replace u_char with uchar_t 29// Version 8, 02 Nov 2011 Support the endianness conversion functions by excluding the 30// tlm_endian_context extension from the protocol checks 31// Version 9, 17 Aug 2012 Fix LRM reference on line 805 (should be 8.2.11 a) [NOT YET RELEASED] 32// Version 10, 3 Jan 2013 Updated messages to refer to IEEE Std 1666-2011, the combined SystemC + TLM-2.0 LRM 33// Added checks related to the generic payload option attribute 34// Version 11, 14 Mar 2016 Fix minor bug - start_phase should be a copy, not a reference 35 36// TLM-2.0 Base Protocol Compliance Checker 37 38/* 39Instantiate this checker module in-line between initiator and target, initiator and interconnect, 40or interconnect and target by binding the target_socket and initiator_socket 41Binding two checkers either side of an interconnect component, or interleaving a series of 42checkers with interconnect components, will enable some deeper checks as against having just 43a single checker 44 45For example 46 47 Initiator *initiator; 48 Bus *bus; 49 Memory *memory; 50 ... 51 initiator->socket.bind(bus->target_socket); 52 bus->initiator_socket.bind(memory->socket); 53 54might become 55 56 tlm_utils::tlm2_base_protocol_checker<32> *checker1; 57 tlm_utils::tlm2_base_protocol_checker<32> *checker2; 58 ... 59 initiator->socket.bind(checker1->target_socket); 60 checker1->initiator_socket.bind(bus->target_socket); 61 bus->initiator_socket.bind(checker2->target_socket); 62 checker2->initiator_socket.bind(memory->socket); 63 64 65GENERAL FEATURES OF THE BASE PROTOCOL CHECKER 66 67The checks are relatively expensive, hence by default the number of checks is limited. 68A maximum number can be set explicitly by calling set_num_checks(max) 69Checking can be deactivated at any time by calling set_num_checks(0) 70All checkers decrement a single global count, because having some checkers running and 71others not can cause bogus violation reports 72It is not permitted to turn checks on by calling set_num_checks() once checking has been 73deactivated, because this could cause bogus violation reports 74 75The DMI and debug checks are unaffected by the num_checks count (because they are cheap) 76 77The error messages contain User Manual references 78 79The checker is designed to be used with a transaction pool: otherwise it could consume 80a lot of memory. The checker keeps a local copy of each transaction object 81Failures are reported with a severity of SC_ERROR. The actions may be overridden by calling: 82 sc_report_handler::set_actions("tlm2_protocol_checker", ...); 83 84SPECIFIC CHECKS 85 86nb_transport: phase sequence BEGIN_REQ -> END_REQ -> BEGIN_RESP -> END_RESP 87Must not have two outstanding requests or responses (exclusion rules) 88Must not have decreasing timing annotations on calls to or returns from nb_transport_fw/bw 89Phase extensions permitted and ignored 90Must not call b_transport during nb_transport phase sequence and vice-versa 91 92nb_transport: memory manager must be set 93nb_transport: reference count must be non-zero 94First checker in BEGIN_REQ path should see ref_count == 1 (warning only) 95An interconnect component that sets a memory manager should also clear it 96An interconnect component that sets extensions with no memory manager should also clear them 97(Does not bother with these memory manager checks for DMI and debug) 98 99Transaction object must be properly initialized 100Many generic payload attributes must not be modified during the transaction lifetime 101Transaction object must not be re-allocated for a new transaction while still in use 102DMI descriptor must be properly initialized 103Debug transaction must be properly initialized 104Debug byte count must be less than data_length 105 106Checks that require multiple checkers to be instantiated along a transaction path: 107The BEGIN_RESP path must be the reverse of the BEGIN_REQ path 108Transaction object must not be sent with BEGIN_REQ while participating in a previous response 109Interconnect component must not set response status attribute to TLM_OK_RESPONSE 110Interconnect component must not modify data array on the response path 111 112Generic payload option attribute (IEEE Std 1666-2011, SystemC 2.3.x) 113gp_option must be properly initialized and only used for DMI and debug transport 114When gp_option is used, other gp attributes must be initalized and used as per the transport interfaces 115*/ 116 117 118// ******************** PREAMBLE ******************** 119 120 121#ifndef __tlm2_base_protocol_checker__ 122#define __tlm2_base_protocol_checker__ 123 124#include "systemc" 125using std::cout; 126using std::endl; 127using std::dec; 128using std::hex; 129 130#include "tlm.h" 131#include <sstream> 132#include <map> 133 134 135namespace tlm_utils { 136 137 138// Number of checks remaining 139const sc_dt::uint64 default_num_checks = 100000; 140static sc_dt::uint64 num_checks = default_num_checks; 141 142 143// Types used when building a trace of the transaction path 144typedef unsigned char uchar_t; 145typedef std::deque<sc_core::sc_module*> deque_t; 146 147struct path_t { 148 path_t () { response_in_progress = false; ok_response = false; resp_data_ptr = 0; } 149 150 bool response_in_progress; 151 bool ok_response; 152 deque_t path; 153 uchar_t* resp_data_ptr; // Copy of data on response path 154}; 155 156// Global variable used for checks involving multiple checkers along a transaction path 157static std::map<tlm::tlm_generic_payload*, path_t> shared_map; 158 159 160// ******************** CLASS DEFINITION ******************** 161 162 163template <unsigned int BUSWIDTH = 32> 164class tlm2_base_protocol_checker 165 166: public sc_core::sc_module 167, public tlm::tlm_fw_transport_if<tlm::tlm_base_protocol_types> 168, public tlm::tlm_bw_transport_if<tlm::tlm_base_protocol_types> 169{ 170public: 171 172 // Instantiate and bind checker inline between an existing pair of initiator and target sockets 173 174 tlm::tlm_target_socket <BUSWIDTH, tlm::tlm_base_protocol_types, 1> target_socket; 175 tlm::tlm_initiator_socket<BUSWIDTH, tlm::tlm_base_protocol_types, 1> initiator_socket; 176 177 SC_CTOR(tlm2_base_protocol_checker) 178 : m_request_in_progress(0), m_response_in_progress(0) 179 { 180 target_socket .bind( *this ); 181 initiator_socket.bind( *this ); 182 } 183 184 185 // Access methods for num_checks count 186 187 static void set_num_checks(sc_dt::uint64 n) { 188 if (num_checks == 0) 189 SC_REPORT_FATAL("tlm2_protocol_checker", "Method set_num_checks called after checking has stopped due to maximum number of checks being reached"); 190 num_checks = n; 191 } 192 193 static sc_dt::uint64 get_num_checks() { return num_checks; } 194 195 196 // TLM-2.0 interface methods for initiator and target sockets, instrumented with checks 197 198 virtual tlm::tlm_sync_enum nb_transport_fw( 199 tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay) 200 { 201 tlm::tlm_phase start_phase = phase; 202 203 if (num_checks) 204 nb_transport_fw_pre_checks( trans, phase, delay ); 205 206 tlm::tlm_sync_enum status; 207 status = initiator_socket->nb_transport_fw( trans, phase, delay ); 208 209 if (num_checks) 210 nb_transport_fw_post_checks( trans, start_phase, phase, delay, status ); 211 212 return status; 213 } 214 215 virtual tlm::tlm_sync_enum nb_transport_bw( 216 tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay) 217 { 218 if (num_checks) 219 nb_transport_bw_pre_checks( trans, phase, delay ); 220 221 tlm::tlm_sync_enum status; 222 status = target_socket->nb_transport_bw( trans, phase, delay ); 223 224 if (num_checks) 225 nb_transport_bw_post_checks( trans, phase, delay, status ); 226 227 return status; 228 } 229 230 virtual void b_transport( tlm::tlm_generic_payload& trans, sc_core::sc_time& delay ) 231 { 232 if (num_checks) 233 b_transport_pre_checks( trans, delay ); 234 235 initiator_socket->b_transport( trans, delay ); 236 237 if (num_checks) 238 b_transport_post_checks( trans, delay ); 239 } 240 241 virtual bool get_direct_mem_ptr(tlm::tlm_generic_payload& trans, 242 tlm::tlm_dmi& dmi_data) 243 { 244 get_direct_mem_ptr_pre_checks( trans, dmi_data ); 245 246 bool status; 247 status = initiator_socket->get_direct_mem_ptr( trans, dmi_data ); 248 249 get_direct_mem_ptr_post_checks( trans, dmi_data ); 250 return status; 251 } 252 253 virtual void invalidate_direct_mem_ptr(sc_dt::uint64 start_range, 254 sc_dt::uint64 end_range) 255 { 256 target_socket->invalidate_direct_mem_ptr(start_range, end_range); 257 } 258 259 virtual unsigned int transport_dbg(tlm::tlm_generic_payload& trans) 260 { 261 transport_dbg_pre_checks( trans ); 262 263 unsigned int count; 264 count = initiator_socket->transport_dbg( trans ); 265 266 transport_dbg_post_checks( trans, count ); 267 return count; 268 } 269 270 271private: 272 void b_transport_pre_checks( tlm::tlm_generic_payload& trans, sc_core::sc_time& delay); 273 274 void b_transport_post_checks( tlm::tlm_generic_payload& trans, sc_core::sc_time& delay); 275 276 void nb_transport_fw_pre_checks( 277 tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay); 278 279 void nb_transport_fw_post_checks( 280 tlm::tlm_generic_payload& trans, tlm::tlm_phase& start_phase, tlm::tlm_phase& phase, 281 sc_core::sc_time& delay, tlm::tlm_sync_enum status); 282 283 void nb_transport_bw_pre_checks( 284 tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay); 285 286 void nb_transport_bw_post_checks( 287 tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay, 288 tlm::tlm_sync_enum status); 289 290 void nb_transport_response_checks( 291 tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay, 292 const char* txt2, const char* txt3, const char* txt4); 293 294 void check_initial_state( tlm::tlm_generic_payload& trans, const char* txt2 ); 295 void check_trans_not_modified( tlm::tlm_generic_payload& trans, const char* txt2 ); 296 void check_response_path( tlm::tlm_generic_payload& trans, const char* txt2 ); 297 void remember_gp_option( tlm::tlm_generic_payload& trans ); 298 299 void get_direct_mem_ptr_pre_checks( tlm::tlm_generic_payload& trans, tlm::tlm_dmi& dmi_data ); 300 301 void get_direct_mem_ptr_post_checks( tlm::tlm_generic_payload& trans, tlm::tlm_dmi& dmi_data ); 302 303 void transport_dbg_pre_checks( tlm::tlm_generic_payload& trans ); 304 305 void transport_dbg_post_checks( tlm::tlm_generic_payload& trans, unsigned int count ); 306 307 void tlm2error( tlm::tlm_generic_payload& trans, const char* ref, bool warning = false ); 308 309private: 310 311 struct state_t { 312 state_t() { b_call = 0; ph = tlm::UNINITIALIZED_PHASE; gp = 0; } 313 314 bool has_mm; 315 unsigned int b_call; // Number of b_transport calls in progress 316 tlm::tlm_phase ph; 317 sc_core::sc_time time; // Current time + annotated delay 318 tlm::tlm_generic_payload* gp; // Points to new data and byte enable buffers 319 uchar_t* data_ptr; // Stores original pointers 320 uchar_t* byte_enable_ptr; 321 }; 322 323 // Transaction state for the specific hop where this checker is inlined 324 std::map<tlm::tlm_generic_payload*, state_t> m_map; 325 326 // Flags for exclusion rules 327 tlm::tlm_generic_payload* m_request_in_progress; 328 tlm::tlm_generic_payload* m_response_in_progress; 329 330 std::ostringstream txt; 331 332}; 333 334 335 336// ******************** MEMBER FUNCTION DEFINITIONS ******************** 337 338 339#define BOILERPLATE \ 340template <unsigned int BUSWIDTH> \ 341void tlm2_base_protocol_checker<BUSWIDTH>:: 342 343 344BOILERPLATE 345b_transport_pre_checks( 346 tlm::tlm_generic_payload& trans, sc_core::sc_time& delay) 347{ 348 ++ m_map[&trans].b_call; 349 350 if ( trans.has_mm() && trans.get_ref_count() == 0) 351 { 352 txt << "Transaction passed to b_transport with memory manager and reference count of 0"; 353 tlm2error(trans, "14.5 t)"); 354 } 355 check_initial_state(trans, "b_transport"); 356 357#if !(defined SYSTEMC_VERSION & SYSTEMC_VERSION <= 20050714) 358 if (sc_core::sc_get_current_process_handle().proc_kind() == sc_core::SC_METHOD_PROC_) 359 { 360 txt << "b_transport called from method process"; 361 tlm2error(trans, "11.1.1.4 b)"); 362 } 363#endif 364 365 if (m_map[&trans].ph > 0 && m_map[&trans].ph < 4) 366 { 367 txt << "b_transport called during a sequence of nb_transport calls"; 368 tlm2error(trans, "15.2.10 c)"); 369 } 370} 371 372 373BOILERPLATE 374b_transport_post_checks( 375 tlm::tlm_generic_payload& trans, sc_core::sc_time& delay) 376{ 377 check_response_path(trans, "b_transport"); 378 check_trans_not_modified(trans, "b_transport"); 379 -- m_map[&trans].b_call; 380} 381 382 383BOILERPLATE 384nb_transport_fw_pre_checks( 385 tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay) 386{ 387 if ( !trans.has_mm() ) 388 { 389 txt << "Transaction passed to nb_transport_fw with no memory manager set"; 390 tlm2error(trans, "14.5 i)"); 391 } 392 if ( trans.get_ref_count() == 0) 393 { 394 txt << "Transaction passed to nb_transport_fw with reference count of 0"; 395 tlm2error(trans, "14.5 t)"); 396 } 397 398 switch (phase) 399 { 400 case tlm::BEGIN_REQ: 401 check_initial_state(trans, "nb_transport_fw"); 402 403 if (m_map[&trans].ph > 0 && m_map[&trans].ph < 4) // END_RESP -> BEGIN_REQ is legal 404 { 405 txt << "Phase " << phase << " sent out-of-sequence on forward path, detected in nb_transport_fw"; 406 tlm2error(trans, "15.2.4"); 407 } 408 409 if (m_request_in_progress) 410 { 411 txt << "Transaction violates BEGIN_REQ exclusion rule, detected in nb_transport_fw"; 412 tlm2error(trans, "15.2.6 e)"); 413 } 414 m_request_in_progress = &trans; 415 416 if (m_map[&trans].b_call) 417 { 418 txt << "nb_transport_fw called during a b_transport call"; 419 tlm2error(trans, "15.2.10 c)"); 420 } 421 break; 422 423 case tlm::END_REQ: 424 case tlm::BEGIN_RESP: 425 case tlm::UNINITIALIZED_PHASE: 426 txt << "Phase " << phase << " sent on forward path, detected in nb_transport_fw"; 427 tlm2error(trans, " 15.2.3 c)"); 428 break; 429 430 case tlm::END_RESP: 431 if (m_map[&trans].ph != tlm::BEGIN_RESP) 432 { 433 txt << "Phase " << phase << " sent out-of-sequence on forward path, detected in nb_transport_fw"; 434 tlm2error(trans, "15.2.4"); 435 } 436 m_response_in_progress = 0; 437 break; 438 } 439 440 if (phase < 5) // Ignore extended phases 441 m_map[&trans].ph = phase; 442 443 if (sc_core::sc_time_stamp() + delay < m_map[&trans].time) 444 { 445 txt << "nb_transport_fw called with decreasing timing annotation:" 446 << " delay = " << delay 447 << ", sc_time_stamp() + delay from previous call = " << m_map[&trans].time; 448 tlm2error(trans, "15.2.7 c)"); 449 } 450 m_map[&trans].time = sc_core::sc_time_stamp() + delay; 451} 452 453 454BOILERPLATE 455nb_transport_fw_post_checks( 456 tlm::tlm_generic_payload& trans, tlm::tlm_phase& start_phase, tlm::tlm_phase& phase, 457 sc_core::sc_time& delay, tlm::tlm_sync_enum status) 458{ 459 if (status == tlm::TLM_UPDATED) 460 { 461 nb_transport_response_checks( 462 trans, phase, delay, "(forward) return", "Return from nb_transport_fw", "nb_transport_fw"); 463 } 464 else if (status == tlm::TLM_COMPLETED) 465 { 466 if (start_phase == tlm::BEGIN_REQ) 467 check_response_path(trans, "nb_transport_fw"); 468 m_request_in_progress = 0; 469 m_map[&trans].ph = tlm::UNINITIALIZED_PHASE; 470 } 471 472 // Transaction object should not be re-allocated, even during the END_RESP phase 473 //if (phase != tlm::END_RESP) 474 { 475 std::ostringstream txt; 476 txt << "nb_transport_fw, phase = " << phase; 477 check_trans_not_modified(trans, txt.str().c_str()); 478 } 479} 480 481 482BOILERPLATE 483nb_transport_bw_pre_checks( 484 tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay) 485{ 486 if ( !trans.has_mm() ) 487 { 488 txt << "Transaction passed to nb_transport_bw with no memory manager set"; 489 tlm2error(trans, "14.5 i)"); 490 } 491 if ( trans.get_ref_count() == 0) 492 { 493 txt << "Transaction passed to nb_transport_bw with reference count of 0"; 494 tlm2error(trans, "14.5 t)"); 495 } 496 nb_transport_response_checks( 497 trans, phase, delay, "backward", "nb_transport_bw called", "nb_transport_bw"); 498} 499 500 501BOILERPLATE 502nb_transport_bw_post_checks( 503 tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay, 504 tlm::tlm_sync_enum status) 505{ 506 if (status == tlm::TLM_UPDATED) 507 { 508 switch (phase) 509 { 510 case tlm::BEGIN_REQ: 511 txt << "Phase " << phase << " sent out-of-sequence on (backward) return path, detected in nb_transport_bw"; 512 tlm2error(trans, "15.2.4"); 513 break; 514 515 case tlm::END_REQ: 516 case tlm::BEGIN_RESP: 517 case tlm::UNINITIALIZED_PHASE: 518 txt << "Phase " << phase << " sent on (backward) return path, detected in nb_transport_bw"; 519 tlm2error(trans, "15.2.3 c)"); 520 break; 521 522 case tlm::END_RESP: 523 if (m_map[&trans].ph != tlm::BEGIN_RESP) 524 { 525 txt << "Phase " << phase << " sent out-of-sequence on (backward) return path, detected in nb_transport_bw"; 526 tlm2error(trans, "15.2.4"); 527 } 528 529 m_response_in_progress = 0; 530 break; 531 } 532 533 if (phase < 5) // Ignore extended phases 534 m_map[&trans].ph = phase; 535 536 if (sc_core::sc_time_stamp() + delay < m_map[&trans].time) 537 { 538 txt << "Return from nb_transport_bw with decreasing timing annotation:" 539 << " delay = " << delay 540 << ", sc_time_stamp() + delay from previous call = " << m_map[&trans].time; 541 tlm2error(trans, "15.2.7 c)"); 542 } 543 m_map[&trans].time = sc_core::sc_time_stamp() + delay; 544 } 545 else if (status == tlm::TLM_COMPLETED) 546 { 547 m_response_in_progress = 0; 548 m_map[&trans].ph = tlm::UNINITIALIZED_PHASE; 549 } 550 551 // Transaction object should not be re-allocated, even during the END_RESP phase 552 //if (phase != tlm::END_RESP) 553 { 554 std::ostringstream txt; 555 txt << "nb_transport_bw, phase = " << phase; 556 check_trans_not_modified(trans, txt.str().c_str()); 557 } 558} 559 560 561BOILERPLATE 562nb_transport_response_checks( 563 tlm::tlm_generic_payload& trans, tlm::tlm_phase& phase, sc_core::sc_time& delay, 564 const char* txt2, const char* txt3, const char* txt4) 565{ 566 if (trans.is_response_ok()) 567 if (shared_map[&trans].response_in_progress && !shared_map[&trans].ok_response) 568 { 569 txt << "Interconnect component sets response status attribute to TLM_OK_RESPONSE" 570 << ", detected in " << txt4; 571 tlm2error(trans, "14.7"); 572 573 } 574 575 switch (phase) 576 { 577 case tlm::BEGIN_REQ: 578 case tlm::END_RESP: 579 case tlm::UNINITIALIZED_PHASE: 580 txt << "Phase " << phase << " sent on " << txt2 << " path" 581 << ", detected in " << txt4; 582 tlm2error(trans, "15.2.3 c)"); 583 break; 584 585 case tlm::END_REQ: 586 if (m_map[&trans].ph != tlm::BEGIN_REQ) 587 { 588 txt << "Phase " << phase << " sent out-of-sequence on " << txt2 << " path" 589 << ", detected in " << txt4; 590 tlm2error(trans, "15.2.4"); 591 } 592 593 m_request_in_progress = 0; 594 break; 595 596 case tlm::BEGIN_RESP: 597 if (m_map[&trans].ph != tlm::BEGIN_REQ && m_map[&trans].ph != tlm::END_REQ) 598 { 599 txt << "Phase " << phase << " sent out-of-sequence on " << txt2 << " path" 600 << ", detected in " << txt4; 601 tlm2error(trans, "15.2.4"); 602 } 603 604 if (&trans == m_request_in_progress) 605 m_request_in_progress = 0; 606 607 if (m_response_in_progress) 608 { 609 txt << "Transaction violates BEGIN_RESP exclusion rule" 610 << ", detected in " << txt4; 611 tlm2error(trans, "15.2.6 f)"); 612 } 613 m_response_in_progress = &trans; 614 615 check_response_path(trans, txt4); 616 break; 617 } 618 619 if (phase < 5) // Ignore extended phases 620 m_map[&trans].ph = phase; 621 622 if (sc_core::sc_time_stamp() + delay < m_map[&trans].time) 623 { 624 txt << txt3 << " with decreasing timing annotation:" 625 << " delay = " << delay 626 << ", sc_time_stamp() + delay from previous call = " << m_map[&trans].time; 627 tlm2error(trans, "15.2.7 c)"); 628 } 629 m_map[&trans].time = sc_core::sc_time_stamp() + delay; 630} 631 632 633BOILERPLATE 634check_initial_state( 635 tlm::tlm_generic_payload& trans, const char* txt2 ) 636{ 637 if (num_checks > 0) 638 { 639 --num_checks; 640 if (num_checks == 0) 641 SC_REPORT_INFO("tlm2_protocol_checker", "Checkers deactivated after executing the set number of checks"); 642 } 643 644 if ( trans.has_mm() && trans.get_ref_count() > 1 && shared_map[&trans].path.empty() ) 645 { 646 txt << "New transaction passed to " << txt2 << " with reference count = " 647 << trans.get_ref_count(); 648 tlm2error(trans, "14.5 t)", true); 649 } 650 if (trans.get_data_ptr() == 0 && trans.get_command() != tlm::TLM_IGNORE_COMMAND) 651 { 652 txt << "Transaction not properly initialized: data_ptr == 0, detected in " << txt2; 653 tlm2error(trans, "14.11 e)"); 654 } 655 if (trans.get_data_length() == 0 && trans.get_command() != tlm::TLM_IGNORE_COMMAND) 656 { 657 txt << "Transaction not properly initialized: data_langth == 0, detected in " << txt2; 658 tlm2error(trans, "14.12 d)"); 659 } 660 if (trans.get_byte_enable_ptr() != 0 && trans.get_byte_enable_length() == 0) 661 { 662 txt << "Transaction not properly initialized: " 663 << "byte_enable_ptr != 0 and byte_enable_length == 0, detected in " << txt2; 664 tlm2error(trans, "14.14 f)"); 665 } 666 if (trans.get_streaming_width() == 0) 667 { 668 txt << "Transaction not properly initialized: streaming_width == 0, detected in " << txt2; 669 tlm2error(trans, "14.15 f)"); 670 } 671 if (trans.is_dmi_allowed()) 672 { 673 txt << "Transaction not properly initialized: dmi_allowed == true, detected in " << txt2; 674 tlm2error(trans, "14.16"); 675 } 676 if (trans.get_response_status() != tlm::TLM_INCOMPLETE_RESPONSE) 677 { 678 txt << "Transaction not properly initialized: response_status != TLM_INCOMPLETE_RESPONSE, detected in " << txt2; 679 tlm2error(trans, "14.17 e)"); 680 } 681 if (trans.get_gp_option() != tlm::TLM_MIN_PAYLOAD) 682 { 683 txt << "Transaction not properly initialized: gp_option != TLM_MIN_PAYLOAD, detected in " << txt2; 684 tlm2error(trans, "14.8 g)"); 685 } 686 687 // Setup clones of transaction and buffers in map 688 tlm::tlm_generic_payload* gp = m_map[&trans].gp; 689 if (gp == 0) 690 gp = new tlm::tlm_generic_payload; // Memory leak: transactions are never cleared from map 691 else 692 { 693 delete [] gp->get_data_ptr(); 694 gp->free_all_extensions(); 695 } 696 gp->set_data_ptr( new uchar_t[trans.get_data_length()] ); 697 m_map[&trans].data_ptr = trans.get_data_ptr(); 698 699 if (gp->get_byte_enable_ptr()) 700 delete [] gp->get_byte_enable_ptr(); 701 if (trans.get_byte_enable_ptr()) 702 gp->set_byte_enable_ptr( new uchar_t[trans.get_byte_enable_length()] ); 703 else 704 gp->set_byte_enable_ptr(0); 705 m_map[&trans].byte_enable_ptr = trans.get_byte_enable_ptr(); 706 707 gp->deep_copy_from(trans); 708 m_map[&trans].gp = gp; 709 m_map[&trans].time = sc_core::SC_ZERO_TIME; 710 m_map[&trans].has_mm = trans.has_mm(); 711 712 // Store request path checker sequence 713 if (shared_map[&trans].resp_data_ptr) 714 { 715 delete [] shared_map[&trans].resp_data_ptr; 716 shared_map[&trans].resp_data_ptr = 0; 717 } 718 if (shared_map[&trans].response_in_progress) 719 { 720 txt << "Transaction object sent with BEGIN_REQ while still being used on a previous response path, detected in " << txt2; 721 tlm2error(trans, "14.5 x)"); 722 } 723 shared_map[&trans].ok_response = false; 724 shared_map[&trans].path.push_back(this); 725} 726 727 728BOILERPLATE 729remember_gp_option( 730 tlm::tlm_generic_payload& trans) 731{ 732 // Setup clone of transaction in map in order to check gp_option only 733 tlm::tlm_generic_payload* gp = m_map[&trans].gp; 734 if (gp == 0) 735 gp = new tlm::tlm_generic_payload; // Memory leak: transactions are never cleared from map 736 gp->set_gp_option( trans.get_gp_option() ); 737 m_map[&trans].gp = gp; 738} 739 740 741BOILERPLATE 742check_trans_not_modified( 743 tlm::tlm_generic_payload& trans, const char* txt2 ) 744{ 745 tlm::tlm_generic_payload* init = m_map[&trans].gp; 746 747 if (trans.get_command() != init->get_command()) 748 { 749 txt << "Command attribute modified during transaction lifetime, detected in " << txt2; 750 tlm2error(trans, "14.7"); 751 } 752 if (trans.get_data_ptr() != m_map[&trans].data_ptr) 753 { 754 txt << "Data pointer attribute modified during transaction lifetime, detected in " << txt2; 755 tlm2error(trans, "14.7"); 756 } 757 if (trans.get_data_length() != init->get_data_length()) 758 { 759 txt << "Data length attribute modified during transaction lifetime, detected in " << txt2; 760 tlm2error(trans, "14.7"); 761 } 762 if (trans.get_command() == tlm::TLM_WRITE_COMMAND) 763 for (unsigned int i = 0; i < init->get_data_length(); i++) 764 if (trans.get_data_ptr()[i] != init->get_data_ptr()[i]) 765 { 766 txt << "Data array modified during transaction lifetime, detected in " << txt2; 767 tlm2error(trans, "14.7"); 768 } 769 if (trans.get_byte_enable_ptr() != m_map[&trans].byte_enable_ptr) 770 { 771 txt << "Byte enable pointer attribute modified during transaction lifetime, detected in " << txt2; 772 tlm2error(trans, "14.7"); 773 } 774 if (trans.get_byte_enable_length() != init->get_byte_enable_length()) 775 { 776 txt << "Byte enable length attribute modified during transaction lifetime, detected in " << txt2; 777 tlm2error(trans, "14.7"); 778 } 779 if (trans.get_byte_enable_ptr()) 780 for (unsigned int i = 0; i < init->get_byte_enable_length(); i++) 781 if (trans.get_byte_enable_ptr()[i] != init->get_byte_enable_ptr()[i]) 782 { 783 txt << "Byte enable array modified during transaction lifetime, detected in " << txt2; 784 tlm2error(trans, "14.7"); 785 } 786 if (trans.get_streaming_width() != init->get_streaming_width()) 787 { 788 txt << "Streaming width attribute modified during transaction lifetime, detected in " << txt2; 789 tlm2error(trans, "14.7"); 790 } 791 if (init->get_gp_option() == tlm::TLM_MIN_PAYLOAD && trans.get_gp_option() != tlm::TLM_MIN_PAYLOAD) 792 { 793 txt << "Generic payload option attribute modified during transaction lifetime, detected in " << txt2; 794 tlm2error(trans, "14.8 g)"); 795 } 796 if ( !m_map[&trans].has_mm ) 797 { 798 if (trans.has_mm()) 799 { 800 txt << "Interconnect component sets a memory manager, but does not clear it on return, detected in " << txt2; 801 tlm2error(trans, "14.5 aa)"); 802 } 803 804 for (unsigned int i = 0; i < tlm::max_num_extensions(); i++) 805 // Exclude tlm_endian_context extension from the check because it is not cloned in m_map 806 if (i != tlm::tlm_endian_context::ID) 807 if (trans.get_extension(i)) 808 if ( !m_map[&trans].gp->get_extension(i) ) 809 { 810 txt << "Extension set (index = " << i << ") without also being deleted in the absence of a memory manager, detected in " << txt2; 811 tlm2error(trans, "14.5 aa)"); 812 } 813 } 814 815 uchar_t* resp_data_ptr = shared_map[&trans].resp_data_ptr; 816 if (resp_data_ptr) 817 for (unsigned int i = 0; i < trans.get_data_length(); i++) 818 if (trans.get_data_ptr()[i] != resp_data_ptr[i]) 819 { 820 txt << "Transaction data array modified in interconnect component on response path, detected in " << txt2; 821 tlm2error(trans, "14.7"); 822 } 823} 824 825 826BOILERPLATE 827check_response_path( 828 tlm::tlm_generic_payload& trans, const char* txt2 ) 829{ 830 if ( !shared_map[&trans].path.empty() ) 831 { 832 if ( this != shared_map[&trans].path.back() ) 833 { 834 txt << "BEGIN_RESP path is not the reverse of the BEGIN_REQ path."; 835 txt << "\nBEGIN_REQ path includes these checkers: -> "; 836 deque_t path = shared_map[&trans].path; 837 for (deque_t::iterator i = path.begin(); i < path.end(); i++) 838 txt << (*i)->name() << " -> "; 839 txt << "\nDetected in " << txt2; 840 tlm2error(trans, "15.2.11 a)"); 841 } 842 shared_map[&trans].path.pop_back(); 843 shared_map[&trans].response_in_progress = !shared_map[&trans].path.empty(); 844 shared_map[&trans].ok_response = trans.is_response_ok(); 845 846 // Create a copy of the data array for comparison on the response path 847 if ( !shared_map[&trans].resp_data_ptr ) 848 { 849 shared_map[&trans].resp_data_ptr = new uchar_t[trans.get_data_length()]; 850 memcpy(shared_map[&trans].resp_data_ptr, trans.get_data_ptr(), trans.get_data_length()); 851 } 852 } 853} 854 855 856BOILERPLATE 857get_direct_mem_ptr_pre_checks( 858 tlm::tlm_generic_payload& trans, tlm::tlm_dmi& dmi_data ) 859{ 860 remember_gp_option(trans); 861 862 if (dmi_data.get_dmi_ptr() != 0) 863 { 864 txt << "DMI descriptor not properly initialized: dmi_ptr != 0"; 865 tlm2error(trans, "11.2.5 f)"); 866 } 867 if (!dmi_data.is_none_allowed()) 868 { 869 txt << "DMI descriptor not properly initialized: granted_access != DMI_ACCESS_NONE"; 870 tlm2error(trans, "11.2.5 a)"); 871 } 872 if (dmi_data.get_start_address() != 0) 873 { 874 txt << "DMI descriptor not properly initialized: start_address != 0"; 875 tlm2error(trans, "11.2.5 u)"); 876 } 877 if (dmi_data.get_end_address() != (sc_dt::uint64)(-1)) 878 { 879 txt << "DMI descriptor not properly initialized: end_address != 0"; 880 tlm2error(trans, "11.2.5 u)"); 881 } 882 if (dmi_data.get_read_latency() != sc_core::SC_ZERO_TIME) 883 { 884 txt << "DMI descriptor not properly initialized: read_latency != SC_ZERO_TIME"; 885 tlm2error(trans, "11.2.5 ac)"); 886 } 887 if (dmi_data.get_write_latency() != sc_core::SC_ZERO_TIME) 888 { 889 txt << "DMI descriptor not properly initialized: write_latency != SC_ZERO_TIME"; 890 tlm2error(trans, "11.2.5 ac)"); 891 } 892 893 if (trans.get_gp_option() == tlm::TLM_FULL_PAYLOAD) 894 { 895 /* 896 if (trans.is_dmi_allowed()) // Would be rather brutal to flag dmi_allowed as an arror for a DMI transaction! 897 { 898 txt << "DMI transaction not properly initialized: dmi_allowed == true"; 899 tlm2error(trans, "14.8 e) & 14.16"); 900 } 901 */ 902 if (trans.get_response_status() != tlm::TLM_INCOMPLETE_RESPONSE) 903 { 904 txt << "DMI transaction not properly initialized: response_status != TLM_INCOMPLETE_RESPONSE"; 905 tlm2error(trans, "14.8 e) & 14.17 e)"); 906 } 907 } 908 else if (trans.get_gp_option() == tlm::TLM_FULL_PAYLOAD_ACCEPTED) 909 { 910 txt << "DMI transaction not properly initialized: gp_option == TLM_FULL_PAYLOAD_ACCEPTED"; 911 tlm2error(trans, "14.8 c) & e) & j)"); 912 } 913} 914 915 916BOILERPLATE 917get_direct_mem_ptr_post_checks( tlm::tlm_generic_payload& trans, tlm::tlm_dmi& dmi_data ) 918{ 919 tlm::tlm_generic_payload* init = m_map[&trans].gp; 920 921 if (init->get_gp_option() == tlm::TLM_MIN_PAYLOAD && trans.get_gp_option() != tlm::TLM_MIN_PAYLOAD) 922 { 923 txt << "DMI transaction gp_option attribute value TLM_MIN_PAYLOAD modified during transaction lifetime"; 924 tlm2error(trans, "14.8 h)"); 925 } 926 else if (init->get_gp_option() == tlm::TLM_FULL_PAYLOAD && trans.get_gp_option() == tlm::TLM_MIN_PAYLOAD) 927 { 928 txt << "DMI transaction gp_option attribute value changed from TLM_FULL_PAYLOAD to TLM_MIN_PAYLOAD"; 929 tlm2error(trans, "14.8 j)"); 930 } 931} 932 933 934BOILERPLATE 935transport_dbg_pre_checks( tlm::tlm_generic_payload& trans ) 936{ 937 remember_gp_option(trans); 938 939 if (trans.get_data_length() > 0 && trans.get_data_ptr() == 0) 940 { 941 txt << "Debug transaction has data_ptr == 0"; 942 tlm2error(trans, "11.3.4 l)"); 943 } 944 945 if (trans.get_gp_option() == tlm::TLM_FULL_PAYLOAD) 946 { 947 if (trans.get_byte_enable_ptr() != 0 && trans.get_byte_enable_length() == 0) 948 { 949 txt << "Debug transaction not properly initialized: " 950 << "byte_enable_ptr != 0 and byte_enable_length == 0"; 951 tlm2error(trans, "14.8 f) & 14.14 f)"); 952 } 953 if (trans.get_streaming_width() == 0) 954 { 955 txt << "Debug transaction not properly initialized: streaming_width == 0"; 956 tlm2error(trans, "14.8 f) & 14.15 f)"); 957 } 958 if (trans.is_dmi_allowed()) 959 { 960 txt << "Debug transaction not properly initialized: dmi_allowed == true"; 961 tlm2error(trans, "14.8 f) & 14.16"); 962 } 963 if (trans.get_response_status() != tlm::TLM_INCOMPLETE_RESPONSE) 964 { 965 txt << "Debug transaction not properly initialized: response_status != TLM_INCOMPLETE_RESPONSE"; 966 tlm2error(trans, "14.8 f) & 14.17 e)"); 967 } 968 } 969 else if (trans.get_gp_option() == tlm::TLM_FULL_PAYLOAD_ACCEPTED) 970 { 971 txt << "Debug transaction not properly initialized: gp_option == TLM_FULL_PAYLOAD_ACCEPTED"; 972 tlm2error(trans, "14.8 c) & f) & l)"); 973 }} 974 975 976BOILERPLATE 977transport_dbg_post_checks( tlm::tlm_generic_payload& trans, unsigned int count ) 978{ 979 tlm::tlm_generic_payload* init = m_map[&trans].gp; 980 981 if (trans.get_data_length() > 0 && trans.get_data_ptr() == 0) 982 { 983 txt << "Debug transaction has data_ptr == 0"; 984 tlm2error(trans, "11.3.4 l)"); 985 } 986 if (count > trans.get_data_length()) 987 { 988 txt << "Count returned from transport_dbg is greater than data_length"; 989 tlm2error(trans, "11.3.4 s)"); 990 } 991 992 if (init->get_gp_option() == tlm::TLM_MIN_PAYLOAD && trans.get_gp_option() != tlm::TLM_MIN_PAYLOAD) 993 { 994 txt << "Debug transaction gp_option attribute value TLM_MIN_PAYLOAD modified during transaction lifetime"; 995 tlm2error(trans, "14.8 h)"); 996 } 997 else if (init->get_gp_option() == tlm::TLM_FULL_PAYLOAD && trans.get_gp_option() == tlm::TLM_MIN_PAYLOAD) 998 { 999 txt << "Debug transaction gp_option attribute value changed from TLM_FULL_PAYLOAD to TLM_MIN_PAYLOAD"; 1000 tlm2error(trans, "14.8 l)"); 1001 }} 1002 1003 1004BOILERPLATE 1005tlm2error( tlm::tlm_generic_payload& trans, const char* ref, bool warning ) 1006{ 1007 txt << "\n\nRefer to IEEE Std 1666-2011, clause " << ref; 1008 txt << "\n\nChecker instance: " << this->name(); 1009 txt << "\n\nTransaction details:"; 1010 txt << "\n has_mm = " << dec << trans.has_mm() << " (bool)"; 1011 txt << "\n ref_count = " << dec << trans.get_ref_count() << " (int)"; 1012 txt << "\n\n gp_option = " << 1013 (trans.get_gp_option() == tlm::TLM_MIN_PAYLOAD ? "TLM_MIN_PAYLOAD" 1014 :trans.get_gp_option() == tlm::TLM_FULL_PAYLOAD ? "TLM_FULL_PAYLOAD" 1015 : "TLM_FULL_PAYLOAD_ACCEPTED"); 1016 txt << "\n command = " << 1017 (trans.get_command() == tlm::TLM_READ_COMMAND ? "TLM_READ_COMMAND" 1018 :trans.get_command() == tlm::TLM_WRITE_COMMAND ? "TLM_WRITE_COMMAND" 1019 : "TLM_IGNORE_COMMAND"); 1020 txt << "\n address = " << hex << trans.get_address() << " (hex)"; 1021 txt << "\n data_ptr = " << hex 1022 << reinterpret_cast<int*>(trans.get_data_ptr()) << " (hex)"; 1023 txt << "\n data_length = " << hex << trans.get_data_length() << " (hex)"; 1024 txt << "\n streaming_width = " << hex << trans.get_streaming_width() << " (hex)"; 1025 txt << "\n byte_enable_ptr = " << hex 1026 << reinterpret_cast<int*>(trans.get_byte_enable_ptr()) << " (hex)"; 1027 txt << "\n byte_enable_length = " << hex << trans.get_byte_enable_length() << " (hex)"; 1028 txt << "\n dmi_allowed = " << dec << trans.is_dmi_allowed() << " (bool)"; 1029 txt << "\n response_status = " << trans.get_response_string(); 1030 1031 bool extensions_present = false; 1032 for (unsigned int i = 0; i < tlm::max_num_extensions(); i++) 1033 { 1034 tlm::tlm_extension_base* ext = trans.get_extension(i); 1035 if (ext) 1036 { 1037 if (!extensions_present) 1038 txt << "\n\n extensions:"; 1039 txt << "\n index = " << i << " type = " << typeid(*ext).name(); 1040 extensions_present = true; 1041 } 1042 } 1043 1044 txt << "\n\n"; 1045 if (warning) 1046 SC_REPORT_WARNING("tlm2_protocol_checker", txt.str().c_str()); 1047 else 1048 SC_REPORT_ERROR("tlm2_protocol_checker", txt.str().c_str()); 1049} 1050 1051 1052 1053} // namespace tlm_utils 1054 1055#endif // __tlm2_base_protocol_checker__ 1056